- •Глава 10. Подсистема управления вводом-выводом
- •10.1 Взаимодействие драйверов с программной и аппаратной средой
- •10.1.1 Конфигурация системы
- •10.1.2 Системные функции и взаимодействие с драйверами
- •1. Просматривается таблица файлов для того, чтобы убедиться в том, что ни
- •2. Если устройство символьного типа, ядро запускает процедуру закрытия уст-
- •Ibm 370 имеется инструкция "Start I/o" (Начать ввод-вывод), которая иниции-
- •10.1.2.4 Стратегический интерфейс
- •10.1.2.5 Ioctl
- •Ioctl(fd,command,arg);
- •10.1.2.6 Другие функции, имеющие отношение к файловой системе
- •10.1.3 Программы обработки прерываний
- •5, Как пользуясь блочным интерфейсом, так и не прибегая к структурированию
- •0, Младший - 21. Файл "/dev/rdsk15" соответствует устройству посимвольного
- •10.3 Терминальные драйверы
- •Ioctl. Когда соответствующие критерии удовлетворены, программа обработки
- •Ioctl для того, чтобы перевести терминал в режим без обработки: он отключает
- •10.3.5 Назначение операторского терминала
- •10.3.6 Драйвер косвенного терминала
- •10.3.7 Вход в систему
- •10.4 Потоки
- •10.4.2 Анализ потоков
Ioctl. Когда соответствующие критерии удовлетворены, программа обработки
прерываний строкового интерфейса возобновляет выполнение всех приостановлен-
ных процессов. Драйвер пересылает все символы из списка для хранения нест-
руктурированных вводных данных в канонический список и выполняет запрос про-
цесса на чтение, следуя тому же самому алгоритму, что и в случае работы в
каноническом режиме. Режим без обработки символов особенно важен в экран-
но-ориентированных приложениях, таких как экранный редактор vi, многие из
команд которого не заканчиваются символом возврата каретки. Например, коман-
да dw удаляет слово в текущей позиции курсора.
На Рисунке 10.17 приведена программа, использующая функцию ioctl для
сохранения текущих установок терминала для файла с дескриптором 0, что соот-
ветствует значению дескриптора файла стандартного ввода. Функция ioctl с ко-
мандой TCGETA приказывает
драйверу извлечь установки и сохранить их в структуре с именем savetty в ад-
ресном пространстве задачи. Эта команда часто используется для того, чтобы
определить, является ли файл терминалом или нет, поскольку она ничего не из-
меняет в системе: если она завершается неудачно, процессы предполагают, что
файл не является терминалом. Здесь же, процесс вторично вызывает функцию
Ioctl для того, чтобы перевести терминал в режим без обработки: он отключает
эхо-сопровождение ввода символов и готовится к выполнению операций чтения с
+----------------------------------------------------------------+
| #include |
| #include |
| struct termio savetty; |
| main() |
| { |
| extern sigcatch(); |
| struct termio newtty; |
| int nrd; |
| char buf[32]; |
| signal(SIGINT,sigcatch); |
| if (ioctl(0,TCGETA,&savetty) == -1) |
| { |
| printf("ioctl завершилась неудачно: нет терминала\n"); |
| exit(); |
| } |
| newtty = savetty; |
316
| newtty.c_lflag &= ~ICANON;/* выход из канонического режима */|
| newtty.c_lflag &= ~ECHO; /* отключение эхо-сопровождения*/ |
| newtty.c_cc[VMIN] = 5; /* минимум 5 символов */ |
| newtty.c_cc[VTIME] = 100; /* интервал 10 секунд */ |
| if (ioctl(0,TCSETAF,&newtty) == -1) |
| { |
| printf("не могу перевести тер-л в режим без обработки\n");|
| exit(); |
| } |
| for(;;) |
| { |
| nrd = read(0,buf,sizeof(buf)); |
| buf[nrd] = 0; |
| printf("чтение %d символов '%s'\n",nrd,buf); |
| } |
| } |
| sigcatch() |
| { |
| ioctl(0,TCSETAF,&savetty); |
| exit(); |
| } |
+----------------------------------------------------------------+
Рисунок 10.17. Режим без обработки - чтение 5-символьных блоков
+----------------------------------------------------------------+
| #include |
| |
| main() |
| { |
| register int i,n; |
| int fd; |
| char buf[256]; |
| |
| /* открытие терминала только для чтения с опцией "no delay" */ |
| if((fd = open("/dev/tty",O_RDONLY|O_NDELAY)) == -1) |
| exit(); |
| |
| n = 1; |
| for(;;) /* всегда */ |
| { |
| for(i = 0; i < n; i++) |
| ; |
| |
| if(read(fd,buf,sizeof(buf)) > 0) |
| { |
| printf("чтение с номера %d\n",n); |
| n--; |
| } |
| else |
| /* ничего не прочитано; возврат вследствие "no delay" */ |
| n++; |
| } |
| } |
+----------------------------------------------------------------+
Рисунок 10.18. Опрос терминала
317
терминала по получении с терминала 5 символов, как минимум, или по прохожде-
нии 10 секунд с момента ввода первой порции символов. Когда процесс получает
сигнал о прерывании, он сбрасывает первоначальные параметры терминала и за-
вершается.
10.3.4 Опрос терминала
Иногда удобно производить опрос устройства, то есть считывать с него
данные, если они есть, или продолжать выполнять обычную работу - в противном
случае. Программа на Рисунке 10.18 иллюстрирует этот случай: после открытия
терминала с параметром "no delay" (без задержки) процессы, ведущие чтение с
него, не приостановят свое выполнение в случае отсутствия данных, а вернут
управление немедленно (см. алгоритм terminal_read, Рисунок 10.15). Этот ме-
тод работает также, если процесс следит за множеством устройств: он может
открыть каждое устройство с параметром "no delay" и опросить всех из них,
ожидая поступления информации с каждого. Однако, этот метод растрачивает вы-
числительные мощности системы.
В системе BSD есть системная функция select, позволяющая производить оп-
рос устройства. Синтаксис вызова этой функции:
select(nfds,rfds,wfds,efds,timeout)
где nfds - количество выбираемых дескрипторов файлов, а rfds, wfds и efds
указывают на двоичные маски, которыми "выбирают" дескрипторы открытых фай-
лов. То есть, бит 1 << fd (сдвиг на 1 разряд влево значения дескриптора фай-
ла) соответствует установке на тот случай, если пользователю нужно выбрать
этот дескриптор файла. Параметр timeout (тайм-аут) указывает, на какое время
следует приостановить выполнение функции select, ожидая поступления данных,
например; если данные поступают для любых дескрипторов и тайм-аут не закон-
чился, select возвращает управление, указывая в двоичных масках, какие деск-
рипторы были выбраны. Например, если пользователь пожелал приостановиться до
момента получения данных по дескрипторам 0, 1 или 2, параметр rfds укажет на
двоичную маску 7; когда select возвратит управление, двоичная маска будет
заменена маской, указывающей, по каким из дескрипторов имеются готовые дан-
ные. Двоичная маска wfds выполняет похожую функцию в отношении записи деск-
рипторов, а двоичная маска efds указывает на существование исключительных
условий, связанных с конкретными дескрипторами, что бывает полезно при рабо-
те в сети.