7. Ядро системы UNIX по умолчанию предполагает, что файловая система располагается на идеальных дисках. Однако, диски могут содержать ошибки, которые делают непригодными и выводят из строя определенные сектора, несмотря на то, что остальная часть диска осталась 'пригодной'. Как дисковому драйверу (или интеллектуальному контроллеру диска) следует учитывать небольшое количество плохих секторов. Как это отразилось бы на производительности системы?
8. При монтировании файловой системы ядро запускает процедуру открытия для данного драйвера, но позже освобождает индекс специального файла устройства по завершении выполнения вызова системной функции mount. При демонтировании файловой системы ядро обращается к индексу специального файла устройства, запускает процедуру закрытия для данного драйвера и вновь освобождает индекс. Сравните эту последовательность операций над индексом, а также обращений к процедурам открытия и закрытия драйвера, с последовательностью действий, совершаемых при открывании и закрывании устройства блочного типа. Прокомментируйте результаты сравнения.
9. Выполните программу, приведенную на Рисунке 10.14, но направьте вывод данных в файл. Сравните содержимое файла с содержимым выводного потока, когда вывод идет на терминал. Вам придется прервать процессы, чтобы остановить их; только прежде пусть они получат достаточно большое количество данных. Что произойдет, если вызов функции write в программе заменить на printf(output);
10. Что произойдет, если пользователь попытается выполнить редактирование текста на фоне программы:
ed file&
Обоснуйте ответ.
11. К файлам терминалов обычно устанавливаются следующие права доступа
crw-w-w- 2 mjb lus 33,11 Oct 25 20:27 tty61
при входе пользователя в систему. То есть, чтение и запись разрешаются пользователю с именем 'mjb', а остальным пользователям разрешена только запись. Почему?
12. Предположим, что вам известно имя файла терминала вашего товарища. Напишите программу записи сообщений с вашего терминала на терминал вашего товарища. Какая еще информация вам нужна, чтобы закодировать приемлемое воспроизведение обычной команды write?
13. Выполните команду stty: если параметры не указаны, она выбирает значения установок терминала и сообщает их пользователю. В противном случае пользователь может в интерактивном режиме сделать различные установки сам.
14. Напишите элементарный строковый интерфейс, записывающий идентификатор машины в начале каждой строки выводного потока.
15. В каноническом режиме пользователь может на время приостановить вывод данных на терминал, нажав последовательность клавиш ‹Ctrl-s›, и продолжить вывод, нажав ‹Ctrl-q›. Как в стандартном строковом интерфейсе реализуется эта особенность?
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 становится нелегко обнаружить в таблице соответствующие поля. Разработайте драйвер, нечувствительный к изменениям среды.
ГЛАВА 11. ВЗАИМОДЕЙСТВИЕ ПРОЦЕССОВ
Наличие механизмов взаимодействия дает произвольным процессам возможность осуществлять обмен данными и синхронизировать свое выполнение с другими процессами. Мы уже рассмотрели несколько форм взаимодействия процессов, такие как канальная связь, использование поименованных каналов и посылка сигналов. Каналы (непоименованные) имеют недостаток, связанный с тем, что они известны только потомкам процесса, вызвавшего системную функцию pipe: не имеющие родственных связей процессы не могут взаимодействовать между собой с помощью непоименованных каналов. Несмотря на то, что поименованные каналы позволяют взаимодействовать между собой процессам, не имеющим родственных связей, они не могут использоваться ни в сети (см. главу 13), ни в организации множественных связей между различными группами взаимодействующих процессов: поименованный канал не поддается такому мультиплексированию, при котором у каждой пары взаимодействующих процессов имелся бы свой выделенный канал. Произвольные процессы могут также связываться между собой благодаря посылке сигналов с помощью системной функции kill, однако такое 'сообщение' состоит из одного только номера сигнала.
В данной главе описываются другие формы взаимодействия процессов. В начале речь идет о трассировке процессов, о том, каким образом один процесс следит за ходом выполнения другого процесса, затем рассматривается пакет IPC: сообщения, разделяемая память и семафоры. Делается обзор традиционных методов сетевого взаимодействия процессов, выполняющихся на разных машинах, и, наконец, дается представление о 'гнездах', применяющихся в системе BSD. Вопросы сетевого взаимодействия, имеющие специальный характер, такие как протоколы, адресация и др., не рассматриваются, поскольку они выходят за рамки настоящей работы.
11.1 ТРАССИРОВКА ПРОЦЕССОВ
В системе UNIX имеется простейшая форма взаимодействия процессов, используемая в целях отладки, — трассировка процессов. Процесс-отладчик, например sdb, порождает трассируемый процесс и управляет его выполнением с помощью системной функции ptrace, расставляя и сбрасывая контрольные точки, считывая и записывая данные в его виртуальное адресное пространство. Трассировка процессов, таким образом, включает в себя синхронизацию выполнения процесса-отладчика и трассируемого процесса и управление выполнением последнего.
if ((pid = fork()) == 0) {
/* потомок — трассируемый процесс */
ptrace(0, 0, 0, 0);
exec('имя трассируемого процесса');
}
/* продолжение выполнения процесса-отладчика */
for (;;) {
wait((int *) 0);
read(входная информация для трассировки команд);
ptrace(cmd, pid, …);
if (условие завершения трассировки) break;
}
Рисунок 11.1. Структура процесса отладки
Псевдопрограмма, представленная на Рисунке 11.1, имеет типичную структуру отладочной программы. Отладчик порождает новый процесс, запускающий системную функцию ptrace, в результате чего в соответствующей процессу-потомку записи таблицы процессов ядро устанавливает бит трассировки. Процесс- потомок предназначен для запуска (exec) трассируемой программы. Например, если пользователь ведет отладку программы a.out, процесс-потомок запускает файл с тем же именем. Ядро отрабатывает функцию exec обычным порядком, но в финале замечает, что бит трассировки установлен, и посылает процессу-