Главная » Ядро Linux » Вызовы syscall

0

Системные вызовы (часто  называемые syscall в ОС  Linux)  обычно реализуются в виде  вызова  функции. Для  них  могут  быть  определены один   или  более  аргументов (inputs), которые могут  приводить к тем  или  иным побочным эффектам3 , например к записи данных  в файл  или  к копированию некоторых данных  в область  памяти, на которую указывает переданный  указатель. Системные  вызовы также  имеют  возвращаемое значение типа  long 4 , которое указывает на  успешность выполнения  операции  или  на возникшие ошибки. Обычно, но  не всегда, возвращение отрицательного значения указывает на  то, что  произошла ошибка. Возвращение нулевого значения обычно (но  не  всегда)  указывает на  успешность выполнения операции. Системные вызовы ОС  Unix  в  случае  ошибки записывают специальный код  ошибки в  глобальную  переменную errno . Значение этой  переменной может  быть  переведено в удобочитаемую формy  с помощью библиотечной функции perro r () .

Системные вызовы, конечно, имеют  определенное поведение. Например, системный  вызов   getpi d  ()  определен для  того,  чтобы  возвращать целочисленное  значение,  равное значению идентификатора PID  текущего процесса.  Реализация  этой функции в ядре  очень  проста.

3Следует   обратит ь  внимани е  на  слово   "могут".   Хотя   почти   вге  вызовы  создают   различны е  побочные  эффект ы  (т.е.  приводят к  каким-либо иэменениям в  состоянии  системы), тем  не  менее  небольшое  количество вызовов, как,  например,  вызов   getpid (),  просто возвращают некоторы е данные ядра.

4Тип   long используется для  совместимости с  64-разрядными платформами.

asmlinkage long sys_getpid(void)

{

return current->tgid;

)

Следует  заметить, что  в определении ничего  не  говорится о способе реализации. Ядро  должно обеспечить необходимую функциональность системного вызова, но  реализация может  быть  абсолютно свободной,  главное,  чтобы  результат  был  правильный.  Конечно,  рассматриваемый системный вызов  в действительности является таким  же простым, как  и показано, и существует не так уж много  различных вариантов для  его  реализации (на  самом  деле  более  простого метода  не  существует)5.

Даже   из  такого   пример а  можно сделать   пару  наблюдений,  которы е  касаются  системных вызовов.  Во-первых,  следует  обратить внимание  на  модификатор asmlinkag e  в объявлении функции. Это  волшебное слово  дает компилятору информацию о том, что  обращение к  аргументам этой   функции  должно производиться только  через  стек.  Для  всех  системных вызовов использование этого  модификатора является обязательным. Во-вторых, следует  обратить внимание,  что  системный вызов  getpi d ()   объявлен в ядре, как  sys_getpi d () .  Это  соглашение о присваивании имен   используется для  всех  системных вызовов операционной  системы Linux:  системный вызов  ba r ()   должен  быть  реализован с  помощью функции  sys_ba r () .

Номера системных вызовов

Каждому системному  вызову  операционной  системы Linux  присваивается  номер системного вызова (syscall number). Этот уникальный номер  используется для обращения к  определенному системному вызову.   Когда  процесс выполняет системный вызов  из пространства пользователя,  процесс не  обращается к системному вызову  по  имени.

Номер системного вызова  является важным атрибутом. Однажды назначенный номер  не должен   меняться никогда,  иначе  это  нарушит работу  уже скомпилированных  прикладных программ.  Если  системный  вызов  удаляется,  то  соответствующий номер  не  может  использоваться повторно. В операционной системе Linux  предусмотрен  так  называемый "не  реализованный" ("not  implemented") системный  вызов  — функция  sys_ni_syscal l  () , которая не делает  ничего, кроме  того, что возвращает значение, равное -ENOSYS, — код  ошибки,  соответствующий неправильному системному  вызову.   Эта  функция служит  для  "затыкания дыр"  в случае  такого  редкого событии, как  удаление системного  вызова.

Ядро  поддерживает список  зарегистрированных системных  вызовов  в  таблице системных вызовов. Эта  таблица хранится в памяти, на  которую указывает переменная  sys_call_table .  Данная таблица зависит от аппаратной платформы  и  обычно определяется в файле  entry.S .  В таблице системных вызовов каждому  уникальному номеру  системного  вызова   назначается существующая функция  syscall .

5 Может быть,  интересно , почему вызо в  getpi d ()   возвращает поле  tgid,  которое является идентификаторо м  группы потоков (thread group  ID)? Это  делается потому, что  дли  обычных процессов значение параметра TGID равно  значению параметра PID.  Пр и наличии нескольких потоков  значение параметра TGID  одинаково дли  всек  потоков одной группы. Такая реализация дает  возможность  различным  потокам   вызывать  функцию  getpid ()  и  получать  одинаковое значение  параметра  PID.

Производительность системных  вызовов

Системные  вызовы  в операционной  системе  Linux  работают быстрее,  чем  во многих  других  операционных  системах. Это  отчасти  связано с  невероятно малым временем переключения контекста. Переход в режим  ядра  и выход  из него  являются хорошо отлаженным процессом и простым делом.  Другой  фактор — это  простота как механизма обработки системных вызовов, так  и  самих  системных вызовов.

Источник: Лав,  Роберт. Разработка ядра  Linux, 2-е  издание. : Пер.  с англ.  — М.  : ООО  «И.Д.  Вильяме» 2006. — 448 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии