Эта функция адресует очередь следующего модуля параметром q
xx
put этой очереди, передавая ей сообщение mp
. Не поощряется непосредственный вызов функции xx
put следующего модуля, поскольку это может вызвать определенные проблемы переносимости.Передача данных внутри потока осуществляется асинхронно и не может блокировать процесс. Блокирование процесса возможно только при передаче данных между процессом и головным модулем. Таким образом, функции обработки данных потока —
xx
service не могут блокироваться. Если процедура xx
put не может передать данные следующему модулю, она помещает сообщение в собственную очередь, откуда оно может быть передано позже процедурой xx
service. Если и процедура xx
service не может осуществить передачу сообщения, например, из-за переполнения очереди следующего модуля, она не будет ожидать изменения ситуации, а вернет сообщение обратно в собственную очередь и завершит выполнение. Попытка передачи повторится, когда ядро через некоторое время опять запустит xx
service.Процедура
xx
service может заблокировать (перевести в состояние сна) независимый процесс, что может привести к непредсказуемым результатам и потому недопустимо. Решение этой проблемы заключается в запрещении процедурам xx
put и xx
service блокирования своего выполнения.Блокирование недопустимо и для драйвера. Обычно прием данных драйвером осуществляется с использованием прерываний. Таким образом процедура
Когда процедура
#include
int putq(queue_t *q, mblk_t *mp);
Функция
xx
service. Планирование вызова процедур xx
service производится функцией ядра runqueues
.[59] Функция runqueues
вызывается ядром в двух случаях:Когда какой-либо процесс выполняет операцию ввода/вывода над потоком.
Непосредственно перед переходом какого-либо процесса из режима ядра в режим задачи.
Заметим, что планирование обслуживания очередей не связано с конкретным процессом и производится для всей подсистемы STREAMS в целом.
Функция runqueue
xx
service. Каждая процедура xx
service, в свою очередь, пытается передать все сообщения очереди следующему модулю. Если для каких-либо сообщений это не удается, они остаются в очереди, ожидая следующего вызова runqueue
, после чего процесс повторяется.Управление передачей данных
Деление процесса передачи данных на два этапа, выполняемых, соответственно, функциями
xx
service, позволяет реализовать механизм управления передачей данных.Как уже упоминалось, обязательной для модуля является лишь функция
xx
service. В этом случае, проиллюстрированном на рис. 5.19, каждый предыдущий модуль вызывает функцию xx
put следующего, передавая ему сообщение, с помощью функции ядра xx
put немедленно вызывает xxput(queue_t *q, mblk_t *mp) {
putnext(q, mp);
}
Рис. 5.19
. Передача данных без управления потокомКогда данные достигают драйвера, он передает их непосредственно устройству. Если устройство занято, или драйвер не может немедленно обработать данные, сообщение уничтожается. В данном примере никакого управления потоком не происходит, и очереди сообщений не используются.