Скачиваний:
21
Добавлен:
09.05.2014
Размер:
354.82 Кб
Скачать

10.1.2 Системные функции и взаимодействие с драйверами

В этом разделе рассматривается взаимодействие ядра с драйверами устрой-

ств. При выполнении тех системных функций, которые используют дескрипторы

файлов, ядро, следуя за указателями, хранящимися в пользовательском дескрип-

торе файла, обращается к таблице

+-----------------------------------------------+

| таблица ключей устройств ввода-вывода блоками |

+-------+--------+---------+--------------------+

| вход | open | close | strategy |

+-------+--------+---------+--------------------+

| 0 | gdopen | gdclose | gdstrategy |

+-------+--------+---------+--------------------+

| 1 | gtopen | gtclose | gtstrategy |

+-------+--------+---------+--------------------+

+----------------------------------------------------------------+

| таблица ключей устройств посимвольного ввода-вывода |

+------+-----------+-----------+---------+-----------+-----------+

| вход | open | close | read | write | ioctl |

+------+-----------+-----------+---------+-----------+-----------+

| 0 | conopen | conclose | conread | conwrite | conioctl |

+------+-----------+-----------+---------+-----------+-----------+

| 1 | dzbopen | dzbclose | dzbread | dzbwrite | dzbioctl |

+------+-----------+-----------+---------+-----------+-----------+

| 2 | syopen | nulldev | syread | sywrite | syioctl |

+------+-----------+-----------+---------+-----------+-----------+

| 3 | nulldev | nulldev | mmread | mmwrite | nodev |

+------+-----------+-----------+---------+-----------+-----------+

| 4 | gdopen | gdclose | gdread | gdwrite | nodev |

+------+-----------+-----------+---------+-----------+-----------+

| 5 | gtopen | gtclose | gtread | gtwrite | nodev |

+------+-----------+-----------+---------+-----------+-----------+

Рисунок 10.2. Пример заполнения таблиц ключей устройств ввода-

вывода блоками и символами

файлов ядра и к индексу, где оно проверяет тип файла, и переходит к таблице

ключей устройств ввода-вывода блоками или символами. Ядро извлекает из ин-

декса старший и младший номера устройства, использует старший номер в качес-

тве указателя на точку входа в соответствующей таблице и вызывает выполнение

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

младший номер в качестве параметра. Важным различием в реализации системных

функций для файлов устройств и для файлов обычного типа является то, что ин-

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

программу драйвера. Драйверы часто приостанавливают свою работу, ожидая свя-

зи с аппаратными средствами или поступления данных, поэтому ядро не в состо-

293

янии определить, на какое время процесс будет приостановлен. Если индекс

заблокирован, другие процессы, обратившиеся к индексу (например, посредством

системной функции stat), приостановятся на неопределенное время, поскольку

один процесс приостановил драйвер.

Драйвер устройства интерпретирует параметры вызова системной функции в

отношении устройства. Драйвер поддерживает структуры данных, описывающие

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

драйвера и программы обработки прерываний реализуются в соответствии с сос-

тоянием драйвера и с тем, какое действие выполняется в этот момент (напри-

мер, данные вводятся или выводятся). Теперь рассмотрим каждый интерфейс бо-

лее подробно.

+------------------------------------------------------------+

| алгоритм open /* для драйверов устройств */ |

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

| режим открытия |

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

| { |

| преобразовать имя пути поиска в индекс, увеличить значе-|

| ние счетчика ссылок в индексе; |

| выделить в таблице файлов место для пользовательского |

| дескриптора файла, как при открытии обычного файла; |

| |

| выбрать из индекса старший и младший номера устройства; |

| |

| сохранить контекст (алгоритм setjmp) в случае передачи |

| управления от драйвера; |

| |

| если (устройство блочного типа) |

| { |

| использовать старший номер устройства в качестве ука-|

| зателя в таблице ключей устройств ввода-вывода бло- |

| ками; |

| вызвать процедуру открытия драйвера по данному индек-|

| су: передать младший номер устройства, режимы откры-|

| тия; |

| } |

| в противном случае |

| { |

| использовать старший номер устройства в качестве ука-|

| зателя в таблице ключей устройств посимвольного вво-|

| да-вывода; |

| вызвать процедуру открытия драйвера по данному индек-|

| су: передать младший номер устройства, режимы откры-|

| тия; |

| } |

| |

| если (открытие в драйвере не выполнилось) |

| привести таблицу файлов к первоначальному виду, |

| уменьшить значение счетчика в индексе; |

| } |

+------------------------------------------------------------+

Рисунок 10.3. Алгоритм открытия устройства

10.1.2.1 Opeп

При открытии устройства ядро следует той же процедуре, что и при откры-

294

тии файлов обычного типа (см. раздел 5.1), выделяя в памяти индексы, увели-

чивая значение счетчика ссылок и присваивая значение точки входа в таблицу

файлов и пользовательского дескриптора файла. Наконец, ядро возвращает зна-

чение пользовательского дескриптора файла вызывающему процессу, так что отк-

рытие устройства выглядит так же, как и открытие файла обычного типа. Одна-

ко, перед тем, как вернуться в режим задачи, ядро запускает

зависящую от устройства процедуру open (Рисунок 10.3). Для устройства вво-

да-вывода блоками запускается процедура open, закодированная в таблице клю-

чей устройств ввода-вывода блоками, для устройств посимвольного ввода-вывода

- процедура open, закодированная в соответствующей таблице. Если устройство

имеет как блочный, так и символьный тип, ядро запускает процедуру open, со-

ответствующую типу файла устройства, открытого пользователем: обе процедуры

могут даже быть идентичны, в зависимости от конкретного драйвера.

Зависящая от типа устройства процедура open устанавливает связь между

вызывающим процессом и открываемым устройством и инициализирует информацион-

ные структуры драйвера. Например, процедура open для терминала может приос-

тановить процесс до тех пор, пока в машину не поступит сигнал (аппаратный) о

том, что пользователь предпринял попытку зарегистрироваться. После этого

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

ми установками терминала (например, скоростью передачи информации в бодах).

Для "программных устройств", таких как память системы, процедура open может

не включать в себя инициализацию.

Если во время открытия устройства процессу пришлось приостановиться по

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

жно было бы вызвать возобновление выполнения процесса, так никогда и не про-

изойдет. Например, если на данном терминале еще не зарегистрировался ни один

из пользователей, процесс getty, "открывший" терминал (раздел 7.9), приоста-

навливается до тех пор, пока пользователем не будет предпринята попытка ре-

гистрации, при этом может пройти достаточно большой промежуток времени. Ядро

должно иметь возможность возобновить выполнение процесса и отменить вызов

функции open по получении сигнала: ему следует сбросить индекс, отменить

точку входа в таблице файлов и пользовательский дескриптор файла, которые

были выделены перед входом в драйвер, поскольку открытие не произошло. Ядро

сохраняет контекст процесса, используя алгоритм setjmp (раздел 6.4.4), преж-

де чем запустить процедуру open; если процесс возобновляется по сигналу, яд-

ро восстанавливает контекст процесса в том состоянии, которое он имел перед

обращением к драйверу, используя алгоритм longjmp (раздел 6.4.4), и возвра-

щает системе все выделенные процедуре open структуры данных. Точно так же и

драйвер может уловить сигнал и очистить доступные ему структуры данных, если

это необходимо. Ядро также переустанавливает структуры данных файловой сис-

темы, когда драйвер сталкивается с исключительными ситуациями, такими, как

попытка пользователя обратиться к устройству, отсутствующему в данной конфи-

гурации. В подобных случаях функция open не выполняется.

Процессы могут указывать значения различных параметров, характеризующие

особенности выполнения процедуры открытия. Из них наиболее часто использует-

ся "no delay" (без задержки), означающее, что процесс не будет приостановлен

во время выполнения процедуры open, если устройство не готово. Системная

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

узнает, произошло ли аппаратное соединение или нет. Открытие устройства с

параметром "no delay", кроме всего прочего, затронет семантику вызова функ-

ции read, что мы увидим далее (раздел 10.3.4).

Если устройство открывается многократно, ядро обрабатывает пользователь-

ские дескрипторы файлов, индекс и записи в таблице файлов так, как это опи-

сано в главе 5, запуская определяемую типом устройства процедуру open при

каждом вызове системной функции open. Таким образом, драйвер устройства мо-

жет подсчитать, сколько раз устройство было "открыто", и прервать выполнение

функции open, если количество открытий приняло недопустимое значение. Напри-

295

мер, имеет смысл разрешить процессам многократно "открывать" терминал на за-

пись для того, чтобы пользователи могли обмениваться сообщениями. Но при

этом не следует допускать многократного "открытия" печатающего устройства

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

мацию. Эти различия имеют смысл скорее на практике, нежели на стадии разра-

ботки: разрешение одновременной записи на терминалы способствует установле-

нию взаимодействия между пользователями; запрещение одновременной записи на

принтеры служит повышению читабельности машинограмм (**).

+------------------------------------------------------------+

| алгоритм close /* для устройств */ |

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

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

| { |

| выполнить алгоритм стандартного закрытия (глава 5ххх); |

| если (значение счетчика ссылок в таблице файлов не 0) |

| перейти на finish; |

| если (существует еще один открытый файл, старший и млад-|

| ший номера которого совпадают с номерами закрываемого |

| устройства) |

| перейти на finish; /* не последнее закрытие */ |

| если (устройство символьного типа) |

| { |

| использовать старший номер в качестве указателя в |

| таблице ключей устройства посимвольного ввода-выво- |

| да; |

| вызвать процедуру закрытия, определяемую типом драй- |

| вера и передать ей в качестве параметра младший но- |

| мер устройства; |

| } |

| если (устройство блочного типа) |

| { |

| если (устройство монтировано) |

| перейти на finish; |

| переписать блоки устройства из буферного кеша на уст-|

| ройство; |

| использовать старший номер в качестве указателя в |

| таблице ключей устройства ввода-вывода блоками; |

| вызвать процедуру закрытия, определяемую типом драй- |

| вера и передать ей в качестве параметра младший но- |

| мер устройства; |

| сделать недействительными блоки устройства, оставшие-|

| ся в буферном кеше; |

| } |

| finish: |

| освободить индекс; |

| } |

+------------------------------------------------------------+

Рисунок 10.4. Алгоритм закрытия устройства

----------------------------------------

(**) На практике вывод на печать обычно управляется специальными процессами

буферизации, и права доступа устанавливаются таким образом, чтобы толь-

ко система буферизации могла обращаться к принтеру.

296

10.1.2.2 Closе

Процесс разрывает связь с открытым устройством, закрывая его. Однако,

ядро запускает определяемую типом устройства процедуру close только в пос-

леднем вызове функции close для этого устройства, и то только если не оста-

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

закрытия устройства завершается разрывом аппаратного соединения; отсюда яс-

но, что ядру следует подождать, пока не останется ни одного процесса, обра-

щающегося к устройству. Поскольку ядро запускает процедуру открытия устройс-

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

один раз, драйверу устройства неведомо, сколько процессов используют устрой-

ство в данный момент. Драйверы могут легко выйти из строя, если при их напи-

сании не соблюдалась осторожность: когда при выполнении процедуры close они

приостанавливают свою работу и какой-нибудь процесс открывает устройство до

того, как завершится процедура закрытия, устройство может стать недоступным

для работы, если в результате комбинации вызовов open и close сложилась не-

распознаваемая ситуация.

Алгоритм закрытия устройства похож на алгоритм закрытия файла обычного

типа (Рисунок 10.4). Однако, до того, как ядро освобождает индекс, в нем вы-

полняются действия, специфичные для файлов устройств.

Соседние файлы в папке материалы к собеседованию