赞
踩
Linux
内核中 spinlock
相关数据结构和代码实现涉及的文件还是挺多的,这篇博客尝试从文件的角度来梳理一下 spinlock
的相关数据结构和代码实现,适合想大概了解 Linux
内核中 spinlock
从上层 API
到底层实现间的调用路径和传参变化,尤其适合了解 spinlock
和 qspinlock
之间的关系。
这里只以 spinlock
的 加锁函数 为切入点,梳理该函数从上层 API
到底层实现涉及的文件。
spinlock
的加锁函数是 spin_lock()
spin_lock()
的位置:include/linux/spinlock.h
spin_lock()
的内容:
static __always_inline void spin_lock(spinlock_t *lock)
{
raw_spin_lock(&lock->rlock);
}
看到这里,需要关注该函数的入参类型:spinlock_t
spinlock_t
的位置: include/linux/spinlock_types.h
spinlock_t
的内容:
typedef struct spinlock {
union {
struct raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
struct {
u8 __padding[LOCK_PADSIZE];
struct lockdep_map dep_map;
};
#endif
};
} spinlock_t;
从上面可以看到,spin_lock()
调用了 raw_spin_lock()
, 而 raw_spin_lock()
是一个宏,将它展开后得到:__raw_spin_lock()
,同时假定 CONFIG_INLINE_SPIN_LOCK
配置项打开,则
__raw_spin_lock()
的位置:include/linux/spinlock_api_smp.h
__raw_spin_lock()
的内容:
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);
}
__raw_spin_lock()
的参数类型是:raw_spinlock_t
,它和 struct raw_spinlock
是同一个类型,对应 spinlock_t
中 rlock
成员变量的类型
raw_spinlock_t
的位置:include/linux/spinlock_types.h
raw_spinloct_t
的内容:
typedef struct raw_spinlock {
arch_spinlock_t raw_lock;
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned int magic, owner_cpu;
void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} raw_spinlock_t;
从上面可以看到, __raw_spin_lock()
调用了 do_raw_spin_lock()
do_raw_spin_lock()
的位置:include/linux/spinlock.h
do_raw_spin_lock()
的内容:
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{
__acquire(lock);
arch_spin_lock(&lock->raw_lock);
}
从上面可以看到,do_raw_spin_lock()
调用了 arch_spin_lock()
arch_spin_lock()
和它的入参 arch_spinlock_t
是与体系结构相关的,这里面基本能分成两派,
一派是自己实现 arch_spin_lock()
和 arch_spinlock_t
,
一派是使用通用的 qspinlock
实现,也即 #define arch_spin_lock(l) queued_spin_lock(l)
和 typedef struct qspinlock {...} arch_spinlock_t
体系结构自己实现的架构包括:alpha
, arc
, arm
, hexagon
, ia64
, parisc
, powerpc
, riscv
, s390
, sh
, sparc-32
, xtensa
具体列举其中的 5 个:
alpha
架构
arch_spin_lock()
的位置:arch/alpha/include/asm/spinlock.h
arch_spinlock_t
的位置:arch/alpha/include/asm/spinlock_types.h
arc
架构
arch_spin_lock()
的位置:arch/arc/include/asm/spinlock.h
arch_spinlock_t
的位置:arch/arc/include/asm/spinlock_types.h
arm
架构
arch_spin_lock()
的位置:arch/arm/include/asm/spinlock.h
arch_spinlock_t
的位置:arch/arm/include/asm/spinlock_types.h
hexagon
架构
arch_spin_lock()
的位置:arch/hexagon/include/asm/spinlock.h
arch_spinlock_t
的位置:arch/hexagon/include/asm/spinlock_types.h
ia64
架构
arch_spin_lock()
的位置:arch/ia64/include/asm/spinlock.h
arch_spinlock_t
的位置:arch/ia64/include/asm/spinlock_types.h
使用 qspinlock
实现的架构包括:mips
, sparc-64
, x86
, arm64
, openrisc
queued_spin_lock()
的位置:include/asm-generic/qspinlock.h
queued_spin_lock()
的内容是:
static __always_inline void queued_spin_lock(struct qspinlock *lock)
{
u32 val;
val = atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL);
if (likely(val == 0))
return;
queued_spin_lock_slowpath(lock, val);
}
struct qspinlock
的位置:include/asm-generic/qspinlock_types.h
struct qspinlock
的内容是:
typedef struct qspinlock { union { atomic_t val; /* * By using the whole 2nd least significant byte for the * pending bit, we can allow better optimization of the lock * acquisition for the pending bit holder. */ #ifdef __LITTLE_ENDIAN struct { u8 locked; u8 pending; }; struct { u16 locked_pending; u16 tail; }; #else struct { u16 tail; u16 locked_pending; }; struct { u8 reserved[2]; u8 pending; u8 locked; }; #endif }; } arch_spinlock_t;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。