Читаем без скачивания Операционная система UNIX - Андрей Робачевский
Шрифт:
Интервал:
Закладка:
Если головной модуль не может обработать команду, он формирует сообщение M_IOCTL и копирует в него команду (ic_cmd) и блок параметров (ic_len, ic_dp). После этого сообщение направляется вниз по потоку. Когда модуль получает сообщение, оно содержит все необходимые данные для обработки команды. Если команда предполагает передачу информации процессу, модуль записывает необходимые данные в то же сообщение, изменяет его тип на M_IOCACK и отправляет его вверх по потоку. В свою очередь головной модуль получает сообщение и производит передачу параметров процессу.
Другой подход получил название прозрачных команд ioctl(2) (transparent ioctl). Он позволяет использовать стандартные команды ioctl(2), решая при этом проблему копирования данных. Когда процесс выполняет вызов ioctl(2), головной модуль формирует сообщение M_IOCTL и копирует в него параметры вызова — command и arg. Обычно параметр arg является указателем на блок параметров, размер и содержимое которого известны только модулю (или драйверу), отвечающему за обработку данной команды. Поэтому головной модуль просто копирует этот указатель, не интерпретируя его и тем более не копируя в сообщение сам блок параметров. Сообщение передается вниз по потоку.
Когда модуль получает сообщение, в ответ он отправляет сообщение M_COPYIN, содержащее размер и расположение данных[65], необходимых для выполнения команды. Головной модуль пробуждает процесс, вызвавший ioctl(2), для копирования параметров. Поскольку последующие операции выполняются в контексте процесса, никаких проблем доступа к его адресному пространству не возникает. Головной модуль создает сообщение M_IOCARGS, копирует в него параметры команды и направляет сообщение вниз по потоку. После этого процесс опять переходит в состояние сна.
Когда модуль получает сообщение M_IOCARGS, он интерпретирует содержащиеся в нем параметры и выполняет команду. В некоторых случаях для получения всех параметров, необходимых для выполнения команды, может потребоваться дополнительный обмен сообщениями M_COPYIN и M_IOCARGS. Такая ситуация может возникнуть, например, если один из параметров являлся указателем на структуру данных. Для получения копии структуры модулю потребуется дополнительная итерация.
После получения всех необходимых данных и выполнения команды в случае, если результат должен быть передан процессу, модуль формирует одно или несколько сообщений M_COPYOUT, помещая в них требуемые данные, и направляет их вверх по потоку. Головной модуль пробуждает процесс, передавая ему результаты выполнения команды. Когда все результаты переданы процессу, модуль посылает подтверждение M_IOCACK, в результате которого головной модуль пробуждает процесс в последний раз, завершая тем самым выполнение вызова ioctl(2).
Мультиплексирование
Подсистема STREAMS обеспечивает возможность мультиплексирования потоков с помощью мультиплексора, который может быть реализован только драйвером STREAMS. Различают три типа мультиплексоров — верхний, нижний и гибридный. Верхний мультиплексор, называемый также мультиплексором N:1, обеспечивает подключение нескольких каналов вверх по потоку к одному каналу вниз по потоку. Нижний мультиплексор, называемый также мультиплексором 1:M, обеспечивает подключение нескольких каналов вниз по потоку к одному каналу вверх по потоку. Гибридный мультиплексор, как следует из названия, позволяет мультиплексировать несколько каналов вверх по потоку с несколькими каналами вниз по потоку.
Заметим, что подсистема STREAMS обеспечивает возможность мультиплексирования, но за идентификацию различных каналов и маршрутизацию данных между ними отвечает сам мультиплексор.
Мультиплексирование каналов вверх по потоку осуществляется в результате открытия одного и того же драйвера с различными младшими номерами. Верхний мультиплексор должен обеспечить возможность одновременной работы с устройством с использованием различных младших номеров. Если два процесса открывают поток, используя различные младшие номера, ядро создаст отдельный канал для каждого из них, каждый из них будет адресоваться отдельным vnode, и процедура xxopen() драйвера будет вызвана дважды. Драйвер при этом будет обрабатывать две пары очередей, каждая из которых отвечает за отдельный поток. Когда данные поступают от устройства, драйвер должен принять решение, в какую очередь чтения их направить. Обычно такое решение делается на основании управляющей информации, содержащейся в полученных данных. На рис. 5.23 представлен вид верхнего мультиплексора с двумя подключенными потоками.
Рис. 5.23. Верхний мультиплексор
Нижний мультиплексор представляет собой драйвер псевдоустройства. Вместо работы с физическим устройством он взаимодействует с несколькими каналами вниз по потоку. Для этого нижний мультиплексор обеспечивает работу с еще одной парой очередей — нижними очередями чтения и записи. Структура streamtab нижнего мультиплексора адресует процедурный интерфейс работы с нижними очередями соответственно полями st_muxrinit и st_muxwinit.
Для работы с мультиплексированными потоками подсистема STREAMS поддерживает четыре команды ioctl(2):
I_LINK Используется для объединения потоков. При этом файловый дескриптор указывает на поток, подключенный к мультиплексору. Второй файловый дескриптор, передаваемый в качестве аргумента команды, указывает на поток, который необходимо подключить ниже мультиплексора. I_PLINK Используется для потоков, которое сохраняется при закрытии файлового дескриптора. В остальном аналогично команде I_LINK. I_UNLINK, I_PUNLINK Используются для разъединения потоков, созданных командами I_LINK и I_PLINK.Создание мультиплексированного потока происходит в два этапа. Поясним этот процесс на примере создания стека протокола IP, поддерживающего работу как с адаптером Ethernet, так и с адаптером FDDI. Для этого необходимо объединить драйвер адаптера Ethernet, драйвер адаптера FDDI и драйвер IP, который является нижним мультиплексором. Процесс должен выполнить следующие действия:
fdenet = open("/dev/le", O_RDWR);
fdfddi = open("/dev/fddi", O_RDWR);
fdip = open("/dev/ip", O_RDWR);
ioctl(fdip, I_LINK, fdenet);
ioctl(fdip, I_LINK, fdfddi);
Сначала процесс создает три независимых потока, адресуемых дескрипторами fdenet, fdfddi и fdip (рис. 5.24, а) Для объединения потоков используется команда I_LINK системного вызова ioctl(2). В результате получается конфигурация, представленная на рис. 5.24, б.
Рис. 5.24. Создание мультиплексированного потока
В результате объединения потоков очереди и процедурный интерфейс головного модуля нижнего потока (в данном случае, потока, подключенного к драйверу Ethernet или FDDI), реализованный самой подсистемой STREAMS, заменяются на нижние очереди и соответствующий процедурный интерфейс мультиплексора. Более детально процесс объединения потока IP и потока Ethernet показан на рис. 5.25.
Рис. 5.25. Объединение верхнего и нижнего потоков
Задачей нижнего мультиплексора является хранение информации обо всех подключенных ниже потоках и обеспечение правильной маршрутизации между ними.
Заключение
Эта глава посвящена внутренней архитектуре подсистемы ввода/вывода, движущей силой которой являются драйверы устройств. Были рассмотрены традиционные типы драйверов, присутствующих в операционной системе UNIX с ранних ее версий, — символьные и блочные драйверы. Важную роль в процессе обмена данными с драйвером играют файловый интерфейс и файловая система.
Во второй части главы была описана архитектура драйверов подсистемы STREAMS, имеющая модульную структуру и позволяющая более изящно осуществить буферизацию данных и управление их передачей. Вопросы, затронутые в этой части, будут также рассмотрены в следующей главе при обсуждении архитектуры сетевого доступа в операционной системы UNIX.
Глава 6
Поддержка сети в операционной системе UNIX
Сегодня изолированный компьютер имеет весьма ограниченную функциональность. Дело даже не в том, что пользователи лишены возможности доступа к обширным информационным и вычислительным ресурсам, расположенным на удаленных системах. Изолированная система не имеет требуемой в настоящее время гибкости и масштабируемости. Возможность обмена данными между рассредоточенными системами открыла новые горизонты для построения распределенных ресурсов, их администрирования и наполнения, начиная от распределенного хранения информации (сетевые файловые системы, файловые архивы, информационные системы с удаленным доступом), и заканчивая сетевой вычислительной средой. UNIX — одна из первых операционных систем, которая обеспечила возможность работы в сети. И в этом одна из причин ее потрясающего успеха и долгожительства.