【问题标题】:How to compare and swap atomically in ARM7?如何在ARM7中原子地比较和交换?
【发布时间】:2013-08-30 18:51:18
【问题描述】:

我想修改一个由 RTOS 中不同任务和 IRQ 上下文共享的全局变量。因此我需要原子地修改这个变量。 在我当前的实现中,我一直在使用 enable_irq/disable_irq 函数来原子地修改语句。

extern int g_var;

void set_bit_atomic(int mask)
{
    disable_irq();
    g_var |= mask;
    enable_irq();
}

我在 GCC documentation 中找到了 __sync_bool_compare_and_swap 函数作为原子操作的助手。

我目前的工具链是KEIL MDK,我想切换到如下所示的方法,

void set_bit_atomic(int mask)
{
    volatile int tmp;
    do {
        tmp = g_var;
    } while (!__sync_bool_compare_and_swap(&g_var, tmp, tmp | mask));
}

如何在 ARMv4 命令集中编写__sync_bool_compare_and_swap 函数(作为内联汇编)?

【问题讨论】:

  • 你可以看到 GCC 在汇编中是如何做到的,并通过修改克隆它 (gcc -S file.c)
  • ARM 使用加载链接/存储条件指令来执行原子操作。 (请参阅this question 中的链接。)
  • 我不相信会有很大的不同。据我了解,LDREX/STREX 指令需要 ARMV6,这就是 ARM 上“比较和交换”指令对的作用。
  • @Kerrek SB Link 显示 ARMv6 或更高版本的指令集。我正在使用 ARM7TDMI (ARMv4),不幸的是它不支持这些功能。
  • @KerrekSB:据我了解,这对 AMRv4 架构没有帮助。

标签: c atomic keil arm7


【解决方案1】:

我在 Linux 内核源代码中找到了 __kernel_cmpxchg 函数的类似实现。

它是为 ARMv5 及更早版本编写的,它似乎适用于 ARM7TDMI (ARMv4)。

1:      ldr     r3, [r2]        @ load current val
        subs    r3, r3, r0      @ compare with oldval
2:      streq   r1, [r2]        @ store newval if eq
        rsbs    r0, r3, #0      @ set return val and C flag
        bx      lr              @ or "mov pc, lr" if no thumb support

详情请见this链接。

我想警告两个重要问题,

1- __kernel_cmpxchg 发生交换时返回 0,而 __sync_bool_compare_and_swap 函数返回 true。

2- 函数原型不同。

typedef int (*__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
#define __kernel_cmpxchg ((__kernel_cmpxchg_t)0xffff0fc0)

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)

因此我不得不改变如下用法,

void set_bit_atomic(int mask)
{
    volatile int tmp;
    do {
        tmp = g_var;
    } while (my_compare_and_swap(tmp, tmp | mask, &g_var));
}

警告:如果没有内核支持,此代码将无法正常工作。请参阅下面的 cmets。

【讨论】:

  • 此功能在没有内核支持的情况下无法正常工作。如果在没有操作系统支持的情况下使用此功能,ldr r3, [r2]subs r3, r3, r0 之间的任何中断或抢占都会影响操作。简单的 ARM7TDMI (ARMv4) 对这个问题没有帮助。
  • 问题是关于 ARM7 (ARMv4)。但是让我注意到 ARMv6 引入了SWP 指令。这已在 ARMv7 中被弃用,取而代之的是 LDREX/STREX
猜你喜欢
  • 2021-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 2010-12-03
  • 2011-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多