阅读:2237回复:9
问一个分层驱动的IRP发送问题。
我写的分层驱动,上层驱动用用IoRegisterPlugPlayNotification()监听USB设备的插拔,然后用IoGetDeviceObjectPointer()取得其deviceObject,然后IoBuildDeviceIoControlRequest()构造IRP让他们通信。
现在问题是,如果上层驱动将IRP发给下层,而在等待下层驱动返回IRP的过程中,下层设备被拔掉,会造成死机。请问这个问题如何处理, 请有经验的大侠指教。 程序结构如下: KeInitializeEvent(&kevent, SynchronizationEvent, false); pIrp = IoBuildDeviceIoControlRequest(); if(pIrp == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } status = IoCallDriver(DeviceObject, pIrp); if (status == STATUS_PENDING) { KeWaitForSingleObject( &kevent, Executive, KernelMode, FALSE, NULL ); status = IoStatus.Status; } 我想知道,如果在KeWaitForSingleObject()中,下层设备拔掉,造成死机怎么处理,谢谢! |
|
沙发#
发布于:2004-05-27 11:32
可能是下层驱动没有结束你的请求,应该在你的下层驱动的CleanUp例程(IRP_MJ_CLEANUP)中结束所有IRP。
|
|
|
板凳#
发布于:2004-05-27 15:50
谢谢你的回复,能具体讲讲吗?我的下层驱动是在DDk带的BulkUsb基础上改的,里面没有用IRP_MJ_CLEANUP,而是在IRP_MN_SURPRISE_REMOVAL和IRP_MN_REMOVE_DEVICE中cancel了IRP。IRP_MJ_CLEANUP是PnP管理器自动发送给驱动的吗?
|
|
地板#
发布于:2004-05-28 17:26
请大侠指教,我写了个IRP_MJ_CLEANUP的处理函数,但是怎么觉得突然拔出后,没有调用它啊。另外,我在IRP_MN_SURPRISE_REMOVAL和IRP_MN_REMOVE_DEVICE中用IoCancelIrp()直接cancel掉了上层驱动发过来,但还没有完成的IRP。但仍然会产生DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS的错误,请大侠们指点一下了。
|
|
地下室#
发布于:2004-06-02 11:14
是否应该先判断是否可以cancel,然后在进一步处理。
cancel不行的话,可以直接iocompleterequest吧。 另:你没有添加完成历程,那没你的kewaitforsingleobject(0 什么时候才会满足呢? |
|
5楼#
发布于:2004-06-03 16:45
能讲讲什么时候可以cancel,什么时候要完成啊,不是很明白。我在kewaitforsingleobject()中设了等待时间,超时就返回STATUS_TIMEOUT
|
|
6楼#
发布于:2004-06-04 08:53
我的理解是这样的,当你下层正在处理这个 Irp 时,我们就不能够 cancel它,而如果这个Irp在队列里的话呢,可以直接cancel掉。
这些动作都应该在下层完成。 上层在构造Irp的时候,要设置一个完成例程。 [编辑 - 6/4/04 by Shentu] |
|
7楼#
发布于:2004-06-04 17:22
请大侠指教,我写了个IRP_MJ_CLEANUP的处理函数,但是怎么觉得突然拔出后,没有调用它啊。另外,我在IRP_MN_SURPRISE_REMOVAL和IRP_MN_REMOVE_DEVICE中用IoCancelIrp()直接cancel掉了上层驱动发过来,但还没有完成的IRP。但仍然会产生DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS的错误,请大侠们指点一下了。 如果设备突然拔出,pnp mgr会发送surprise_removal,然后发送remove_device。此后如果你的driver还有app CreateFile以后没有CloseHandle的话,直到你的app调用CloseHandle的时候,才会调用你的Cleanup和Close。所以USB驱动要做好这一点的操作。 还有一点:IoCancelIrp只能由最高层的发送IoCallDriver的driver层可以调用。其他层调用不知道会产生什么效果,我没有试过。 |
|
8楼#
发布于:2004-06-05 11:24
应该可以不用设置完成例程,event对象对于自己创建的irp可以在下层驱动调用completerequest的时候设置,不过如果下层没有执行complete的时候,可能就需要完成例程了了。
|
|
9楼#
发布于:2004-06-07 13:44
在你的底层驱动里的入口函数里做个同步就可以了。进入DispatchIoControl后先申请RemoveLock锁,这样在SupriseRemove时等待DispatchIoControl执行结束后再执行卸载动作。另外还可做一个引用计数,当发现在设备被拔出时还有人访问你的驱动时,不释放DeviceObject对象,只是标记设备被删除,此时所有的DeviceIoControl都返回失败,直到调用者调用了你的DispatchClose函数后再释放DeviceObject对象。
|
|