X86 Linux/SMP自旋锁是否太慢了?

X86 Linux/SMP自旋锁是否太慢了?,x86,linux-kernel,spinlock,X86,Linux Kernel,Spinlock,通过阅读了解Linux内核(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 这会简单得多。但是,我明白他们为什么这样做了,因为锁会影响其他CPU,b

通过阅读
了解Linux内核(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
这会简单得多。但是,我明白他们为什么这样做了,因为
会影响其他CPU,
btsl
的计时比简单的
testb
的计时要大

有一件事我还没有弄清楚,那就是随后的自旋锁的释放。该书指出,其结果如下:

   lock:
   btrl    $0, slp
我的问题是为什么?在我看来,
lock/mov immediate
组合更快

您不需要将旧状态设置为carry标志,因为按照内核没有bug的规则(假设在内核中的许多其他地方),旧状态将为1(如果您还没有获得它,您就不会尝试释放它)

而且
mov
btrl
快得多,至少在386上是这样

那么我错过了什么

在以后的芯片上,这些指令的计时是否改变了

自从这本书出版以来,内核已经更新了吗

这本书是不是完全错了(或者显示了简化的说明)


我是否错过了其他一些涉及CPU之间同步的方面,而这些方面是更快的指令无法满足的?

好吧,
理解Linux内核已经很老了。自编写以来,Linux内核被更新为使用所谓的票据自旋锁。锁基本上是一个16位的数量,分为两个字节:让我们调用一个
Next
(就像自动售票机中的下一张票)和另一个
Owner
(就像柜台上的“正在服务”号码)。自旋锁在两个部分都设置为零的情况下初始化。锁定记录spinlock的值,然后按原子顺序递增。如果递增前的Next值等于Owner,则已获得锁。否则,它会旋转,直到所有者增加到正确的值,依此类推

相关代码位于中(对于x86)。解锁操作确实比书中所说的要快得多,也简单得多:

static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
{
    asm volatile(UNLOCK_LOCK_PREFIX "incb %0"
         : "+m" (lock->slock)
         :
         : "memory", "cc");
}
因为
inc
大约比
btr
快8到9倍

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