Chinaunix

标题: armv7的atomic_add实现,为什么不禁止中断 [打印本页]

作者: arm-linux-gcc    时间: 2014-03-25 10:04
标题: armv7的atomic_add实现,为什么不禁止中断
本帖最后由 arm-linux-gcc 于 2014-03-25 11:29 编辑

static inline void atomic_add(int i, atomic_t *v)
{
        unsigned long tmp;
        int result;

        __asm__ __volatile__("@ atomic_add\n"
"1:        ldrex        %0, [%3]\n"
"        add        %0, %0, %4\n"
"        strex        %1, %0, [%3]\n"
"        teq        %1, #0\n"
"        bne        1b"
        : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
        : "r" (&v->counter), "Ir" (i)
        : "cc");
}

ldrex/strex只能保证多个核一起访问同一个地址的时候具有排他性吧

如果core a在调用atomic_add时,在ldrex和strex之间core a发生了中断,而在core a上运行的中断处理程序刚好也要对同一个原子变量做atomic_add操作,那么就死锁了啊

作者: humjb_1983    时间: 2014-03-25 10:38
arm的不懂~~
我看x86的代码中是加了LOCK的。
作者: smalloc    时间: 2014-03-25 11:14
这个得自己编程考虑,如果中断程序会影响,就自己加了禁止中断了.
作者: arm-linux-gcc    时间: 2014-03-25 11:20
回复 3# smalloc


    但是老的armv5的实现,是有关中断的啊

static inline int atomic_add_return(int i, atomic_t *v)
{
        unsigned long flags;
        int val;

        raw_local_irq_save(flags);
        val = v->counter;
        v->counter = val += i;
        raw_local_irq_restore(flags);

        return val;
}
作者: 墙根下的水壶    时间: 2014-03-25 11:47
引入ldrex strex后,只要在ldrex和strex之间对应的原子变量被修改,则strex失败。那么多核环境下,保证了多核间的互斥,同样的,如果单核上,atomic_add执行中产生了中断,影响了对应的v->counter,则atomic_add这次的原子加操作失败了,便重新来过。这样保证了操作的原子性。至于如何判断中断是否影响了对应的v->counter,有的是只要产生总线操作就视为影响,有的则在硬件上处理更为细致。
总而言之,ldrex/strex机制避免了x86的锁总线操作,采用的是出错回退策略,可能对流水线性能有积极作用。
作者: arm-linux-gcc    时间: 2014-03-25 11:56
回复 5# 墙根下的水壶


    假如在进程上下文中ldrex执行之后、strex执行之前,同一个核就发生了中断,并且在中断处理中也对同一个原子变量atomic_add
那么在中断上下文的atomic_add就永远不能成功了啊,就一直在bne        1b,然后中断上下文的atomic_add就无法完成了,而进程上下文却由于被中断而无法做完strex,那么这个核就死锁了啊



作者: 墙根下的水壶    时间: 2014-03-25 12:44
回复 6# arm-linux-gcc


   实际上,中断的atomic_add是可以成功的,因为在他的ldrex和strex之间没有任何访存指令
作者: arm-linux-gcc    时间: 2014-03-25 12:58
本帖最后由 arm-linux-gcc 于 2014-03-25 16:16 编辑

回复 7# 墙根下的水壶


    我之前理解错了,新的ldrex来到时,会更新状态,于是中断上下文中的strex能成功,中断返回之后,进程上下文中的strex会失败
作者: liuiang    时间: 2014-03-25 13:09
ARMv5只支持单核,不支持多核,基于这样的架构,要想实现原子操作,必须要锁中断。

对于你说的情况,ldrex和strex之间其他core或者中断终止了指令流,那么,中断或其他core中的    ldrex和strex  获得配对执行,而当程序流再次返回原始任务,strex执行就会失败,指令流会执行bne指令,进行重新执行尝试。

大多数RISC都是采用LL/SC结构完成原子操作,很少处理器像x86一样,提供lock前缀或直接的CAS原子指令。
作者: smalloc    时间: 2014-03-25 14:37
之前有错,X86能直接操内存,所以一条指令搞定,不存在中断的问题.
上面的ARMV5版本因为多个指令,所以需要关中断.
出错尝试的说法是对的,这篇给了详细解释.
http://blog.chinaunix.net/uid-20543672-id-3262230.html
作者: smalloc    时间: 2014-03-25 14:46
回复 8# arm-linux-gcc


    有意思的是,ldrex请求开始一个总线监控.




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2