一、中断级IRQL
高级别可以打断低级别的调用,同级别不能打断同级别的调用。
中断级在软件层面分为三级,再高的级别是硬件发送的中断。
- - 0 pass_level
- - 1 apc_level
- - 2 dpc_level 只有硬件中断能打断
1.获取中断级
DbgPrint("当前执行中断级为 %d\n", KeGetCurrentIrql());
2.提高中断级
DPC这个级别是软件层面能提升到的最高权限,ISR(延迟过程调用)当某个硬件设备引发一个高中断的时候,可以把不那么紧急的任务放在DPC里边来执行,同时又把中断级降低。
DPC是一个队列,当CPU处理完高于DPC中断级的任务后就来找这个表,然后挨个拿出来执行,也可以不插队的形式短暂的把我们当前任务请求级提高到DPC。
KIRQL originIrql = KeGetCurrentIrql();
DbgPrint("当前执行中断级为 %d\n", KeGetCurrentIrql());
//提升中断级
originIrql = KeRaiseIrqlToDpcLevel();
DbgPrint("提升后请求中断级为 %d\n", KeGetCurrentIrql());
在使用API函数的时候关注一下中断级别。
当我们在一个DPC例程里边访问一个换页内存的时候,页面在物理内存中时,一切OK。但是当页面被换到磁盘上的pagefile.sys,缺页中断无法打断DPC过程(弹幕大佬:“准确说缺页中断会产生,但页面错误异常处理函数无法回应中断请求”),结果是访问一个无效内存,导致BSOD
DPC编程的时候不要使用换页内存(动态申请的时候有标志)
二、自旋锁
防止重入,保证资源使用时的唯一性,比如在尝试重入全局变量。自旋锁的本质是一种忙等待,一直在尝试获取,只有在上锁部分动作执行完毕,解锁完成后,才能被其他请求再次获取。(弹幕大佬:“也就是说获取自旋锁的线程中断级更高,被抢占的概率更小,从而能尽可能快的释放锁,避免其他线程长时间忙等待”)。