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

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等待的处理器
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值