Читать «Разработка ядра Linux» онлайн - страница 76

Роберт Лав

long open(const char *filename, int flags, int mode)

Макрос для вызова этой системной функции будет выглядеть так.

#define NR_open 5

_syscall3(long, NR_open, const char*, filename, int, flags, int, mode);

После этого приложение может просто вызывать функцию open().

Каждый макрос принимает 2 + 2*n параметров. Первый параметр соответствует типу возвращаемого значения системного вызова. Второй параметр — имя системного вызова. После этого следуют тип и имя каждого параметра в том же порядке, что и у системного вызова. Постоянная NR_open, которая определена в файле <asm/unistd.h>, — это номер системного вызова. В функцию на языке программирования С такой вызов превращается с помощью вставок на языке ассемблера, которые выполняют рассмотренные в предыдущем разделе шаги. Значения аргументов помещаются в соответствующие регистры, и выполняется программное прерывание, которое перехватывается в режиме ядра. Вставка данного макроса в приложение — это все, что необходимо для выполнения системного вызова open().

Напишем макрос, который позволяет вызвать нашу замечательную системную функцию, и соответствующий код, который позволяет этот вызов протестировать.

#define __NR_foo 283

__syscall0()(long, foo)

int main() {

 long stack_size;

stack_size = foo();

 printf("Размер стека ядра равен %ld\n" , stack_size);

 return 0;

}

Почему не нужно создавать системные вызовы

Новый системный вызов легко реализовать, тем не менее это необходимо делать только тогда, когда ничего другого не остается. Часто, для того чтобы обеспечить новый системный вызов, существуют более подходящие варианты. Давайте рассмотрим некоторые "за" и "против" и возможные варианты.

Для создания нового интерфейса в виде системного вызова могут быть следующие "за".

• Системные вызовы просто реализовать и легко использовать.

• Производительность системных вызовов в операционной системе Linux очень высока.

Возможные "против".

• Необходимо получить номер системного вызова, который должен быть официально назначен в период работы над разрабатываемыми сериями ядер.

• После того как системный вызов включен в стабильную серию ядра, он становится "высеченным в камне". Интерфейс не должен меняться, чтобы не нарушить совместимости с прикладными пользовательскими программами.

• Для каждой аппаратной платформы необходимо регистрировать отдельный системный вызов и осуществлять его поддержку.

• Для простого обмена информацией системный вызов — это "стрельба из пушки по воробьям".

Возможные варианты.

• Реализовать файл устройства и использовать функции read() и write() для этого устройства, а также использовать функцию ioctl() для манипуляции специфическими параметрами или для получения специфической информации.