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的实现:
KeAcquireSpinLock调用KfAcquireSpinLock.KfAcquireSpinLock干的第一件事就是提升IRQL到DISPATCH_LEVEL。因此直到释放自旋锁,使得IRQL降低到DISPATCH_LEVEL一下,整个代码段都在DISPATCH_LEVEL级别上运行,因此,这个IRQL级别上需要遵守的规则在KeAcquireSpinLock函数中也得遵守
4.拥有自旋锁时,不能调用IoStartNextPacket和IoCompleteRequest例程,一定不要在取消例程中调用 IoAcquireCancelSpinLock,这会引起系统死锁
至于不要在取消例程中调用 IoAcquireCancelSpinLock,这个可以看下IoCancelIrp的实现:
这个没什么好说的
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,如果在取消函数中再次调用这个就会因递归调用自旋锁而造成死锁
相关文章推荐
- Log4j分层次记录到MySQL数据库和HTML等文件
- JDK1.8源码中的设计模式
- kali arp欺骗嗅探局域网中所有数据包
- 从头开始,学习Java Web
- eclipse 运行Maven时报错总结
- Android ShareSDK 微信,QQ,新浪微博第三方登录
- 键约束和唯一性约束的区别
- android屏幕适配
- redis学习之redis的安装,类库及demo
- 设计模式之外观模式
- Java并发编程:Callable、Future和FutureTask
- sqlite3数据库的简要应用
- 表单验证
- 欢迎使用CSDN-markdown编辑器
- ASP.NET立即上传图片
- HDFS相关概念
- 如何安装nginx第三方模块
- next数组介绍
- Spring Mvc那点事---(7)Spring Mvc @Autowired注解
- HBase新版本与MapReduce集成