您的位置:首页 > 其它

wdk中使用自旋锁SpinLock的规则及原因分析

2016-05-17 21:56 513 查看
1.尽早释放自旋锁,因为拥有它,其他cpu的活动就要被阻止。

这个没什么好说的

2.拥有自旋锁时不要引起硬件或软件异常,否则系统会崩溃

3.拥有自旋锁是不要访问任何分页代码或数据。

2和3得放一起讨论。这里引用MSDN上的一篇文章:Preventing Errors and Deadlocks While Using Spin Locks 这篇文章中罗列了拥有SpinLock时不应该触发的异常。粗看很疑惑,为什么不能在此期间触发异常?那换个说法,在IRQL>=DISPATCH_LEVEL时,不能使用分页内存,这个驱动开发规则大家都能理解和接受吧?其实2和3是这个规则的演化版,看下KeAcquireSpinLock的实现:

VOID
NTAPI
KeAcquireSpinLock(PKSPIN_LOCK SpinLock,
PKIRQL OldIrql)
{
/* Call the fastcall function */
*OldIrql = KfAcquireSpinLock(SpinLock);
}

KIRQL FASTCALL
KfAcquireSpinLock (
PKSPIN_LOCK	SpinLock
)
{
KIRQL OldIrql;

ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);

OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
KiAcquireSpinLock(SpinLock);

return OldIrql;
}


KeAcquireSpinLock调用KfAcquireSpinLock.KfAcquireSpinLock干的第一件事就是提升IRQL到DISPATCH_LEVEL。因此直到释放自旋锁,使得IRQL降低到DISPATCH_LEVEL一下,整个代码段都在DISPATCH_LEVEL级别上运行,因此,这个IRQL级别上需要遵守的规则在KeAcquireSpinLock函数中也得遵守

4.拥有自旋锁时,不能调用IoStartNextPacket和IoCompleteRequest例程,一定不要在取消例程中调用 IoAcquireCancelSpinLock,这会引起系统死锁
至于不要在取消例程中调用 IoAcquireCancelSpinLock,这个可以看下IoCancelIrp的实现:

BOOLEAN
NTAPI
IoCancelIrp(IN PIRP Irp)
{
KIRQL OldIrql;
PDRIVER_CANCEL CancelRoutine;
IOTRACE(IO_IRP_DEBUG,
"%s - Canceling IRP %p\n",
__FUNCTION__,
Irp);
ASSERT(Irp->Type == IO_TYPE_IRP);

/* Acquire the cancel lock and cancel the IRP */
IoAcquireCancelSpinLock(&OldIrql);
Irp->Cancel = TRUE;

/* Clear the cancel routine and get the old one */
CancelRoutine = IoSetCancelRoutine(Irp, NULL);
if (CancelRoutine)
{
...
CancelRoutine(IoGetCurrentIrpStackLocation(Irp)->DeviceObject, Irp);
return TRUE;
}
IoReleaseCancelSpinLock(OldIrql);
return FALSE;
}
在调用取消函数之前,IoCancelIrp已经调用过IoAcquireCancelSpinLock,如果在取消函数中再次调用这个就会因递归调用自旋锁而造成死锁
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: