Литмир - Электронная Библиотека
Содержание  
A
A

 открыть терминальную линию; /* приостанов до завершения открытия */

 if (открытие завершилось успешно) 
{

  исполнить программу регистрации: запросить имя пользователя;

  отключить эхо-сопровождение, запросить пароль;

  if (регистрация прошла успешно) { /* найден соответствующий пароль в /etc/passwd */

   перевести терминал в канонический режим (ioctl);

   исполнить shell;

  }

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

 }

}

Рисунок 10.19. Алгоритм регистрации

10.4 ПОТОКИ

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

Ричи недавно разработал схему, получившую название "потоки" (streams), для повышения модульности и гибкости подсистемы управления вводом-выводом. Нижеследующее описание основывается на его работе [Ritchie 84b], хотя реализация этой схемы в версии V слегка отличается. Поток представляет собой полнодуплексную связь между процессом и драйвером устройства. Он состоит из совокупности линейно связанных между собой пар очередей, каждая из которых (пара) включает одну очередь для ввода и другую — для вывода. Когда процесс записывает данные в поток, ядро посылает данные в очереди для вывода; когда драйвер устройства получает входные данные, он пересылает их в очереди для ввода к процессу, производящему чтение. Очереди обмениваются сообщениями с соседними очередями, используя четко определенный интерфейс. Каждая пара очередей связана с одним из модулей ядра, таким как драйвер, строковый интерфейс или протокол, и модули ядра работают с данными, прошедшими через соответствующие очереди.

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

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

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

• процедуры "вывода", вызываемой для передачи сообщения в очередь

• процедуры "обслуживания", вызываемой, когда очередь запланирована к исполнению

• указателя на следующую очередь в потоке

• указателя на список сообщений, ожидающих обслуживания

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

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

Ядро выделяет пары очередей, соседствующие в памяти; следовательно, очередь легко может отыскать своего партнера по паре.

Архитектура операционной системы UNIX (ЛП) - pic_102.png

Рисунок 10.20. Поток после открытия

Устройство с потоковым драйвером является устройством посимвольного ввода-вывода; оно имеет в таблице ключей устройств соответствующего типа специальное поле, которое указывает на структуру инициализации потока, содержащую адреса процедур, а также верхнюю и нижнюю отметки, упомянутые выше. Когда ядро выполняет системную функцию open и обнаруживает, что файл устройства имеет тип "специальный символьный", оно проверяет наличие нового поля в таблице ключей устройств посимвольного ввода-вывода. Если в таблице отсутствует соответствующая точка входа, то драйвер не является потоковым, и ядро выполняет процедуру, обычную для устройств посимвольного ввода-вывода. Однако, при первом же открытии потокового драйвера ядро выделяет две пары очередей одну для заголовка потока и другую для драйвера. У всех открытых потоков модуль заголовка имеет идентичную структуру: он содержит общую процедуру "вывода" и общую процедуру "обслуживания" и имеет интерфейс с модулями ядра более высокого уровня, выполняющими функции read, write и ioctl. Ядро инициализирует структуру очередей драйвера, назначая значения указателям каждой очереди и копируя адреса процедур драйвера из структуры инициализации драйвера, и запускает процедуру открытия. Процедура открытия драйвера выполняет обычную инициализацию, но при этом сохраняет информацию, необходимую для повторного обращения к ассоциированной с этой процедурой очереди. Наконец, ядро отводит специальный указатель в копии индекса в памяти для ссылки на заголовок потока (Рисунок 10.20). Когда еще один процесс открывает устройство, ядро обнаруживает назначенный ранее поток с помощью этого указателя и запускает процедуру открытия для всех модулей потока.

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

Архитектура операционной системы UNIX (ЛП) - pic_103.png

Рисунок 10.21. Сообщения в потоках

Когда процесс производит запись в поток, ядро копирует данные из адресного пространства задачи в блоки сообщения, которые выделяются модулем заголовка потока. Модуль заголовка потока запускает процедуру "вывода" для модуля следующей очереди, которая обрабатывает сообщение, незамедлительно передает его в следующую очередь или ставит в эту же очередь для последующей обработки. В последнем случае модуль связывает заголовки блоков сообщения в список с указателями, формируя двунаправленный список (Рисунок 10.21). Затем он устанавливает в структуре данных очереди флаг, показывая тем самым, что имеются данные для обработки, и планирует собственное обслуживание. Модуль включает очередь в список очередей, требующих обслуживания и запускает механизм диспетчеризации; планировщик (диспетчер) вызывает процедуры обслуживания для каждой очереди в списке. Ядро может планировать обслуживание модулей по программному прерыванию, подобно тому, как оно вызывает функции в таблице ответных сигналов (см. главу 8); обработчик программных прерываний вызывает индивидуальные процедуры обслуживания.

114
{"b":"96903","o":1}