The design of the unix operating system by Maurice J
Вид материала | Реферат |
- Лекция 10. Файловые системы Unix, 116.79kb.
- Уровни рассмотрения, 314.07kb.
- Курс по операционным системам (на примере ос windows) Основан на учебном курсе Windows, 29.21kb.
- Выполнил ученик 11 «А» класса, 443.51kb.
- Ос лекция 1 (2-й семестр – временно), 101.4kb.
- Operating System, 7686.97kb.
- Unix-подобные операционные системы, характеристики, особенности, разновидности, 40.63kb.
- 1. ms sql server. Общие сведения, 66.03kb.
- Shanti ananda maurice, 89.84kb.
- Методические материалы, 3002.45kb.
│ │ │
│ │ Сохранить регистровый кон- │
│ │ текст пользовательского │
│ │ уровня │
Вызов системной функции L--------------------------------
│
│
│
│
│
│
Исполнение в режиме задачи
Рисунок 6.11. Примеры прерываний
На Рисунке 6.11 показан пример, в котором процесс запрашивает
выполнение системной функции (см. следующий раздел) и получает
прерывание от диска при ее выполнении. Запустив программу обра-
ботки прерывания от диска, система получает прерывание по таймеру
и вызывает уже программу обработки прерывания по таймеру. Каждый
раз, когда система получает прерывание (или вызывает системную
функцию), она создает в стеке новый контекстный уровень и сохра-
няет регистровый контекст предыдущего уровня.
6.4.2 Взаимодействие с операционной системой через вызовы
системных функций
Такого рода взаимодействие с ядром было предметом рассмотре-
ния в предыдущих главах, где шла речь об обычном вызове функций.
Очевидно, что обычная последовательность команд обращения к функ-
ции не в состоянии переключить выполнения процесса с режима зада-
чи на режим ядра. Компилятор с языка Си использует библиотеку
функций, имена которых совпадают с именами системных функций,
иначе ссылки на системные функции в пользовательских программах
были бы ссылками на неопределенные имена. В библиотечных функциях
обычно исполняется команда, переводящая выполнение процесса в ре-
жим ядра и побуждающая ядро к запуску исполняемого кода системной
функции. В дальнейшем эта команда именуется "внутренним прерыва-
нием операционной системы". Библиотечные процедуры исполняются в
режиме задачи, а взаимодействие с операционной системой через вы-
зов системной функции можно определить в нескольких словах как
особый случай программы обработки прерывания. Библиотечные функ-
ции передают ядру уникальный номер системной функции одним из ма-
шинно-зависимых способов - либо как параметр внутреннего прерыва-
ния операционной системы, либо через отдельный регистр, либо
через стек - а ядро таким образом определяет тип вызываемой функ-
ции.
-------------------------------------------------------------┐
│ алгоритм syscall /* алгоритм запуска системной функции */│
│ входная информация: номер системной функции │
│ выходная информация: результат системной функции │
│ { │
│ найти запись в таблице системных функций, соответствую-│
│ щую указанному номеру функции; │
│ определить количество параметров, передаваемых функции;│
│ скопировать параметры из адресного пространства задачи │
│ в пространство процесса; │
│ сохранить текущий контекст для аварийного завершения │
│ (см. раздел 6.44); │
│ запустить в ядре исполняемый код системной функции; │
│ если (во время выполнения функции произошла ошибка) │
│ { │
│ установить номер ошибки в нулевом регистре сохра- │
│ ненного регистрового контекста задачи; │
│ включить бит переноса в регистре PS сохраненного │
│ регистрового контекста задачи; │
│ } │
│ в противном случае │
│ занести возвращаемые функцией значения в регистры 0 │
│ и 1 в сохраненном регистровом контексте задачи; │
│ } │
L-------------------------------------------------------------
Рисунок 6.12. Алгоритм обращения к системным функциям
Обрабатывая внутреннее прерывание операционной системы, ядро
по номеру системной функции ведет в таблице поиск адреса соот-
ветствующей процедуры ядра, то есть точки входа системной функ-
ции, и количества передаваемых функции параметров (Рисунок 6.12).
Ядро вычисляет адрес (пользовательский) первого параметра функ-
ции, прибавляя (или вычитая, в зависимости от направления увели-
чения стека) смещение к указателю вершины стека задачи (аналогич-
но для всех параметров функции). Наконец, ядро копирует параметры
задачи в пространство процесса и вызывает соответствующую проце-
дуру, которая выполняет системную функцию. После исполнения про-
цедуры ядро выясняет, не было ли ошибки. Если ошибка была, ядро
делает соответствующие установки в сохраненном регистровом кон-
тексте задачи, при этом в регистре PS обычно устанавливается бит
переноса, а в нулевой регистр заносится номер ошибки. Если при
выполнении системной функции не было ошибок, ядро очищает в ре-
гистре PS бит переноса и заносит возвращаемые функцией значения в
регистры 0 и 1 в сохраненном регистровом контексте задачи. Когда
ядро возвращается после обработки внутреннего прерывания операци-
онной системы в режим задачи, оно попадает в следующую библиотеч-
ную инструкцию после прерывания. Библиотечная функция интерпрети-
рует возвращенные ядром значения и передает их программе пользо-
вателя.
В качестве примера рассмотрим программу, которая создает файл
с разрешением чтения и записи в него для всех пользователей (ре-
жим доступа 0666) и которая приведена в верхней части Рисунка
6.13. Далее на рисунке изображен отредактированный фрагмент сге-
нерированного кода программы после компиляции и дисассемблирова-
ния (создания по объектному коду эквивалентной программы на языке
ассемблера) в системе Motorola 68000. На Рисунке 6.14 изображена
конфигурация стека для системной функции создания. Компилятор ге-
нерирует программу помещения в стек задачи двух параметров, один
из которых содержит установку прав доступа (0666), а другой - пе-
ременную "имя файла" (**). Затем из адреса 64 процесс вызывает
библиотечную функцию creat (адрес 7a), аналогичную соответствую-
щей системной функции. Адрес точки возврата из функции - 6a, этот
адрес помещается процессом в стек. Библиотечная функция creat за-
сылает в регистр 0 константу 8 и исполняет команду прерывания
(trap), которая переключает процесс из режима задачи в режим ядра
и заставляет его обратиться к системной функции. Заметив, что
процесс вызывает системную функцию, ядро выбирает из регистра 0
номер функции (8) и определяет таким образом, что вызвана функция
creat. Просматривая внутреннюю таблицу, ядро обнаруживает, что
системной функции creat необходимы два параметра; восстанавливая
регистровый контекст предыдущего уровня, ядро копирует параметры
из пользовательского пространства в пространство процесса. Проце-
дуры ядра, которым понадобятся эти параметры, могут найти их в
определенных местах адресного пространства процесса. По заверше-
нии исполнения кода функции creat управление возвращается прог-
рамме обработки обращений к операционной системе, которая прове-
ряет, установлено ли поле ошибки в пространстве процесса (то есть
имела ли место во время выполнения функции ошибка); если да,
программа устанавливает в регистре PS бит переноса, заносит в ре-
гистр 0 код ошибки и возвращает управление ядру. Если ошибок не
было, в регистры 0 и 1 ядро заносит код завершения. Возвращая уп-
---------------------------------------
(**) Очередность, в которой компилятор вычисляет и помещает в
стек параметры функции, зависит от реализации системы.
-----------------------------------------┐
│ char name[] = "file"; │
│ main() │
│ { │
│ int fd; │
│ fd = creat(name,0666); │
│ } │
L-----------------------------------------
----------------------------------------------------------------┐
│ Фрагменты ассемблерной программы, сгенерированной в │
│ системе Motorola 68000 │
│ │
│ Адрес Команда │
│ │
│ │
│ # текст главной программы │
│ │
│ 58: mov &Ox1b6,(%sp) # поместить код 0666 в стек │
│ 5e: mov &Ox204,-(%sp) # поместить указатель вершины │
│ # стека и переменную "имя файла"│
│ # в стек │
│ 64: jsr Ox7a # вызов библиотечной функции │
│ # создания файла │
│ │
│ │
│ # текст библиотечной функции создания файла │
│ 7a: movq &Ox8,%d0 # занести значение 8 в регистр 0│
│ 7c: trap &Ox0 # внутреннее прерывание операци-│
│ # онной системы │
│ 7e: bcc &Ox6 <86> # если бит переноса очищен, │
│ # перейти по адресу 86 │
│ 80: jmp Ox13c # перейти по адресу 13c │
│ 86: rts # возврат из подпрограммы │
│ │
│ │
│ # текст обработки ошибок функции │
│ 13c: mov %d0,&Ox20e # поместить содержимое регистра │
│ # 0 в ячейку 20e (переменная │
│ # errno) │
│ 142: movq &-Ox1,%d0 # занести в регистр 0 константу │
│ # -1 │
│ 144: mova %d0,%a0 │
│ 146: rts # возврат из подпрограммы │
L----------------------------------------------------------------
Рисунок 6.13. Системная функция creat и сгенерированная прог-
рамма ее выполнения в системе Motorola 68000
равление из программы обработки обращений к операционной системе
в режим задачи, библиотечная функция проверяет состояние бита пе-
реноса в регистре PS (по адресу 7): если бит установлен, управле-
ние передается по адресу 13c, из нулевого регистра выбирается код
ошибки и помещается в глобальную переменную errno по адресу 20, в
регистр 0 заносится -1, и управление возвращается на следующую
после адреса 64 (где производится вызов функции) команду. Код за-
вершения функции имеет значение -1, что указывает на ошибку в вы-
полнении системной функции. Если же бит переноса в регистре PS
при переходе из режима ядра в режим задачи имеет нулевое значе-
ние, процесс с адреса 7 переходит по адресу 86 и возвращает уп-
равление вызвавшей программе (адрес 64); регистр 0 содержит возв-
ращаемое функцией значение.
----------┐ │ │
│ │ │ │
│ │ │ │
│ │ │стек ядра для кон-│
│ │ │текстного уровня 1│
+---------+ │ │
│ 1b6 │ код режима доступа │последовательность│
│ │ (666 в восьмиричной системе) │команд обращения к│
│ 204 │ адрес переменной "имя файла" │ функции creat │
│ 6a │ адрес точки возврата после +------------------+
│ │ вызова библиотечной функции │сохраненный регис-│
+---------+<-----┐ │ тровый контекст │
│ внутрен-│ │ │ для уровня 0 │
│ нее пре-│ │ │(пользовательско- │
│ рывание │ значение указателя │ го) │
│ в │ вершины стека в мо- │ │
│ 7c │ мент внутреннего пре- │ счетчик команд, │
L---------- рывания операционной │ установленный на │
направление системы │ 7e │
увеличения стека │ │
│ │указатель вершины │
│ │ стека │
v │ │
│ регистр PS │
│ │
│регистр 0 (введено│
│ значение 8) │
│ │
│ другие регистры │
│общего назначения │
L-------------------
Рисунок 6.14. Конфигурация стека для системной функции creat
Несколько библиотечных функций могут отображаться на одну
точку входа в список системных функций. Каждая точка входа опре-
деляет точные синтаксис и семантику обращения к системной функ-
ции, однако более удобный интерфейс обеспечивается с помощью биб-
лиотек. Существует, например, несколько конструкций системной
функции exec, таких как execl и execle, выполняющих одни и те же
действия с небольшими отличиями. Библиотечные функции, соответс-
твующие этим конструкциям, при обработке параметров реализуют за-
явленные свойства, но в конечном итоге, отображаются на одну и ту
же функцию ядра.
6.4.3 Переключение контекста
Если обратиться к диаграмме состояний процесса (Рисунок 6.1),
можно увидеть, что ядро разрешает производить переключение кон-
текста в четырех случаях: когда процесс приостанавливает свое вы-
полнение, когда он завершается, когда он возвращается после вызо-
ва системной функции в режим задачи, но не является наиболее под-
ходящим для запуска, или когда он возвращается в режим задачи
после завершения ядром обработки прерывания, но так же не являет-
ся наиболее подходящим для запуска. Как уже было показано в главе
2, ядро поддерживает целостность и согласованность своих внутрен-
них структур данных, запрещая произвольно переключать контекст.
Прежде чем переключать контекст, ядро должно удостовериться в
согласованности своих структур данных: то есть в том, что сделаны
все необходимые корректировки, все очереди выстроены надлежащим
образом, установлены соответствующие блокировки, позволяющие из-
бежать вмешательства со стороны других процессов, что нет излиш-
них блокировок и т.д. Например, если ядро выделяет буфер, считы-
вает блок из файла и приостанавливает выполнение до завершения
передачи данных с диска, оно оставляет буфер заблокированным,
чтобы другие процессы не смогли обратиться к буферу. Но если про-
цесс исполняет системную функцию link, ядро снимает блокировку с
первого индекса перед тем, как снять ее со второго индекса, и тем
самым предотвращает возникновение тупиковых ситуаций (взаимной
блокировки).
Ядро выполняет переключение контекста по завершении системной
функции exit, поскольку в этом случае больше ничего не остается
делать. Кроме того, переключение контекста допускается, когда
процесс приостанавливает свою работу, поскольку до момента возоб-
новления может пройти немало времени, в течение которого могли бы
выполняться другие процессы. Переключение контекста допускается и
тогда, когда процесс не имеет преимуществ перед другими процесса-
ми при исполнении, с тем, чтобы обеспечить более справедливое
планирование процессов: если по выходе процесса из системной
функции или из прерывания обнаруживается, что существует еще один
процесс, который имеет более высокий приоритет и ждет выполнения,
то было бы несправедливо оставлять его в ожидании.
Процедура переключения контекста похожа на процедуры обработ-
ки прерываний и обращения к системным функциям, если не считать
того, что ядро вместо предыдущего контекстного уровня текущего
процесса восстанавливает контекстный уровень другого процесса.
Причины, вызвавшие переключение контекста, при этом не имеют зна-
чения. На механизм переключения контекста не влияет и метод выбо-
ра следующего процесса для исполнения.
---------------------------------------------------------┐
│ 1. Принять решение относительно необходимости переклю- │
│ чения контекста и его допустимости в данный момент. │
│ 2. Сохранить контекст "прежнего" процесса. │
│ 3. Выбрать процесс, наиболее подходящий для исполнения,│
│ используя алгоритм диспетчеризации процессов, приве-│
│ денный в главе 8. │
│ 4. Восстановить его контекст. │
L---------------------------------------------------------
Рисунок 6.15. Последовательность шагов, выполняемых при пе-
реключении контекста
Текст программы, реализующей переключение контекста в системе
UNIX, из всех программ операционной системы самый трудный для по-
нимания, ибо при рассмотрении обращений к функциям создается впе-
чатление, что они в одних случаях не возвращают управление, а в
других - возникают непонятно откуда. Причиной этого является то,
что ядро во многих системных реализациях сохраняет контекст про-
цесса в одном месте программы, но продолжает работу, выполняя пе-
реключение контекста и алгоритмы диспетчеризации в контексте
"прежнего" процесса. Когда позднее ядро восстанавливает контекст
процесса, оно возобновляет его выполнение в соответствии с ранее
сохраненным контекстом. Чтобы различать между собой те случаи,
когда ядро восстанавливает контекст нового процесса, и когда оно
продолжает исполнять ранее сохраненный контекст, можно варьиро-
вать значения, возвращаемые критическими функциями, или устанав-
ливать искусственным образом текущее значение счетчика команд.
На Рисунке 6.16 приведена схема переключения контекста. Функ-
ция save_context сохраняет информацию о контексте исполняемого
процесса и возвращает значение 1. Кроме всего прочего, ядро сох-
раняет текущее значение счетчика команд (в функции save_context)
и значение 0 в нулевом регистре при выходе из функции. Ядро про-
должает исполнять контекст "прежнего" процесса (A), выбирая для
выполнения следующий процесс (B) и вызывая функцию resume_context
-------------------------------------------------------------┐
│ if (save_context()) /* сохранение контекста выполняющегося│
│ процесса */ │
│ { │
│ /* выбор следующего процесса для выполнения */ │
│ │
│ │
│ │
│ resume_context(new_process); │
│ /* сюда программа не попадает ! */ │
│ } │
│ /* возобновление выполнение процесса начинается отсюда */ │
L-------------------------------------------------------------
Рисунок 6.16. Псевдопрограмма переключения контекста
для восстановления его контекста. После восстановления контекста
система выполняет процесс B; прежний процесс (A) больше не испол-
няется, но он оставил после себя сохраненный контекст. Позже,
когда будет выполняться переключение контекста, ядро снова избе-
рет процесс A (если только, разумеется, он не был завершен). В
результате восстановления контекста A ядро присвоит счетчику ко-
манд то значение, которое было сохранено процессом A ранее в
функции save_context, и возвратит в регистре 0 значение 0. Ядро
возобновляет выполнение процесса A из функции save_context, пусть
даже при выполнении программы переключения контекста оно не доб-
ралось еще до функции resume_context. В конечном итоге, процесс A
возвращается из функции save_context со значением 0 (в нулевом
регистре) и возобновляет выполнение после строки комментария "во-
зобновление выполнение процесса начинается отсюда".
6.4.4 Сохранение контекста на случай аварийного завершения
Существуют ситуации, когда ядро вынуждено аварийно прерывать
текущий порядок выполнения и немедленно переходить к исполнению
ранее сохраненного контекста. В последующих разделах, где пойдет
речь о приостановлении выполнения и о сигналах, будут описаны об-
стоятельства, при которых процессу приходится внезапно изменять
свой контекст; в данном же разделе рассматривается механизм ис-
полнения предыдущего контекста. Алгоритм сохранения контекста на-
зывается setjmp, а алгоритм восстановления контекста - longjmp
(***). Механизм работы алгоритма setjmp похож на механизм функции
save_context, рассмотренный в предыдущем разделе, если не считать
того, что функция save_context помещает новый контекстный уровень
в стек, в то время как setjmp сохраняет контекст в пространстве
процесса и после выхода из него выполнение продолжается в прежнем
контекстном уровне. Когда ядру понадобится восстановить контекст,
---------------------------------------
(***) Эти алгоритмы не следует путать с имеющими те же названия
библиотечными функциями, которые могут вызываться непос-
редственно из пользовательских программ (см. [SVID 85]).
Однако действие этих функций похоже.
сохраненный в результате работы алгоритма setjmp, оно исполнит
алгоритм longjmp, который восстанавливает контекст из пространс-
тва процесса и имеет, как и setjmp, код завершения, равный 1.
6.4.5 Копирование данных между адресным пространством сис-
темы и адресным пространством задачи
До сих пор речь шла о том, что процесс выполняется в режиме
ядра или в режиме задачи без каких-либо перекрытий (пересечений)
86>