/*
* LL/SC
*/
load-link与store-conditional (LL/SC)是一对用于并发同步访问内存的CPU指令。Load-link返回内存位置处的当前值,
随后的store-conditional在该内存位置处保存新值。 这被用于实现锁算法与read-modify-write原子操作。
LL操作返回一个内存地址上当前存储的值,后面的SC操作,会向这个内存地址写入一个新值,但是只有在这个内存地址上存储的值,
从上个LL操作开始直到现在都没有发生改变的情况下,写入操作才能成功,否则都会失败。这个操作非常重要,是很多平台实现基本原子操作的基础。
对于ARM平台来说,也在硬件层面上提供了对LL/SC的支持,LL操作用的是LDREX指令,SC操作用的是STREX指令。
/*
* LSE
*/
LSE(Large System Extensions), 大型系统扩展
ARMv8.1指令集相对于ARMv8指令集添加了不少新的功能,其中有很大的一块功能称作LSE(Large System Extensions),
这其中添加了很多平台原生就支持的原子操作指令。
在这之前,如果想实现某个原子操作,必须要使用LL/SC操作,在ARMv8以前的32位系统中使用LDREX和STREX指令,从ARMv8起,它们被改名成了LDXR和STXR。
LL/SC操作本质上是很多CPU核去抢某个内存变量的独占访问,以前ARM主要用来在低功耗设备上运行,CPU核也不会太多,不会存在太大的问题。
但是,现在ARM已经往数据中心发展了,几十核的ARM处理器都已经出现了,如果还是大家一起抢可能会存在严重的性能问题。因此,为了支持这种大型系统,
在ARMv8.1中特意加入了大量原生原子操作指令。
与spin lock 和 rwlock 相关的几个arm64指令;
/*
* WFI、WFE、SEV、SEVL
*/
WFI(Wait for interrupt)和WFE(Wait for event)是两个让ARM核进入low-power standby模式的指令,由ARM architecture定义,由ARM core实现。
WFE
等待事件(Wait For Event)指令。
ARM架构下,有一个全局的事件寄存器(Event Register),系统中的每一个CPU核在这个寄存器上都有对应的位。
当当前CPU执行WFE指令的时候,如果事件寄存器对应当前CPU的位没有被设置(也就是0),则当前CPU核会进入低功耗模式,会被挂起,
不会再执行其它操作;而如果事件寄存器对应当前CPU的位被设置了(也就是1),则会将事件寄存器对应当前CPU的位清空(设置成0),
然后立即返回,继续执行下面的指令,不会进入低功耗模式。
如果当前CPU核通过WFE指令进入了低功耗模式,那么只有在如下情况下才可能被重新唤醒:
发生了IRQ中断(前提是没有被屏蔽);
发生了FIQ中断(前提是没有被屏蔽);
发生了SError中断(前提是没有被屏蔽);
事件寄存器对应当前CPU核的位被置位(设置成1),如果是通过这种方式唤醒的,唤醒后会立即将事件寄存器对应当前CPU核的位清0。
注意,WFE指令到底让CPU核干什么,其实是没有具体定义的,只要不让内存丢失数据就行。所以,其可以只是一条空(NOP)指令,
或者像绝大多数Arm核心设计的那样,可以进入低功耗状态。但是,如果实现了WFE指令将当前CPU核切换到低功耗模式,
那就一定要实现后面说的SEV指令,否则该CPU核有可能会一直不被唤醒。
在Arm架构下,Linux内核的自旋锁就使用到了WFE指令。
WFI
等待中断(Wait For Interrupt)指令。
和前面说的WFE指令不同,执行WFI指令后,当前CPU核会立即进入低功耗状态。
如果当前CPU核通过WFI指令进入了低功耗模式,那么只有在如下情况下才可能被重新唤醒:
发生了IRQ中断(不管有没有被屏蔽);
发生了FIQ中断(不管有没有被屏蔽);
发生了SError中断(不管有没有被屏蔽)。
SEV
发送事件(Send Event)指令。
这条指令将想系统中的所有CPU核发送事件。对应系统中的每个CPU核,设置事件寄存器(Event Register)相应的位。
如果某个CPU核正在等待事件(WFE),那么该CPU核会被立即唤醒,并清除掉表示该CPU的事件寄存器相应的位。
SEVL
发送本地事件(Send Event Locally)指令。
不同于前面说的SEV指令,这条指令只会向当前CPU核心发送。如果是多核CPU那也只向当前核心,不会向CPU内的其它核心发送。
值得注意的是,这条指令只有在支持ARMv8指令集之后的处理器中才有效。