为什么Linux中的spin_lock和spin_unlock之间的中断被禁用?

时间:2016-05-10 18:49:54

标签: linux synchronization mutex interrupt atomicity

我正在阅读Linux信号量的实现。由于原子性,信号和等待(源代码中的上下)使用自旋锁。然后我看到了spin_lock_irqsave中的Linux禁用中断和spin_unlock中的reenabled中断。这困惑了我。在我看来,在一个关键部分中确实没有任何禁止中断的点。

例如,proc A(当前处于活动状态)获取锁定,proc B(被阻止)正在等待锁定,proc C正在执行一些不相关的操作。在A和B之间的关键部分内切换到C的上下文是完全合理的。即使C也试图获取锁,由于锁已经被A锁定,结果将是C被阻塞并且A恢复执行。 / p>

因此,我不知道为什么Linux决定禁用由自旋锁保护的关键部分中的中断。它可能不会导致任何问题,但对我来说似乎是一个多余的操作。

3 个答案:

答案 0 :(得分:3)

请允许我从免责声明开始,我不是Linux专家,所以我的答案可能不是最准确的。请指出您可能发现的任何缺陷和问题。

想象一下,如果内核的各个部分使用了某些共享数据,包括需要快速且无法阻塞的中断处理程序等操作。假设系统调用foo当前处于活动状态并已获得锁定以使用/访问共享数据bar,并且在获取所述锁定之前/之前不会禁用中断。

现在是一个(硬件)中断处理程序,例如键盘,启动并且还需要访问bar(硬件中断的优先级高于系统调用)。由于bar当前被syscall foo锁定,因此中断处理程序无法执行任何操作。中断处理程序确实需要快速和虽然没有被阻止,所以他们只是在尝试获取锁定时继续旋转,这会导致死锁(即系统冻结),因为系统调用foo永远不会有机会完成并释放它锁。

如果在尝试获取foo中的锁之前禁用中断,那么foo将能够完成正在执行的操作并最终释放锁(并恢复中断)。在foo持有自旋锁时尝试进入的任何中断都将保留在队列中,并且能够在释放锁时启动。这样,您就不会遇到上述问题。但是,还必须注意确保bar的锁定尽可能短,以便其他更高优先级的操作可以在需要时接管。

答案 1 :(得分:0)

但是如果中断想要发出等待线程的信号怎么办?或者想测试sempahore值? irq禁用不是为了防止两个进程之间的上下文切换,而是为了防止irq。这一切都在文件开头的注释中:

  /*
   * Some notes on the implementation:
   *
   * The spinlock controls access to the other members of the semaphore.
   * down_trylock() and up() can be called from interrupt context, so we
   * have to disable interrupts when taking the lock.  It turns out various
   * parts of the kernel expect to be able to use down() on a semaphore in
   * interrupt context when they know it will succeed, so we have to use
   * irqsave variants for down(), down_interruptible() and down_killable()
   * too.
   *
   * The ->count variable represents how many more tasks can acquire this
   * semaphore.  If it's zero, there may be tasks waiting on the wait_list.
   */

答案 2 :(得分:0)

答案很简单:试图获取锁的线程无法知道将中断它的ISR是否会尝试获取相同的锁。如果发生这种情况,ISR将永远在同一锁上旋转,并且系统将死锁。