Run-down Protection
2015-08-18 16:08
435 查看
原文连接:
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。
下面我一一介绍。 先说一下功能,顺便说一下原理。
代码:
这个函数就是清0 run-down 数据块。不多说。 可以看到,它的数据结构其实就是一个引用计数器与一个指针的共用体。
代码:
这个函数获取run-down protection。 这个函数其实就是增加引用计数。 它有两种返回值。 如果对象已经被设置为销毁中(EX_RUNDOWN_ACTIVE标志被设置),那么直接返回FALSE,否则增加引用计数,然后返回TRUE。 有源代码的同学可以看看它的源代码。 它先判断EX_RUNDOWN_ACTIVE标示是否设置,然后不断试着使用InterlockedCompareExchangePointer来原子的增加引用计数,直到成功。 需要不断循环的原因是,可能在这个过程中,run-down protection的状态已经被改变。 只有在确定按预期修改了状态时,才会退出循环。
代码:
正如你猜测的那样,这个函数减少引用计数。源代码里头有着和ExfAcquireRundownProtection中类似的循环,原因上面解释过。还有一个不同的是,当EX_RUNDOWN_ACTIVE标志被设置时,减少了引用计数后,如果计数已经为0, 它会触发一个内核事件(KEVENT),具体原因,后面讲。
代码:
这个函数是run-down protection最核心的一个函数。 它的作用是等待所有对该对象的引用释放。 也就是等待对象的引用计数减到0. 因为它会把对象设为run-down状态(EX_RUNDOWN_ACTIVE标志被设置),所以这个函数调用后,所有对该对象的引用都会失败。然后它就等待一个代表引用计数减到0的内核事件。当所有正在使用的对象都释放了引用,最后一个调用ExfReleaseRundownProtection的执行点会触发内核事件(KEVENT),ExfWaitForRundownProtectionRelease接收到事件通知,完成等待退出。驱动程序或内核代码即可以对对象进行内存层面的清除了。
也许有人会疑惑,那个KEVENT,在哪个地方保存?EX_RUNDOWN_REF 里并没有相应的数据结构。答案在这里。
代码:
这段代码在ExfWaitForRundownProtectionRelease里,所以这个等待块在栈上,所以KEVENT在栈上。在ExfWaitForRundownProtectionRelease被调用时,kevent才建立。这样做的原因应该是出于空间效率的考虑。大部分时间,这个event对象确实也是没有用的。
在这里, WaitBlock要取代原来的引用计数。所以你可以看到EX_RUNDOWN_REF里Count和Ptr共用内存空间。在ExfWaitForRundownProtectionRelease调用前Count被用来计数,ExfWaitForRundownProtectionRelease调用之后,Ptr指向了WaitBlock,接管计数,并且提供KEVENT等待计数归0。*转载请注明来自看雪论坛@PEdiy.com
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
相关文章推荐
- asp.net页面中如何获取Excel表的内容
- JSON技术-Gson将bean转换json确保数据的正确,使用FastJson将Json转换Bean
- OC构造函数详解
- C++三大继承构造函数的执行顺序详解
- 如何实现springmvc+mybatis用多选框批量删除的功能Java代码
- 实体框架(Entity Frmaework)简介
- javascript 基础3第13节
- 数据库层面记录操作日志
- Python——内置类型
- Silver Cow Party
- 一个简单的jQuery插件ajaxfileuplo 4000 ad实现ajax上传文件例子
- jQuery垂直多级导航菜单代码分享
- ListView添加事件并获取选中项的值
- 在ATL中创建对话框失败的问题
- 哈希表及处理冲突的方法
- c++ 执行命令行获取执行结果
- win32 调用窗体 实现代码
- 让UITableView的headerView或footerView跟随cell一起滚动
- postgresql继承方式实现分区
- websocket