ARM64+Linux5.0 自旋锁

目录

1、资源竞争

2、自旋锁


之前 《转载 Linux 内核同步(二):自旋锁(Spinlock)》文章是 ARMv7 架构以及 Linux 4.x 的自旋锁相关的原理和实现,最近在看 ARMv8 + Linux 5.x 相关的内容,所以稍微更新一点东西;

他们之间的主要区别在于处理器架构的变化,之前的独占指令有些变化,导致最后和处理器相关的调用部分有些许更新,同时也在之前的基础之上新增了部分插图,来更加清晰的说明情况;

1、资源竞争

首先说明导致竞争的所有情况:

1、单个 CPU 上多个任务访问同一个资源,导致竞争:

2、单个 CPU 上任务与中断访问同一个资源,导致竞争:

3、SMP,多个任务访问同一个资源,导致竞争:

4、SMP,任务和中断访问同一个资源,导致竞争:

5、SMP,中断访问同一个资源,导致竞争:

2、自旋锁

自旋锁的原理是,尝试获取锁,如果获取不到,那么就原地“自旋”,说是自旋,其实实现上使用了 WFE 指令,让 CPU 进入等待状态,当另外一个持有锁的释放后,使用 SEV 唤醒处于 WFE 等待状态下的 CPU;

自旋锁的使用要求是:不允许睡眠,并且不应该被长时间的持有;

spin_lock spin_unlock 自旋锁在实现上,是需要关闭 CPU 抢占的,原因如下图:

进程 A 拿到了锁,还未释放的时候,被中断唤醒了进程 B,想去拿锁,就导致死锁;

如果要在中断上下文使用自旋锁呢?不仅仅需要关闭抢占,还需关闭中断,否则就会出现如下死锁:

所以中断上下文使用 spin_lock_irq/spin_unlock_irq(软中断上下文使用 spin_lock_bh/spin_unlock_bh),他和 spin_lock 不一样的地方在于,它关闭了中断

自旋锁最底层的实现,是和处理器相关的,处理器需要提供独占指令,以便可以进行独占访问,在 ARM64 上实现如下:

static inline void arch_spin_lock(arch_spinlock_t *lock)
{
	unsigned int tmp;
	arch_spinlock_t lockval, newval;

	asm volatile(
	/* Atomically increment the next ticket. */
	ARM64_LSE_ATOMIC_INSN(
	/* LL/SC */
"	prfm	pstl1strm, %3\n"
"1:	ldaxr	%w0, %3\n"
"	add	%w1, %w0, %w5\n"
"	stxr	%w2, %w1, %3\n"
"	cbnz	%w2, 1b\n",
	/* LSE atomics */
"	mov	%w2, %w5\n"
"	ldadda	%w2, %w0, %3\n"
	__nops(3)
	)

	/* Did we get the lock? */
"	eor	%w1, %w0, %w0, ror #16\n"
"	cbz	%w1, 3f\n"
	/*
	 * No: spin on the owner. Send a local event to avoid missing an
	 * unlock before the exclusive load.
	 */
"	sevl\n"
"2:	wfe\n"
"	ldaxrh	%w2, %4\n"
"	eor	%w1, %w2, %w0, lsr #16\n"
"	cbnz	%w1, 2b\n"
	/* We got the lock. Critical section starts here. */
"3:"
	: "=&r" (lockval), "=&r" (newval), "=&r" (tmp), "+Q" (*lock)
	: "Q" (lock->owner), "I" (1 << TICKET_SHIFT)
	: "memory");
}

static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
	unsigned long tmp;

	asm volatile(ARM64_LSE_ATOMIC_INSN(
	/* LL/SC */
	"	ldrh	%w1, %0\n"
	"	add	%w1, %w1, #1\n"
	"	stlrh	%w1, %0",
	/* LSE atomics */
	"	mov	%w1, #1\n"
	"	staddlh	%w1, %0\n"
	__nops(1))
	: "=Q" (lock->owner), "=&r" (tmp)
	:
	: "memory");
}

内嵌汇编代码,使用独占指令进行操作;

这里定义了自旋锁的占用规则,使用 FIFO tickets 机制(owner + next),即先来先拿锁,后来的按照先后顺序进行排队,在线发牌(next);

owner 指向了当前哪个拿到牌子的人,next 指向下一个拿到牌子的:

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值