当前位置: 代码迷 >> 综合 >> 4.2 spinlock
  详细解决方案

4.2 spinlock

热度:45   发布时间:2024-02-09 10:02:41.0

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寄存器的指令。

  相关解决方案