【问题标题】:How is this a guarantee a value has been atomically updated in ARM?这如何保证值已在 ARM 中自动更新?
【发布时间】:2021-01-07 18:40:15
【问题描述】:

ARM 提供 LDREX/STREX 来自动加载/存储值,但我觉得我在这仍然是一个原子操作方面遗漏了一些东西。以下通常是如何增加一。但是,是什么阻止了某些东西在 ADD 指令期间抢占,从而使 r2 不再匹配存储在 [r0] 中的内容?

(Assuming r0 is valid and r1 = 1)

ADD
    LDREX r2, [r0]
    ADDS  r2, r2, #1
    STREXNE r2, r1, [r0]        @ Store 1 if the original [r0] was not -1
    CMPNE r2, #1
    BEQ ADD

【问题讨论】:

  • 当操作被抢占时,代码表现得好像从未发生过一样,r2 设置为 0 表示这种情况。然后代码可以重试。
  • fuz:或者至少,就好像商店从未发生过一样。 AFAIK,中间的其他指令不会回滚。
  • 应该是ADDS 而不是ADD,这样你就只在[r0] 中的值以前是-1 时才进行存储?否则我不清楚条件应该完成什么。正如代码所示,您无条件存储1,而不是[r0] 的增量值; STREXNE 的操作数可能会颠倒,在这种情况下,CMPNE 可能希望使用 r1 而不是 r2
  • @Maxthecat:我明白了。正如 old_timer 指出的那样,在这种情况下发生的情况是原始线程根本 存储。 STREX 指令检测到其他人同时写入了该地址,而不是执行存储它返回失败,导致循环重复并加载新值 101。这正是 *EX 指令提供的额外功能超过常规加载/存储。
  • @Nate:我认为中断处理程序还必须清除“监视器”(CLREX 或虚拟 strex,除非在某些 Cortex-M CPU 上会在中断时自动发生),否则如果您上下文从一个线程中的 LDREX 切换到另一个线程中的 STREX,在不按地址监视的 CPU 上可能会出现误报(“成功的”strex)。见When is CLREX actually needed on ARM Cortex M7?。但是对于表现良好的操作系统,是的,Atomic operations in ARM 适用:STREX 确保跨线程的排他性。

标签: assembly arm atomic cpu-architecture load-link-store-conditional


【解决方案1】:

ldrex/strex 的工作基于跟踪与进程 ID 相关的独占访问的逻辑,这两者都在当时的总线上呈现。

所以如果 ldrex 和 strex 之间存在访问权限

ldrex process x
strex process x

由于中断或其他原因,逻辑应该返回一个 not OK 并且 strex 返回:

1 If the operation fails to update memory.

如文档所述。

现在这里的灰色区域是多方面的。 arm 逻辑本身(由 arm l1 制作的缓存,如果您从他们那里购买了 l2)将支持独占访问。有时arm文档可能仍然存在,如果这是一个单处理器(仅实现一个核心),您不必支持独占访问。您可能会发现非支持只是在总线上返回 EXOKAY 而不是 OKAY(成功与失败),而不是实际跟踪。但是您必须获得该访问权限才能错过缓存层,这意味着它们已关闭,这几乎意味着您没有运行操作系统,因为禁用或不启用缓存很痛苦。

硬件人员被告知您不必支持单处理器的独占访问。 ldrex/strex 不能替代 SWP(仍然存在于许多内核中)的一般人群。那个ldrex/strex是专门针对多核共享资源的,就是让不同的核基本可以互相通信,共享资源,不是一个核自己竞争。

软件人员在某些地方被告知他们是 SWP 的替代品。你也有进程ID的问题,如果单处理器你在这些事务上有不同的ID吗?如果是这样,您是如何以及何时设置这些 ID 的?即使硬件被实现为正确支持独占访问和多处理器,如果您的两个线程共享相同的 id,或者该内核上的所有线程共享相同的 id,那么它们将相互干扰。尽管通过实验进行测试应该是微不足道的。

该软件,特别是 Linux 社区,专注于将其作为 swp 的替代品,这使得阅读您不必支持它并且导致 Linux 无法工作的少数供应商很难。同时,Linux 内核中存在大量与 arm 相关的错误,尤其是与 arm 相关的错误,移植每个新版本都需要大量工作,因为放置了许多不正确的勘误表和其他解决方法。而且我怀疑许多移植 Linux 的人并没有意识到他们正在创建和/或留在移植中的错误。

简而言之,理论是每个线程都有自己的进程 ID,并且逻辑会跟踪对相关地址和进程 ID 的访问,如果在一个进程 ldrex 和 strex 之间存在访问,那么strex 将失败,您必须从另一个 ldrex 重新开始,这就是它处于循环中的原因。

所以

ldrex id x
...
strex id x  (passes)


ldrex id x
...
ldrex id y
...
strex id x (pass)
...
strex id y (fail)


ldrex id x
... 
ldrex id y
...
strex id y (pass)
...
strex id x (fail)

等等。

显然,该逻辑无法存储无限数量的地址和进程 ID 的历史记录,所以如果 ...

ldrex id x
...
strex id x

之间有大量的访问。然后您可能会不时地期待失败。

另外请注意,我认为一个或多个 cortex-ms 不支持 arm 逻辑中的 ldrex/strex。

好吧,好吧,例如有这种语言:

Cortex-M3 处理器实现了本地独占监视器。处理器内的本地监视器已构建为不保存任何物理地址,而是将任何访问视为与前一个 LDREX 的地址匹配。这意味着实现的独占预留颗粒是整个内存地址范围。

我在其他 cortex-ms 中也看到了。

文档中有更多文字可供思考。

Load-Exclusive 指令总是成功地从内存地址 x 读取一个值。

仅当没有其他处理器或进程对地址 x 执行更新的存储时,相应的 Store-Exclusive 指令才能成功写回内存地址 x。 Store-Exclusive 操作返回一个状态位,指示内存写入是否成功。

对于没有可共享属性的内存区域,独占访问指令依赖于本地监视器,该监视器标记处理器执行加载独占的任何地址。同一处理器使用 Store-Exclusive 修改任何地址的任何未中止尝试都保证清除标签。

注意处理器和/或进程是如何使用的,而不是像线程这样的术语。还要注意关于商店独家而不是一般商店的评论。因此,在进行试验时,您还应该:

ldrex
...
str
...
strex

看看会发生什么。

【讨论】:

    猜你喜欢
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 2012-11-14
    • 2014-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多