Как сравнить и поменять атомарно в ARM7?

Я хотел бы изменить глобальную переменную, которая совместно используется различными задачами и контекстами IRQ в ОСРВ. Поэтому мне нужно изменить эту переменную атомарно. В моей текущей реализации я использовал функции enable_irq/disable_irq для атомарного изменения оператора.

extern int g_var;

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

Я нашел __sync_bool_compare_and_swap функция в документации GCC как помощник для атомарных операций.

Мой текущий набор инструментов - 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));
}

Как я могу написать __sync_bool_compare_and_swap функция в наборе команд ARMv4 (как встроенная сборка)?

1 ответ

Решение

Я нашел похожую реализацию для __kernel_cmpxchg функция в исходном коде ядра Linux.

Он был написан для 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

Подробности можно найти по этой ссылке.

Есть два важных вопроса, которые я хотел бы предупредить,

1- __kernel_cmpxchg возвращает 0, когда произошел обмен, в то время как __sync_bool_compare_and_swap функция возвращает истину.

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

Предостережение: этот код не работает должным образом без поддержки ядра. Смотрите комментарии ниже.

Другие вопросы по тегам