ответствующие очереди.
Каждая очередь представляет собой структуру данных, состоящую из следую-
щих элементов:
* процедуры открытия, вызываемой во время выполнения системной функции
open
* процедуры закрытия, вызываемой во время выполнения системной функции
close
* процедуры "вывода", вызываемой для передачи сообщения в очередь
* процедуры "обслуживания", вызываемой, когда очередь запланирована к ис-
полнению
* указателя на следующую очередь в потоке
* указателя на список сообщений, ожидающих обслуживания
* указателя на внутреннюю структуру данных, с помощью которой поддержива-
ется рабочее состояние очереди
* флагов, а также верхней и нижней отметок, используемых для управления
потоками данных, диспетчеризации и поддержания рабочего состояния очере-
ди.
Ядро выделяет пары очередей, соседствующие в памяти; следовательно, оче-
редь легко может отыскать своего партнера по паре.

+----------+
| Индекс |
+-----------------------+ файла |
| |устройства|
v +----------+
+------------+-----------+
Заголовок | Очередь | Очередь |
потока | для вывода | для ввода |
+------+-----+-----------+
| ^
v |
+------------+-----+-----+
Драйвер | Очередь | Очередь |------- пара очередей
| для вывода | для ввода |
+------------+-----------+

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


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

321

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

Сообщение 1 Сообщение 2 Сообщение 3
+---------+ +---------+ +---------+
| Блок +--------->| +-------->| |
+----+----+ +---------+ +----+----+
v v
+---------+ +---------+
| | | |
+----+----+ +---------+
v
+---------+
| |
+---------+

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


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

322

ния для каждой очереди в списке. Ядро может планировать обслуживание модулей
по программному прерыванию, подобно тому, как оно вызывает функции в таблице
ответных сигналов (см. главу 8); обработчик программных прерываний вызывает
индивидуальные процедуры обслуживания.
+----------+
| Индекс |
+-----------------------+ файла |
| |устройства|
v +----------+
+------------+-----------+
Заголовок | Очередь | Очередь |
потока | для вывода | для ввода |
+------+-----+-----------+
| ^
| |
v |
+------------+-----------+
Строковый | Очередь | Очередь |
интерфейс | для вывода | для ввода |
+------+-----+-----------+
| ^
| |
v |
+------------+-----+-----+
Терминальный | Очередь | Очередь |
драйвер | для вывода | для ввода |
+------------+-----------+

Рисунок 10.22. Продвижение модуля к потоку


Процессы могут "продвигать" модули к открытому потоку, используя вызов
системной функции ioctl. Ядро помещает выдвинутый модуль сразу под заголов-
ком потока и связывает указатели очереди таким образом, чтобы сохранить дву-
направленную структуру списка. Модули, расположенные в потоке ниже, не бес-
покоятся о том, связаны ли они с заголовком потока или же с выдвинутым моду-
лем: интерфейсом выступает процедура "вывода" следующей очереди в потоке; а
следующая очередь принадлежит только что выдвинутому модулю. Например, про-
цесс может выдвинуть модуль строкового интерфейса в поток терминального
драйвера с целью обработки символов стирания и удаления (Рисунок 10.22); мо-
дуль строкового интерфейса не имеет тех же составляющих, что и строковые ин-
терфейсы, рассмотренные в разделе 10.3, но выполняет те же функции. Без мо-
дуля строкового интерфейса терминальный драйвер не обработает вводные симво-
лы и они поступят в заголовок потока в неизмененном виде. Сегмент программы,
открывающий терминал и выдвигающий строковый интерфейс, может выглядеть сле-
дующим образом:

fd = open("/dev/ttyxy",O_RDWR);
ioctl(fd,PUSH,TTYLD);

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

ioctl(fd,POP,0);

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

323

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


    10.4.1 Более детальное рассмотрение потоков



Пайк описывает реализацию мультиплексных виртуальных терминалов, исполь-
зующую потоки (см. [Pike 84]). Пользователь видит несколько виртуальных тер-
миналов, каждый из которых занимает отдельное окно на экране физического
терминала. Хотя в статье Пайка рассматривается схема для интеллектуальных
графических терминалов, она работала бы и для терминалов ввода-вывода тоже;
каждое окно занимало бы целый экран и пользователь для переключения вирту-
альных окон набирал бы последовательность управляющих клавиш.

+---------+ +---------+ +-----------------+
Уровень | shell 1 | | shell 2 | | mpx |
пользователя +---------+ +---------+ +-----------------+
---------------+---------------+-----------+---+-------+----
Уровень ядра | ^ | ^ +--+ ^ | ^ | ^
| | | | | +--+ | | | |
| | | | | | | | | |
v | v | со- v | v | со- | |
терми- +-+++ терми- +-+++ об-+-+++ +-+++об- | |
нальная | | | нальная | | | ще-| | | | | |ще- | |
линия +++-+ линия +++-+ ния+++-+ +++-+ния | |
| ^ +-----------+-^------+ ^ | ^ | |
| | | +---------+-+--------+ | | | |
| | | | | | +-----------+ | | |
v | v | v | v +-----------+ v |
+-+++-+++ +-+++-+++ +-+++
псевдо- | | | | | | | | | | псевдо- | | |
терми- +++-+++-+ +++-+++-+ терми- +-+-+
нальная | ^ | ^ | ^ | ^ нальная терми-
пара 1 | +-+ | | +-+ | пара 2 нальный
+-----+ +-----+ драйвер

Рисунок 10.23. Отображение виртуальных окон на экране физи-
ческого терминала


На Рисунке 10.23 показана схема расположения процессов и модулей ядра.
Пользователь вызывает процесс mpx, контролирующий работу физического терми-
нала. Mpx читает данные из линии физического терминала и ждет объявления об
управляющих событиях, таких как создание нового окна, переключение управле-
ния на другое окно, удаление окна и т.п.
Когда mpx получает уведомление о том, что пользователю нужно создать но-
вое окно, он создает процесс, управляющий новым окном, и поддерживает связь
с ним через псевдотерминал. Псевдотерминал - это программное устройство, ра-
ботающее по принципу пары: выходные данные, направляемые к одной составляю-
щей пары, посылаются на вход другой составляющей; входные данные посылаются
тому модулю потока, который расположен выше по течению. Для того, чтобы отк-
рыть окно (Рисунок 10.24), mpx назначает псевдотерминальную пару и открывает
одну из составляющих пары, направляя поток к ней (открытие драйвера служит
гарантией того, что псевдотерминальная пара не была выбрана раньше). Mpx
ветвится и новый процесс открывает другую составляющую псевдотерминальной


324

+----------------------------------------------------------------+
| /* предположим, что дескрипторы файлов 0 и 1 уже относятся к |
| физическому терминалу */ |
| для(;;) /* цикл */ |
| { |
| выбрать(ввод); /* ждать ввода из какой-либо линии */ |
| прочитать данные, введенные из линии; |
| переключить(линию с вводимыми данными) |
| { |
| если выбран физический терминал: /* данные вводятся по ли- |
| нии физического терми- |
| нала */ |
| если(считана управляющая команда) /* например, создание |
| нового окна */ |
| { |
| открыть свободный псевдотерминал; |
| пойти по ветви нового процесса: |
| если(процесс родительский) |
| { |
| выдвинуть интерфейс сообщений в сторону mpx; |
| продолжить; /* возврат в цикл "для" */ |
| } |
| /* процесс-потомок */ |
| закрыть ненужные дескрипторы файлов; |
| открыть другой псевдотерминал из пары, выбрать stdin, |
| stdout, stderr; |
| выдвинуть строковый интерфейс терминала; |
| запустить shell; /* подобно виртуальному терминалу */|
| } |
| /* "обычные" данные, появившиеся через виртуальный терминал */ |
| демультиплексировать считывание данных с физического тер-|
| минала, снять заголовки и вести запись на соответствую- |
| щий псевдотерминал; |
| продолжить; /* возврат в цикл "для" */ |
| |
| если выбран логический терминал: /* виртуальный терминал |
| связан с окном */ |
| закодировать заголовок, указывающий назначение информации|
| окна; |
| переписать заголовок и информацию на физический терминал;|
| продолжить; /* возврат в цикл "для" */ |
| } |
| } |
+----------------------------------------------------------------+

Рисунок 10.24. Псевдопрограмма мультиплексирования окон


пары. Mpx выдвигает модуль управления сообщениями в псевдотерминальный по-
ток, чтобы преобразовывать управляющие сообщения в информационные (об этом в
следующем параграфе), а порожденный процесс помещает в псевдотерминальный
поток модуль строкового интерфейса перед запуском shell'а. Этот shell теперь
выполняется на виртуальном терминале; для пользователя виртуальный терминал
неотличим от физического.
Процесс mpx является мультиплексором, направляющим вывод данных с вирту-
альных терминалов на физический терминал и демультиплексирующим ввод данных
с физического терминала на подходящий виртуальный. Mpx ждет поступления дан-
ных по любой из линий, используя системную функцию select. Когда данные пос-
тупают от физического терминала, mpx решает вопрос, являются ли поступившие

325

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


    10.4.2 Анализ потоков



Ричи упоминает о том, что им была предпринята попытка создания потоков
только с процедурами "вывода" или только с процедурами обслуживания. Однако,
процедура обслуживания необходима для управления потоками данных, так как
модули должны иногда ставить данные в очередь, если соседние модули на время
закрыты для приема данных. Процедура "вывода" так же необходима, поскольку
данные должны иногда доставляться в соседние модули незамедлительно. Напри-
мер, строковому интерфейсу терминала нужно вести эхо-сопровождение ввода
данных на терминале в темпе с процессом. Системная функция write могла бы
запускать процедуру "вывода" для следующей очереди непосредственно, та, в
свою очередь, вызывала бы процедуру "вывода" для следующей очереди и так да-
лее, не нуждаясь в механизме диспетчеризации. Процесс приостановился бы в
случае переполнения очередей для вывода. Однако, со стороны ввода модули не
могут приостанавливаться, поскольку их выполнение вызывается программой об-
работки прерываний, иначе был бы приостановлен совершенно безобидный про-
цесс. Связь между модулями не должна быть симметричной в направлениях ввода
и вывода, хотя это и делает схему менее изящной.
Также было бы желательно реализовать каждый модуль в виде отдельного
процесса, но использование большого количества модулей привело бы к перепол-
нению таблицы процессов. Модули наделяются специальным механизмом диспетче-
ризации - программным прерыванием, независимым от обычного планировщика про-
цессов. По этой причине модули не могут приостанавливать свое выполнение,
так как они приостанавливали бы тем самым произвольный процесс (тот, который
прерван). Модули должны хранить внутри себя информацию о своем состоянии,
что делает лежащие в их основе программы более громоздкими, чем если бы при-
остановка выполнения была разрешена.
В реализации потоков можно выделить несколько отклонений или несоответс-
твий:
* Учет ресурсов процесса в потоках затрудняется, поскольку модулям необя-
зательно выполняться в контексте процесса, использующего поток. Ошибочно
предполагать, что все процессы одинаково используют модули потоков, пос-
кольку одним процессам может потребоваться использование сложных сетевых
протоколов, тогда как другие могут использовать простые строковые интер-
фейсы.
* Пользователи имеют возможность переводить терминальный драйвер в режим
без обработки, в котором функция read возвращает управление через корот-
кий промежуток времени в случае отсутствия данных (например, если

326

newtty.c_cc[VMIN] = 0 на Рисунке 10.17). Эту особенность сложно реализо-
вать в потоковой среде без подключения специальной программы на уровне
заголовка потока.
* Потоки выступают средствами линейной связи и не могут позволить произво-
дить с легкостью мультиплексирование на уровне ядра. В примере использо-
вания окон, рассмотренном в предыдущем разделе, выполнялось мультиплек-
сирование на уровне пользовательского процесса.
Несмотря на эти несоответствия, с потоками связываются большие надежды в
совершенствовании разработки модулей драйвера.


.te1 10.5 ВЫВОДЫ

Данная глава представляет собой обзор драйверов устройств в системе
UNIX. Устройства могут быть либо блочного, либо символьного типа; интерфейс
между устройствами и остальной частью ядра определяется типом устройств. Ин-
терфейсом для устройств блочного типа выступает таблица ключей устройств
ввода-вывода блоками, состоящая из точек входа, соответствующих процедурам
открытия и закрытия устройств и стратегической процедуре. Стратегическая
процедура управляет передачей данных от и к устройству блочного типа. Интер-
фейсом для устройств символьного типа выступает таблица ключей устройств по-
символьного ввода-вывода, которая состоит из точек входа, соответствующих
процедурам открытия и закрытия устройства, чтения, записи и процедуре ioctl.
Системная функция ioctl использует при обращении к устройствам символьного
типа свой собственный интерфейс, который позволяет осуществлять передачу уп-
равляющей информации между процессами и устройствами. По получении прерыва-
ния от устройства ядро вызывает программу обработки соответствующего преры-
вания, опираясь на информацию, хранящуюся в таблице векторов прерываний, и
на параметры, сообщенные устройством, от которого поступило прерывание.
Дисковые драйверы превращают номера логических блоков, используемые фай-
ловой системой, в физические адреса на диске. Блочный интерфейс дает возмож-
ность ядру буферизовать данные. Взаимодействие без обработки ускоряет
ввод-вывод на диск, но игнорирует буферный кеш, увеличивая тем самым шансы
разрушить файловую систему.
Терминальные драйверы осуществляют непосредственное взаимодействие с
пользователями. Ядро связывает с каждым терминалом три символьных списка,
один для неструктурированного ввода с клавиатуры, один для ввода с обработ-
кой символов стирания, удаления и возврата каретки и один для вывода. Сис-
темная функция ioctl дает процессам возможность следить за тем, как ядро об-
рабатывает вводимые данные, переводя терминал в канонический режим или уста-
навливая значения различных параметров для режима без обработки символов.
Getty-процесс открывает терминальные линии и ждет связи: он формирует группу
процессов во главе с регистрационным shell'ом, инициализирует с помощью фун-
кции ioctl параметры терминала и обращается к пользователю с предложением
зарегистрироваться. Установленный таким образом операторский терминал посы-
лает процессам в группе сигналы в ответ на возникновение таких событий, как
"зависание" пользователя или нажатие им клавиши прерывания.
Потоки выступают средством повышения модульности построения драйверов
устройств и протоколов. Поток - это полнодуплексная связь между процессами и
драйверами устройств, которая может включать в себя строковые интерфейсы и
протоколы для промежуточной обработки данных. Модули потоков характеризуются
четко определенным взаимодействием и гибкостью, позволяющей использовать их
в сочетании с другими модулями. Эта гибкость имеет особое значение для сете-
вых протоколов и драйверов.

.te1 10.6 УПРАЖНЕНИЯ

*1. Предположим, что в системе имеются два файла устройств с одними и теми
же старшим и младшим номерами, при том, что оба устройства - символьно-

327

го типа. Если два процесса желают одновременно открыть физическое уст-
ройство, не будет никакой разницы, открывают ли они один и тот же файл
устройства или же разные файлы. Что произойдет, когда они станут закры-
вать устройство ?
*2. Вспомним из главы 5, что системной функции mknod требуется разрешение
суперпользователя на создание нового специального файла устройства. Ес-
ли доступ к устройству управляется правами доступа к файлу, почему фун-
кции mknod нужно разрешение суперпользователя ?
3. Напишите программу, которая проверяет, что файловые системы на диске не
перекрываются. Этой программе потребовались бы два аргумента: файл уст-
ройства, представляющий дисковый том, и дескриптор файла, откуда берут-
ся номера секторов и их размер для диска данного типа. Для проверки от-
сутствия перекрытий этой программе понадобилась бы информация из супер-
блоков. Будет ли такая программа всегда правильной ?
4. Программа mkfs инициализирует файловую систему на диске путем создания
суперблока, выделения места для списка индексов, включения всех инфор-
мационных блоков в связанный список и создания корневого каталога. Как
бы вы написали программу mkfs ? Как изменится эта программа при наличии
таблицы содержимого тома ? Каким образом следует инициализировать таб-
лицу содержимого тома ?
5. Программы mkfs и fsck (глава 5) являются программами пользовательского
уровня, а не частью ядра. Прокомментируйте это.
6. Предположим, что программисту нужно разработать базу данных, работающую
в среде ОС UNIX. Программы базы данных выполняются на пользовательском
уровне, а не в составе ядра. Как система управления базой данных будет
взаимодействовать с диском ? Подумайте над следующими вопросами:
* Использование стандартного интерфейса файловой системы вместо непос-
редственной работы с неструктурированными данными на диске,
* Потребность в быстродействии,
* Необходимость знать, когда фактически данные располагаются на диске,
* Размер базы данных: должна ли она помещаться в одной файловой систе-
ме, занимать собой весь дисковый том или же располагаться на несколь-
ких дисковых томах ?
7. Ядро системы UNIX по умолчанию предполагает, что файловая система рас-
полагается на идеальных дисках. Однако, диски могут содержать ошибки,
которые делают непригодными и выводят из строя определенные сектора,
несмотря на то, что остальная часть диска осталась "пригодной". Как
дисковому драйверу (или интеллектуальному контроллеру диска) следует
учитывать небольшое количество плохих секторов. Как это отразилось бы
на производительности системы ?
8. При монтировании файловой системы ядро запускает процедуру открытия для
данного драйвера, но позже освобождает индекс специального файла уст-
ройства по завершении выполнения вызова системной функции mount. При
демонтировании файловой системы ядро обращается к индексу специального
файла устройства, запускает процедуру закрытия для данного драйвера и
вновь освобождает индекс. Сравните эту последовательность операций над
индексом, а также обращений к процедурам открытия и закрытия драйвера,
с последовательностью действий, совершаемых при открывании и закрывании
устройства блочного типа. Прокомментируйте результаты сравнения.
9. Выполните программу, приведенную на Рисунке 10.14, но направьте вывод
данных в файл. Сравните содержимое файла с содержимым выводного потока,
когда вывод идет на терминал. Вам придется прервать процессы, чтобы ос-
тановить их; только прежде пусть они получат достаточно большое коли-
чество данных. Что произойдет, если вызов функции write в программе за-
менить на printf(output);
10. Что произойдет, если пользователь попытается выполнить редактирование
текста на фоне программы:
ed file &
Обоснуйте ответ.

328

11. К файлам терминалов обычно устанавливаются следующие права доступа

crw--w--w- 2 mjb lus 33,11 Oct 25 20:27 tty61

при входе пользователя в систему. То есть, чтение и запись разрешаются
пользователю с именем "mjb", а остальным пользователям разрешена только
запись. Почему ?
12. Предположим, что вам известно имя файла терминала вашего товарища. На-
пишите программу записи сообщений с вашего терминала на терминал вашего
товарища. Какая еще информация вам нужна, чтобы закодировать приемлемое
воспроизведение обычной команды write ?
13. Выполните команду stty: если параметры не указаны, она выбирает значе-
ния установок терминала и сообщает их пользователю. В противном случае
пользователь может в интерактивном режиме сделать различные установки
сам.
14. Напишите элементарный строковый интерфейс, записывающий идентификатор
машины в начале каждой строки выводного потока.
15. В каноническом режиме пользователь может на время приостановить вывод
данных на терминал, нажав последовательность клавиш , и продол-
жить вывод, нажав . Как в стандартном строковом интерфейсе реа-
лизуется эта особенность ?
*16. Процесс начальной загрузки порождает getty-процесс для каждой терми-
нальной линии в системе. Что произошло бы, если бы для одного и того же
терминала существовали бы одновременно два getty-процесса, ожидающие
регистрации пользователя ? Может ли ядро помешать этому ?
17. Пусть командный процессор shell реализован таким образом, что он "игно-
рирует" конец файла и продолжает считывать данные из стандартного вво-
да. Что произошло бы, если бы пользователь (в регистрационном shell'е)
угадал конец файла и продолжил ввод с клавиатуры ?
*18. Предположим, что процесс считывает данные с операторского терминала, но
игнорирует или улавливает сигналы о "зависании". Что произойдет, когда
процесс продолжит считывать данные с операторского терминала после за-
висания ?
19. Программа getty-процесса несет ответственность за открытие терминальной
линии, а программа login - за проверку регистрационных имен и паролей.
Какие преимущества в том, что эти функции выполняются отдельными прог-
раммами ?
20. Рассмотрим два метода реализации драйвера косвенного терминала ("/dev
/tty"), описанные в разделе 10.3.6. Какие различия между ними чувствует
пользователь ? (Совет: подумайте о системных функциях stat и fstat).
21. Разработайте метод планирования выполнения модулей потока, в соответст-
вии с которым ядро имеет в своем составе специальный процесс, выполняю-
щий процедуры обслуживания модулей тогда, когда выполнение этих проце-
дур запланировано.
*22. Разработайте схему построения виртуальных терминалов (окон) с использо-
ванием традиционных (не потоковых) драйверов.
*23. Разработайте метод реализации виртуальных терминалов с использованием
потоков, в котором мультиплексированием ввода-вывода между виртуальным
и физическим терминалами занимался бы один из модулей ядра, а не поль-
зовательский процесс. Опишите механизм соединения потоков со сверткой и
разверткой. Что лучше: включить модуль, осуществляющий мультиплексиро-
вание, в состав ядра или построить его как пользовательский процесс ?
24. Команда ps сообщает интересную информацию об активности процессов в ра-
ботающей системе. В традиционных реализациях ps считывает информацию из
таблицы процессов, прямо из памяти ядра. Такой метод не совсем удобен в
среде разработки, когда размер записей таблицы процессов меняется и ко-
манде ps становится нелегко обнаружить в таблице соответствующие поля.
Разработайте драйвер, нечувствительный к изменениям среды.


329