NDIS自旋锁是否可作为DMA操作的内存屏障?
结论
你这里必须显式添加内存屏障,NDIS自旋锁自带的隐式内存屏障不足以规避该竞态风险。
原因说明
- NDIS自旋锁的内存屏障语义是:
NdisAcquireSpinLock自带获取屏障,仅保证锁之后的内存操作不会被重排到锁获取操作之前;NdisReleaseSpinLock自带释放屏障,仅保证锁区间内的内存操作不会被重排到锁释放操作之后。 - 释放屏障没有限制「锁释放之后的操作重排到锁释放之前」的能力,你的
NdisWriteRegisterUlong处于锁释放后的代码区间,CPU完全可能将该寄存器写操作重排到writeDataToSharedMem的共享内存写操作之前执行,导致硬件先收到通知、读取共享内存时数据还未写入,触发竞态。 - 额外注意:
NdisWriteRegisterUlong这类寄存器访问函数仅保证多个寄存器读写操作之间的执行顺序,不会约束寄存器读写和普通内存读写的顺序,因此不能依赖该函数自带的屏障能力。
正确代码示例
NdisAcquireSpinLock(); writeDataToSharedMem(); NdisReleaseSpinLock(); MemoryBarrier(); // 显式屏障保证所有共享内存写入完成后,再发送硬件通知 NdisWriteRegisterUlong(); // 通知硬件数据已写入
补充说明
如果你将NdisWriteRegisterUlong操作放到自旋锁的保护区间内,就不需要额外添加显式内存屏障,锁的释放屏障会保证锁内的共享内存写、寄存器写都在锁释放前完成,不会发生异常重排。
内容的提问来源于stack exchange,提问作者Rony Ross
相关产品推荐
相关产品推荐

