Linux设备驱动程序:睡眠持续重新访问锁定

时间:2018-05-20 20:20:04

标签: c linux-kernel linux-device-driver

我一直被教导说,在内核代码中按住自旋锁是睡不着觉。原因如下:

  1. 线程A获取锁,执行某些操作,并调用进入休眠状态的内核函数,释放CPU。
  2. 线程B现在运行,它试图获取锁定,但是因为线程A保持锁定而不能。
  3. 这是一个僵局。线程A无法唤醒,因为线程B不断旋转,线程B无法取得任何进展,因为它无法获得锁定。
  4. 我正在维护一个使用大量锁的驱动程序,并且在一些锁定的部分内部是显而易见的事情,如内存分配,copy_to_user()等。

    然而,我并不完全相信我的手上有一个虫子。使用上面的场景,线程A是用户上下文(即在read()的实现中),而线程B是中断上下文(在ISR内)。锁定通过spin_lock_irqsave()锁定。因此,当线程A保持锁定时,线程B无法运行,从而无法实现死锁。

    我还考虑了以下内容:

    1. 线程A =中断上下文。这里线程A无法休眠(并且没有),所以我们永远不会陷入死锁状态。
    2. 线程A和B都是用户上下文(即对read()的并发调用)。由于其他机制的存在,这种情况不会发生。
    3. 我有什么遗失的吗?在我上面描述的内容中,握住锁定时是否存在与睡眠有关的真正危险?

2 个答案:

答案 0 :(得分:3)

  

我一直被教导说,在内核代码中按住自旋锁是睡不着觉。

您混淆自旋锁已禁用的中断(原子上下文,IRQ)。

  1. 只有睡眠,而自旋锁(使用spin_lock获取)会伤害性能,因为另一个线程,想要锁定自旋锁,浪费时间等待忙碌。但除此之外系统还可以。

  2. 正在休眠 已禁用中断表示CPU内核已死:它没有执行任何操作且无法做出反应来自其他核心和外部世界的中断。

    如果您的呼叫spin_lock_irqsave后跟copy_from_user,则会发生这种情况:第一个操作会禁用中断,第二个操作可能会休眠。

  3. 通常禁用中断伴随自旋锁(通过spin_lock_irqsave或类似方式)。否则,如果IRQ线程将尝试获取相同的自旋锁,将观察到死锁:所有者线程无法继续,因为它被抢占,并且IRQ线程因为等待自旋锁而无法继续。

    如果没有IRQ线程(或因其他原因而禁用中断的线程)锁定给定的自旋锁,则不需要禁用中断。如果不需要禁用中断,则可以使用spin_lock代替spin_lock_irqsave。但非常推荐互斥锁替换非IRQ自旋锁

答案 1 :(得分:1)

这个问题没有加起来。

  

使用上面的场景,线程A是用户上下文(即内部)   执行read())而线程B是中断上下文   (在ISR内)。锁通过spin_lock_irqsave()锁定。作为一个   结果,线程B不能运行而线程A持有锁,使得   死锁是不可能的。

如果您在copy_to_user&上持有螺旋锁朋友们,带调试的内核会警告你,你做错了。如果需要让线程进入睡眠状态,它就会进入睡眠状态。然后你回到原点。