Чтение онлайн

ЖАНРЫ

Шрифт:

Сообщения

В подсистеме STREAMS все данные передаются в виде сообщений. С помощью сообщений передаются данные от приложений к драйверу и обратно. Сообщения используются для взаимодействия модулей между собой. Модули могут также генерировать сообщения для уведомления прикладного процесса или друг друга о возникновении ошибок или непредвиденных ситуаций. Таким образом, сообщения являются единственным способом передачи информации между различными компонентами потока и потому занимают ключевое место в подсистеме STREAMS.

Сообщение описывается двумя структурами данных: заголовком сообщения

msgb
(message block) и заголовком блока данных
datab
(data block). Обе эти структуры адресуют буфер данных, где находятся фактические данные сообщения.

Заголовок сообщения

msgb
имеет следующие поля:

b_next
,
b_prev
Используются для формирования связанного списка сообщений и соответственно адресуют следующее и предыдущее сообщение очереди
b_cont
Указывает
на продолжение сообщения и используется для связывания различных частей одного сообщения
b_datap
Указатель на заголовок блока данных
b_rptr
,
b_wptr
Указатели, определяющие расположение (начало и конец) данных в буфере данных
b_cont
Содержит ссылку на следующую структуру
msgb

Заголовок блока данных

datab
используется для описания буфера и имеет следующие поля:

db_base
Адрес начала буфера
db_lim
Адрес ячейки памяти, следующей непосредственно за буфером. Таким образом, размер буфера равен
db_lim - db_base
db_type
Тип сообщения
db_ref
Число заголовков сообщения, адресующих этот блок

Использование этих структур данных для формирования очереди сообщений и сообщений, состоящих из нескольких частей, показано на рис. 5.17.

Рис. 5.17. Сообщения STREAMS

Поле

b_cont
заголовка сообщения позволяет объединять несколько блоков данных в одно сообщение. Эта возможность особенно полезна при использовании подсистемы STREAMS для реализации сетевых протоколов. Сетевые протоколы имеют уровневую организацию. По мере передачи данных вниз по потоку, каждый последующий модуль (реализующий протокол определенного уровня) добавляет собственную управляющую информацию. Поскольку протоколы верхнего уровня не имеют представления об архитектуре нижних, невозможно заранее зарезервировать необходимую память под сообщение. Вместо того чтобы изменять размер буфера данных сообщения, модуль может добавлять управляющую информацию в виде отдельных частей, связывая их с помощью указателя
b_cont
. Этот процесс, получивший название инкапсуляции данных, графически представлен на рис. 5.18.

Рис. 5.18. Инкапсуляция данных с использованием составных сообщений

Поле

db_ref
заголовка блока данных позволяет нескольким заголовкам сообщения совместно использовать один и тот же буфер. При этом происходит виртуальное копирование сообщения, каждая копия которого может обрабатываться отдельно. Как правило, такой буфер используется совместно только для чтения, хотя сама подсистема STREAMS не накладывает никаких ограничений, возлагая всю ответственность за обработку данных на модули потока.

В качестве примера виртуального копирования можно привести реализацию протокола TCP. Протокол TCP является надежным, т.е. данные считаются доставленными только после того, как от получателя поступит подтверждение. Это означает, что протокол должен хранить копии всех отправленных, но не подтвержденных сообщений. Вместо неэффективного физического копирования, производится виртуальное дублирование сообщения, одна копия которого затем передается вниз по потоку (модулю IP), а вторая сохраняется до получения подтверждения. После отправления сообщения драйвером сетевого адаптера, одна из копий будет уничтожена, что выразится в уменьшении поля

db_ref
заголовка блока данных, но сам блок данных сохранится, поскольку значение счетчика по-прежнему будет превышать 0. И только после получения подтверждения
db_ref
станет равным 0, и соответствующий буфер будет освобожден.

Типы сообщений

Каждое сообщение принадлежит определенному типу, определяющему назначение сообщения и его приоритет. В зависимости от типа сообщения попадают в одну из двух категорий: обычные сообщения и приоритетные сообщения. Категория определяет порядок, в котором сообщения будут обрабатываться соответствующей процедурой

xxservice
. Приоритетные сообщения всегда помещаются перед обычными сообщениями и потому обрабатываются в первую очередь.

В подсистеме STREAMS определены следующие типы обычных сообщений:

M_DATA
Содержит обычные данные. Например, системные вызовы read(2) и write(2) осуществляют передачу данных в виде сообщений этого типа.
M_PROTO
Содержит управляющую информацию. Обычно сообщение этого типа содержит также несколько блоков типа
M_DATA
. С помощью системных вызовов putmsg(2) и getmsg(2) процесс имеет возможность отправлять и получать как управляющую часть сообщения (блок
M_PROTO
), так и данные (блоки
M_DATA
).
M_BREAK
Посылается драйверу устройства для генерации команды break.
M_PASSFP
Используется в каналах STREAMS (STREAMS pipe) для передачи файлового указателя от одного конца канала к другому.
M_SIG
Генерируется модулями или драйверами и передается вверх по потоку головному модулю для отправления процессу сигнала.
M_DELAY
Передается
драйверу устройства и указывает задержку между последовательно передаваемыми символами. Как правило, используется при работе с медленными устройствами во избежание переполнения их буферов.
M_CTL
Используется для взаимодействия модулей потока друг с другом. Все сообщения этого типа уничтожаются головным модулем и, таким образом, не могут распространяться за пределы потока.
M IOCTL
Формируется головным модулем в ответ на управляющие команды, переданные процессом с помощью системного вызова ioctl(2):
I_LINK
,
I_UNLINK
,
I_PLINK
,
I_PUNLINK
и
I_STR
. Эти команды используются для создания мультиплексированных потоков. Последняя команда используется для управления модулями потока.
M_SETOPTS
Используется для задания различных характеристик головного модуля.
M_RSE
Зарезервировано для внутреннего использования. Модули и драйверы должны передавать его без изменений.

Как мы увидим далее, на передачу обычных сообщений влияет механизм управления потоком данных, который может быть реализован модулями потока. Этот механизм не оказывает влияния на передачу приоритетных сообщений. Сообщения этой категории будут переданы следующему модулю, независимо от того, насколько заполнена его очередь. Эти сообщения обеспечивают основное взаимодействие между компонентами потока. Перечисленные ниже сообщения являются высокоприоритетными:

M_COPYIN
Передается вверх по потоку головному модулю и указывает ему скопировать данные от процесса для команды ioctl(2). Сообщение допустимо в интервале между получением сообщения
M_IOCTL
и сообщения
M_IOCACK
или
M_IOCNAK
.
M_COPYOUT
Передается вверх по потоку головному модулю и указывает ему передать данные, связанные с вызовом ioctl(2), процессу. Сообщение допустимо в интервале между получением сообщения
M_IOCTL
и сообщений
M_IOCACK
или
M_IOCNAK
.
M_ERROR
Передается вверх по потоку головному модулю и указывает на возникновение ошибки вниз по потоку. Последующие операции с потоком будут заканчиваться ошибкой, за исключением системных вызовов close(2) и poll(2).
M_FLUSH
При получении этого сообщения модуль должен очистить очередь (чтения, записи или обе) от сообщений.
M_HANGUP
Передается вверх по потоку головному модулю и указывает, что драйвер не может передавать данные, обычно из-за обрыва линии (связи с удаленным объектом).
M_IOCACK
Подтверждение предыдущего сообщения
M_IOCTL
. В ответ головной модуль возвратит необходимые данные процессу, сделавшему системный вызов ioctl(2).
M_IOCNAK
Если выполнение команды ioctl(2) закончилось неудачей, это сообщение передается вверх по потоку головному модулю, в ответ на это последний возвратит процессу ошибку.
M_PCPROTO
Высокоприоритетная версия сообщения
M_PROTO
.
M_PCSIG
Высокоприоритетная версия сообщения
M_SIG
.
M_PCRSE
Зарезервировано для внутреннего использования в подсистеме.
M_READ
Сообщение передается вниз по потоку, когда от процесса поступает запрос на чтение, но в головном модуле отсутствуют данные.
M_STOP
Предписывает немедленно прекратить передачу.
M_START
Предписывает продолжить передачу после останова, вызванного сообщением
M_STOP
.

Передача данных

Как уже обсуждалось, передача данных в потоке происходит в виде сообщений. Процесс инициирует передачу данных с помощью системных вызовов write(2) и putmsg(2), которые непосредственно взаимодействуют с головным модулем. Головной модуль формирует сообщение, копируя в него прикладные данные, и передает его следующему модулю вниз по потоку. В конечном итоге сообщение принимается драйвером, который выполняет необходимые операции с конкретным устройством. В случае, когда драйвер получает данные от устройства, он также передает их в виде сообщений вверх по потоку. Процесс имеет возможность получить данные с помощью системных вызовов read(2) или getmsg(2). Если в головном модуле данные отсутствуют, процесс блокируется и переходит в состояние сна.

Сообщения передаются модулями с помощью системной функции putnext(9F):

#include <sys/stream.h>

#include <sys/ddi.h>

int putnext(queue_t *q, mblk_t *mp);

Эта функция адресует очередь следующего модуля параметром

q
и вызывает процедуру
xxput
этой очереди, передавая ей сообщение
mp
. Не поощряется непосредственный вызов функции
xxput
следующего модуля, поскольку это может вызвать определенные проблемы переносимости.

Поделиться с друзьями: