Читаем Операционная система UNIX полностью

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

Передача данных внутри потока осуществляется асинхронно и не может блокировать процесс. Блокирование процесса возможно только при передаче данных между процессом и головным модулем. Таким образом, функции обработки данных потока — xxput и xxservice не могут блокироваться. Если процедура xxput не может передать данные следующему модулю, она помещает сообщение в собственную очередь, откуда оно может быть передано позже процедурой xxservice. Если и процедура xxservice не может осуществить передачу сообщения, например, из-за переполнения очереди следующего модуля, она не будет ожидать изменения ситуации, а вернет сообщение обратно в собственную очередь и завершит выполнение. Попытка передачи повторится, когда ядро через некоторое время опять запустит

xxservice.

Процедура xxservice вызывается в системном контексте, а не в контексте процесса, который инициировал передачу данных. Таким образом, блокирование процедуры xxservice может заблокировать (перевести в состояние сна) независимый процесс, что может привести к непредсказуемым результатам и потому недопустимо. Решение этой проблемы заключается в запрещении процедурам xxput и xxservice блокирования своего выполнения.

Блокирование недопустимо и для драйвера. Обычно прием данных драйвером осуществляется с использованием прерываний. Таким образом процедура xxput вызывается в контексте прерывания и не может блокировать свое выполнение.

Когда процедура xxput не может передать сообщение следующему модулю, она вызывает функцию putq(9F), имеющую следующий вид:

#include


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

Функция putq(9F) помещает сообщение mp в очередь q, где сообщение ожидает последующей передачи, и заносит очередь в список очередей, нуждающихся в обработке. Для таких очередей ядро автоматически вызывает процедуру xxservice. Планирование вызова процедур xxservice производится функцией ядра runqueues.[59] Функция runqueues вызывается ядром в двух случаях:

 Когда какой-либо процесс выполняет операцию ввода/вывода над потоком.

 Непосредственно перед переходом какого-либо процесса из режима ядра в режим задачи.

Заметим, что планирование обслуживания очередей не связано с конкретным процессом и производится для всей подсистемы STREAMS в целом.

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

Управление передачей данных

Деление процесса передачи данных на два этапа, выполняемых, соответственно, функциями xxput и xxservice, позволяет реализовать механизм управления передачей данных.

Как уже упоминалось, обязательной для модуля является лишь функция xxput. Рассмотрим ситуацию, когда модули потока не содержат процедур xx

service. В этом случае, проиллюстрированном на рис. 5.19, каждый предыдущий модуль вызывает функцию
xxput следующего, передавая ему сообщение, с помощью функции ядра putnext(9F). Функция xxput немедленно вызывает putnext(9F) и т.д.:

xxput(queue_t *q, mblk_t *mp) {

 putnext(q, mp);

}

Рис. 5.19. Передача данных без управления потоком

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

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже