Иллюстрированный самоучитель по программированию систем защиты

Передача данных от приложения к драйверу. Асинхронная обработка.

Выполнение асинхронного запроса

Выполняя асинхронный ввод/вывод, поток пользовательского режима может использовать для синхронизации с моментом завершения операции ввода/вывода:

  1. ожидание у описателя файла;
  2. ожидание у объекта-события, используемого для каждого запроса ввода/вывода;
  3. асинхронный вызов процедуры (Asynchronous procedure call, АРС) пользовательского режима.

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

Вместо повторного использования одного IRP, драйвер верхнего уровня может создать группу ассоциированных IRP, которые будут управлять одним запросом параллельно. Этот драйвер отслеживает завершение всех ассоциированных IRP, и только потом завершает исходный IRP.

  1. Подсистема среды или клиентская DLL вызывает функцию "родного" API NtWriteFile() с описателем файлового объекта.
  2. Диспетчер ввода/вывода создает IRP, в котором он сохраняет указатель на файловый объект и код функции, указывающий драйверу верхнего уровня тип операции. Далее диспетчер ввода/вывода отыскивает драйвер верхнего уровня и передает ему IRP.
  3. Драйвер верхнего уровня определяет по информации в соответствующей ему области стека IRP, какую операцию он должен выполнить. Драйвер верхнего уровня может, либо разбить первоначальный запрос на несколько запросов, путем размещения новых пакетов IRP (возможно для нескольких драйверов устройств), либо может повторно использовать первоначальный IRP, заполнив область стека IRP, соответствующую нижележащему драйверу. Затем драйвер передает этот IRP (или несколько ассоциированных IRP) посредством вызова диспетчера ввода/вывода.
  4. Вызванный драйвер нижнего уровня (пусть это будет уже драйвер устройства) проверяет свою область стека IRP, чтобы определить какую операцию он должен выполнить на устройстве, и в поле статуса операции ввода/вывода в пакете IRP ставит код "ввод/вывод выполняется". Затем он вызывает функцию loStartPacket(), реализуемую менеджером ввода/вывода.
  5. Диспетчер ввода/вывода определяет, занято ли уже устройство обработкой другого IRP, и если да, то ставит текущий IRP в очередь устройства и возвращает управление. Если нет, то диспетчер ввода/вывода передает IRP соответствующей процедуре драйвера устройства, которая начинает операцию ввода/вывода на устройстве. Начав операцию на устройстве, драйвер устройства возвращает управление. Заметьте, что асинхронный запрос ввода/вывода возвращает управление вызывающей программе немедленно, даже если очередь устройства пуста.

Вторая стадия обработки запроса ввода/вывода, состоит в обслуживании прерывания от устройства:

  1. После завершения передачи данных устройство генерирует прерывание для обслуживания. Диспетчер прерываний ядра передает управление процедуре обслуживания прерываний (Interrupt Service Routine, ISR) драйвера устройства.
  2. ISR выполняет минимум работы по сохранению необходимого контекста операции. ISR также вызывает соответствующие сервисы диспетчера ввода/вывода для постановки в очередь отложенного вызова процедуры (Deferred Procedure Call, DPC). DPC – асинхронная процедура драйвера устройства, выполняющая завершение требуемой операции при более низком уровне IRQL процессора.
    Прерывания от устройств имеют высокий IRQL, но IRQL процессора, выполняющего ISR, остается на этом уровне только на время, необходимое для того, чтобы запретить новые прерывания от устройства. После завершения ISR, ядро понижает IRQL процессора до уровня, на котором тот находился до прерывания.
  3. Если IRQL процессора понизится ниже уровня планирования потоков и обработки отложенного вызова процедуры (Dispatch level), возникнет прерывание DPC, и диспетчер прерываний передаст управление процедуре DPC драйвера устройства.
  4. Процедура DPC использует для завершения операции сохраненный в процедуре ISR контекст операции, запоминает статус завершившейся операции и выбирает из очереди следующий пакет IRP, запустив тем самым новый запрос ввода/вывода. Затем устанавливает статус только что завершенной операции в поле статуса IRP и вызывает диспетчер ввода/вывода для завершения обработки запроса и удаления IRP.
  5. Диспетчер ввода/вывода обнуляет область стека IRP, соответствующую драйверу устройства, и вызывает завершающую процедуру драйвера верхнего уровня. Эта процедура проверяет поле статуса операции, чтобы определить, нужно ли повторить запрос, или можно освободить этот IRP (если это IRP было размещено этим драйвером). Драйвер верхнего уровня собирает информацию о статусах операций для всех размещенных им пакетов IRP, чтобы установить общий статус в первоначальном пакете IRP и завершить его.
  6. Диспетчер ввода/вывода ставит в очередь АРС-объект (Asynchronous Procedure Call – асинхронный вызов процедуры) для завершения ввода/вывода в контексте потока – инициатора запроса. (Подсистема ввода/вывода должна скопировать некоторые данные из системной области памяти в виртуальное адресное пространство процесса, поток которого инициировал запрос ввода/вывода, во время исполнения такого потока, это достигается путем пересылки АРС-объекта режима ядра в очередь АРС-объектов этого потока.)
  7. Когда поток – инициатор запроса, начнет исполняться в следующий раз, то возникнет прерывание обработки асинхронного вызова процедуры. Диспетчер прерываний передает управление процедуре АРС режима ядра (процедуре АРС диспетчера ввода/вывода).
  8. Процедура АРС режима ядра записывает данные в адресное пространство потока-инициатора запроса, устанавливает описатель файла в состояние "свободен", устанавливает в очередь на исполнение АРС-объект пользовательского режима (если нужно) и удаляет IRP.
Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.