这可以原子地执行吗?

时间:2011-03-24 11:47:55

标签: c assembly arm atomic interrupt

我想知道是否有可能确保line原子执行,因为它可以由ISR和Main上下文执行。我正在使用 ARM9 (LPC313x)并使用 RealView 4 (armcc)。

foo() { 
  ..
  stack_var = ++volatile_var; // line
  ..
}

我正在为C166寻找任何类似_atomic_的例程,直接汇编代码等。我宁愿不必禁用中断。

非常感谢。

2 个答案:

答案 0 :(得分:8)

不,我认为即使你没有作业,你也不能指望++volatile_var是原子的。为此使用适当的原子基元。如果您的编译器没有提供这样的扩展,您可以在Web上轻松找到简短的内联汇编程序。我认为汇编程序指令是调用ldrexstrex进行原子交换。

编辑:似乎问题中要求的特定处理器类型未实现这些说明。

编辑:以下内容适用于gcc,对于另一个编译器,可能需要调整__asm__部分。

inline
size_t arm_ldrex(size_t volatile*ptr) {
  size_t ret;
  __asm__ volatile ("ldrex %0,[%1]\t@ load exclusive\n"
                    : "=&r" (ret)
                    : "r" (ptr)
                    : "cc", "memory"
                    );
  return ret;
}

inline
_Bool arm_strex(size_t volatile*ptr, size_t val) {
  size_t error;
  __asm__ volatile ("strex %0,%1,[%2]\t@ store exclusive\n"
                    : "=&r" (error)
                    : "r" (val), "r" (ptr)
                    : "cc", "memory"
                    );
  return !error;
}

inline
size_t atomic_add_fetch(size_t volatile *object, size_t operand) {
  for (;;) {
    size_t oldval = arm_ldrex(object);
    size_t newval = oldval + operand;
    if (arm_strex(object, newval)) return newval;
  }
}

答案 1 :(得分:6)

从快速看,C166 _atomic_宏似乎利用了一条指令,该指令在指定数量的指令期间有效地屏蔽了中断。 没有什么能与ARM架构中的内容直接对应。

您当然可以使用swp指令(或RealView工具链中的__swp内在函数)来实现围绕关键部分的锁定。 ARM体系结构版本5(包括ARM9处理器)中不存在另一个答案中提到的ldrex / strex。 <{3}}和http://infocenter.arm.com/help/topic/com.arm.doc.dui0491c/CJAHDCHB.html

围绕此实现的简单锁定实现(使用RealView工具链)将是:

{
    /* Loop until lock acquired */
    while (__swp(LOCKED, &lockvar) == LOCKED);
    ..
    /* Critical section */
    ..
    lockvar = UNLOCKED;
}

但是,当主线程持有锁时,此导致ISR上下文中的死锁。

我认为围绕操作的屏蔽中断可能是最不费力的解决方案,但如果您的Main上下文在用户模式下执行,则需要系统调用才能实现。