驱动开发:内核中的自旋锁结构

编程入门 行业动态 更新时间:2024-10-10 03:32:06

驱动开发:<a href=https://www.elefans.com/category/jswz/34/1769575.html style=内核中的自旋锁结构"/>

驱动开发:内核中的自旋锁结构

提到自旋锁那就必须要说链表,在上一篇《驱动开发:内核中的链表与结构体》文章中简单实用链表结构来存储进程信息列表,相信读者应该已经理解了内核链表的基本使用,本篇文章将讲解自旋锁的简单应用,自旋锁是为了解决内核链表读写时存在线程同步问题,解决多线程同步问题必须要用锁,通常使用自旋锁,自旋锁是内核中提供的一种高IRQL锁,用同步以及独占的方式访问某个资源。

自旋锁的基本原理是通过原子操作的方式对锁进行获取和释放。当一个线程想要获取自旋锁时,它会不断地检查锁的状态,如果锁被其他线程持有,则继续自旋等待;如果锁没有被持有,则将自己标记为锁的持有者,并继续执行。当线程完成对共享资源的操作后,会释放自旋锁,允许其他线程获取锁。

内核IRQL(Interrupt Request Level)锁是操作系统内核中用于保护关键数据结构或临界区的一种同步机制。它的作用是限制中断的处理级别,防止在关键代码段执行期间被更高优先级的中断打断,从而保证数据的一致性和可靠性。

内核IRQL锁的基本原理是通过调整中断处理级别来实现。在Windows操作系统中,有多个IRQL级别,从最低的PASSIVE_LEVEL到最高的DISPATCH_LEVEL。当执行关键代码段时,可以提高当前线程的IRQL级别,使得其他具有相同或更低IRQL级别的中断无法打断该代码段的执行。这样可以确保关键数据结构在执行期间不会被破坏或修改。

使用内核IRQL锁的步骤如下:

  • 保存当前的IRQL级别。
  • 提高当前线程的IRQL级别到所需的级别。
  • 执行关键代码段。
  • 恢复之前保存的IRQL级别。

内核IRQL锁适用于需要保护关键数据结构或临界区,并且不能被中断打断的场景,例如在中断处理程序中访问共享资源。通过提高IRQL级别,可以确保关键代码段在执行期间不会被其他中断打断,保证数据的完整性和一致性。

首先以简单的链表为案例,链表主要分为单向链表与双向链表,单向链表的链表节点中只有一个链表指针,其指向后一个链表元素,而双向链表节点中有两个链表节点指针,其中Blink指向前一个链表节点Flink指向后一个节点,以双向链表为例。

#include <ntifs.h>
#include <ntstrsafe.h>/*
// 链表节点指针
typedef struct _LIST_ENTRY
{struct _LIST_ENTRY *Flink;   // 当前节点的后一个节点struct _LIST_ENTRY *Blink;   // 当前节点的前一个结点
}LIST_ENTRY, *PLIST_ENTRY;
*/typedef struct _MyStruct
{ULONG x;ULONG y;LIST_ENTRY lpListEntry;
}MyStruct,*pMyStruct;VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint("驱动卸载成功 \n");
}// By: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("By:LyShark \n");DbgPrint("Email:me@lyshark \n");// 初始化头节点LIST_ENTRY ListHeader = { 0 };InitializeListHead(&ListHeader);// 定义链表元素MyStruct testA = { 0 };MyStruct testB = { 0 };MyStruct testC = { 0 };testA.x = 100;testA.y = 200;testB.x = 1000;testB.y = 2000;testC.x = 10000;testC.y = 20000;// 分别插入节点到头部和尾部InsertHeadList(&ListHeader, &testA.lpListEntry);InsertTailList(&ListHeader, &testB.lpListEntry);InsertTailList(&ListHeader, &testC.lpListEntry);// 节点不为空 则 移除一个节点if (IsListEmpty(&ListHeader) == FALSE){RemoveEntryList(&testA.lpListEntry);}// 输出链表数据PLIST_ENTRY pListEntry = NULL;pListEntry = ListHeader.Flink;while (pListEntry != &ListHeader){// 计算出成员距离结构体顶部内存距离pMyStruct ptr = CONTAINING_RECORD(pListEntry, MyStruct, lpListEntry);DbgPrint("节点元素X = %d 节点元素Y = %d \n", ptr->x, ptr->y);// 得到下一个元素地址pListEntry = pListEntry->Flink;}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

链表输出效果如下:

如上所述,内核链表读写时存在线程同步问题,解决多线程同步问题必须要用锁,通常使用自旋锁,自旋锁是内核中提供的一种高IRQL锁,用同步以及独占的方式访问某个资源。

#include <ntifs.h>
#include <ntstrsafe.h>/*
// 链表节点指针
typedef struct _LIST_ENTRY
{
struct _LIST_ENTRY *Flink;   // 当前节点的后一个节点
struct _LIST_ENTRY *Blink;   // 当前节点的前一个结点
}LIST_ENTRY, *PLIST_ENTRY;
*/typedef struct _MyStruct
{ULONG x;ULONG y;LIST_ENTRY lpListEntry;
}MyStruct, *pMyStruct;// 定义全局链表和全局锁
LIST_ENTRY my_list_header;
KSPIN_LOCK my_list_lock;// 初始化
void Init()
{InitializeListHead(&my_list_header);KeInitializeSpinLock(&my_list_lock);
}// 函数内使用锁
void function_ins()
{KIRQL Irql;// 加锁KeAcquireSpinLock(&my_list_lock, &Irql);DbgPrint("锁内部执行 \n");// 释放锁KeReleaseSpinLock(&my_list_lock, Irql);
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint("驱动卸载成功 \n");
}// By: LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("By:LyShark \n");DbgPrint("Email:me@lyshark \n");// 初始化链表Init();// 分配链表空间pMyStruct testA = (pMyStruct)ExAllocatePool(NonPagedPoolExecute, sizeof(pMyStruct));pMyStruct testB = (pMyStruct)ExAllocatePool(NonPagedPoolExecute, sizeof(pMyStruct));// 赋值testA->x = 100;testA->y = 200;testB->x = 1000;testB->y = 2000;// 向全局链表中插入数据if (NULL != testA && NULL != testB){ExInterlockedInsertHeadList(&my_list_header, (PLIST_ENTRY)&testA->lpListEntry, &my_list_lock);ExInterlockedInsertTailList(&my_list_header, (PLIST_ENTRY)&testB->lpListEntry, &my_list_lock);}function_ins();// 移除节点A并放入到remove_entry中PLIST_ENTRY remove_entry = ExInterlockedRemoveHeadList(&testA->lpListEntry, &my_list_lock);// 输出链表数据while (remove_entry != &my_list_header){// 计算出成员距离结构体顶部内存距离pMyStruct ptr = CONTAINING_RECORD(remove_entry, MyStruct, lpListEntry);DbgPrint("节点元素X = %d 节点元素Y = %d \n", ptr->x, ptr->y);// 得到下一个元素地址remove_entry = remove_entry->Flink;}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

加锁后执行效果如下:

更多推荐

驱动开发:内核中的自旋锁结构

本文发布于:2024-03-09 07:24:18,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1724276.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:内核   结构

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!