А. Робачевский - Операционная система UNIX (1114671), страница 69
Текст из файла (страница 69)
Процесс инициирует передачу данных с помощью системных вы!www.books-shop.comSTREAMS363зововикоторые непосредственно взаимодействуют с го!ловным модулем. Головной модуль формирует сообщение, копируя в негоприкладные данные, и передает его следующему модулю вниз по потоку. Вконечном итоге сообщение принимается драйвером, который выполняетнеобходимые операции с конкретным устройством.
В случае, когда драй!вер получает данные от устройства, он также передает их в виде сообще!ний вверх по потоку. Процесс имеет возможность получить данные с по!мощью системных вызовов read(2) илиЕсли в головном модуледанные отсутствуют, процесс блокируется и переходит в состояние сна.Сообщенияintпередаютсямодулямиспомощьюсистемнойфункции*q,Эта функция адресует очередь следующего модуля параметром q и вызы!вает процедуру xxputэтой очереди, передавая ей сообщение тр. Непоощряется непосредственный вызов функции xxputследующего моду!ля, поскольку это может вызвать определенные проблемы переносимости.Передача данных внутри потока осуществляется асинхронно и не можетблокировать процесс. Блокирование процесса возможно только при пере!даче данных между процессом и головным модулем.
Таким образом,функции обработки данных потока — xxputи xxserviceне могутблокироваться. Если процедура xxputне может передать данные сле!дующему модулю, она помещает сообщение в собственную очередь, откудаоно может быть передано позже процедуройЕсли и про!цедура() не может осуществить передачу сообщения, напри!мер, из!за переполнения очереди следующего модуля, она не будет ожи!дать изменения ситуации, а вернет сообщение обратно в собственную оче!редь и завершит выполнение.
Попытка передачи повторится, когда ядрочерез некоторое время опять запустит xxserviceПроцедура() вызывается в системном контексте, а не в кон!тексте процесса, который инициировал передачу данных. Таким образом,блокирование процедуры() может заблокировать (перевести всостояние сна) независимый процесс, что может привести к непредска!зуемым результатам и потому недопустимо.
Решение этой проблемы за!ключается в запрещении процедурам xxput () и() блокирова!ния своего выполнения.Блокирование недопустимо и для драйвера. Обычно прием данных драй!вером осуществляется с использованием прерываний. Таким образом про!цедура xxputвызывается в контексте прерывания и не может блокиро!вать свое выполнение.www.books-shop.com364Глава 5.Когда процедура xxputне может передать сообщение следующему мо!дулю, она вызывает функциюимеющую следующий вид:*q,Функцияпомещает сообщение mp в очередь q, где сообщениеожидает последующей передачи, и заносит очередь в список очередей, ну!ждающихся в обработке. Для таких очередей ядро автоматически вызываетпроцедуруПланирование вызова процедурпроизводится функцией ядра runqueuesФункциявы!зывается ядром в двух случаях:Когда какой!либо процесс выполняет операцию ввода/вывода надпотоком.Непосредственно перед переходом какого!либо процесса из режимаядра в режим задачи.Заметим, что планирование обслуживания очередей не связано с конкрет!ным процессом и производится для всей подсистемы STREAMS в целом.Функция runqueueпроизводит поиск всех потоков, нуждающихся вобработке очередей.
При наличии таковых просматривается список очере!дей, ожидающих обработки, и для каждой из них вызывается соответст!вующая функцияКаждая процедурав своюочередь, пытается передать все сообщения очереди следующему модулю.Если для каких!либо сообщений это не удается, они остаются в очереди,ожидая следующего вызова runqueueпослепроцесс повторяется.Управление передачей данныхДеление процесса передачи данных на два этапа, выполняемых, соответст!венно, функциями xxputи xxserviceпозволяет реализовать меха!низм управления передачей данных.Как уже упоминалось, обязательной для модуля является лишь функцияxxputРассмотрим ситуацию, когда модули потока не содержат про!цедурВ этом случае, проиллюстрированном на рис. 5.19,каждый предыдущий модуль вызывает функцию xxputследующего, пе!редавая ему сообщение, с помощью функции ядраФункцияxxputнемедленно вызываети т.
д.:*mp){СистемаSTREAMS использует собственные функции иния к планированию процессов в UNIX.www.books-shop.com365STREAMSРис. 5.19. Передачауправления потокомданныхбезКогда данные достигают драйвера, он передает их непосредственно устрой!ству. Если устройство занято, или драйвер не может немедленно обработатьданные, сообщение уничтожается. В данном примере никакого управленияпотоком не происходит, и очереди сообщений не используются.Хотя такой вариант может применяться для некоторых драйверов (какправило, для псевдоустройств, например,в общем случае уст!ройство не может быть все время готово к обработке данных, а потеряданных из!за занятости устройства недопустима.
Таким образом, в потокеможет происходить блокирование передачии эта ситуация недолжна приводить к потере сообщений, во избежание которой необходимсогласованный между модулями механизм управления потоком. Для этогосообщения обрабатываются и буферизуются в соответствующей очередимодуля, а их передача возлагается на функциювызываемуюядром автоматически. Для каждой очередидве ватерлинии —Блокирование передачи может происходить не только в драйвере (оконечном модуле)из!за занятости устройства. Возможна ситуация, когда отдельный модульден отложить обработку сообщений до наступления некоторого события.www.books-shop.com366Глава 5.
Подсистемаверхняя и нижняя, которые используются для контроля заполненностиочереди. Если число сообщений превышает верхнюю ватерлинию, очередьсчитается переполненной, и передача сообщений блокируется, пока ихчисло не станет меньше нижней ватерлинии.Рассмотрим пример потока, модули 1 и 3 которого поддерживают управ!ление потоком данных, а модуль 2 — нет. Другими словами, модуль 2 неимеет процедурыКогда сообщение достигает модуля 3, вы!зывается его функция xxputПосле необходимой обработки сообщения,оно помещается в очередь модуля 3 с помощью функцииЕслипри этом число сообщений в очереди превышает верхнюю ватерлинию,устанавливает специальный флаг, сигнализирующий о том, чтоочередь переполнена:*q,{/* Необходимая обработка}Через некоторое время ядро автоматически запускает процедуруxxserviceмодуля 3.
Для каждого сообщения очереди xxputвызыва!ет функциюкоторая проверяет заполненность очереди следую!щего по потоку модуля. Функцияимеет вид:intЗаметим, чтопроверяет заполненность очереди следующего мо!дуля, реализующего механизм управления передачей данных, т. е. произ!водящего обработку очереди с помощью процедурыВ про!тивном случае, как уже говорилось, очередь модуля не принимает участияв передаче данных.
В нашем примере,проверит заполненностьочереди записи модуля 1. Функция возвращает истинное значение, еслиочередь может принять сообщение, и ложное — в противном случае. В зави!симости от результата проверки процедуралибо передастсообщение следующему модулю (в нашем примере — модулю 2, которыйпосле необходимой обработки сразу же передаст его модулю 1), либо вер!нет сообщение обратно в очередь, если следующая очередь переполнена.Описанная схема показана на рис. 5.20.
Ниже приведен скелет процедурымодуля 3, иллюстрирующий описанный алгоритм передачисообщений с использованием механизма управления передачей данных.{=!=NULL) {ifwww.books-shop.comSTREAMS367elsebreak;}}Рис. 5.20. Управление потоком данныхВ этом примере функция getq(9F) используется для извлечения следующегосообщения из очереди, а функция— для помещенияв начало очереди. Если модуль 1 блокирует передачу, т. е.вер!нет "ложно", процедуразавершает свою работу, и сообщенияначинают буферизироваться в очереди модуля 3.
При этом очередь вре!менно исключается из списка очередей, ожидающих обработки, и про!цедура xxservice () для нее вызываться не будет. Данная ситуация про!www.books-shop.com368Глава 5. Подсистемадлится до тех пор, пока число сообщений очереди записи модуля 1 не ста!нет меньше нижней ватерлинии.Пока существует возникшая блокировка передачи, затор будет постепеннораспространяться вверх по потоку, последовательно заполняя очереди мо!дулей, пока, в конечном итоге, не достигнет головного модуля.
Посколькупередачу данных в головной модуль (вниз по потоку) инициирует прило!жение, попытка передать данные в переполненный головной модуль вызо!вет блокированиеи переход его в состояние сна.В конечном итоге, модуль 1 обработает сообщения своей очереди, и ихчисло станет меньше нижней ватерлинии. Как только очередь модуля 1станет готовой к приему новых сообщений, планировщик STREAMS ав!томатически вызовет процедуры xxserviceдля модулей, ожидавшихосвобождения очереди модуляв нашем примере — для модуля 3.Управление передачей данных в потоке требует согласованной работы всехмодулей.
Например, если процедура xxputбуферизирует сообщениядля последующей обработки xxserviceтакой алгоритм должен выпол!няться для всех сообщений". В противном случае, это может привести кнарушению порядка сообщений, и как следствие, к потере данных.Когда запускается процедураона должна обработать всесообщения очереди.