chapter 8.5: I/O Queues

为driver控制I/O请求流,跟踪活动的请求状态,支持取消请求、管理请求的并发、能选择性同步关于设备PnP和Power状态的操作。
创建queue:
    1.UMDF,调用IWDFDevice::CreateIoQueue
    2.KMDF,调用WdfIoQueueCreate
驱动可以创建一至多个queue,对于每个queue的配置:
    1.接收quests的types
    2.power management选项
    3.queue的dispatch方法(几个quest可以同时active)
    4.queue是否接收0长度buffer
在queue中的请求,owner是queue,分派到驱动里时,就是in-flight request,owner是driver。驱动能通过函数把请求从一个queue转移到另一个queue。


queue配置和请求类型
驱动可以有多个queue和不同的配置,read/write/CTL/内部使用
不是所有的请求都能使用queue,一些请求需要即刻通过callback分派。
分派机制表如下:

I/O request type

UMDF delivery mechanism

KMDF delivery mechanism

Read

Queue

Queue

Write

Queue

Queue

Device I/O control

Queue

Queue

Internal device I/O control

Queue

Queue

Create

Queue

Queue or callback

Close

Callback

Callback

Cleanup

Callback

Callback

table8.4


为queue指定Request类型
UMDF===
KMDF:
WdfDeviceConfigureRequestDispatching,类型有:
    WdfRequestTypeCreate 
    WdfRequestTypeRead 
    WdfRequestTypeWrite 
    WdfRequestTypeDeviceControl 
    WdfRequestTypeDeviceControlInternal 
驱动必须在queue configuration structure中注册I/O事件回调函数


Queue回调函数:

Associated event

UMDF callback interface

KMDF callback function

Read request

IQueueCallbackRead

EvtIoRead

Write request

IQueueCallbackWrite

EvtIoWrite

Device I/O control request

IQueueCallbackDeviceIoControl

EvtIoDeviceIoControl

Internal device I/O control request

Not applicable

EvtIoInternalDeviceIoControl

Create request

IQueueCallbackCreate

EvtIoDefault

I/O request for which no other callback is implemented

IQueueCallbackDefaultIoHandler

EvtIoDefault

Power-managed queue stop notification

IQueueCallbackIoStop

EvtIoStop

Power-managed queue resume notification

IQueueCallbackIoResume

EvtIoResume

Queue state change notification

IQueueCallbackStateChange

EvtIoQueueState

Queued request cancellation notification

Not applicable

EvtIoCanceledOnQueue

表8.5
种类:Power change,Queue state change, I/O request cancellation


默认queue
把所有其他的quest放入默认queue中。驱动可以没有default queue


Queue和电源管理
Power-managed queue
========
Non-Power-Managed Queue
    若请求到达且设备在sleep时,WDF不会启动设备
    只有Power-managed queue才会影响idle timer。驱动能调用WdfDeviceStopIdle影响idle状态
Driver可以实现I/O stop回调函数EvtIoStop,只在设备移除时调用


queue的分派类型:
    顺序:直到完成请求或请求被转到另一个queue时,才push出下一个请求。
    并行:queue尽快push I/O 请求
    手动:由driver调用获取方法
driver不必像WDM driver一样把请求标记为pending
分派类型只是说明同一时间活动的请求数,而并发性由同步范围确定:并行queue的请求也可能是不并行的(不过驱动里会有很多in-flight请求)
不用标记请求为pending和callback不用返回status的原因:
    在callback时,framework总是标记IRP为pending,并返回STATUS_PENDING


Queue控制
驱动可以调用方法停止、开始、消耗和清空,确定queue状态:
    UMDF使用IWDFIoQueue方法
    KMDF使用WdfIoQueueXxx方法
对于消耗和清空方法,WDF提供了同步和非同步的方法。

Operation

UMDF method in IWDFIoQueue interface

KMDF method

Stops adding requests to the queue.

Optionally notifies the driver or returns control to the driver after all pending I/O requests have been completed.

Drain

DrainSynchronously

WdfIoQueueDrain

WdfIoQueueDrainSynchronously

Returns the state of the I/O queue.

GetState

WdfIoQueueGetState

Stops adding requests to the queue.

Cancels all requests that are already in the queue and all in-flight requests that are in a cancelable state.

Notifies the driver or returns control to the driver only after all pending I/O requests have been completed.

Purge

PurgeSynchronously

WdfIoQueuePurge

WdfIoQueuePurgeSynchronously

Resumes delivery of requests from the queue.

Start

WdfIoQueueStart

Stops delivery of requests from the queue but continues to add new requests to the queue.

Stop

StopSynchronously

WdfIoQueueStop

WdfIoQueueStopSynchronously

表8.7
驱动可以把控制方法和self-managed I/O回调结合使用来手动控制non-power-managed queue的状态。


UMDF例子
================


KMDF例子
KMDF创建和配置一个I/O queue步骤:
    1.定义WDF_IO_QUEUE_CONFIG structure
    2.使用WDF_IO_QUEUE_CONFIG_INIT或WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE初始化configuration
    3. 在WDF_IO_QUEUE_CONFIG structure设置事件回调函数,设置queue分派类型。
    4.在CONFIG中设置是否电源管理和是否允许0长度请求
    5.通过WdfIoQueueCreate创建queue,(WDFDEVICIE指针,config,attr,接受queue的指针)
    6.WdfDeviceConfigureRequestDispatching来声明queue接受的I/O请求类型
Osrusbfx2例子:Device.c的OsrFxDeviceAdd方法
    1.IOCTL:并行默认queue
    2.read和write两个queue
代码例子:KMDF默认queue,KMDF非默认queue的创建方法


从Manual queue中获取请求
UMDF:IWDFIoQueue
KMDF:WdfIoQueueXxx 
方法列表:
   

Operation

UMDF method

KMDF method

Retrieve the next request from the queue.

IWDFIoQueue:: RetrieveNextRequest

WdfIoQueueRetrieveNextRequest

Retrieve the next request for a particular file object.

IWDFIoQueue::RetrieveNextRequestByFileObject

WdfIoQueueRetrieveRequestByFileObject

Search the queue for a particular request and then retrieve that request.

None

WdfIoQueueFindRequest followed by WdfIoQueueRetrieveFoundRequest


默认,queue使用FIFO机制
驱动可以在请求到达queue是获得通知:
    UMDF:==
    KMDF:调用WdfIoQueueReadyNotify,并传递EvtIoQueueState方法的指针,framework会在请求到达时调用EvtIoQueueState方法
[KMDF]
WdfIoQueueFindRequest:检查传入的request是否在queue中
WdfIoQueueRetrieveFoundRequest:把找到的request dequeue
代码例子:Pcidrv sample,Pcidrv\sys\hw\nic_req.c:在manual device I/O CTL
queue中获得特定function code的请求。
NTSTATUS NICGetIoctlRequest(
    IN WDFQUEUE Queue,
    IN ULONG FunctionCode,
    OUT WDFREQUEST*  Request
    )
{
    NTSTATUS            status = STATUS_UNSUCCESSFUL;
    WDF_REQUEST_PARAMETERS params;
    WDFREQUEST          tagRequest;
    WDFREQUEST          prevTagRequest;
    WDF_REQUEST_PARAMETERS_INIT(&params);
    *Request = NULL;
    prevTagRequest = tagRequest = NULL;
    do {
       WDF_REQUEST_PARAMETERS_INIT(&params);
       status = WdfIoQueueFindRequest(Queue,
                                      prevTagRequest,
                                      NULL,
                                      &params,
                                      &tagRequest);
       // WdfIoQueueFindRequest takes an extra reference on tagRequest to prevent
       // the memory from being freed. However, tagRequest is still in the queue
       // and can be cancelled or removed by another thread and completed.
       if(prevTagRequest) {
           WdfObjectDereference(prevTagRequest);
       }
       if(status == STATUS_NO_MORE_ENTRIES) {
           status = STATUS_UNSUCCESSFUL;
           break;
       }
       if(status == STATUS_NOT_FOUND) {
           // The prevTagRequest disappeared from the queue. Either it was
           // cancelled or dispatched to the driver. Other requests might match
           // our criteria so restart the search.
           prevTagRequest = tagRequest = NULL;
           continue;
       }
       if( !NT_SUCCESS(status)) {
           status = STATUS_UNSUCCESSFUL;
           break;
       }
       if(FunctionCode == params.Parameters.DeviceIoControl.IoControlCode){
           status = WdfIoQueueRetrieveFoundRequest(Queue, tagRequest, Request);
           WdfObjectDereference(tagRequest);
           if(status == STATUS_NOT_FOUND) {
               // The prevTagRequest disappeared from the queue.
               // Restart the search.
               prevTagRequest = tagRequest = NULL;
               continue;
           }
           if( !NT_SUCCESS(status)) {
               status = STATUS_UNSUCCESSFUL;
               break;

           }
               // Found a request. Drop the extra reference before returning.
               ASSERT(*Request == tagRequest);
               status =  STATUS_SUCCESS;
               break;
           }
           else {
               // This is not the request we need. Drop the reference
               // on the tagRequest after looking for the next request.
               prevTagRequest = tagRequest;
               continue;
           }
       } while (TRUE);
       return status;
}
表8-7
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值