The queue must be accessed whenever an IRP is added or removed from the queue.
Spin lock用于Queue.
2.
ToasterAddDevice also initializes the kernel event members of the device
extension that are used to synchronize the processing of
IRP_MN_QUERY_STOP_DEVICE, IRP_MN_QUERY_REMOVE_DEVICE and IRP_MN_REMOVE_DEVICE.
The mechanism to synchronize the processing of these IRPs uses the
RemoveEvent, StopEvent, and OutstandingIO members of the device extension.
The OutstandingIO member keeps the count of uncompleted IRPs that the system
has dispatched to the function driver. OutstandingIO controls when the
RemoveEvent and StopEvent kernel events are signaled.
ToasterAddDevice initializes OutstandingIO to 1. That is, when there are zero
uncompleted IRPs to process, OutstandingIo equals 1, not zero. The function
driver calls ToasterIoIncrement to increment OutstandingIO every time the
system dispatches a new IRP to the function driver. The function driver calls
ToasterIoDecrement to decrement OutstandingIO when the function driver
completes a dispatched IRP. The function driver must make an equal number of
calls to increment and decrement OutstandingIO, except when ToasterDispatchPnP
processes IRP_MN_REMOVE_DEVICE. When the function driver processes
IRP_MN_REMOVE_DEVICE, the function driver must call ToasterIoDecrement twice
in order to signal RemoveEvent. The extra call to ToasterIoDecrement is the
only time OutstandingIO is decremented to 0.
ToasterDispatchPnP uses StopEvent to synchronize the processing of
IRP_MN_QUERY_STOP_DEVICE and IRP_MN_QUERY_REMOVE_DEVICE with any other threads
that might be processing other IRPs in the function driver. Any thread that
processes IRP_MN_QUERY_STOP_DEVICE or IRP_MN_QUERY_REMOVE_DEVICE is blocked
from completing its respective IRP until ToasterIoDecrement signals StopEvent.
ToasterDispatchPnP uses RemoveEvent to synchronize the processing of
IRP_MN_REMOVE_DEVICE with any other threads that might be processing other IRPs
in the function driver. Any thread that processes IRP_MN_REMOVE_DEVICE is
blocked from completing the IRP until ToasterIoDecrement signals RemoveEvent.
RemoveEvent, StopEvent, and OutstandingIO三者的使用方法
它们与IRP_MN_QUERY_STOP_DEVICE, IRP_MN_QUERY_REMOVE_DEVICE, IRP_MN_REMOVE_DEVICE的关系.
3.
//
// Initialize RemoveEvent to an unsignaled state. ToasterIoDecrement later
// signals RemoveEvent when OutstandingIO transitions from 1 to 0.
//
KeInitializeEvent(&fdoData->RemoveEvent,
SynchronizationEvent,
FALSE);
//
// Initialize StopEvent to a signaled state. ToasterIoIncrement unsignals
// StopEvent when OutstandingIO transitions from 1 to 2. When StopEvent is in an
// unsignaled state, ToasterDispatchPnP is blocked from continuing to process
// IRP_MN_QUERY_STOP_DEVICE or IRP_MN_QUERY_REMOVE_DEVICE until a call to
// ToasterIoDecrement later signals StopEvent when OutstandingIO transitions
// from 2 to 1.
//
KeInitializeEvent(&fdoData->StopEvent,
SynchronizationEvent,
TRUE);
//
// Initialize OutstandingIO to 1. The function driver must make an equal number
// of calls to ToasterIoIncrement and ToasterIoDecrement in order for
// ToasterIoDecrement to properly signal StopEvent or RemoveEvent. The only time
// OutstandingIO equals 0 is when ToasterDispatchPnP processes
// IRP_MN_REMOVE_DEVICE and calls ToasterIoDecrement twice. Otherwise, if there
// are not an equal number of calls to ToasterIoIncrement and ToasterIoDecrement
// then StopEvent and RemoveEvent may be prematurely signaled, resulting in
// unpredictable behavior in the function driver.
//
fdoData->OutstandingIO = 1;
三者的初始化及说明
4.
// Block ToasterDispatchPnP from passing IRP_MN_QUERY_STOP_DEVICE down the
// device stack until StopEvent is signaled. IRP_MN_QUERY_STOP_DEVICE must
// not be passed down the device stack to be processed by the bus driver
// until the hardware instance is idle and no longer processing any requests.
//
// The call to KeWaitForSingleObject does not return until StopEvent is
// signaled. For example, if no other threads are processing IRPs when the
// system dispatches IRP_MN_QUERY_STOP_DEVICE to the function driver, then
// the earlier call to ToasterIoDecrement signals StopEvent. However, if
// another thread is processing an IRP, then StopEvent is signaled when that
// thread calls ToasterIoDecrement.
//
KeWaitForSingleObject(
&fdoData->StopEvent,
Executive,
KernelMode,
FALSE,
NULL);
具体到IRP_MN_QUERY_STOP_DEVICE与StopEvent, ToasterIoDecrement, ToasterIoIncrement, 以及下层BUS DRIVER, 其它处理线程的关系.
5.
//
// Block ToasterDispatchPnP from passing IRP_MN_QUERY_REMOVE_DEVICE down the
// device stack until StopEvent is signaled. IRP_MN_QUERY_REMOVE_DEVICE must
// not be passed down the device stack to be processed by the bus driver
// until the hardware instance is idle and no longer processing any requests.
//
// When ToasterDispatchPnP processes IRP_MN_QUERY_REMOVE_DEVICE, the call to
// KeWaitForSingleObject waits on StopEvent instead of RemoveEvent because
// processing IRP_MN_QUERY_REMOVE_DEVICE is similar to processing
// IRP_MN_QUERY_STOP_DEVICE. ToasterDispatchPnP only waits on RemoveEvent
// when it processes IRP_MN_REMOVE_DEVICE.
//
// The call to KeWaitForSingleObject does not return until StopEvent is
// signaled. For example, if no other threads are processing IRPs when the
// system dispatches IRP_MN_QUERY_REMOVE_DEVICE to the function driver, then
// the earlier call to ToasterIoDecrement signals StopEvent. However, if
// another thread is processing an IRP, then StopEvent is signaled when that
// thread calls ToasterIoDecrement.
//
KeWaitForSingleObject(
&fdoData->StopEvent,
Executive,
KernelMode,
FALSE,
NULL);
具体到IRP_MN_QUERY_REMOVE_DEVICE与StopEvent, ToasterIoDecrement, ToasterIoIncrement, 以及下层BUS DRIVER, 其它处理线程的关系.
6.
The system dispatches IRP_MJ_CREATE IRPs to ToasterCreate. ToasterCreate
processes user-mode CreateFile calls.
The presence of a driver-implemented routine in the IRP_MN_CREATE MajorFunction
array entry of the DriverObject parameter in DriverEntry allows the system to
successfully return a handle to the hardware instance to the CreateFile call.
Without a driver implemented routine in this array entry, the system fails
any calls to CreateFile.
A DispatchCreate routine for PnP hardware is not usually required to perform
any special tasks to create and return a handle to the caller, except return
STATUS_SUCCESS to the caller.
In the case of the Toaster sample function driver, it is not necessary to
access the toaster instance's hardware to process a create request. The
hardware state does not need to be changed, and the driver-managed IRP queue
does not need to be manipulated.
IRP_MJ_CREATE的处理方法.
IRP_MJ_CREATE处理主要是为了给CreateFile返回一个handle.
类似的IRP_MJ_CLOSE对应于CloseHandle.
7.
Queue State的状态:
ToasterAddDevice : HoldRequests
IRP_MN_QUERY_STOP_DEVICE: HoldRequests
IRP_MN_CANCEL_STOP_DEVICE: AllowRequests
IRP_MN_QUERY_REMOVE_DEVICE: HoldRequests
IRP_MN_CANCEL_REMOVE_DEVICE: AllowRequests
IRP_MN_SURPRISE_REMOVAL: FailRequests
IRP_MN_REMOVE_DEVICE: FailRequests
8.
The Toaster sample function driver implements its own driver-managed IRP queue
instead of using the system-managed IRP queue. When a driver relies on the
system-managed IRP queue, the driver can only process a single IRP at a time.
For simple hardware devices, this method is acceptable. However, for more
complex hardware, such as Toaster class hardware, implementing a
driver-managed IRP queue is more efficient because it allows multiple threads
to process IRPs in the function driver simultaneously.
driver-managed IRP queue与system-managed IRP queue的比较
相对来讲,一个代码实现简单, 一个复杂
一个能够支持多线程同时执行,另外一个却不能够, 但需要StartIo, IoStartNextPacket函数.
9.
// Mark the incoming IRP as pending. Because the IRP is going to be added to the
// driver-managed IRP queue and will not be processed immediately, it must be
// marked pending. When an IRP is marked pending, the function driver must return
// STATUS_PENDING to the system.
//
// The function driver will later resume processing the IRP in
// ToasterDispatchPnpComplete. The system calls ToasterDispatchPnpComplete after
// the bus driver has completed the IRP.
//
IoMarkIrpPending(Irp);
// Return STATUS_PENDING. ToasterQueueRequest must return STATUS_PENDING to the
// caller because ToasterQueueRequest called IoMarkIrpPending earlier. If the
// read, write, or device control operation is synchronous (that is, the
// lpOverlapped parameter of the user-mode call equals NULL), then the caller
// cannot continue its execution until the function driver completes the pending
// IRP. However, if the operation is asynchronous (that is, the lpOverlapped
// parameter of the user-mode call does not equal NULL), then the user-mode call
// returns ERROR_IO_PENDING and the caller can resume its execution. When the
// function driver later completes the pending IRP, the I/O manager signals the
// event specified in the overlapped structure and the caller can process the
// results of the read, write, or device control operation.
//
return STATUS_PENDING;
IoMarkIrpPending与STATUS_PENDING的使用方法.
10.
// STATUS_PENDING can also be returned if ToasterReadWrite or
// ToasterDispatchIoctl pass the IRP down the device stack and the
// underlying bus driver returns STATUS_PENDING. In this case the
// function driver's dispatch routines must be modified to return the
// reason that STATUS_PENDING was returned. Then the logic in this
// routine must be changed to determine whether to continue to dispatch
// queued IRPs, or break out of the for loop.
代码没有给出如果BUS DRIVER返回STATUS_PENDING的处理方法
具体内容请参照
Incomplete 2.
要学会Windows驱动, 一定要学WDM.
同时, BUS DRIVER是不可能使用WDF来写的.