Linux-2.6.25采用Ticket Spinlock,锁本身是一个32位的int型变量,初始化为0
8bits 3 | 8bits 2 | 8bits 1 | 8bits 0 |
在NR_CPUS < 256的情况下,高16位不用;低16位的上下8位分别用来记录next和owner:
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
short inc = 0x0100;
__asm__ __volatile__ (
LOCK_PREFIX "xaddw %w0, %1\n" // 交换inc和lock->slock的值,并将其和存入lock->slock
"1:\t"
"cmpb %h0, %b0\n\t" // 比较inc的上下8位 (此时inc等于原来的lock->slock)
"je 2f\n\t" //相等则跳到2:
"rep ; nop\n\t" //为了降低功耗,暂停此CPU
"movb %1, %b0\n\t" // 将lock->slock的第0个8bits赋值给inc的第0个8bits
/* don't need lfence here, because loads are in-order */
"jmp 1b\n"
"2:"
:"+Q" (inc), "+m" (lock->slock)
:
:"memory", "cc");
}
static inline void __raw_spin_unlock(raw_spinlock_t *lock)
{
__asm__ __volatile__(
UNLOCK_LOCK_PREFIX "incb %0"
:"+m" (lock->slock)
:
:"memory", "cc");
}
对于NR_CPUS >= 256的情况,高低16位分别用来记录next和owner:
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
int inc = 0x00010000;
int tmp;
__asm__ __volatile__ (
"lock ; xaddl %0, %1\n"
"movzwl %w0, %2\n\t"
"shrl $16, %0\n\t"
"1:\t"
"cmpl %0, %2\n\t"
"je 2f\n\t"
"rep ; nop\n\t"
"movzwl %1, %2\n\t"
/* don't need lfence here, because loads are in-order */
"jmp 1b\n"
"2:"
:"+Q" (inc), "+m" (lock->slock), "=r" (tmp)
:
:"memory", "cc");
}
评论