Run-down Protection

原文连接:

http://bbs.pediy.com/showthread.php?t=173763

NT 5.1 内核引入的Run-down Protection


XP以后的windows内核,引用了一种新的同步技术,微软叫它: Run-down Protection。这种同步技术至今还很神密,连很多搞内核和驱动很有经验的朋友,和他们讨论起来的时候,了解的人也不多。所以今天我写篇短文简单介绍一下。

我们知道对象的删除在并行系统中是一个问题,如果一个对象一个执行流在使用对象,而另一个执行流却在删除对象,就会出现问题。解决这个问题的一个办法就是引用计数。我们今天介绍的 Run-down Protection 其实也就是引用计数,不过它还做了一些额外的工作。

Drivers can use run-down protection to safely access objects in shared system memory that are created and deleted by another kernel-mode driver.

这句话是微软MSDN里的介绍。简单点说,就是为了保护对象的安全的删除。现在XP中,主要用它来保护内核中进程对象和线程对象的删除。

我这里主要介绍它的四个例程  ExfInitializeRundownProtection,ExfAcquireRundownProtection, ExfReleaseRundownProtection,ExfWaitForRundownProtectionRelease

指出一下,在内核导出时,为这几个函数使用了别名, Exf的前缀换成了Ex。 例如 ExfInitializeRundownProtection 变成了 ExInitializeRundownProtection。

下面我一一介绍。 先说一下功能,顺便说一下原理。

代码:
typedef struct _EX_RUNDOWN_REF {

#define EX_RUNDOWN_ACTIVE      0x1
#define EX_RUNDOWN_COUNT_SHIFT 0x1
#define EX_RUNDOWN_COUNT_INC   (1<<EX_RUNDOWN_COUNT_SHIFT)
    union {
        ULONG_PTR Count;
        PVOID Ptr;
    };
} EX_RUNDOWN_REF, *PEX_RUNDOWN_REF;

NTKERNELAPI
VOID
FASTCALL
ExfReInitializeRundownProtection (
     __out PEX_RUNDOWN_REF RunRef
     )。 
这个函数就是清0 run-down 数据块。不多说。 可以看到,它的数据结构其实就是一个引用计数器与一个指针的共用体。


代码:
NTKERNELAPI
BOOLEAN
FASTCALL
ExfAcquireRundownProtection (
     __inout PEX_RUNDOWN_REF RunRef
     )
这个函数获取run-down protection。 这个函数其实就是增加引用计数。 它有两种返回值。 如果对象已经被设置为销毁中(EX_RUNDOWN_ACTIVE标志被设置),那么直接返回FALSE,否则增加引用计数,然后返回TRUE。 有源代码的同学可以看看它的源代码。 它先判断EX_RUNDOWN_ACTIVE标示是否设置,然后不断试着使用InterlockedCompareExchangePointer来原子的增加引用计数,直到成功。 需要不断循环的原因是,可能在这个过程中,run-down protection的状态已经被改变。 只有在确定按预期修改了状态时,才会退出循环。

代码:
NTKERNELAPI
VOID
FASTCALL
ExfReleaseRundownProtection (
     __inout PEX_RUNDOWN_REF RunRef
     )
正如你猜测的那样,这个函数减少引用计数。源代码里头有着和ExfAcquireRundownProtection中类似的循环,原因上面解释过。还有一个不同的是,当EX_RUNDOWN_ACTIVE标志被设置时,减少了引用计数后,如果计数已经为0, 它会触发一个内核事件(KEVENT),具体原因,后面讲。


代码:
NTKERNELAPI
VOID
FASTCALL
ExfWaitForRundownProtectionRelease (
     __inout PEX_RUNDOWN_REF RunRef
     )
这个函数是run-down protection最核心的一个函数。 它的作用是等待所有对该对象的引用释放。 也就是等待对象的引用计数减到0. 因为它会把对象设为run-down状态(EX_RUNDOWN_ACTIVE标志被设置),所以这个函数调用后,所有对该对象的引用都会失败。然后它就等待一个代表引用计数减到0的内核事件。当所有正在使用的对象都释放了引用,最后一个调用ExfReleaseRundownProtection的执行点会触发内核事件(KEVENT),ExfWaitForRundownProtectionRelease接收到事件通知,完成等待退出。驱动程序或内核代码即可以对对象进行内存层面的清除了。

也许有人会疑惑,那个KEVENT,在哪个地方保存?EX_RUNDOWN_REF 里并没有相应的数据结构。答案在这里。
代码:
EX_RUNDOWN_WAIT_BLOCK WaitBlock;
这段代码在ExfWaitForRundownProtectionRelease里,所以这个等待块在栈上,所以KEVENT在栈上。在ExfWaitForRundownProtectionRelease被调用时,kevent才建立。这样做的原因应该是出于空间效率的考虑。大部分时间,这个event对象确实也是没有用的。
在这里, WaitBlock要取代原来的引用计数。所以你可以看到EX_RUNDOWN_REF里Count和Ptr共用内存空间。在ExfWaitForRundownProtectionRelease调用前Count被用来计数,ExfWaitForRundownProtectionRelease调用之后,Ptr指向了WaitBlock,接管计数,并且提供KEVENT等待计数归0。*转载请注明来自看雪论坛@PEdiy.com  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值