0.driverbase-自旋锁(SpinLock)wrk代码分析

http://hgy413.com/1335.html

简介自旋锁的注意点和自旋锁实现原型代码

自旋锁是一种轻量级的多处理器间的同步机制(对单处理器无效) :roll: 
它要求所占用的时间尽可能短(一般不超过25ms),因为此时别的处理器正在高速运转并等待锁的释放,所以不能长时间占有
与其他相比,采用自旋锁的好处是:不会被中断或调度打断(它运行在DISPATCH_LEVEL上,不会被软中断)

自旋锁注意点:

1.被自旋锁保护的临界区代码执行时不能睡眠。单核处理器下,获取到锁的线程睡眠,若恰好此时CPU调度的另一个执行线程也需要获取这个锁,则会造成死锁;多核处理器下,若想获取锁的线程在同一个处理器下,同样会造成死锁,若位于另外的处理器,则会长时间占用CPU等待睡眠的线程释放锁,从而浪费CPU资源

2. 一定不要使自旋锁 (Spin Lock) 保持锁定状态的时间超过您的需要。 要使系统获得更好的总体性能,请不要使任何系统范围内有效的自旋锁的锁定时间超过 25 微秒

3.一定不要通过调用 KeReleaseSpinLockFromDpcLevel 来释放 KeAcquireSpinLock 所获取的自旋锁,因为这会使原始 IRQL 无法被还原

4.自旋锁锁定时,一定不要调用 IoStartNextPacket。 这将使系统死锁

5.自旋锁锁定时,一定不要调用 IoCompleteRequest。 这将使系统死锁

6.一定不要在取消例程中调用 IoAcquireCancelSpinLock,因为该例程被调用时已经获取了系统级的取消自旋锁

7.在自旋锁锁定时,一定不要调用驱动程序以外的代码,因为这会引起死锁

简单贴下WRK下自旋锁的实现代码:

1.初始化

FORCEINLINE
VOID
NTAPI
KeInitializeSpinLock (
	__out PKSPIN_LOCK SpinLock
	)
{
	*SpinLock = 0;
}
KSPIN_LOCK  SpinLock实际是一个操作系统相关的无符号整数,初始化,置为0,有信号状态

2.获取

//宏定义
#define KeAcquireSpinLock(SpinLock, OldIrql) \
	*(OldIrql) = KeAcquireSpinLockRaiseToDpc(SpinLock)
 
	-->
KIRQL KeAcquireSpinLockRaiseToDpc (__inout PKSPIN_LOCK SpinLock)
{
	KIRQL OldIrql;
 
	//提IRQL到DISPATCH_LEVEL,这样不会发生线程切换(线程调度也是在DISPATCH_LEVEL)
	//单核下,由于线程不会被切换,自然就达到了互斥效果
	OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
	KxAcquireSpinLock(SpinLock);
	return OldIrql; //返回原始的IRQL
}
	-->
 
VOID KxAcquireSpinLock (__inout PKSPIN_LOCK SpinLock)
{
	if (InterlockedBitTestAndSet64((LONG64 *)SpinLock, 0))
	{
		KxWaitForSpinLockAndAcquire(SpinLock);
	}
	return;
}
	-->InterlockedBitTestAndSet
BOOLEAN InterlockedBitTestAndSet (IN LONG *Base,IN LONG Bit)
{
__asm {
		   mov eax, Bit
		   mov ecx, Base
 
		   //lock指令是一种前缀,它可与其他指令联合,用来维持总线的锁存信号直到与其联合的指令执行完为止。当CPU与其他CPU协同工作时,该指令可避免破坏有用信息。
		   lock bts [ecx], eax//eax传入的是0,所以bts是把*SpinLock的第0位设置为1
		   setc al
	};
}
   -->
ULONG64 KxWaitForSpinLockAndAcquire (__inout PKSPIN_LOCK SpinLock)
{
	ULONG64 SpinCount = 0;
 
	// Wait for spin lock to become free.循环等待,直到SpinLock为0
	do {
		do {
			KeYieldProcessor();
		} while (*(volatile LONG64 *)SpinLock != 0);
	} while(InterlockedBitTestAndSet64((LONG64 *)SpinLock, 0));
 
	return SpinCount;
}

3. 释放

VOID KeReleaseSpinLock (__inout PKSPIN_LOCK SpinLock,
	__in KIRQL OldIrql)
{
	KxReleaseSpinLock(SpinLock);
	KeLowerIrql(OldIrql);// 恢复IRQL
	return;
}
-->
VOID KxReleaseSpinLock (__inout PKSPIN_LOCK SpinLock)
{
	InterlockedAnd64((LONG64 *)SpinLock, 0);//释放时进行与操作设置其为0
	return;
}






你可能感兴趣的:(0.driverbase-自旋锁(SpinLock)wrk代码分析)