鸿蒙内核源码分析(原子操作篇) | 谁在为原子操作保驾护航

基本概念

在支持多任务的操作系统中,修改一块内存区域的数据需要“读取-修改-写入”三个步骤。然而同一内存区域的数据可能同时被多个任务访问,如果在修改数据的过程中被其他任务打断,就会造成该操作的执行结果无法预知。

使用开关中断的方法固然可以保证多任务执行结果符合预期,但这种方法显然会影响系统性能。

ARMv6架构引入了LDREXSTREX指令,以支持对共享存储器更缜密的非阻塞同步。由此实现的原子操作能确保对同一数据的“读取-修改-写入”操作在它的执行期间不会被打断,即操作的原子性。

有多个任务对同一个内存数据进行加减或交换操作时,使用原子操作保证结果的可预知性。

看过自旋锁篇的应该对LDREX和STREX指令不陌生的,自旋锁的本质就是对某个变量的原子操作,而且一定要通过汇编代码实现,也就是说LDREXSTREX指令保证了原子操作的底层实现.

回顾下自旋锁申请和释放锁的汇编代码.

ArchSpinLock 申请锁代码

    FUNCTION(ArchSpinLock)  @死守,非要拿到锁
        mov     r1, #1      @r1=1
    1:                      @循环的作用,因SEV是广播事件.不一定lock->rawLock的值已经改变了
        ldrex   r2, [r0]    @r0 = &lock->rawLock, 即 r2 = lock->rawLock
        cmp     r2, #0      @r2和0比较
        wfene               @不相等时,说明资源被占用,CPU核进入睡眠状态
        strexeq r2, r1, [r0]@此时CPU被重新唤醒,尝试令lock->rawLock=1,成功写入则r2=0
        cmpeq   r2, #0      @再来比较r2是否等于0,如果相等则获取到了锁
        bne     1b          @如果不相等,继续进入循环
        dmb                 @用DMB指令来隔离,以保证缓冲中的数据已经落实到RAM中
        bx      lr          @此时是一定拿到锁了,跳回调用ArchSpinLock函数

ArchSpinUnlock 释放锁代码

    FUNCTION(ArchSpinUnlock)    @释放锁
        mov     r1, #0          @r1=0               
        dmb                     @数据存储隔离,以保证缓冲中的数据已经落实到RAM中
        str     r1, [r0]        @令lock->rawLock = 0
        dsb                     @数据同步隔离
        sev                     @给各CPU广播事件,唤醒沉睡的CPU们
        bx      lr              @跳回调用ArchSpinLock函数

运作机制

鸿蒙通过对ARMv6架构中的LDREXSTREX进行封装,向用户提供了一套原子操作接口。

  • LDREX Rx, [Ry]
    读取内存中的值,并标记对该段内存为独占访问:

    • 读取寄存器Ry指向的4字节内存数据,保存到Rx寄存器中。
    • 对Ry指向的内存区域添加独占访问标记。
  • STREX Rf, Rx, [Ry]
    检查内存是否有独占访问标记,如果有则更新内存值并清空标记,否则不更新内存:

    • 有独占访问标记
      • 将寄存器Rx中的值更新到寄存器Ry指向的内存。
      • 标志寄存器Rf置为0。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值