• 【原创】CancellableWait


    应用程序不能正常退出,导致无法关机,这种情况通常是应用程序在等待一些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来实现.




  • 相关阅读:
    什么是索引?怎么创建索引?索引的使用原则?
    Cookie和Session的区别
    HashMap、Hashtable、ConcurrentHashMap的原理与区别
    vxlogcfg vxlogcfg – 修改统一日志记录配置设置
    磁盘阵列RAID介绍及计算公式
    二叉树的最近公共祖先 递归
    LRU 缓存机制
    从前序与中序遍历序列构造二叉树 递归
    MySQL 数据结构常用命令
    Node.Js 搭建简单的 EggJs 示例项目
  • 原文地址:https://www.cnblogs.com/sysnap/p/4621888.html
Copyright © 2020-2023  润新知