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

举报
王瑞专家 发表于 2022/11/02 13:56:07 2022/11/02
1.4k+ 0 0
【摘要】 提到自旋锁那就必须要说链表,在上一篇`《驱动开发:内核中的链表与结构体》`文章中简单实用链表结构来存储进程信息列表,相信读者应该已经理解了内核链表的基本使用,本篇文章将讲解自旋锁的简单应用,自旋锁是为了解决内核链表读写时存在线程同步问题,解决多线程同步问题必须要用锁,通常使用自旋锁,自旋锁是内核中提供的一种高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.com \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;
}

链表输出效果如下:

image.png

如上所述,内核链表读写时存在线程同步问题,解决多线程同步问题必须要用锁,通常使用自旋锁,自旋锁是内核中提供的一种高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.com \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;
}

加锁后执行效果如下:

image.png

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。