Linux kernel 手持旋转锁时避免睡眠

Linux kernel 手持旋转锁时避免睡眠,linux-kernel,sleep,atomic,spinlock,Linux Kernel,Sleep,Atomic,Spinlock,我最近读了LDDv3书的一节(自旋锁和原子上下文): 在拿着锁的时候避免睡觉可能会更困难;许多内核函数都可以休眠,而且这种行为并不总是被很好地记录下来。将数据复制到用户空间或从用户空间复制数据就是一个明显的例子:在继续复制之前,可能需要从磁盘交换所需的用户空间页,并且该操作显然需要睡眠。几乎任何必须分配内存的操作都可以休眠;kmalloc可以决定放弃处理器,并等待更多内存可用,除非明确告诉它不要这样做。睡觉可能发生在令人惊讶的地方;编写将在自旋锁下执行的代码需要注意调用的每个函数 我很清楚,自旋

我最近读了LDDv3书的一节(自旋锁和原子上下文):

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

我很清楚,自旋锁必须始终保持在尽可能短的时间内,我认为使用从头开始的代码编写正确的自旋锁相对容易

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


提前谢谢

为内核启用“自旋锁内睡眠检查”怎么样?当您运行make config时,通常会在内核调试下找到它。您还可以尝试在代码中复制它的行为。

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

linux自旋锁仅存在于多处理器构建中(在自旋锁预处理器定义的单进程构建中为空),自旋锁用于多处理器平台上的短期锁

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

irqsave spinlock原语是一种禁用/启用中断的简洁方法,因此驱动程序可以锁定中断处理程序,但该原语只能保持足够长的时间,以便进程更新与中断处理程序共享的一些变量,如果禁用中断,则不会安排

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

对于一般的内核锁定,您应该使用互斥/信号量api,如果需要,它将在锁上休眠

要锁定在其他进程中运行的代码,请使用muxtex/semaphore 要锁定在中断上下文中运行的代码,请使用irq save/restore或spinlock\u irq save/restore

要锁定在其他处理器上运行的代码,请使用自旋锁并避免长时间保持锁定


我希望这会有所帮助

正如paul在回答中所解释的,自旋锁在单处理器系统上也具有相关性,因为抢占。
spin_lock()
对具有抢占功能的单处理器系统也有影响:当自旋锁被锁定时,抢占功能被禁用。这确保了具有抢占功能的单处理器系统中的互斥。对于只需要强制数据访问互斥且无法睡眠的短时锁,自旋锁比互斥/信号量更适合。对于此类使用,它们的性能高于互斥/信号量。仅供参考,此选项为
CONFIG\u DEBUG\u ATOMIC\u SLEEP