spinlock要解决的问题:保证临界区代码执行过程的原子性。
1、spinlock特性:
1.1、忙等待锁机制。
1.2、同一时刻只能有一个内核代码路径可以获得该锁。
1.3、要求spinlock锁持有者尽快完成临界区的执行任务。
1.4、spinlock锁可以在中断上下文中使用。
2、spinlock的实现:
typedef struct {
____union {
________u32 slock; /*兼容Linux2.6.25之前的锁机制*/
________struct __raw_tickets {
#ifdef __ARMEB__
____________u16 next;
____________u16 owner;
#else
____________u16 owner; /*当前正在占用锁的编号*/
____________u16 next; /*下一次将要使用锁的编号*/
#endif
________} tickets;
____};
} arch_spinlock_t;typedef struct raw_spinlock {
____arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
____unsigned int break_lock;
#endif
#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;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的实现及变种:
static inline void spin_lock(spinlock_t *lock)
{
____raw_spin_lock(&lock->rlock);
}#define raw_spin_lock(lock)__raw_spin_lock(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);
}static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{
______acquire(lock);
____arch_spin_lock(&lock->raw_lock);
}static inline void arch_spin_lock(arch_spinlock_t *lock)
{
____unsigned long tmp;
____u32 newval;
____arch_spinlock_t lockval;____prefetchw(&lock->slock);
______asm__ __volatile__(
"1:_ldrex___%0, [%3]\n" @ lockval = lock->slock
"___add_%1, %0, %4\n" @ newval = lockval + 1 << TICKET_SHIFT
"___strex___%2, %1, [%3]\n" @ *(&lock->slock) = newval
"___teq_%2, #0\n"
"___bne_1b"
____: "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
____: "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
____: "cc");____while (lockval.tickets.next != lockval.tickets.owner) {
________wfe(); /*wfe指令让CPU进入等待状态*/
________lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);
____}____smp_mb();
}
在ARM体系中,WFI(Wait For Interrupt)和WFE(Wait For Event)指令都是让ARM核进入standby睡眠模式。
WFI/WFE等到有各自对应的事件发生时,才会被唤醒。它们唯一的区别在于,WFE可以被其他CPU上的SEV指令唤醒,SEV指令用于修改Event寄存器的指令。