Системная очередь запросов IRP (System Queuing)
Системная очередь запросов IRP (System Queuing)
Простейший способ, с помощью которого драйвер может организовать очередь IRP - использовать Системную Очередь. Для этого драйвер предоставляет диспетчерскую точку входа Startle (DriverObject->DriverStartIo). При получении пакета IRP, который необходимо поставить в Системную Очередь, такой пакет необходимо пометить как отложенный с помощью вызова IoMarkIrpPending(), а затем вызвать функцию IoStartPacket().
VOID loStartPacket(IN PDEVICEJDBJECT Device-Object, IN PIRP Irp, IN PULONG Key,
IN PDRIVER_CANCEL CancelFunction);
Где: DeviceObject - Указатель на устройство, которому направлен запрос ввода/ вывода;
Irp - Указатель на пакет IRP, описывающий запрос ввода/вывода;
Key - Необязательный указатель на значение, определяющее позицию в очереди IRP, в которую будет вставлен пакет IRP. Если указатель NULL, IRP помещается в конец очереди;
CancelFunction - Необязательный указатель на функцию - точку входа драйвера, которая будет вызвана при отмене данного запроса ввода/вывода диспетчером ввода/ вывода.
Вызов этой функции ставит пакет IRP для данного устройства в Системную Очередь. При этом, если в момент вызова loStartPacket() функция Startlo не выполняется, происходит выборка из очереди очередного IRP.
При выборке очередного пакета IRP из очереди, если очередь не пуста, для очередного IRP будет вызвана функция Startlo. Функция имеет такой же прототип, как и все диспетчерские функции, но вызывается в случайном контексте потока на уровне IRQL DISPATCH_LEVEL: NTSTATUS Startlo (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp).
Структура функции Startlo практически такая же, как у диспетчерской функции, не использующей организацию очередей, за двумя важными исключениями:
раздел «Описание Буфера Данных»).
Прототип функции IoStartNextPacket():
VOID IoStartNextPacket(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN Cancel able);
Где: DeviceObject - Указатель на устройство, для которого необходимо выбрать следующий пакет из системной очередиIRP;
Cancelable - Указывает, может ли выбираемый из очереди пакетIRP быть отменен в процессе обработки. Если при вызове loStartPacketQ была указана ненулевая функция отмены, параметр Cancelable обязан быть равным TRUE.
Вместо IoStartNextPacket() может быть использована функция loStartNext PacketByKey():
VOID loStartNextPacketByKey(IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN Cancelable, IN ULONG Key);
В этом случае из очереди будет выбран очередной пакет IRP с заданным значением Key (это значение могло быть установлено при помещении пакета в очередь при вызове loStartPacket()).
При использовании системной очереди диспетчер ввода/вывода отслеживает, когда данный объект-устройство свободен или занят обработкой очередного IRP. Это осуществляется с помощью специального объекта ядра Очередь Устройства (Device Queue Object, тип - структура KDEVICE_QUEUE), помещенного внутрь объекта-устройства в поле DeviceQueue. Поле DeviceQueue.Busy устанавливается диспетчером ввода/вывода равным TRUE непосредственно перед вызовом функции Startlo, и FALSE, если вызвана функция IoStartNextPacket(ByKey)(), а системная очередь не содержит пакетов IRP для данного устройства. При обработке очередного IRP указатель на него находится в объекте-устройстве в поле Currentlrp.