Поток создается при первом открытии с помощью системного вызова специального файла устройства, ассоциированного с драйвером STREAMS. Как правило, процесс создает поток в два этапа: сначала создается элементарный поток, состоящий из нужного драйвера и головного модуля (являющегося обязательным приложением), а затем производится встраивание дополнительных модулей для получения требуемой функциональности.
Процесс открывает поток с помощью системного вызова open
spec_open
. В свою очередь spec_open
находит требуемый элемент коммутатора cdevsw[]
и обнаруживает, что поле d_str
ненулевое. Тогда она вызывает процедуру подсистемы STREAMS stropen
, которая отвечает за размещение головного модуля и подключение драйвера. После выполнения необходимых операций поток приобретает вид, изображенный на рис. 5.22.Рис. 5.22
. Структура потока после открытияГоловной модуль представлен структурой stdata
q_ptr
структур queue
головного модуля также указывают на stdata
. Поля q_qinfo
очередей queue
указывают на структуры qinit
, адресующие общие для всех головных модулей функции, реализованные самой подсистемой STREAMS.Очереди чтения и записи драйвера связываются с соответствующими очередями головного модуля. Информация, хранящаяся в структуре streamtab
q_qinfo
соответствующих структур queue драйвера указателями на процедурные интерфейсы очередей чтения и записи.В завершение вызывается функция
stropen
последовательно вызовет функции xx
open каждого модуля и драйвера, тем самым информируя их, что другой процесс открыл тот же поток, и позволяя разместить соответствующие структуры данных для обработки нескольких каналов одновременно. Обычно открытие потоков производится через драйвер клонов.После открытия потока процесс может произвести встраивание необходимых модулей. Для этого используется системный вызов
I_PUSH
этой функции служит для встраивания модулей, а команда I_POP
— для извлечения модулей из потока. Приведем типичный сценарий конструирования потока:fd = open("/dev/stream", O_RDWR);
ioctl(fd, I_PUSH, "module1");
ioctl(fd, I_PUSH, "module2");
...
ioctl(fd, I_POP, (char*)0);
ioctl(fd, I_POP, (char*)0);
close(fd);
В этом примере процесс открыл поток /dev/stream
, а затем последовательно встроил модули module1 и module2. Заметим, что командаI_PUSH
системного вызова Поскольку модули описываются такими же структурами данных, что и драйверы, схемы их встраивания похожи. Как и в случае драйверов, для заполнения полей q_qinfo
streamtab
модуля. Для хранения информации, необходимой для инициализации модуля, во многих версиях UNIX используется таблица fmodsw[]
, каждый элемент которой хранит имя модуля и указатель на структуру streamtab
. После установления всех связей вызывается функция xx
open модуля.Управление потоком
Управление потоком осуществляется прикладным процессом с помощью команд системного вызова
#include
#include
#include
int ioctl(int fildes, int command, ... /* arg */);
Хотя часть команд обрабатывается исключительно головным модулем потока, другие предназначены промежуточным модулям или драйверу. Для этого головной модуль преобразует команды