Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
199
Добавлен:
20.02.2016
Размер:
110.59 Кб
Скачать

[10.2.2.2.2] Функции управления очередью высокого уровня – “Очередь Устройства” (Device Queue)

Драйвер создает дополнительные Очереди Устройства с помощью выделения памяти из невыгружаемой памяти под дополнительные объекты-Очереди Устройства KDEVICE_QUEUE и инициализирует эти объекты с помощью функции KeInitializeDeviceQueue(). Добавление пакетов IRP в эти очереди производится с помощью функци KeInsertDeviceQueue()или KeInsertByKeyDeviceQueue(), а выборка пакетов из очереди - KeRemoveDeviceQueue(), KeRemoveByKeyDeviceQueue() или KeRemoveEntryDeviceQueue().

Для организации очереди пакетов IRP используется структура типа KDEVICE_QUEUE_ENTRY, указатель на которую содержится в пакете IRP в поле Tail.Overlay.DeviceQueueEntry.

[10.3] Отмена запросов в/в

Всякий раз, когда запрос в/в удерживается драйвером в течение продолжительного отрезка времени, драйвер должен быть готов к отмене данного запроса. В случае закрытия потока диспетчер в/в пытается отменить все запросы в/в, отправленные этим потоком и еще не завершенные. Пока все такие запросы в/в не будут завершены устройством, ему не придет запрос IRP_MJ_CLOSE, и, следовательно, не освободится объект-файл, а впоследствии – и само устройство (драйвер никогда не получит запрос DriverUnload).

Для обеспечения отмены запроса в/в в пакете IRP,представляющем такой запрос, должен быть указан адрес диспетчерской точки входа драйвера, собственно отменяющей запрос. Для этого служит функция IoSetCancelRoutine().

PDRIVER_CANCEL IoSetCancelRoutine(IN PIRPIrp, PDRIVER_CANCELCancelRoutine);

Функция CancelRoutine() имеет такой же прототип, как и все диспетчерские функции.

VOID CancelRoutine(IN PDEVICE_OBJECTDeviceObject, IN PIRPIrp);

Она вызывается на уровне IRQL DISPATCH_LEVELв случайном контексте потока, однако перед ее вызовом происходит захват специальной системной спин-блокировки. До тех пор, пока системная спин-блокировка не будет освобождена, функция CancelRoutine() работает на уровне IRQL DISPATCH_LEVEL.Уровень IRQL, на который нужно перейти после освобождения блокировки указывается при вызове IoReleaseCancelSpinLock() (см. ниже). Принцип реализации функции следующий:

  • Если указанный пакет IRPне может быть отменен или не принадлежит драйверу, освободить системную спин-блокировку и завершить работу функции.

  • В противном случае:

  • удалить пакет IRPиз любых очередей, в которых он присутствует

  • установить функцию отмены IRP в NULL с помощью IoSetCancelRoutine()

  • освободить системную спин-блокировку

  • установить в IRPполе IoStatus.Information=0, IoStatus.Status=STATUS_CANCELLED

  • завершить IRP с помощью IoCompleteRequest().

Системная спин-блокировка отмены IRP освобождается с помощью IoReleaseCancelSpinLock()

VOID IoReleaseCancelSpinLock(IN KIRQL Irql);

где Irql – уровень IRQL, на который система должна вернуться после освобождения спин-блокировки. Это значение хранится в IRP в поле CancelIrql.

[10.3.1] Отмена irp и Системная Очередь

Пример функции отмены IRP драйвера, использующего системную очередь, показан в следующем листинге. Необходимо отметить, что для удаления IRP из системной очереди используется функция KeRemoveEntryDeviceQueue() так, как это показано в листинге.

VOID Cancel(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

{

//Обрабатывается ли отменяемый запрос в данный момент?

if (Irp ==DeviceOb]ect->CurrentIrp)

{

//Да. Освободить системную спин-блокировку и указать диспетчеру в/в

//начать обработку следующего пакета.Отмена IRP –в конце функции

IoReleaseCancelSpinLock(Irp->CancelIrql);

IoStartNextPacket(DeviceOb]ect, TRUE);

}

else

{

//Нет. Отменяемый IRP находится в очереди. Удалить его из очереди

KeRemoveEntryDeviceQueue(&DeviceOb]ect->DeviceQueue,

&Irp->Tail.Overlay.DeviceQueueEntry);

IoReleaseCancelSpinLock(Irp->CancelIrql);

}

//Отменить IRP

Irp->IoStatus.Status =STATUS_CANCELLED;

Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

return;

}

Соседние файлы в папке Лабы по драйверам