Linux Kernel (Ядро линукса) (часть 2)


Системные вызовы

Операционные системы предлагают процессам, работающим в режиме пользователя, набор интерфейсов для взаимодействия с аппаратными устройствами, такими как процессор, диски или принтеры. Создание дополнительного программного слоя между приложением и аппаратной частью компьютера имеет ряд преимуществ. Во-первых, это облегчает программирование, потому что программисты избавлены от необходимости изучать низкоуровневые характеристики аппаратных устройств. Во-вторых, такой подход существенно повышает безопасность системы, поскольку ядро может проверить корректность запроса на уровне интерфейса до выполнения этого запроса. Наконец, что не менее важно, подобные интерфейсы делают программы более переносимыми, позволяя компилировать и корректно выполнять их в каждом ядре, предлагающем такой же набор интерфейсов.

В Unix-системах большинство интерфейсов между процессами режима пользователя и аппаратными устройствами реализовано с помощью системных вызовов, направляемых ядру. В этой главе подробно рассматривается, как Linux реализует системные вызовы, передаваемые ядру пользовательскими программами.
API-интерфейсы стандарта POSIX и системные вызовы.

Мы начнем с обсуждения различия между API (Application Programmer Interface, интерфейс прикладного программирования) и системным вызовом. Первый представляет собой определение функции, описывающее, как получить данную услугу, а второй является явным запросом к ядру, выполненным с помощью программного прерывания.

Unix-системы включают в себя несколько библиотек функций, предоставляющих программистам API-интерфейсы. Некоторые из интерфейсов, определенных в стандартной библиотеке С, называемой libc, обращаются к интерфейсным процедурам (процедурам, единственным назначением которых является выдача системного вызова). Обычно каждый системный вызов имеет интерфейсную процедуру, определяющую API-интерфейс, которому должна следовать прикладная программа.

Между прочим, обратное неверно. Интерфейс API не обязательно соответствует какому-либо системному вызову. Во-первых, API может предлагать свои услуги непосредственно в режиме пользователя. (Для таких абстрактных функций, какими являются математические, нет смысла делать системные вызовы.) Во-вторых, одна API-функция может сделать несколько системных вызовов. Более того, несколько API-функций могут делать один и тот же системный вызов, но нагружать” его дополнительными особенностями. Например, в Linux API-функции maiioc , caiioc и free реализованы в библиотеке libc. Код в этой библиотеке отслеживает запросы на выделение и освобождение памяти и использует системный вызов brk о для увеличения или уменьшения кучи процесса
Стандарт POSIX описывает API-интерфейсы, но не системные вызовы. Система может быть сертифицирована как удовлетворяющая стандарту POSIX, если она предоставляет прикладным программам надлежащий набор API- интерфейсов, независимо от того, как реализованы соответствующие функции. На практике несколько систем, не являющихся Unix-подобными, были сертифицированы как удовлетворяющие стандарту POSIX, поскольку они предлагали все традиционные службы Unix в своих библиотеках режима пользователя.

С точки зрения программиста, различие между API и системным вызовом не имеет значения. Единственное, что ему нужно знать, — это имя функции, типы параметров и смысл возвращаемого значения. Зато с точки зрения разработчика ядра это различие принципиально, ведь системные вызовы принадлежат ядру, а библиотеки режима пользователя — нет.

Большинство интерфейсных процедур возвращает целое значение, смысл которого зависит от системного вызова. Код возврата -1, как правило, указывает на то, что ядро не смогло удовлетворить запрос процесса. Неудача обработчика системного вызова могла быть следствием некорректных параметров, недостатка системных ресурсов, аппаратных проблем и т. п. Конкретный код ошибки содержится в переменной errno, которая определена в библиотеке libc.
Каждый код ошибки определен в виде макроконстанты, возвращающей положительное значение. Стандарт POSIX устанавливает имена макросов для
некоторых кодов ошибок. В Linux, на платформе 80x86 , эти макросы определены в заголовочном файле include/asm-i386/ermo.h. Для обеспечения переносимости программ на языке С между системами Unix заголовочный файл include/asm-i386/ermo.h, в свою очередь, включен в стандартный заголовочный файл библиотеки С, называемый /usr/include/ermo.h. Другие системы имеют свои собственные специализированные подкаталоги для заголовочных файлов.

Предыдущая страница | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без про...

ВведениеЕсли вы цените свое время, умеете считать деньги и знаете стоимость информации, то эта книга...

Linux Kernel (Ядро линукса) (ч...

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть...

Linux Kernel (Ядро линукса) (ч...

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно...

Linux Kernel (Ядро линукса) (ч...

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer...