如何在ARM7中进行原子方式的比较和交换?

时间:2013-08-27 20:57:48

标签: c atomicity keil arm7

我想修改由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函数(作为内联汇编)?

1 个答案:

答案 0 :(得分:2)

我在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));
}

警告:没有内核支持,此代码无法正常运行。请参阅以下评论。