- •Лекция №10. Сериализация. System Queuing и Driver Queuing
- •[10.1] Завершение запроса в/в.
- •[10.2] Задержка обработки запросов irp и постановка запросов irp в очередь [10.2.1] Задержка обработки запросов irp
- •[10.2.2] Постановка запросов irp в очередь
- •[10.2.2.1] Системная очередь запросов irp (System Queuing)
- •[10.2.2.1.1] Обработка пакетов irp в функции StartIo
- •[10.2.2.2] Очереди, управляемые драйвером
- •[10.2.2.2.1] Функции управления очередью низкого уровня
- •[10.2.2.2.2] Функции управления очередью высокого уровня – “Очередь Устройства” (Device Queue)
- •[10.3] Отмена запросов в/в
- •[10.3.1] Отмена irp и Системная Очередь
- •[10.3.2] Отмена irp и очереди, управляемые драйвером
[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;
}