中断是异步过程调用,简而言之就是打断当前CPU正在执行的任务转而去执行另一个任务
windows在初始化时,为每种中断安装了一个中断处理例程---ISR(intterupt service routine),它们储存在IDT(intterupt dispatch table中断分发表)中,每次发生中断,处理都将询问中断控制器,中断控制器会将当前发生中断映射成一个中断号,用这个中断号作为索引在IDT中查询,然后CPU将转到对应的ISR去执行(当然,此时我们还没有考虑中断请求级的问题),顺便说明,如果是多CPU,那么每个CPU都会有自己的IDT
中断分硬件中断和软件中断,硬件中断一般是由可中断的外部设备造成的,比如说鼠标呀,键盘呀,网卡呀,等等……
软件中断一般是什么APC(
Asynchronous procedure call)调用啊,DPC(Dispatch/deferred procedure call)调用啊……貌似也就这些哦,嘿嘿
至于中断请求级,系统为每种硬件中断定义了一个请求级,与其说定义,不如说是一种算法。比如在单CPU的X86系统上,会简单的用27减去中断号,得到中断请求级(IRQL),
我们常见的x86系统上,请求级只有0-31个级别,数字越大,级别越高
软件中断只有两种中断请求级,APC_LEVEL,DISPATCH_LEVEL,对应我前面说的两种软软件中断
至于最后一种,PASSIVE_LEVEL,听名字你就知道,它是最低的,是被动的,所有用户模式代码和大部分驱动设备都运行在这个级别上
中断请求级有什么用?
中断请求级是控制当前处理器任务的关键,此时你必须明白,每个处理器都会有自己当前的中断请求级,这是处理器的一个状态,记住,是状态,可变的
中断级其实是作为一个屏蔽界限在使用,为什么这么说? 很简单,如果此时处理器正运行在IRQL为A上,此时所有硬件和软件产生的中断的IRQL为B,如果B<=A,B被屏蔽,如果B>A,然后处理器保存当前运行的线程环境,转到处理中断B。在B<A的情况下,处理器可能将B交给其他处理器去处理(多核情况下),也可能保留这个中断,直到某个时刻,处理器的中断请求级降下来了,满足B抢断CPU任务条件了,那么B中断就会被处理了
看某些书时,总是会有这么醒目的一行字,
运行在DISPATCH_LEVEL上的代码,绝对不能等待一个内核对象,也绝对不能出现页故障
为什么?简单解释下
如果运行在DISPATCH_LEVEL级别的代码,等待一个内核对象,那么此时CPU是闲置的,线程调度器将强制切换到另一个需要执行的线程,但是线程调度和我们此时运行的代码是同一个中断级啊,按照前面的规则,是不能打断我们的代码执行的,那么将不会有任何线程切换,CPU将一直因为我们的代码等待内核对象而空闲,这叫啥,占着茅坑不XX……嘿嘿。 至于不能发生也故障,其实也一样,因为我们的代码如果访问一个处于分页池中的内存的地址,那么将触发页故障,内存管理器将产生I/0异常,CPU此时就得等待文件系统将磁盘数据读入内存,这样一来,又是等待了,和前面等待内核对象一样,线程调度器必须调度,却调度不了,然后当前线程继续执行,访问错误的内存,继续BSOD!
再来聊聊DPC例程:分发(或者叫调度)或延迟调用例程
DPC例程,望文生义下下,运行在DISPATH_LEVEL上 = =
A:分发例程调用(dispatch procedure call)
1:系统的线程调度运行在DISPATCH_LEVEL上,每当一个线程时间片用完,而此时线程未完成其任务,系统将插入一个DISPATCH_LEVEL的中断请求调用线程调度器,但是它将等到当前线程完成某些任务直到其中断级降至DISPATCH_LEVEL以下,调度器才会运行。如果线程是主动结束或者等待,那么调度器将直接运行并切换线程
2:对内核共享数据的访问,应该将当前线程提升至DISPATCH_LEVEL,此时任何软中断,包括线程时间片用完时系统插入的DISPATCH_LEVEL级别的线程调度中断,都将被屏蔽,直到对数据操作完,降低IRQL,其他软中断才会得以处理……这样就保证了数据在可以完整的被读写
B:延迟例程调用(deferred procedure call)
1:延迟例程是完成某一项不是特别紧要的任务的函数
2:延迟例程以对象表示
3:每个CPU都有一个延迟例程队列
4:系统将在DISPATCH_LEVEL上处理延迟例程,即是,当前线程所在的CPU中断级即将从DISPATCH_LEVEL降下来,系统将保持此时的CPU中断级为DISPATCH_LEVEL,然后一个个调用DPC对象,直到DPC列为空时。另外,当满足任一一种抽空条件时,系统会执行抽空动作,若此时CPU中断级小于DISPATCH_LEVEL,系统将直接处理DPC队列并提升至DISPATCH_LEVEL……当抽空动作完成后,系统恢复原有的中断级,继续原有的任务(注意:因为DPC是在DISPATCH_LEVEL上被处理,所以延迟例程中,不能调用)
未完待续…………