快速连接
👉👉👉【精选】ARMv8/ARMv9架构入门到精通-目录 👈👈👈
说明:本文虽然以spinlock函数为例,但并不会深度解读spinlock函数。本文重点解读exclusive机制。
基础知识
- 每一个core都有一个Internal exclusive monitor,它有open和exclusive两个状态,管理着:Load-Exclusive accesses 、Store-Exclusive accesses、Clear-Exclusive(CLREX) instructions
- Load-Exclusive instruction和Store-Exclusive instruction是LDX, LDAX, STX, STLX
- 可以使用这些指令去构造semaphores、spinlock,以确保在同一个core之间的不同线程的同步操作。在不同的core之间也是可以使用同一个的coherent memory locations来确保同步。
- Load-Exclusive instruction标记一个block用于独占访问的内存, CTR_EL0定义了这个block的大小。
LDXR Wt, [base{,#0}]
(1)、从base
地址处读取一个数字,存放到Wt寄存器中;
(2)、将Monitor的状态变成exclusiveSTXR Ws, Wt, [base{,#0}]
(1)、将Wt中的数据写入到base
地址处,如果成功Ws返回0,否则返回1;
(2)、将Monitor从exclusive状态切换成open, 如果切换成功,则说明写入成功,Ws返回0; 如果切换失败,则数据不会写入到内存,Ws返回1
剖析:如果想用独占指令去store一个数,那么必需先要ldx/ldax指令,让Monitor置为exclusive状态,此时它才能继续进行store操作,store完成之后,Monitor将会从exclusive切回open状态。
继续白话剖析:我想独占方式往一个地址写数,那么我必需独占monitor,然后我才能往相关地址写数据。
示例1:同一个core上访问不同的锁
如下一个spinlock的实现,在同一个核上,当有两个线程都要执行这一段代码时。
FUNC cpu_spin_lock , :
mov w2, #SPINLOCK_LOCK
sevl
l1: wfe
l2: ldaxr w1, [x0]
cbnz w1, l1
stxr w1, w2, [x0]
cbnz w1, l2
ret
END_FUNC __cpu_spin_lock
- 1、thread1先调用cpu_spin_lock[&lock1]执行到ldaxr时,此时Internal Exclusive Monitor将标记为exclusive状态。换句话说,core已经是 Exclusive Access state,马上就要准备写操作了。
- 2、接着thread2也调用cpu_spin_lock*[&lock2]执行了到ldaxr,此时Internal Exclusive Monitor已经是exclusive状态了,无需重新设置。换句话说,core依然是 Exclusive Access state,马上就要准备写操作了。
- 3、接着thread1先调用了stxr操作,窝槽牛逼啊,直接就成功了,成功将w2写入到[X0]地址处,w1并返回0表示操作成功。此时Internal Exclusive Monitor将会从exclusive切换成open状态。。
- 4、接着thread2也调用了stxr操作,因为此时Internal Exclusive Monitor已经是open状态了,所以此时的写入操作将会失败。即w2不会被写入到[X0],且w1返回1,反馈给程序一个结果,告诉他:嗨,这步执行没有通过哦。
- 5、按照上述程序的逻辑,thread2在执行stxr失败后,w1返回1, 此时将程序跳回
l2
处,重新来一遍...
示例2:不同的core上访问不同的锁
依然是上述的例子,如果是不同的CPU在获取同一把锁会怎样呢?
由于[X0]标记exclusive访问,将会被缓存到Coherent memory中,此memory遵循MESI协议,故此时
- 1、thread1先调用cpu_spin_lock[&lock1]执行到ldaxr时,此时core1的Internal Exclusive Monitor将标记为exclusive状态。换句话说,core1已经是 Exclusive Access state,马上就要准备写操作了。
- 2、接着thread2也调用cpu_spin_lock*[&lock2]执行了到ldaxr,此时core2的Internal Exclusive Monitor将标记exclusive状态,换句话说,core依然是 Exclusive Access state,马上就要准备写操作了。
- 3、接着thread1先调用了stxr操作,窝槽牛逼啊,直接就成功了,成功将w2写入到[X0]地址处,w1并返回0表示操作成功。此时Internal Exclusive Monitor将会从exclusive切换成open状态。。
- 4、接着thread2也调用了stxr操作,因为此时core2的Internal Exclusive Monitor依然经是exclusive状态了,所以此时的写入操作会成功。
示例3:不同的core上,访问相同的锁。
依然是上述的例子,如果是不同的CPU在获取同一把锁会怎样呢?
由于[X0]标记exclusive访问,将会被缓存到Coherent memory中,此memory遵循MESI协议,故此时
- 1、thread1先调用cpu_spin_lock[&lock1]执行到ldaxr时,此时core1的Internal Exclusive Monitor将标记为exclusive状态。换句话说,core1已经是 Exclusive Access state,马上就要准备写操作了。
- 2、接着thread2也调用cpu_spin_lock*[&lock1]执行了到ldaxr,此时core2的Internal Exclusive Monitor将标记exclusive状态,由于[X0]标记exclusive访问,将会被缓存到Coherent memory中,此memory遵循MESI协议,故此时该地址数据也会被同步到Global Monitor的cache和Core2的Internal Monior的cache中,也就是说,此时Global Exclusive Monitor也换成了该地址数据,并且也是exclusive状态了。
- 3、接着thread1先调用了stxr操作,窝槽牛逼啊,直接就成功了,成功将w2写入到[X0]地址处,w1并返回0表示操作成功。此时core1的Internal Exclusive Monitor将会从exclusive切换成open状态。 Global Monitor也会从exclusive切换成open状态
- 4、接着thread2也调用了stxr操作,根据MESI协议,core2在执行store操作时,必先去snoop core1的cache,此时该地址数据将同步到Global Monitor的cache和core2的Internal Monitore的cache中,此时Global exclusive Monitor将会被置为open状态。因为Global exclusive Monitor缓存了该地址数据,并且为open状态,故stxr操作将失败;
- 5、如果此时core2再次执行一次ldaxr,然后再去执行stxr则能成功。
6、按照上述程序的逻辑,core2在执行stxr失败后,w1返回1, 此时将程序跳回
l2
处,重新来一遍...关注"Arm精选"公众号,备注进ARM交流讨论区。