在SMP机,我们必须使用 spin_lock_irqsave 而不 spin_lock_irq 从中断的上下文。

为什么我们要保存的标记(这包含如果)?

是否有另一个中断程序可能中断我们吗?

有帮助吗?

解决方案

我是新来的内核,但是从我从罗伯特·爱的书“Linux内核开发”聚集,如果中断是在处理器上的代码开始锁定,当你调用spin_unlock_irq你会在错误解除锁定之前已被禁用方式。如果保存的标志,并与标志放开,功能spin_lock_irqsave将只恢复到中断到以前的状态。

实施例与spin_lock_irqsave

spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;

spin_lock_irqsave(&mLock, flags); // save the state, if locked already it is saved in flags
// Critical section
spin_unlock_irqrestore(&mLock, flags); // return to the formally state specified in flags

实施例与spin_lock_irq(无irqsave):

spinlock_t mLock = SPIN_LOCK_UNLOCK;
unsigned long flags;

spin_lock_irq(&mLock); // Does not know if already locked
// Critical section
spin_unlock_irq(&mLock); // Could result in an error unlock...

其他提示

spin_lock_irqsave 基本上是用于保存的中断之前的状态下采取的旋锁,这是因为旋锁禁止中断,当锁采取在中断的情况下,并重新启用它,当同时解锁。中断状态是保存,所以它应该恢复中断一次。

例如:

  1. 可以说,中断x是残疾前旋锁被收购
  2. spin_lock_irq 将禁止中断x和采取的锁
  3. spin_unlock_irq 将使该中断。

因此,在第3上述步骤之后释放锁,我们将中断x启用了其较早的禁用以前的锁被收购。

所以只有当你是肯定的中断是不是残疾人才那么你应该 spin_lock_irq 否则你应该始终使用 spin_lock_irqsave.

在需要除了spin_lock_irqsave spin_lock_irq非常类似于需要除了local_irq_save(flags) local_irq_disable的原因。这里是由罗伯特·爱的Linux内核开发第二版采取了这一要求一个很好的解释。

  

在local_irq_disable()例程是危险的,如果中断是   已经它的调用之前禁用。相应的调用   local_irq_enable()无条件使能中断,尽管   事实上,他们是断的开始。取而代之的是,需要一种机制   对中断恢复到以前的状态。这是一个共同关注   因为在内核中给定的代码路径可以达到既和   没有中断功能,这取决于调用链。例如,   想象前面的代码片段是一个更大的功能的一部分。   试想一下,这个功能是由其他两个功能,一个叫这   禁止中断和一个其中没有。因为它正在成为   更难为核心的增长规模和复杂性要知道所有的代码   路径导致到一个函数,它是更安全保存的状态   禁用它之前中断系统。然后,当你准备好   重新启用中断,您只需将它们恢复到原来的状态:

unsigned long flags;

local_irq_save(flags);    /* interrupts are now disabled */ /* ... */
local_irq_restore(flags); /* interrupts are restored to their previous
state */
  

请注意,这些方法是部分地作为宏至少实现的,所以   标志参数(其必须被定义为一个无符号长整数)是   看似按值传递。此参数包含   包含中断的状态架构特定的数据   系统。因为至少有一个支持的体系结构结合   堆栈信息进值(啊哈,SPARC),标志不能被传递   到另一个功能(具体而言,它必须保持相同的堆栈上   帧)。出于这个原因,调用保存和调用恢复   中断必须发生在相同的功能。

     

所有先前的功能可以由两个中断调用并   进程上下文

阅读 为什么核码线执行在中断背景下不能睡觉? 其链接到罗伯特*爱 文章, 我这样说的:

一些中断的处理程序(知 Linux作为快速处理程序的中断)的运行 与所有中断的地方 处理残疾人。这样做是为了 确保处理程序的中断运行 没有中断,尽快 可能的。更是如此,所有中断 处理程序的运行与其目前的 断线无所有 处理器。这确保了两个 中断的处理程序一样的 断线不行 同时进行。它还可以防止设备 驱动程序的作家具有处理 递中断,其复杂 编程。

以下是在Linux内核18年4月15日,的代码的一部分,其示出了该spiin_lock_irq()将调用__raw_spin_lock_irq()。然而,将不保存任何标志,你可以看到下面的代码的一部分,但禁止中断。

  static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)
    {
        local_irq_disable();
        preempt_disable();
        spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
        LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
    }

下面代码所示spin_lock_irqsave()这节省了标志的当前阶段,然后抢先禁用。

static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
    unsigned long flags;

    local_irq_save(flags);
    preempt_disable();
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    /*
     * On lockdep we dont want the hand-coded irq-enable of
     * do_raw_spin_lock_flags() code, because lockdep assumes
     * that interrupts are not re-enabled during lock-acquire:
     */
#ifdef CONFIG_LOCKDEP
    LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
#else
    do_raw_spin_lock_flags(lock, &flags);
#endif
    return flags;
}

此问题来自假断言开始: On an SMP machine we must use spin_lock_irqsave and not spin_lock_irq from interrupt context.

的这些也不应该被从中断使用 背景下,SMP或UP。这就是说,spin_lock_irqsave() 从中断上下文所使用的,为更普遍的 (它可以在两个中断和正常的环境中使用),但 你应该使用spin_lock()从中断上下文, 和spin_lock_irq()spin_lock_irqsave()从正常上下文。 使用spin_lock_irq()的几乎总是错误的事情 在中断上下文做的,是这SMP或UP。它可能工作 因为用的IRQ运行大多数中断处理程序在本地启用, 但你不应该尝试的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top