1. spin_lock作为一种轻量级的同步机制,在内核应用广泛,本文将基于ARMv8讲述其具体实现。由于spin_lock家族比较庞大,不大算面面俱到的介绍每一个实现,重点介绍spin_lock和spin_unlock的实现。
include/linux/spinlock.h
static inline void spin_lock(spinlock_t *lock)
{
raw_spin_lock(&lock->rlock);
}
static inline void spin_unlock(spinlock_t *lock)
{
raw_spin_unlock(&lock->rlock);
}
#define raw_spin_lock(lock) _raw_spin_lock(lock)
#define raw_spin_unlock(lock) _raw_spin_unlock(lock)
include/linux/spinlock_api_smp.h
void __lockfunc _raw_spin_lock(raw_spinlock_t *lock) __acquires(lock);
void __lockfunc _raw_spin_unlock(raw_spinlock_t *lock) __releases(lock);
kernel/spinlock.c
void __lockfunc _raw_spin_lock(raw_spinlock_t *lock)
{
__raw_spin_lock(lock);
}
EXPORT_SYMBOL(_raw_spin_lock);
void __lockfunc _raw_spin_unlock(raw_spinlock_t *lock)
{
__raw_spin_unlock(lock);
}
EXPORT_SYMBOL(_raw_spin_unlock);
include/linux/spinlock_api_smp.h
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
preempt_disable(); //禁止强占
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
static inline void __raw_spin_unlock(raw_spinlock_t *lock)
{
spin_release(&lock->dep_map, 1, _RET_IP_);
do_raw_spin_unlock(lock);
preempt_enable();
}
include/linux/lockdep.h
#define LOCK_CONTENDED(_lock, try, lock) \
do { \
if (!try(_lock)) { \
lock_contended(&(_lock)->dep_map, _RET_IP_); \
lock(_lock); \
} \
lock_acquired(&(_lock)->dep_map, _RET_IP_); \
} while (0)
由以上函数调用可以看出spin_lock调用do_raw_spin_lock, spin_unlock调用do_raw_spin_unlock。
include/linux/spinlock.h
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{
__acquire(lock);
arch_spin_lock(&lock->raw_lock);
}
static inline void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock)
{
arch_spin_unlock(&lock->raw_lock);
__release(lock);
}
2. Armv8 arch_spin_lock 和 arch_spin_unlock
41 static inline void arch_spin_lock(arch_spinlock_t *lock)
42 {
43 unsigned int tmp;
44
45 asm volatile(
46 " sevl\n"
47 "1: wfe\n"
48 "2: ldaxr %w0, %1\n"
49 " cbnz %w0, 1b\n"
50 " stxr %w0, %w2, %1\n"
51 " cbnz %w0, 2b\n"
52 : "=&r" (tmp), "+Q" (lock->lock)
53 : "r" (1)
54 : "cc", "memory");
55 }
46行,设置本地事件
47行, 等待事件(可能进入低功耗状态)
48行,独占读取lock->lock
49行, 如果不是0,跳转到47行,等待事件。如果是,继续执行。
50行, 独占向lock->lock写入1.
51行, 如果不成功,跳转到48行。如果成功结束。
73 static inline void arch_spin_unlock(arch_spinlock_t *lock)
74 {
75 asm volatile(
76 " stlr %w1, %0\n"
77 : "=Q" (lock->lock) : "r" (0) : "memory");
78 }
76行,向lock->lock写入0;会发出唤醒事件。