Структура streamtab
используется ядром для доступа к точкам входа драйвера или модуля — к процедурам его очередей xx open()
, xx close()
, xx put()
и xx service()
. Для этого streamtab
содержит два указателя на структуры qinit
, соответственно, для обработки сообщений очереди чтения и записи. Два других указателя, также на структуры qinit
, используются только для мультиплексоров для обработки команды I_LINK
, используемой при конфигурации мультиплексированного потока. Каждая структура qinit
определяет процедуры, необходимые для обработки сообщений вверх и вниз по потоку (очередей чтения и записи). Функции xx open()
и xx close()
являются общими для всего модуля и определены только для очереди чтения. Все очереди модуля имеют ассоциированную с ними процедуру xx put()
, в то время как процедура xx service()
определяется только для очередей, реализующих управление передачей. Каждая структура qinit
также имеет указатель на структуру module_info
, которая обычно определяется для всего модуля и хранит базовые значения таких параметров, как максимальный и минимальный размеры передаваемых пакетов данных ( mi_maxpsz
, mi_minpsz
), значения ватерлиний ( mi_hiwat
, mi_lowait
), а также идентификатор и имя драйвера (модуля) ( mi_idnum
, mi_idname
).
Доступ к драйверам STREAMS осуществляется с помощью коммутатора символьных устройств — таблицы cdevsw[]
. Каждая запись этой таблицы имеет поле d_str
, которое равно NULL
для обычных символьных устройств. Для драйверов STREAMS это поле хранит указатель на структуру streamtab
драйвера. Таким образом, через коммутатор устройств ядро имеет доступ к структуре streamtab
драйвера, а значит и к его точкам входа. Для обеспечения доступа к драйверу из прикладного процесса необходимо создать файловый интерфейс — т.е. специальный файл символьного устройства, старший номер которого был бы равен номеру элемента cdevsw[]
, адресующего точки входа драйвера.
Поток создается при первом открытии с помощью системного вызова специального файла устройства, ассоциированного с драйвером STREAMS. Как правило, процесс создает поток в два этапа: сначала создается элементарный поток, состоящий из нужного драйвера и головного модуля (являющегося обязательным приложением), а затем производится встраивание дополнительных модулей для получения требуемой функциональности.
Процесс открывает поток с помощью системного вызова open (2) , передавая ему в качестве аргумента имя специального файла устройства. При этом ядро производит трансляцию имени и обнаруживает, что адресуемый файл принадлежит файловой системе specfs, через которую в дальнейшем производятся все операции работы с файлом. В памяти размещается vnode этого файла и вызывается функция открытия файла для файловой системы specfs — spec_open()
. В свою очередь spec_open()
находит требуемый элемент коммутатора cdevsw[]
и обнаруживает, что поле d_str
ненулевое. Тогда она вызывает процедуру подсистемы STREAMS stropen()
, которая отвечает за размещение головного модуля и подключение драйвера. После выполнения необходимых операций поток приобретает вид, изображенный на рис. 5.22.
Рис. 5.22. Структура потока после открытия
Головной модуль представлен структурой stdata
, которая выполняет роль интерфейса между потоком и ядром системы при выполнении операций чтения, записи и управления. Индексный дескриптор vnode содержит указатель на эту структуру. Поля q_ptr
структур queue
головного модуля также указывают на stdata
. Поля q_qinfo
очередей queue
указывают на структуры qinit
, адресующие общие для всех головных модулей функции, реализованные самой подсистемой STREAMS.
Очереди чтения и записи драйвера связываются с соответствующими очередями головного модуля. Информация, хранящаяся в структуре streamtab
используется для заполнения полей q_qinfo
соответствующих структур queue драйвера указателями на процедурные интерфейсы очередей чтения и записи.
В завершение вызывается функция xx open()
драйвера. При последующих операциях открытия потока функция stropen()
последовательно вызовет функции xx open()
каждого модуля и драйвера, тем самым информируя их, что другой процесс открыл тот же поток, и позволяя разместить соответствующие структуры данных для обработки нескольких каналов одновременно. Обычно открытие потоков производится через драйвер клонов.
Читать дальше