xiaorain
驱动牛犊
驱动牛犊
  • 注册日期2003-04-21
  • 最后登录2005-11-05
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:3297回复:31

app异常结束的时候,驱动里如何完成已经挂起或尚未完成的irp?

楼主#
更多 发布于:2005-02-05 12:18
驱动中接受app得读请求,然后自己创建irp,注册完成例程,并把它发送给总线驱动,如果此irp尚未完成,此时app被异常结束(如结束任务)了,那我在驱动中应该如何处理irp呢?
如果是用计时器,在dpc例程中取消掉这个irp,然后等待。此时会进入完成例程,等到完成例程处理完毕,在设置事件。现在的问题是:
dpc例程运行在dispatch_level上,在这个irql上不能等待。

告诉我一个可行的方法把,谢谢先了。

异步读写一定会碰到这个问题吧,大家都是怎么解决的呢?

[编辑 -  2/5/05 by  xiaorain]

最新喜欢:

ZhouyZhouy
xiaorain
驱动牛犊
驱动牛犊
  • 注册日期2003-04-21
  • 最后登录2005-11-05
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2005-03-02 10:16
是我在完成历程里又访问了已经释放的内存导致了错误。现在修改已经可以了,谢谢大家的帮助,尤其感谢acidfish与bmyyyud的帮助。
xiaorain
驱动牛犊
驱动牛犊
  • 注册日期2003-04-21
  • 最后登录2005-11-05
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2005-02-28 21:14
我用的是IOAllocateIrp.
我看了DDK的例子。都是在IoCancelIrp后等待完成历程执行完毕再继续执行下去。不等待的我没有尝试,现在不作这个了。

创建自己的irp队列也是一样的,照样要在cancelroutine中把没有做的free掉或者cancel掉。

bmyyyud
驱动老牛
驱动老牛
  • 注册日期2002-02-22
  • 最后登录2010-01-21
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望130点
  • 贡献值0点
  • 好评度106点
  • 原创分0分
  • 专家分0分
地板#
发布于:2005-02-28 09:15
既然你设置不管IRP正常完成、失败、取消都要调用完成例程,在完成例程中取消你自己创建的IRP应该是最好的地方

即为你自己的每个新创建IRP的完成例程释放掉自己
滚滚长江东逝水 浪花淘尽英雄 是非成败转头空 青山依旧在 几度夕阳红 白发渔樵江渚上 惯看秋月春风 一壶浊酒喜相逢 古今多少事 尽付笑谈中
lejianz
驱动中牛
驱动中牛
  • 注册日期2003-03-05
  • 最后登录2023-11-15
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望145点
  • 贡献值0点
  • 好评度116点
  • 原创分0分
  • 专家分0分
  • 社区居民
地下室#
发布于:2005-02-27 17:18
我曾经也遇到相似的情况,我的做法是:
用一个列表结构,存储自己构造的IRP指针,当IRP正常完成时,删除掉它,如果异常退出,从列表中找到所有的IRP,Cancel它。不知这种方法对你是否可行。
一起交流,共同提高!
bmyyyud
驱动老牛
驱动老牛
  • 注册日期2002-02-22
  • 最后登录2010-01-21
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望130点
  • 贡献值0点
  • 好评度106点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2005-02-26 08:52
既然你设置不管IRP正常完成、失败、取消都要调用完成例程,在完成例程中取消你自己创建的IRP应该是最好的地方
滚滚长江东逝水 浪花淘尽英雄 是非成败转头空 青山依旧在 几度夕阳红 白发渔樵江渚上 惯看秋月春风 一壶浊酒喜相逢 古今多少事 尽付笑谈中
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2005-02-25 11:59

谢谢你的关注:)
现在的问题是我结束应用程序发来的IRP的时候,对自己构造的irp没有影响,此时这个irp没有被完成,取消或者失败,也就是不会进入完成历程。
这几天作试验发现应用异常结束后,应用发来的IRP的取消历程立即被调用,但是几分钟后系统才调用dispatchCleanup,在这里我把自己构造的irp给cancel掉了,然后进入完成历程进行处理。
在这个过程中,下层驱动从来没有取消过上层驱动发下去的irp。
 


没明白你的问题所在
acidfish
驱动小牛
驱动小牛
  • 注册日期2002-05-20
  • 最后登录2009-11-11
  • 粉丝0
  • 关注0
  • 积分21分
  • 威望3点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2005-02-25 10:16
这个话题,讨论了这么多,还没有解决方案吗?
我觉得大家提的方案都比较可行。选择其中一个就可以了。
还有我在提醒一下:
1、你自己创建发向底层的Irp用的是什么函数?用IoAllocateIrp要简单一些。要是用IoBuildDeviceIoControl的话,系统给你做了很多工作,包括完成这个Irp的释放工作都不用自己关心,但是创建出来的Irp要加入到当前FileObject的队列里边(可能是,记不清楚了)。应用层关闭该fileObject的时候,这些驱动自己创建的Irp必须要完成,否则系统就会等待。至于说会不会象你所说的那样等待几分钟以后还会再发送IRP_MJ_CLEANUP,我不太清楚。反正使用这个函数要小心!我个人则一般用IoAllocateIrp。
2、你在上层Irp的cancel routine中,取消本层创建的Irp的时候,完全没有必要等待它的完成。

这个问题(驱动创建新的Irp)在是DDK的很多例子里边都有涉及。尤其是usb部分的例子。
xiaorain
驱动牛犊
驱动牛犊
  • 注册日期2003-04-21
  • 最后登录2005-11-05
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2005-02-24 21:18
[quote][quote]简单的方法

这里有两个irp,一个是应用层发给驱动的irp,一个是驱动自己构造发给下层的irp

在应用程序退出的时候(异常退出或正常退出都可以),以失败状态完成应用层发的irp,然后在完成例程里直接free掉自己构造的irp

如何检测应用程序(异常)退出,简单的办法,
把你得设备属性改为独占使用(避免引用计数),在dispatchcleanup中处理任何应用程序的pending irp
因为应用程序(异常)退出的时候会关闭所有打开的句柄,从而引发DispatchCleanup的调用


\"以失败状态完成应用层发的irp,然后在完成例程里直接free掉自己构造的irp\"
这里的完成例程是指应用程序的IRP的完成例程还是驱动构造的IRP地完成例程?如果是驱动的话,不掉用IoCancelIrp()不会进入完成例程的。 [/quote]

当然是自己构造的irp的完成例程,为什么不调用IoCancelIrp就不会进入完成例程?

VOID
  IoSetCompletionRoutine(
    IN PIRP  Irp,
    IN PIO_COMPLETION_ROUTINE  CompletionRoutine,
    IN PVOID  Context,
    IN BOOLEAN    InvokeOnSuccess,
    IN BOOLEAN  InvokeOnError,
    IN BOOLEAN  InvokeOnCancel
    );

InvokeOnSuccess , InvokeOnError, InvokeOnCancel都设为true,不就行了
 [/quote]

谢谢你的关注:)
现在的问题是我结束应用程序发来的IRP的时候,对自己构造的irp没有影响,此时这个irp没有被完成,取消或者失败,也就是不会进入完成历程。
这几天作试验发现应用异常结束后,应用发来的IRP的取消历程立即被调用,但是几分钟后系统才调用dispatchCleanup,在这里我把自己构造的irp给cancel掉了,然后进入完成历程进行处理。
在这个过程中,下层驱动从来没有取消过上层驱动发下去的irp。
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2005-02-24 17:33
[quote]简单的方法

这里有两个irp,一个是应用层发给驱动的irp,一个是驱动自己构造发给下层的irp

在应用程序退出的时候(异常退出或正常退出都可以),以失败状态完成应用层发的irp,然后在完成例程里直接free掉自己构造的irp

如何检测应用程序(异常)退出,简单的办法,
把你得设备属性改为独占使用(避免引用计数),在dispatchcleanup中处理任何应用程序的pending irp
因为应用程序(异常)退出的时候会关闭所有打开的句柄,从而引发DispatchCleanup的调用


\"以失败状态完成应用层发的irp,然后在完成例程里直接free掉自己构造的irp\"
这里的完成例程是指应用程序的IRP的完成例程还是驱动构造的IRP地完成例程?如果是驱动的话,不掉用IoCancelIrp()不会进入完成例程的。 [/quote]

当然是自己构造的irp的完成例程,为什么不调用IoCancelIrp就不会进入完成例程?

VOID
  IoSetCompletionRoutine(
    IN PIRP  Irp,
    IN PIO_COMPLETION_ROUTINE  CompletionRoutine,
    IN PVOID  Context,
    IN BOOLEAN    InvokeOnSuccess,
    IN BOOLEAN  InvokeOnError,
    IN BOOLEAN  InvokeOnCancel
    );

InvokeOnSuccess , InvokeOnError, InvokeOnCancel都设为true,不就行了
xiaorain
驱动牛犊
驱动牛犊
  • 注册日期2003-04-21
  • 最后登录2005-11-05
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2005-02-24 12:56
简单的方法

这里有两个irp,一个是应用层发给驱动的irp,一个是驱动自己构造发给下层的irp

在应用程序退出的时候(异常退出或正常退出都可以),以失败状态完成应用层发的irp,然后在完成例程里直接free掉自己构造的irp

如何检测应用程序(异常)退出,简单的办法,
把你得设备属性改为独占使用(避免引用计数),在dispatchcleanup中处理任何应用程序的pending irp
因为应用程序(异常)退出的时候会关闭所有打开的句柄,从而引发DispatchCleanup的调用


\"以失败状态完成应用层发的irp,然后在完成例程里直接free掉自己构造的irp\"
这里的完成例程是指应用程序的IRP的完成例程还是驱动构造的IRP地完成例程?如果是驱动的话,不掉用IoCancelIrp()不会进入完成例程的。
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2005-02-23 17:32
简单的方法

这里有两个irp,一个是应用层发给驱动的irp,一个是驱动自己构造发给下层的irp

在应用程序退出的时候(异常退出或正常退出都可以),以失败状态完成应用层发的irp,然后在完成例程里直接free掉自己构造的irp

如何检测应用程序(异常)退出,简单的办法,
把你得设备属性改为独占使用(避免引用计数),在dispatchcleanup中处理任何应用程序的pending irp
因为应用程序(异常)退出的时候会关闭所有打开的句柄,从而引发DispatchCleanup的调用
bmyyyud
驱动老牛
驱动老牛
  • 注册日期2002-02-22
  • 最后登录2010-01-21
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望130点
  • 贡献值0点
  • 好评度106点
  • 原创分0分
  • 专家分0分
12楼#
发布于:2005-02-23 15:25
[quote]想了想,为什么不在customerTimerDpc用代码直接取消irp,为什么要调用取消例程再等待呢?Copy/Paste再用些互斥手段不可以吗?

因为自己构造了irp,在取消系统发来的irp的时候,要cancel掉自己构造的irp。而如果cancel自己构造的irp的话,调用IoCancelIrp()后,就会进入完成例程,待到完成例程执行完毕后,再继续执行,所以需要等待,而在customtimerdpc是运行在dispatch_level上的,所以无法等待。 [/quote]
实在不行,就留给System Worker Threads替你做,在customtimerdpc中将释放Irp的工作加入为一个WORK_QUEUE_ITEM。
滚滚长江东逝水 浪花淘尽英雄 是非成败转头空 青山依旧在 几度夕阳红 白发渔樵江渚上 惯看秋月春风 一壶浊酒喜相逢 古今多少事 尽付笑谈中
Shentu
驱动小牛
驱动小牛
  • 注册日期2004-04-05
  • 最后登录2011-01-24
  • 粉丝0
  • 关注0
  • 积分234分
  • 威望24点
  • 贡献值0点
  • 好评度20点
  • 原创分0分
  • 专家分0分
13楼#
发布于:2005-02-22 20:43
Cancel例程是不需要等待的,在你自己的完成例程里面置上一个事件,然后再Passiv_level上等待那个事件不就可以了。IoCancelRoutine不是在CancelRoutine里调用的。

// Cancel routine
VOID
CancelTestIrp(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{
    PDEVICE_EXTENSION  pdx = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;


    Test_KdPrint((\"CancelTestIrp, Irp = 0x%08X\\n\", Irp));

    IoReleaseCancelSpinLock(Irp->CancelIrql);

    CompleteRequest(Irp, STATUS_CANCELLED, 0);
}
xiaorain
驱动牛犊
驱动牛犊
  • 注册日期2003-04-21
  • 最后登录2005-11-05
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2005-02-22 17:17
[quote]今天发现结束任务的时候,如果还有irp没有完成,应用无法结束,总是剩下一个线程。但是过了几分钟后,系统会发送IRP_MJ_CLEANUP的irp,然后我在clean例程中结束irp,应用结束了。
不知道大家以前又没有发现这样的现象?


参看9楼acidfish大哥的办法,应用程序结束的时候会收到IRP_MJ_CLOSE的,处理这个的时候调用IoCancelIrp把等待的irp(必须是自己创建的)结束掉就可以了。

好象是要几分钟以后,那个剩下的内核线程会被os杀掉。 [/quote]
我感觉应用程序异常结束,如从任务管理器中结束任务,os不会立即发送IRp_mj_cleanup,而是要过一段时间,如几分钟再发送,此时内核线程就被结束了。

从任务管理器中结束任务的时候,如果设置了cancelroutine,则cancelroutine将立即被调用,但是I在cancelroutine中调用IoCancelIrp取消自己创建的irp有风险,因为调用IoCancelIrp()后,会进入自己创建的irp地完成例程,这样在cancelroutine()中就需要等待,而cancelroutine是运行在dispatch_level的。
我尝试了在cancelroutine中等待,每次都是蓝屏(driver_irql_not_less_or_equal).
xiaorain
驱动牛犊
驱动牛犊
  • 注册日期2003-04-21
  • 最后登录2005-11-05
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
15楼#
发布于:2005-02-22 17:07
想了想,为什么不在customerTimerDpc用代码直接取消irp,为什么要调用取消例程再等待呢?Copy/Paste再用些互斥手段不可以吗?

因为自己构造了irp,在取消系统发来的irp的时候,要cancel掉自己构造的irp。而如果cancel自己构造的irp的话,调用IoCancelIrp()后,就会进入完成例程,待到完成例程执行完毕后,再继续执行,所以需要等待,而在customtimerdpc是运行在dispatch_level上的,所以无法等待。
Shentu
驱动小牛
驱动小牛
  • 注册日期2004-04-05
  • 最后登录2011-01-24
  • 粉丝0
  • 关注0
  • 积分234分
  • 威望24点
  • 贡献值0点
  • 好评度20点
  • 原创分0分
  • 专家分0分
16楼#
发布于:2005-02-22 16:16
今天发现结束任务的时候,如果还有irp没有完成,应用无法结束,总是剩下一个线程。但是过了几分钟后,系统会发送IRP_MJ_CLEANUP的irp,然后我在clean例程中结束irp,应用结束了。
不知道大家以前又没有发现这样的现象?


参看9楼acidfish大哥的办法,应用程序结束的时候会收到IRP_MJ_CLOSE的,处理这个的时候调用IoCancelIrp把等待的irp(必须是自己创建的)结束掉就可以了。

好象是要几分钟以后,那个剩下的内核线程会被os杀掉。
bmyyyud
驱动老牛
驱动老牛
  • 注册日期2002-02-22
  • 最后登录2010-01-21
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望130点
  • 贡献值0点
  • 好评度106点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2005-02-22 15:16
想了想,为什么不在customerTimerDpc用代码直接取消irp,为什么要调用取消例程再等待呢?Copy/Paste再用些互斥手段不可以吗?
滚滚长江东逝水 浪花淘尽英雄 是非成败转头空 青山依旧在 几度夕阳红 白发渔樵江渚上 惯看秋月春风 一壶浊酒喜相逢 古今多少事 尽付笑谈中
xiaorain
驱动牛犊
驱动牛犊
  • 注册日期2003-04-21
  • 最后登录2005-11-05
  • 粉丝0
  • 关注0
  • 积分7分
  • 威望1点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2005-02-22 12:07
今天发现结束任务的时候,如果还有irp没有完成,应用无法结束,总是剩下一个线程。但是过了几分钟后,系统会发送IRP_MJ_CLEANUP的irp,然后我在clean例程中结束irp,应用结束了。
不知道大家以前又没有发现这样的现象?
bmyyyud
驱动老牛
驱动老牛
  • 注册日期2002-02-22
  • 最后登录2010-01-21
  • 粉丝0
  • 关注0
  • 积分1000分
  • 威望130点
  • 贡献值0点
  • 好评度106点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2005-02-22 11:48
在取消例程中设置变量表明取消,不过我总觉得哪里出问题了,办法太笨。也许看看WINDDK\\2600.1106\\src\\general\\cancel有用,我也得先好好看看
滚滚长江东逝水 浪花淘尽英雄 是非成败转头空 青山依旧在 几度夕阳红 白发渔樵江渚上 惯看秋月春风 一壶浊酒喜相逢 古今多少事 尽付笑谈中
上一页
游客

返回顶部