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 // 电源故障级

中断处理函数设计的时候一定要快速执行,在中断处理函数中不能做一些耗时的动作.因为如果我们正在执行某个中断,那么所有和它同级的,优先级比它低的这些中断都不会被相应了.如果长期调用这个函数,那么就会降低系统的响应能力,系统性能就会大幅下降.

如何遵守中断级别要求?

  1. 驱动中各个函数的中断级别
调用原 一般的运行中断级
DriverEntry,DriverUnload Passive级
各种分发函数 Passive级
完成函数 Dispatch级
各种NDIS回调函数 Dispatch级
  1. 调用的API的运行级别

  2. PASSIVE级别可以使用任何函数和内存

  3. DISPATCH级别只能访问能运行在DISPATCH级别的API和NonPagedPool

  4. NonPagedPool内存可在任何级别使用

  5. PagedPool只能在PASSIVE级别和APC_LEVEL级别使用

  6. 在Passive和APC级别代码中加入PAGED_CODE()宏

     #define PAGED_CODE()  \
         {  if(KeGetCurrentIrql() > APC_LEVEL) {  \
                   KdPrint("EX: Pageable code called at IRQL %d\n",KeGetCurrentIrql(); \
             }  \
         }

推荐阅读更多精彩内容