第十篇:万丈高楼平地起-驱动编程基础知识点(二)

1.  -QueueLock


     The QueueLock member of the device extension is a spin lock that protects
     access to NewRequestsQueue. NewRequestsQueue requires a spin lock to
     synchronize thread access to NewRequestsQueue because multiple threads could
     attempt to simultaneously manipulate the queue's contents, but only one
     thread at a time is allowed have access to the queue. Otherwise the IRPs in
     the queue cannot be processed in order resulting in unpredictable behavior.

     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来写的.

你可能感兴趣的:(Windows,Windows驱动,WDM,thread,kernel,instance)