- •Подсистема управления вводом-выводом
- •Int creat(const char *path, mode_t mode);
- •Int open(const char *path, int oflag, ...);
- •Int fildes;
- •Int close(int fildes);
- •Int fildes;
- •1.Взаимодействие драйверов с программной и аппаратной средой
- •10.3.4 Опрос терминала
- •2. Основы tcp/ip
- •2.1. Модуль ip создает единую логическую сеть
- •-----------------------------¬ --------------------------------¬
- •--------------------------------------------¬
- •Ip-сеть "development" ip-сеть "accounting"
- •223.1.2.1 Alpha
- •Int socket(int domain, int type, int protocol)
- •11.20. Процесс создает в домене "unix system" гнездо потокового
Int fildes;
char *buf;
int size;
Функция read выполняет чтение из файла с дескриптором fildes в пользовательский буфер buf указанного в параметре size количества байт. Функция возвращает число фактически прочитанных байт. Если файл является специальным файлом устройства или каналом и если в вызове функции open был установлен бит O_NDELAY, функция read в случае отсутствия доступных для чтения данных возвратит управление немедленно.
write
write(fd,buf,count)
int fd,count;
char *buf;
Функция write выполняет запись указанного в count количества байт данных, начиная с адреса buf, в файл с дескриптором fd.
ioctl
ioctl(fildes,cmd,arg)
int fildes,cmd;
Функция ioctl выполняет набор специальных операций по отношению к открытому устройству, дескриптор которого указан в параметре fildes. Тип команды, выполняемой по отношению к устройству, описывается параметром cmd, а параметр arg является аргументом команды.
Система поддерживает «программные устройства», с каждым из которых не связано ни одно конкретное физическое устройство. Например, как устройство трактуется физическая память, чтобы позволить процессу обращаться к ней извне, пусть даже память не является периферийным устройством. Команда ps обращается к информационным структурам ядра в физической памяти, чтобы сообщить статистику процессов.
1.Взаимодействие драйверов с программной и аппаратной средой
В системе UNIX имеется два типа устройств - устройства ввода-вывода блоками и устройства неструктурированного или посимвольного ввода-вывода. Устройства ввода-вывода блоками, такие как диски, для остальной части системы выглядят как запоминающие устройства с произвольной выборкой; к устройствам посимвольного ввода-вывода относятся все другие устройства, в том числе терминалы и сетевое оборудование. Пользователь взаимодействует с устройствами через посредничество файловой системы. Каждое устройство имеет имя, похожее на имя файла, и пользователь обращается к нему как к файлу. Специальный файл устройства имеет индекс и занимает место в иерархии каталогов файловой системы. Файл устройства отличается от других файлов типом файла, хранящимся в его индексе, либо «блочный», либо «символьный специальный», в зависимости от устройства, которое этот файл представляет. Если устройство имеет как блочный, так и символьный интерфейс, его представляют два файла: специальный файл устройства ввода-вывода блоками и специальный файл устройства посимвольного ввода-вывода. Системные функции для обычных файлов, такие как open, close, read и write, имеют то же значение и для устройств, в чем мы убедимся позже. Системная функция ioctl предоставляет процессам возможность управлять устройствами посимвольного ввода-вывода, но не применима в отношении к файлам обычного типа. (И наоборот, системная функция fcntl обеспечивает контроль над действиями, производимыми на уровне дескриптора файла, но не на уровне устройства. В других реализациях функция ioctl применима для файлов всех типов).
Подсистема управления вводом-выводом
-------------------------------------------------------------¬
¦ open close ¦
¦ open close read write ioctl read write ¦
¦ mount umount ¦
L--+-----+----+-----+-----+------------+-----+-----+-----+----
¦ ¦ ¦ ¦ ¦ ¦ ¦ --+-----+---¬
¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ функции ¦
¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ работы с ¦
¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ буферным ¦
¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ кешем ¦
¦ ¦ ¦ ¦ ¦ ¦ ¦ L-----T------
¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦
---+-----+----+-----+-----+-¬ -+-----+---------+-----¬
¦ Таблица ключей устройств ¦ ¦ Таблица ключей уст- ¦
¦ посимвольного ввода-вывода¦ ¦ ройств ввода-вывода ¦
¦ ¦ ¦ блоками ¦
L--T-----T----T-----T-----T-- L--T------T--------T----
¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦
¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦
---+-----+----+-----+-----+-¬ ---+------+--------+---¬
¦open close read write ioctl¦ Точки ¦ open close strategy ¦
¦ ¦ входа ¦ ¦
¦ Драйвер ¦ для ¦ Драйвер ¦
¦ ¦ драй- ¦ ¦
¦программа обработки преры- ¦ веров ¦ программа обработки ¦
¦ ваний от устройства ¦ ¦прерываний от устройств¦
L------------+--------------- L-----------+-----------
¦ ¦
---------+----------¬ ----------+---------¬
¦ Вектор прерывания ¦ ¦ Вектор прерывания ¦
L--------T----------- L---------T----------
¦ ¦
L-------------------T-----------------
¦
Прерывания от устройств
Рисунок 1. Точки входа для драйверов
Интерфейс «ядро - драйвер» описывается в таблице ключей устройств ввода-вывода блоками и в таблице ключей устройств посимвольного ввода-вывода (Рисунок 1). Каждый тип устройства имеет в таблице точки входа, которые при выполнении системных функций адресуют ядро к соответствующему драйверу. Функции open и close, вызываемые файлом устройства, «пропускаются» через таблицы ключей устройств в соответствии с типом файла. Функции mount и umount так же вызывают выполнение процедур открытия и закрытия устройств, но для устройств ввода-вывода блоками. Функции read и write, вызываемые устройствами ввода-вывода блоками и файлами в смонтированных файловых системах, запускают алгоритмы работы с буферным кешем, инициирующие реализацию стратегической процедуры работы с устройствами.
Специальные файлы устройств устанавливаются командой mknod, в которой указывается тип файла (блочный или символьный), старший и младший номера устройства. Команда mknod запускает выполнение системной функции с тем же именем, создающей файл устройства. Например, в командной строке
mknod/dev/tty13c2 13
«/dev/tty13» - имя файла устройства, «c» указывает, что тип файла - «символьный специальный» («b», соответственно, блочный), «2» -старший номер устройства, «13» - младший номер устройства. Старший номер устройства показывает его тип, которому соответствует точка входа в таблице ключей устройств, младший номер устройства - это порядковый номер единицы устройства данного типа.
------------------------------------------------¬
¦ таблица ключей устройств ввода-вывода блоками ¦
+-------T--------T---------T--------------------+
¦ вход ¦ open ¦ close ¦ strategy ¦
+-------+--------+---------+--------------------+
¦ 0 ¦ gdopen ¦ gdclose ¦ gdstrategy ¦
+-------+--------+---------+--------------------+
¦ 1 ¦ gtopen ¦ gtclose ¦ gtstrategy ¦
L-------+--------+---------+---------------------
-----------------------------------------------------------------¬
¦ таблица ключей устройств посимвольного ввода-вывода ¦
+------T-----------T-----------T---------T-----------T-----------+
¦ вход ¦ 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 ¦
L------+-----------+-----------+---------+-----------+------------
Рисунок 10.2. Пример заполнения таблиц ключей устройств ввода-
вывода блоками и символами
Если процесс открывает специальный блочный файл с именем «/dev/dsk1» и кодом 0, ядро запускает программу gdopen в точке 0 таблицы ключей устройств блочного ввода-вывода (Рисунок 10.2); если процесс читает специальный символьный файл с именем «/dev/mem» и кодом 3,ядро запускает программу mmread в точке 3 таблицы ключей устройств посимвольного ввода-вывода. Программа nulldev - это «пустая» программа, используемая в тех случаях, когда отсутствует необходимость в конкретной функции драйвера. С одним старшим номером устройства может быть связано множество периферийных устройств; младший номер устройства позволяет отличить их одно от другого. Не нужно создавать специальные файлы устройств при каждой загрузке системы; их только нужно корректировать, если изменилась конфигурация системы, например, если к установленной конфигурации были добавлены устройства.
На Рисунке приведена программа, использующая функцию ioctl для сохранения текущих установок терминала для файла с дескриптором 0, что соответствует значению дескриптора файла стандартного ввода. Функция ioctl с командой TCGETA приказывает
┌────────────────────────────────────────────────────────────────┐
│ #include <signal.h> │
│ #include <termio.h> │
│ 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; │
│ 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-символьных блоков
драйверу извлечь установки и сохранить их в структуре с именем savetty в адресном пространстве задачи. Эта команда часто используется для того, чтобы определить, является ли файл терминалом или нет, поскольку она ничего не изменяет в системе: если она завершается неудачно, процессы предполагают, что файл не является терминалом. Здесь же, процесс вторично вызывает функцию ioctl для того, чтобы перевести терминал в режим без обработки: он отключает эхо-сопровождение ввода символов и готовится к выполнению операций чтения с терминала по получении с терминала 5 символов, как минимум, или по прохождении 10 секунд с момента ввода первой порции символов. Когда процесс получает сигнал о прерывании, он восстанавливает первоначальные параметры терминала и завершается.
┌────────────────────────────────────────────────────────────────┐
│ #include <fcntl.h> │
│ │
│ 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",i); │
│ } │
│ else │
│ /* ничего не прочитано; возврат вследствие "no delay" */ │
│ } │
│ } │
└────────────────────────────────────────────────────────────────┘
Рисунок 10.18. Опрос терминала