Linux / SMP自旋锁不必要地慢吗?

时间:2011-01-19 08:41:50

标签: x86 linux-kernel spinlock

在阅读 Understanding the Linux kernel (Bovet & Cesati), 后,有关内核同步的章节指出自旋锁获取代码归结为:

1: lock:
   btsl    $0, slp
   jnc     3
2: testb   $1, slp
   jne     2
   jmp     1
3: 

现在我原本以为嵌套循环似乎很浪费,你可以实现类似的东西:

1: lock:
   btsl    $0, slp
   jc      1

这会更简单。但是,我知道为什么他们这样做,因为lock会影响其他CPU,而btsl的时间要比简单testb的时间大。

没有能够解决的一件事是旋转锁的后续释放。该书指出它产生以下结果:

   lock:
   btrl    $0, slp

我的问题基本上是为什么?在我看来,lock/mov-immediate组合更快。

您不需要将旧状态转换为进位标志,因为遵循内核无错误的规则(在所述内核中的许多其他位置假设),旧状态将为1(您不会如果你还没有获得它,就试图释放它。)

movbtrl快得多,至少在386上。

那么我错过了什么?

在后来的芯片上有没有改变这些指令的时间?

自书籍印刷以来内核是否已更新?

这本书是否完全错误(或显示简化说明)?

我是否错过了快速指令不满足的CPU之间同步化的其他方面?

1 个答案:

答案 0 :(得分:10)

嗯,Understanding the Linux Kernel已经过时了。自编写以来,Linux内核已更新为使用所谓的票证自旋锁。锁定基本上是一个16位数量,分为两个字节:让我们调用一个Next(就像分配器中的下一张票)和另一个Owner(就像柜台上的“现在服务”号码一样) )。初始化自旋锁,两个部分都设置为零。锁定注意到自旋锁的值并递增下一步,原子地。如果递增前的Next值等于Owner,则已获得锁定。否则,它会旋转,直到所有者增加到正确的值,依此类推。

相关代码位于asm/spinlock.h(适用于x86)。解锁操作确实比书中说的更快更简单:

static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
{
    asm volatile(UNLOCK_LOCK_PREFIX "incb %0"
         : "+m" (lock->slock)
         :
         : "memory", "cc");
}

因为incbtr快8或9倍。

希望这会有所帮助;如果没有,我会很乐意深入挖掘。