【驱动】5-内核自旋锁
概述:Windows 内核自旋锁了解与使用
内存属性
在了解自旋锁之前需要先了解下内核的内存分配相关内容,相关的 API 可以参考 内存相关 一文。
这里补充下 ExAllocatePool
的参数1,也就是申请的页属性参数 POOL_TYPE
:
微软官方说明:_POOL_TYPE (wdm.h) - Windows drivers | Microsoft Learn
这里主要就常用的三个进行简单说明:
-
NonPagedPool
非分页池,这是不可分页的系统内存。 可以从任何 IRQL 访问非分页池,但它是一种稀缺资源,驱动程序应仅在必要时进行分配。该内存不会被交换到磁盘上,并且可以直接被内核访问,适用于需要快速访问的内存,例如驱动程序的代码、中断处理程序、系统调用等。 -
PagePool
分页池,它是可分页的系统内存。 只能在 分配和访问分页池。 -
NonPagedPoolExecute
带有执行权限的非分页内存。如果是使用
NonPagedPoolExecute
申请的内存则需要留意,避免被利用。
从 Windows 8 开始,NonPagedPoolExecute
是NonPagedPool
值的备用名称。 此值指示分配的内存是非分页且可执行的,即在此内存中启用指令执行。 若要从早期版本的 Windows 移植驱动程序,通常应将驱动程序源代码中 NonPagedPool 名称的所有或大多数实例替换为NonPagedPoolNx
。 避免将NonPagedPool
名称的实例替换为NonPagedPoolExecute
,除非显式需要可执行内存。 有关详细信息,请参阅 No-Execute (NX) Nonpaged Pool。
申请
内核自旋锁 KSPIN_LOCK
Windows内核自旋锁(Spin Locks)是内核定义的、仅在内核模式下使用的同步机制,用于保护共享数据或资源免受同时访问的影响。以下是关于Windows内核自旋锁的一些关键信息和使用指南:
-
自旋锁类型:
- KSPIN_LOCK:这是最常用的自旋锁类型,是一个不透明的类型,用于同步对共享资源的访问。
- 执行自旋锁(Executive Spin Locks):任何类型的驱动程序都可能使用一个或多个执行自旋锁。例如,大多数文件系统使用执行自旋锁来保护文件系统驱动程序(FSD)设备扩展中的交错工作队列,该队列存储由文件系统的工作者线程回调例程和FSD处理的IRP。
- 中断自旋锁(Interrupt Spin Locks):每个具有ISR(Interrupt Service Routine)的驱动程序都使用中断自旋锁来保护其ISR和通常从其StartIo和DpcForIsr例程调用的SynchCritSection例程之间共享的任何数据或硬件。
-
自旋锁的获取与释放:
- 在IRQL(Interrupt Request Level)小于或等于DISPATCH_LEVEL时,驱动程序可以使用
KeAcquireInStackQueuedSpinLock
和KeReleaseInStackQueuedSpinLock
来获取和释放自旋锁作为队列自旋锁。 - 对于在IRQL大于或等于DISPATCH_LEVEL的调用者,可以调用
KeAcquireSpinLockAtDpcLevel
和KeReleaseSpinLockFromDpcLevel
以获得更好的驱动程序性能。
- 在IRQL(Interrupt Request Level)小于或等于DISPATCH_LEVEL时,驱动程序可以使用
-
队列自旋锁(Queued Spin Locks):
- 队列自旋锁在多处理器机器上的性能优于普通自旋锁,特别是在高争用锁的情况下。
- 队列自旋锁允许处理器在锁上排队,释放时,锁会传递给排队的处理器,等待的处理器在本地标志上自旋。
-
使用自旋锁的指南:
- 任何由自旋锁保护的数据或资源以及相应的自旋锁的存储必须在驻留系统空间内存(非分页池)中提供。
- 驱动程序必须提供其使用的任何执行自旋锁的存储。但是,设备驱动程序不需要为其中断自旋锁提供存储,除非它具有多向量ISR或多个ISR。
-
注意事项:
- 使用自旋锁时需要注意避免死锁和优先级反转问题,因此在实际应用中需要谨慎使用。
以上信息提供了Windows内核自旋锁的基本概念、类型、使用方法以及注意事项,以帮助理解和正确使用内核自旋锁。