中断级和自旋锁

知识点

中断级

1、中断级(IRQL):数字越大优先级越高,优先执行,等级越低越容易被等级高的程序打断。0级 pass_level 1级 apc_level 2 级 dpc_level,比2级dpc高的是 硬件中断级 。我们一般就是要提高到DPC级

每一个内核函数都要运行优先级
在这里插入图片描述

2、通过编程可以把代码提高到2级 DPC这个中断基本,这个也叫做ISR延时调用,当某个硬件设备引发一个高中断的时候,可以把不那么紧急的任务放在DPC里面跑。DPC是通过无硬件达到的最高例程,这个中断很难被打断,能打断它的只有硬件中断。
dpc有一个队列,也可以叫线程池,当CPU处理完高于DPC中断级的任务后就来找这个队列,然后依次执行这个队列,我们也可以不用插队列的形式短暂的把我们当前任务请求级别提高到DPC

3、通过KeGetCurrentIrql()函数可以知道当前代码运行在哪个中断级。

4、KeRaiseIrqlToDpcLevel() 提高到DPC优先级,返回值是提高前的优选级

5、KeLowerIrql(oldirql) 恢复到以前的优选级

6、如果提高到DPC优选级后不降低优选级会蓝屏

7、要HOOK NtOpenFile 在修改该函数头时,第一,不希望它被执行,第二我们不希望我们正在修改的这个过程被打断,先要把IRQL 提升到DPC 等级 ,而且要关闭CPU中断,然这一小段时间然CPU不接收任何中断,就可确保这个修改函数的过程一次通过

8、DPC的中断级很高,DPC中不允许使用分页内存,当我们在一个DPC例程里面访问一个换页内存的时候,如果这个换页内存刚好换进了物理内存,在物理内存的时候,不在磁盘上,一切OK没有问题,但是当页面被页面被换到磁盘上的pagefile.sys 会引发
swappage换页,引发缺页中断,缺页中断一般打不断DPC的过程,这时DPC访问的是一个无效的内存时会蓝屏。所以DPC编程的时候切记不要使用换页内存,也就是不要使用ExAllocate这个函数

自旋锁

1、就是排队执行,不让多个程序访问一个内核函数时乱套

2、自旋锁机制,本质是提高中断级,进锁以后中断级就在DPC上面,保证进入锁的代码不会被其它代码打断

3、和我写前台多窗口切换线程是一个道理

4、要先初速化自旋锁

KSPIN_LOCK spinlock = {
    
     0 };//自旋锁全局变量    此段代码放在引用头文件后面
//---------------自旋锁开始 可放在入口函数-------------------

	/// KeInitializeSpinLock自旋锁函数
	///&spinlock 全局变量
	KeInitializeSpinLock(&spinlock);//初始化自旋锁全局变量


//*************自旋锁结束******************
自旋锁编码例子1

先创建全局变量

KSPIN_LOCK spinlock = {
    
     0 };//全局变量,自旋锁用

然后把加锁代码

KIRQL oldirql = 0;
KeAcquireSpinLock(&spinlock,&oldirql); //上锁,只让一个程序来访问
//
//添加要执行的代码
//
KeReleaseSpinLock(&spinlock, oldirql); // 解锁
自旋锁编码例子2

创建全局变量

KSPIN_LOCK spinlock = {
    
     0 };//全局变量,自旋锁用

BOOLEAN block = FALSE;//自旋锁开关

自旋锁

	if (!block)
	{
    
    
		KeAcquireSpinLock(&spinlock, &oldirql); //上锁,只让一个程序来访问

		block = TRUE; //别的代码就不能访问到这里

		KeReleaseSpinLock(&spinlock, oldirql); // 解锁
		//
		//后面写需要的代码
		//
	   DbgPrint("自旋锁后代码开始工作");

		block = FALSE; //工作接受后让其它进程来访问
	}

试验

提高优先级试验1

代码:

DbgPrint("----Current Irql=%d---\n",KeGetCurrentIrql());//没有提高执行优先级的等级

	KIRQL oldirql = 0;

	oldirql = KeRaiseIrqlToDpcLevel(); //提高优先级别到Dpc,返回值是没有提高优先级时的等级

	DbgPrint("----Current Irql=%d---\n", KeGetCurrentIrql());//提高执行优先级的等级

	KeLowerIrql(oldirql); //恢复到之前的优选级别

运行结果:
在这里插入图片描述

提高优先级试验2 ,插入函数到DPC队列,这就是上面提到的延时调用

定义一个存放需要提升DPC优先级代码的全局变量

KDPC   dpcobj = {
    
     0 };//存放插入DPC优先级队列函数的一个全局变量

定义一个要插入的DPC队列的代码

VOID DpcRoutine(PVOID conetxt)
{
    
    
	 //往优先级DPC 里面插入的测试代码

	DbgPrint("----in Function DPC=%d---\n", KeGetCurrentIrql());// 打印当前代码优选等级

	return;
}

初始化和插入优先级代码

//---------------往2级DPC优先级的队列插入执行的代码开始-------------------
    ///&dpcobj 全局变量
	///要插入的代码 也就是一个函数
	/// 参数3是参数2函数的参数、如果没有参数就填NULL 
	KeInitializeDpc(&dpcobj, DpcRoutine,NULL);//初始化插入DPC优先级队列的函数

	KeInsertQueueDpc(&dpcobj, NULL, NULL);//往DPC优先级队列插入函数

	DbgPrint("----OUT Function DPC=%d---\n", KeGetCurrentIrql());// 打印当前代码优选等级
		
		
//***************往2级DPC优先级的队列插入执行的代码结束***************

猜你喜欢

转载自blog.csdn.net/lygl35/article/details/112856993