目录
前言
正文
1.RH850U2A上的原子操作
1.1 Link
1.2 Link generation
1.3 Success in storing
1.4 Failure in storing
1.5 Condition for successful storing
1.6 Loss of the link
1.7 示例代码
2.Spinlock代码分析
2.1 尝试获取Spinlock
2.2 释放Spinlock
3.总结
前言
通过<<【OS】AUTOSAR架构下多核通信>>一文中我们知道Spinlock自旋锁用于多核通信间的数据一致性保护。那么,Spinlock到底是什么了,“自旋”的含义又是啥了? 本文就来分析RH850U2A芯片平台下Spinlock的底层实现。
问题:如何理解Spinlok自旋锁中的”自旋“的含义?
缩略词
简写 | 全称 |
PSW | Program State Word |
正文
1.RH850U2A上的Spinlock实现
LDL和STC指令可用于获取原子读-写操作,用于多核系统对内存更新进行精确处理。LDL和STC指令的操作方式如下。
1.1 Link
每个CPU只能创建一个Link(LLbit)。该链接包含关于创建它的地址的信息,并根据STC指令在该地址是否成功或失败以及该链接是否丢失来进行接下来的控制。该链接还包括创建链接时的数据大小信息,因此,数据大小与创建链接的LDL指令不同的任何STC指令总是会失败,STC指令失败则该链接被删除。
1.2 Link generation
每个CPU都能够生成一个到Local RAM和cluster RAM的链接。
在目标RAM上执行LDL指令导致链接地址被注册,同时设置链接标志,并响应该指令读取生成链接。
(a)每个CPU的Local RAM
(b)Cluster RAM
每个CPU都能够生成一个到(a)或(b)的链接。
1.3 Success in storing
在生成Link之后,存储将只响应执行与生成的链路对应的STC指令而进行,也就说说该存储地址只能通过STC指令写入。
1.4 Failure in storing
如果链路丢失,即使处理相应地址的STC指令,存储也不会继续。当处理与链接不对应的STC指令时,也不会继续存储。
个人理解:Link是一个抽象概念,通过LDL指令能够创建一个link,且每个CPU只能创建一个Link,通过STC指令能改写CPU Link的RAM的值。
1.5 Condition for successful storing
如果满足以下条件,则判定STC指令为与该链路对应的地址:
生成链接的LDL指令的地址和大小与STC指令的地址和大小相匹配。
1.6 Loss of the link
当满足某些事件或地址条件时,链接将丢失。表1显示了Link loss情况。如果满足此表中所示的任何条件,则一个链接就会丢失。
Table 1 Link Loss Conditions
Note: 在Local RAM中,如果执行了除STC/CAXI指令以外的存储指令,则链接并不总是丢失。因此,触使Link Loss的指令程序流是可以不需要的。例如,在接下来的示例代码中,在使用LDL指令读取锁变量后,只有在没有锁的情况下才执行STC指令,如果锁已经存在(Link已经建立)则通过Lock Release对应的Link Loss程序流就是不需要的。也就是说,LDL指令Link成功,STC指令存储成功(创建一个Lock),之后的ST等存储指令用于Link Loss才是有意义的。也就是只有GetSpinlock成功之后才能ReleaseSpinlock.
1.7 示例代码
通过使用LDL.W和STC.W指令执行的自旋锁的示例代码如下所示。
一行一行的来分析这段汇编代码:
MOV lock_adr, r20 //lock_adr这个地址值赋值给r20寄存器,lock_adr可以理解为一个存在于RAM的全局变量的地址。
LDL.W [r20], r21 //以原子操作的方式加载r20寄存器保存的地址所在的值给r21寄存器。这个指令执行完后,r20存储lock_adr地址值(全局变量的地址),r21保存了lock_adr地址指向的具体变量值(全局变量的值)。Link Generation
CMP r0, r21 //r0寄存器中值与r21寄存器中的值进行比较。
Note 1: r0是Zero寄存器,其值永远为0.
Note 2: CMP指令的结果在程序状态字寄存器的PSW.Z bit上体现,比较的两个值如果相等则PSW.Z =1;反之,比较的两个值不相等,则PSW.Z = 0.
BNZ lock_wait //如果上一次的cmp结果不为0,则跳转到lock_wait标识符地址处往下执行。
MOV 1, r21 //将1赋值给r21寄存器。r21寄存器中保存的值为1.
STC.W r21, [r20] //将r21寄存器保存的值(1)赋值给r20保存的地址指向的变量。Success in storing.
CMP r0, r21 //比较r0(always retains 0)和r21寄存器中保存的值(也就是比较0和1)。
BNZ lock_success //如果上一次的cmp结果不为0,则跳转到lock_success标识符地址处往下执行。
Lock_wait: SNOOZE
Note: SNOOZE指令是一种在自旋锁期间减少总线带宽使用的指令。该指令完成后,CPU核心进入临时停止状态,以限制后续指令的执行。程序员可以通过将此指令插入到一个自旋锁循环中,从而避免由于短期重复锁定过程而导致的不必要的总线带宽的使用。
BR Lock //无条件跳转到Lock标识符处
Lock_success: //一个标识符,运行到这里表明get spinlock成功,继续往下执行。
ST.W r0, 0[r21] //王r21寄存器保存的地址值指向的变量写入0值。Release spinlock.
2.Spinlock代码分析
2.1 尝试获取Spinlock
准备获取Spinlock的时候,外部就是一个While循环,直到成功获取到Spinlock,否则就会“自旋”。
2.2 释放Spinlock
释放Spinlock对应的C代码,只需将标识Spinlock的全局变量赋值为0即可(对应ST.W r0, 0[r21]的汇编代码)。
3.总结
本文详细分析了Spinlock在RH850U2A芯片平台上的底层实现,着重需要理解RH850U2A芯片架构中的Link概念。Spinlock对应的底层两个特殊的汇编指令:LDL.W和STC.W. 在C语言环境下调用GetSpinlock()的具体实现也就是调用OS_LDLW()和STC_STCW()。值得注意的是,Spinlock的底层实现和具体芯片特性相关,其他芯片平台(比如Tricore芯片)的底层具体实现可能就不一样了,需要具体分析。
问题:如何理解Spinlok自旋锁中的”自旋“的含义?
答:“自旋”对应底层的SNOOZE指令。当前CPU(Core x)执行LDL.W没有建立Link后,CPU执行SNOOZE指令暂停一个机器周期,随后再次尝试去执行LDL.W指令,直到建立Link成功(其他CPU释放Spinlock),这个过程对应“自旋”的含义。
参考文档:
1.RH850/U2A-EVA Group: User’s Manual: Hardware
2.RH850G4MH: User’s Manual: Software
3.MULTI: Building Applications for Embedded V850 and RH850