Процесс может получить данные из потока с помощью системных вызовов
M_DATA
и M_PROTO
, при этом сохраняются границы сообщений. Например, если полученное сообщение состоит из блока M_PROTO
и нескольких блоков M_DATA
, вызов Вызов
#include
int getmsg(int fildes, struct strbuf *ctlptr,
struct strbuf *dataptr, int *flagsp);
С помощью вызова
ctlptr
и dataptr
соответственно. Так же как и в случае strbuf
, которая отличается только тем, что поле maxlen
определяет максимальный размер буфера, a len
устанавливается равным фактическому числу полученных байтов. По умолчанию RS_HIPRI
, установленного в переменной, адресуемой аргументом flagsp
, процесс может потребовать получение только экстренных сообщений.В обоих случаях, если данные находятся в головном модуле, ядро извлекает их из сообщения, копирует в адресное пространство процесса и возвращает управление последнему. Если же в головном модуле отсутствуют сообщения, ожидающие получения, выполнение процесса блокируется, и он переходит в состояние сна до прихода сообщения.
Когда головной модуль получает сообщение, ядро проверяет, ожидает ли его какой-либо процесс. Если такой процесс имеется, ядро пробуждает процесс, копирует данные в пространство задачи и производит возврат из системного вызова. Если ни один из процессов не ожидает получения сообщения, оно буферизуется в очереди чтения головного модуля.
Доступ к потоку
Как и для обычных драйверов устройств, рассмотренных ранее, прежде чем процесс сможет получить доступ к драйверу STREAMS, необходимо встроить драйвер в ядро системы и создать специальный файл устройства — файловый интерфейс доступа. Независимо от того, как именно осуществляется встраивание (статически с перекомпиляцией ядра, или динамически), для этого используются три структуры данных, определенных для любого драйвера или модуля STREAMS: module_info
qinit
и streamtab
. Связь между ними представлена на рис. 5.21.Рис. 5.21
. Конфигурационные данные драйвера (модуля) STREAMSСтруктура 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[]
, адресующего точки входа драйвера.Создание потока