Kernel 为什么自旋锁irqsave需要在多处理器上禁用抢占

Kernel 为什么自旋锁irqsave需要在多处理器上禁用抢占,kernel,spinlock,preemption,Kernel,Spinlock,Preemption,只是好奇为什么spin\u lock\u irqsave在禁用本地中断后需要禁用抢占 static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock) { unsigned long flags; local_irq_save(flags); preempt_disable(); ===> can preemption happen with interrupt disabled?

只是好奇为什么
spin\u lock\u irqsave
在禁用本地中断后需要禁用抢占

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

    local_irq_save(flags);
    preempt_disable(); ===> can preemption happen with interrupt disabled?
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    ...
}

只有在启用中断的情况下才可能进行抢占,因此在禁用中断后不必担心抢占。

因为存在导致抢占的函数,除非明确禁用抢占,而不管中断的状态如何。假设如果不允许抢占,它将被显式禁用,并且函数不会抢占。相反,使用中断进行抢占禁用违反了这一假设

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

    local_irq_save(flags);
    preempt_disable(); ===> can preemption happen with interrupt disabled?
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    ...
}
其中一个函数是cond_resched(),它在core.c()中调用_cond_resched()

它检查是否启用了抢占并调用调度程序。这个函数是从内核中的许多地方调用的,可能会意外触发其中一个,从而破坏自旋锁保护的关键部分


此外,中断禁用自旋锁意味着可以从中断处理程序访问关键部分。如果您使用cond_resched()意外触发抢占,则一旦您的进程得到调度,将重新启用反向中断。如果出现试图获取锁的中断,则会出现死锁。

可能与文档/preempt-locking.txt中的重复:但请记住,“禁用irqs”是禁用抢占的根本不安全方式-任何自旋解锁()将抢占计数减少到0可能会触发重新调度。一个简单的printk()可能会触发重新调度。因此,仅当您知道受影响的代码路径不执行任何操作时,才使用此隐式抢占禁用属性。最好的策略是只对您编写的、不调用复杂函数的小型原子代码使用它。