您的位置:首页 > 运维架构 > Linux

linux 内核自旋锁spinlock实现详解(基于ARM处理器)

2017-08-11 10:48 537 查看

1、自旋锁结构

typedef struct {
union {
u32 slock;
struct __raw_tickets {

#ifdef __ARMEB__
u16 next; ------ 下一个可以获取自旋锁的处理器,处理器请求自旋锁的时候会保存该值并对该值加1,然后与owner比较,检查是否可以获取到自旋锁,每请求一次next都加1
u16 owner; ------ 当前获取到/可以获取自旋锁的处理器,没释放一次都加1,这样next与owner就保存一致

#else
u16 owner;
u16 next;

#endif
} tickets;
};

} arch_spinlock_t;

2、获取自旋锁

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 (如果lock->slock没有被其他处理器独占,则标记当前执行处理器对lock->slock地址的独占访问;否则不影响)

" add %1, %0, %4\n"------ newval = lockval + (1 << TICKET_SHIFT)

" strex
%2, %1, [%3]\n" ------ strex tmp, newval, [&lock->slock] (如果当前执行处理器没有独占lock->slock地址的访问,不进行存储,返回1;如果当前处理器已经独占lock->slock内存访问,则对内存进行写,返回0,清除独占标记) lock->tickets.next = lock->tickets.next + 1

" teq %2, #0\n"------ 检查是否写入成功lockval.tickets.next

" bne 1b"
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
: "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
: "cc");

while (lockval.tickets.next != lockval.tickets.owner) {------ 初始化时lock->tickets.owner、lock->tickets.next都为0,假设第一次执行arch_spin_lock,lockval = *lock,lock->tickets.next++,lockval.tickets.next等于lockval.tickets.owner,获取到自旋锁;自旋锁未释放,第二次执行的时候,lock->tickets.owner
= 0, lock->tickets.next = 1,拷贝到lockval后,lockval.tickets.next != lockval.tickets.owner,会执行wfe等待被自旋锁释放被唤醒,自旋锁释放时会执行lock->tickets.owner++,lockval.tickets.owner重新赋值
wfe(); ------ 暂时中断挂起执行
lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);------ 重新读取lock->tickets.owner
}

smp_mb();

}

3、释放自旋锁

static inline void arch_spin_unlock(arch_spinlock_t *lock)

{
smp_mb();
lock->tickets.owner++;
------ lock->tickets.owner增加1,下一个被唤醒的处理器会检查该值是否与自己的lockval.tickets.next相等,lock->tickets.owner代表可以获取的自旋锁的处理器,lock->tickets.next你一个可以获取的自旋锁的owner;处理器获取自旋锁时,会先读取lock->tickets.next用于与lock->tickets.owner比较并且对lock->tickets.next加1,下一个处理器获取到的lock->tickets.next就与当前处理器不一致了,两个处理器都与lock->tickets.owner比较,肯定只有一个处理器会相等,自旋锁释放时时对lock->tickets.owner加1计算,因此,先申请自旋锁多处理器lock->tickets.next值更新,自然先获取到自旋锁
dsb_sev(); ------ 执行sev指令,唤醒wfe等待的处理器

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: