Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Создай свою операционную систему! #6


Информационный Канал Subscribe.Ru

Сетевые операционные системы

Глава 4. Процессы и потоки

2004-12-20

Продолжение

Процедуры обработки прерываний и текущий процесс

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

Хороший пример того, что не бывает правил без исключений, предос-тавляет нам ОС Windows NT. В ней существуют процедуры обработки пре-рываний, которые выполняются всегда в контексте определенного процесса. Это процедуры, вызываемые с помощью программного прерывания АРС (Asynchronous Procedure Call, вызов асинхронной процедуры). Для них в дис-петчере прерываний предусмотрен свой уровень приоритета IRQL, выше уровня для обычного кода, но ниже уровня DPC. Эти процедуры могут пре-рвать текущий код и выполниться при соблюдении двух условий: текущий код имеет низший уровень приоритета (то есть выполняется обычный код), текущим процессом является вполне определенный процесс, описатель кото-рого был задан в запросе на прерывание для данной процедуры АРС. Проце-дуры АРС могут пользоваться ресурсами текущего процесса, и, собственно, для этого они и были введены. Основное назначение АРС-процедур - пере-мещение данных, полученных драйвером от какого-либо устройства ввода-вывода, из памяти системной области памяти, куда они помещаются после считывания из регистров контроллера этого устройства, в индивидуальную часть адресного пространства процесса, запросившего операцию ввода-вывода. Такое действие постоянно выполняется системой ввода-вывода, и для его реализации были введены такие специфические процедуры обработ-ки прерываний, как АРС.

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

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

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

Реализация системных вызовов должна удовлетворять следующим требованиям:

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

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

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

В большинстве ОС системные вызовы обслуживаются по централизо-ванной схеме, основанной на существовании диспетчера системных вызовов (рис. 4.14, б). При любом системном вызове приложение выполняет про-граммное прерывание с определенным и единственным номером вектора. Например, ОС Linux использует для системных вызовов команду INT 80h, а ОС Windows NT (при работе на платформе Pentium) - INT 2Eh. Перед вы-полнением программного прерывания приложение тем или иным способом передает операционной системе номер системного вызова, который является индексом в таблице адресов процедур ОС, реализующих системные вызовы (таблица sysent на рис. 4.14). Способ передачи зависит от реализации, напри-мер номер можно поместить в определенный регистр общего назначения процессора или передать через стек (в этом случае после прерывания и пере-хода в привилегированный режим их нужно будет скопировать в системный стек из пользовательского, это действие в некоторых процессорах автомати-зировано). Также некоторым способом передаются аргументы системного вызова, они могут как помещаться в регистры общего назначения, так и пе-редаваться через стек или массив, находящийся в оперативной памяти. Мас-сив удобен при большом объеме данных, передаваемых в качестве аргументов, при этом в регистре общего назначения указывается адрес этого массива.

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

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

После завершения работы системного вызова управление возвращает-ся диспетчеру, при этом он получает также код завершения этого вызова. Диспетчер восстанавливает регистры процессора, помещает в определенный регистр код возврата и выполняет инструкцию возврата из прерывания, кото-рая восстанавливает непривилегированный режим работы процессора.

Для приложения системный вызов внешне ничем не отличается от вы-зова обычной библиотечной функции языка С, связанной (динамически или статически) с объектным кодом приложения и выполняющейся в пользова-тельском режиме. И такая ситуация действительно имеет место - для всех системных вызовов в библиотеках, предоставляемых компилятором С, име-ются так называемые "заглушки" (в англоязычном варианте используется термин "stub" - остаток, огрызок). Каждая заглушка оформлена как С-функция, при этом она содержит несколько ассемблерных строк, нужных для выполнения инструкции программного прерывания. Таким образом, пользо-вательская программа вызывает заглушку, а та, в свою очередь, вызывает процедуру ОС.

Для ускорения выполнения некоторых достаточно простых системных вызовов, которым к тому же не требуется работа в привилегированном ре-жиме, требуемая работа полностью выполняется библиотечной функцией, которую несправедливо называть в данном случае заглушкой. Более точно, такая функция не является системным вызовом, а представляет собой "чис-тую" библиотечную функцию, выполняющую всю свою работу в пользова-тельском режиме в виртуальном адресном пространстве процесса, но при-кладной программист может об этом и не знать - для него системные вызовы и библиотечные функции выглядят единообразно. Прикладной программист имеет дело с набором функций прикладного программного интерфейса - API (например, Win32 или POSIX), - состоящего и из библиотечных функций, часть из которых пользуется для завершения работы системными вызовами, а часть - нет.

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

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

Асинхронный системный вызов не приводит к переводу процесса в режим ожидания после выполнения некоторых начальных системных дейст-вий, например запуска операции вывода-вывода, управление возвращается прикладному процессу (рис. 4.15, б).

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

Продолжение следует...



Copyright (C) 2004 UzhOS-Team
Ведущий рассылки Igene Smith (winexp[@]yandex.ru)
Designed by Vladimir Tsarkov (bvbn[@]lipetsk.ru)

http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.othos.osmaker
Отписаться

В избранное