6.4.2 Взаимодействие с операционной системой через вызовы системных функций

We use cookies. Read the Privacy and Cookie Policy

6.4.2 Взаимодействие с операционной системой через вызовы системных функций

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

Рисунок 6.11. Примеры прерываний

Обрабатывая внутреннее прерывание операционной системы, ядро по номеру системной функции ведет в таблице поиск адреса соответствующей процедуры ядра, то есть точки входа системной функции, и количества передаваемых функции параметров (Рисунок 6.12). Ядро вычисляет адрес (пользовательский) первого параметра функции, прибавляя (или вычитая, в зависимости от направления увеличения стека) смещение к указателю вершины стека задачи (аналогично для всех параметров функции). Наконец, ядро копирует параметры задачи в пространство процесса и вызывает соответствующую процедуру, которая выполняет системную функцию. После исполнения процедуры ядро выясняет, не было ли ошибки. Если ошибка была, ядро делает соответствующие установки в сохраненном регистровом контексте задачи, при этом в регистре PS обычно устанавливается бит переноса, а в нулевой регистр заносится номер ошибки. Если при выполнении системной функции не было ошибок, ядро очищает в регистре PS бит переноса и заносит возвращаемые функцией значения в регистры 0 и 1 в сохраненном регистровом контексте задачи. Когда ядро возвращается после обработки внутреннего прерывания операционной системы в режим задачи, оно попадает в следующую библиотечную инструкцию после прерывания. Библиотечная функция интерпретирует возвращенные ядром значения и передает их программе пользователя.

алгоритм syscall /* алгоритм запуска системной функции */

входная информация: номер системной функции

выходная информация: результат системной функции

{

 найти запись в таблице системных функций, соответствующую указанному номеру функции;

 определить количество параметров, передаваемых функции;

 скопировать параметры из адресного пространства задачи в пространство процесса;

 сохранить текущий контекст для аварийного завершения (см. раздел 6.44);

 запустить в ядре исполняемый код системной функции;

 if (во время выполнения функции произошла ошибка) {

  установить номер ошибки в нулевом регистре сохраненного регистрового контекста задачи;

  включить бит переноса в регистре PS сохраненного регистрового контекста задачи;

 }

 else

  занести возвращаемые функцией значения в регистры 0 и 1 в сохраненном регистровом контексте задачи;

}

Рисунок 6.12. Алгоритм обращения к системным функциям

В качестве примера рассмотрим программу, которая создает файл с разрешением чтения и записи в него для всех пользователей (режим доступа 0666) и которая приведена в верхней части Рисунка 6.13. Далее на рисунке изображен отредактированный фрагмент сгенерированного кода программы после компиляции и дисассемблирования (создания по объектному коду эквивалентной программы на языке ассемблера) в системе Motorola 68000. На Рисунке 6.14 изображена конфигурация стека для системной функции создания. Компилятор генерирует программу помещения в стек задачи двух параметров, один из которых содержит установку прав доступа (0666), а другой — переменную «имя файла»[18]. Затем из адреса 64 процесс вызывает библиотечную функцию creat (адрес 7a), аналогичную соответствующей системной функции. Адрес точки возврата из функции 6a, этот адрес помещается процессом в стек. Библиотечная функция creat засылает в регистр 0 константу 8 и исполняет команду прерывания (trap), которая переключает процесс из режима задачи в режим ядра и заставляет его обратиться к системной функции. Заметив, что процесс вызывает системную функцию, ядро выбирает из регистра 0 номер функции (8) и определяет таким образом, что вызвана функция creat. Просматривая внутреннюю таблицу, ядро обнаруживает, что системной функции creat необходимы два параметра; восстанавливая регистровый контекст предыдущего уровня, ядро копирует параметры из пользовательского пространства в пространство процесса. Процедуры ядра, которым понадобятся эти параметры, могут найти их в определенных местах адресного пространства процесса. По завершении исполнения кода функции creat управление возвращается программе обработки обращений к операционной системе, которая проверяет, установлено ли поле ошибки в пространстве процесса (то есть имела ли место во время выполнения функции ошибка); если да, программа устанавливает в регистре PS бит переноса, заносит в регистр 0 код ошибки и возвращает управление ядру. Если ошибок не было, в регистры 0 и 1 ядро заносит код завершения. Возвращая управление из программы обработки обращений к операционной системе в режим задачи, библиотечная функция проверяет состояние бита переноса в регистре PS (по адресу 7): если бит установлен, управление передается по адресу 13c, из нулевого регистра выбирается код ошибки и помещается в глобальную переменную errno по адресу 20, в регистр 0 заносится -1, и управление возвращается на следующую после адреса 64 (где производится вызов функции) команду. Код завершения функции имеет значение -1, что указывает на ошибку в выполнении системной функции. Если же бит переноса в регистре PS при переходе из режима ядра в режим задачи имеет нулевое значение, процесс с адреса 7 переходит по адресу 86 и возвращает управление вызвавшей программе (адрес 64); регистр 0 содержит возвращаемое функцией значение.

char name[] = "file";

main() {

 int fd;

 fd = creat(name, 0666);

}

Фрагменты ассемблерной программы, сгенерированной в системе Motorola 68000

Адрес Команда

         —

# текст главной программы

         —

58: mov &0x1b6, (%sp) # поместить код 0666 в стек

5e: mov &0x204, -(%sp) # поместить указатель вершины стека и переменную «имя файла» в стек

64: jsr 0x7a # вызов библиотечной функции создания файла

         —

# текст библиотечной функции создания файла

7a: movq &0x8, %d0 # занести значение 8 в регистр 0

7c: trap &0x0 # внутреннее прерывание операционной системы

7e: bcc &0x6 ‹86› # если бит переноса очищен, перейти по адресу 86

80: jmp 0x13c # перейти по адресу 13c

86: rts # возврат из подпрограммы

        —

# текст обработки ошибок функции

13c: mov %d0, &0x20e # поместить содержимое регистра 0 в ячейку 20e (переменная errno)

142: movq &-0x1, %d0 # занести в регистр 0 константу -1

144: mova %d0, %a0

146: rts # возврат из подпрограммы

Рисунок 6.13. Системная функция creat и сгенерированная программа ее выполнения в системе Motorola 68000

Рисунок 6.14. Конфигурация стека для системной функции creat

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