2010-09-09 63 views
4

我最近读部分5.5.2(自旋锁和原子上下文)LDDv3书:避免睡在持有自旋锁

避免睡在持有锁会更加困难;许多内核函数可以睡眠,并且这种行为并不总是记录得很好。将数据复制到用户空间或从用户空间复制数据是一个明显的例子:需要的用户空间页面可能需要在复制进行之前从磁盘交换,并且该操作显然需要休眠。几乎任何必须分配内存的操作都可以睡眠; kmalloc可以决定放弃处理器,并等待更多的内存变得可用,除非明确告知不要。睡觉可能发生在令人惊讶的地方;编写将在自旋锁下执行的代码需要注意您称为的每个函数。

我很清楚自旋锁必须始终保持最短时间,我认为从头开始编写正确的自旋锁代码是相对容易的。

但是,假设我们有一个大型项目,其中自旋锁被广泛使用。 我们如何确保从被自旋锁保护的关键部分调用的函数永远不会睡眠?

在此先感谢!

回答

4

如何为内核启用“睡眠内部螺旋锁检查”?它通常在运行make config时在内核调试下找到。您也可以尝试在代码中复制其行为。

+0

好点!不知道这一点。 – 2010-09-09 19:01:06

+0

仅供参考,这个选项是'CONFIG_DEBUG_ATOMIC_SLEEP' – TheCodeArtist 2017-12-26 10:58:28

-1

我在很多项目中注意到的一件事是人们似乎错误地使用了自旋锁,它们被用来代替应该使用的其他锁定原语。

只有在多处理器构建中存在一个linux自旋锁(在单进程构建中,自旋锁预处理器定义为空)自旋锁用于多处理器平台上的短持续时间锁。

如果代码无法获得自旋锁,它只是旋转处理器,直到锁被释放。因此,运行在不同处理器上的另一个进程必须释放锁,或者可能会被中断处理程序释放,但等待事件机制是等待中断的更好方法。

irqsave spinlock原语是禁用/启用中断的一种整齐方式,因此驱动程序可以锁定中断处理程序,但只能保持足够长的时间以使进程更新与中断处理程序共享的某些变量,如果您禁用interupts你不会被安排。

如果需要锁定中断处理程序,请使用带有irqsave的自旋锁。

对于一般的内核锁定,你应该使用互斥锁/信号量API,如果他们需要的话,它会睡在锁上。

要锁定针对码在其它过程中运行使用muxtex /旗语 要锁定针对在中断上下文使用IRQ保存/恢复或spinlock_irq保存运行的代码/恢复

要锁定针对代码上的其他处理器上运行,然后使用自旋锁并避免长时间保持锁。

我希望这可以帮助

+1

正如paul的回答中所解释的,由于抢占,自旋锁也与单处理器系统相关。 – Longfield 2012-06-01 06:39:43

+0

'spin_lock()'也对具有优先权的单处理器系统有效:当自旋锁被锁定时,先占权被禁用。这确保了在具有优先权的单处理器系统中相互排斥。 – 2017-11-29 01:01:14

+0

对于短时间锁定来说,自旋锁比互斥/信号量更适合,它们只需要强制数据访问互斥,并且无法入睡。对于这种用途,它们比互斥/信号量更高。 – 2017-11-29 01:19:50