Обмен данными с пользовательским процессом
Мы уже упоминали, что общение с пользовательским процессом
допустимо только в одном из возможных контекстов нити ядра, а именно в
пользовательском. Во всех остальных контекстах пользовательский процесс
попросту не определен — точнее сказать, активный пользовательский процесс
не совпадает с тем процессом, запрос которого в данный момент обрабатывается
драйвером.
В этой ситуации вызов примитивов взаимодействия с этим процессом может
привести к непредсказуемым результатам.
В ряде случаев вместо драйвера этот обмен осуществляют другие модули ял-ра,
например процедуры пред- и постобработки запроса. Непосредственно с пользовательским
адресным пространством драйвер должен общаться только в синхронной модели.
В этой модели драйвер иногда оказывается вынужден решать и другие, казалось
бы несвойственные ему, задачи.
Обработка сигналов драйвером в Unix
Так, в системах семейства Unix все операции ввода-вывода, а также все
остальные операции, переводящие процесс в состояние ожидания, могут быть
прерваны сигналом. Сигнал представляет собой примитив обработки исключений,
отчасти похожий на аппаратное прерывание тем, что при обработке сигнала
может быть вызвана предоставленная программистом функция-обработчик. Необработанный
сигнал обычно приводит к принудительному завершению процесса.
Будучи прерван сигналом, системный вызов останавливает текущую операцию,
и, если это была операция обмена данными, но данных передано не было,
возвращает код ошибки EINTR, говорящий о том, что вызов был прерван и,
возможно, операцию следует повторить. Код, делающий это, присутствует
в примере 10.1.
Например, пользовательский процесс может использовать сигнал SIGALARM
для того, чтобы установить свой собственный будильник, сигнализирующий,
что операция над устройством исполняется подозрительно долго.
Если драйвер не установит своего будильника и не станет отрабатывать сигналы,
посланные процессу, может возникнуть очень неприятная ситуация.
Дело в том, что в Unix все сигналы, в том числе и сигнал безусловного
убийства SIGKILL, обрабатываются процедурой постобработки системного вызова.
Если драйвер не передает управления процедуре постобработки, то и сигнал,
соответственно, оказывается необработанным, поэтому процесс остается висеть.
Других средств, кроме посылки сигнала, для уничтожения процесса в системах
семейства Unix не предусмотрено. Поэтому процесс, зависший внутри обращения
к драйверу, оказывается невозможно прекратить ни изнутри, ни извне.
Автор столкнулся с этим при эксплуатации многопроцессорной версии системы
SCO Open Desktop 4.0. Система была снабжена лентопротяжным устройством,
подключаемым к внешней SCSI-шине. Из-за аппаратных проблем это устройство
иногда "зависало", прекращая отвечать на запросы системы. Драйвер
лен-топротяжки иногда правильно отрабатывал это состояние как аппаратную
ошибку, а иногда тоже впадал в ступор, не пробуждаясь ни по собственному
будильнику, ни по сигналам, посланным другими процессами. (По имеющимся
у автора сведениям эта проблема специфична именно для многопроцессорной
версии системы. По-видимому, это означает, что ошибка допущена не в драйвере,
а в коде сервисных функций.) В результате процесс, обращавшийся в это
время клеите, также намертво зависал, и от него нельзя было избавиться.
Из-за наличия неубиваемого процесса оказывалось невозможно выполнить нормальное
закрытие системы; в частности, не получалось размонтировать файловые системы,
где зависший процесс имел открытые файлы. Выполнение холодной перезагрузки
системы с неразмонтированными файловыми томами
Введение в операционные систем
приводило к неприятным последствиям для этих томов. Одна из аварий, к
ко торым это привело, подробно описывается в разд. Восстановление
ФС после сбоя.
|