IRQL/DPC/APC
IRQL
IRQL意为中断请求级别,可以简单的看成是代码的执行优先级,「IRQL是CPU的属性」。即代码处于这个级别时,只能被大于这个级别的IRQL打断,一般来说是指外部中断到来是否可以打断当前代码执行,从而抢占CPU执行,可以是指外部设备中断或者是线程调度的时钟中断。
在x64下,IRQL的值为0~15。
正常情况下,驱动程序运行在IRQL 0(PASSIVE_LEVEL)上,没有什么限制
IRQL 1是APC级别(APC_LEVEL)
IRQL 2(DISPATCH_LEVEL),这个级别很重要,因为线程调度运行在这个级别,「如果内核运行在这个级别上的时候,相当于独占CPU,因为线程调度无法打断执行」,在这个级别上,无法访问非分页内存,也不能在内核对象上等待,这样会导致系统崩溃。
IRQL 3-11是设备IRQL,适用IRQL2的规则。
IRQL 15(DISPATCH_LEVEL),最高级别,屏蔽了所有中断,意味着外部设备也无法打断。虚拟机管理程序VMM一般运行在这个IRQL。
用户程序也是运行在IRQL 0(PASSIVE_LEVEL)上,线程调度程序运行IRQL 2(DISPATCH_LEVEL)。
还有一个运行在IRQL 2上的是DPC(延迟过程调用),「每个处理器都有一个DPC队列,并且在处理器降到0之前会检查DPC队列是否存在数据,存在就会先降低IRQL到IRQL 2,并执行DPC队列上的例程。当队列清空,处理器的IRQL才能降到0。」
APC
用户模式APC
这些APC仅在线程进入警报状态时才在用户模式的IRQL PASSIVE_LEVEL上运行。
通常会通过调用如SleepEx、WaitForSingleObjectEx、WaitForMultipleObjectsEx以及类似的API来达到此目的。
这些函数的最后一个参数设置成TRUE时可以使线程进入警报状态。
在警报状态下,线程会检查其APC队列,如果不是空的—其中的APC就会被执行,直到队列为空。
普通内核模式APC
它们在内核模式下的IRQL PASSIVE_LEVEL中执行,能够抢占用户模式代码和用户模式APC。
特殊内核APC
它们在内核模式下的IRQL APC_LEVEL(1)中执行,能够抢占用户模式代码、普通内核APC和用户模式APC
本文使用 markdown.com.cn 排版