您的位置:首页 > 大数据 > 人工智能

【原创】CancellableWait

2015-07-05 11:27 387 查看
应用程序不能正常退出,导致无法关机,这种情况通常是应用程序在等待一些I/O request to finish. 应用程序访问远程文件时,这种情况的发生更加频繁.

If an application needs to terminate such requests, it should cancel the request. During process termination, the system walks the list of I/O requests for a process and attempts to cancel each one. This paper discusses why drivers need to implement cancellation and timely completion of I/O requests.

通常导致程序不能正常关闭的原因可能如下.
1 驱动 用kernel-mode的等待方式阻塞应用线程. 这样结束进程时投递的APC就不能被执行. 这样进程就不能被正常结束了.

XP 上可以用 Cancel-Safe IRP Queues 来解决这类问题.( IoCsqXxx )
VISTA后可以使用 FltCancellableWaitForSingleObject

原则
1 任何IRP的处理如果要耗费比较长的时间,那它必须支持 cancelled 操作.
2 不要去BLOCK Close-IRPs, 除非是必须的一些场景,而且时间必须很短.
3 所有long-term IRPs的处理必须是pended(驱动返回STATUS_PENDING,这样就不会阻塞当前线程了)的. pended 处理也要支持IRP cancellation;或者支持超时机制.

什么情况下需要支持 IRP Cancellation
1 IRP被QUEUE然后做进一步操作
2 IRP的处理时间比较长或者不明确.

FltCancellableWaitForSingleObject 其实就是对 FsRtlCancellableWaitForMultipleObjects的封装,FsRtlCancellableWaitForMultipleObjects实现的功能跟 KeWaitForMultipleObjects 一样,唯一的不同就是等待的对象是Cancellable, (a wait that can be terminated). 下面为例子:
1) 情景1
线程A触发某个文件打开操作.
|
驱动B 捕获IRP_MJ_CREATE -> 调用 KeWaitForMultipleObjects 阻塞线程 A, 如果 KeWaitForMultipleObjects 不返回,那线程A就一直不能被结束.

1) 情景2
线程A触发某个文件打开操作.
|
驱动B 捕获IRP_MJ_CREATE -> 调用 FltCancellableWaitForSingleObject 阻塞线程 A, 如果 FltCancellableWaitForSingleObject 不返回,那线程A结束了,那FltCancellableWaitForSingleObject 就返回了.

常见的使用方法:
KeInitializeEvent( xxSynchronizationEvent, SynchronizationEvent, TRUE ); //初始化为SynchronizationEvent事件,
(A SynchronizationEvent is also called an autoreset or autoclearing event. When such an event is set, a single waiting thread becomes eligible for execution. The kernel automatically resets the event to the not-signaled state each time a wait is satisfied.)

status = FltCancellableWaitForSingleObject( xxSynchronizationEvent,
NULL,
Data );
开始执行为立刻返回,然后把 xxSynchronizationEvent非信号态. 后面的线程再进来就一直在等待,除非有代码手动调用
KeSetEvent( xxSynchronizationEvent, 0, FALSE ); 把事件设置为信号态.

注: 这种应用其实类似于驱动中的互斥体,只不过被阻塞的线程是可以退出的或者结束的. 这种在驱动做串行操作是很合适的.
比如用STREAM CTX对应一个 xxSynchronizationEvent, 对同一个文件的扫描需要串行进行. 当然也可以用STREAN HANDLE CTX来实现.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: