IRQL(多线程中断请求级别)
IRQL
IRQL(Interrupt ReQuest Level)中断请求级别,什么是"中断"呢?
中断就是硬件设备通过8259A中的中断控制器,向CPU发送的一个电信号,电信号表明中断控制码.CPU在收到电信号后就会停止正在执行的程序.识别控制码,根据中断码去中断向量表中找到对应的中断处理函数并执行,这时CUP就处于中断上下文中. 中断上下文就是系统代替硬件去做一些事情,进程上下文是系统代替进程做一些事情.
进程上下文是可以睡眠的,但中断上下文不可以睡眠.
中断又分为:外部中断和内部中断.由CPU内部引起的中断叫"陷阱"或"异常",我们通常所说的中断是由外部中断引起的,就是硬件中断.
中断流程中断优先级
系统中有很多硬件,比如,显卡,鼠标,硬盘,内存,主板,键盘等....如果这些硬件同时向CPU发送电信号,那CUP先响应谁呢?所以,我们就要为这些硬件发过来的电信号为它们拟定一个优先级,这就是中断优先级的由来,优先级越高CPU就优先处理,优先级越低,CPU就最后处理.
内核代码运行在CPU上,同样也是拥有优先级的.就是IRQL:
无中断
PASSIVE_LEVEL(0)
// 级别最低.代表CPU在正常执行,没有中断发生
// DriverEntry、DriverUnload、DispatchRead.....等分发函数都处于这个级别,我们创建的线程也是这个级别
软中断
APC_LEVEL(1)
// 异步过程调用(以后补充)
DISPATCH_LEVEL(2)
// 这个级别重要运行完成例程,回调函数
硬终端
DIRQL // 设备中断请求级处理程序执行
PROFILE_LEVEL // 配置文件定时器
CLOCK@_LEVEL // 时钟
SYNCH_LEVEL // 同步级
IPI_LEVEL // 处理器之间中断级
POWER_LEVEL // 电源故障级
中断处理函数设计的时候一定要快速执行,在中断处理函数中不能做一些耗时的动作.因为如果我们正在执行某个中断,那么所有和它同级的,优先级比它低的这些中断都不会被相应了.如果长期调用这个函数,那么就会降低系统的响应能力,系统性能就会大幅下降.
如何遵守中断级别要求?
- 驱动中各个函数的中断级别
调用原 | 一般的运行中断级 |
---|---|
DriverEntry,DriverUnload | Passive级 |
各种分发函数 | Passive级 |
完成函数 | Dispatch级 |
各种NDIS回调函数 | Dispatch级 |
-
调用的API的运行级别
-
PASSIVE级别可以使用任何函数和内存
-
DISPATCH级别只能访问能运行在DISPATCH级别的API和NonPagedPool
-
NonPagedPool内存可在任何级别使用
-
PagedPool只能在PASSIVE级别和APC_LEVEL级别使用
-
在Passive和APC级别代码中加入PAGED_CODE()宏
#define PAGED_CODE() \ { if(KeGetCurrentIrql() > APC_LEVEL) { \ KdPrint("EX: Pageable code called at IRQL %d\n",KeGetCurrentIrql(); \ } \ }