Atomic Operations?

29 Nov 2011

Are there any portable ways to implmenent atomic operations on the mbed. I'd like to implmement the equivalent of the Windows API's Interlocked family of functions (InterlockedIncrement, InterlockedDecrement, InterlockedExchange, InterlockedCompareExchange, etc)

I've come up with this (not yet debugged), as I'm using a Ticker to schedule callbacks:

class Interlocked
{
public:
    static inline void Lock()
    {
        NVIC_DisableIRQ(TIMER3_IRQn);
    }
    
    static inline void Unlock()
    {
        NVIC_EnableIRQ(TIMER3_IRQn);
    }
    
    static inline int Increment(int volatile *src)
    {
        Lock();
        int val = *++src;
        Unlock();
        return val;
    }
    
    static inline int Decrement(int volatile *src)
    {
        Lock();
        int val = *--src;
        Unlock();
        return val;
    }
    
    static inline int Exchange(int volatile *src, int val)
    {
        Lock();
        int ret = *src;
        *src = val;
        Unlock();
        return ret;
    }
    
    static inline int CompareExchange(int volatile *src, int Exchange, int Comparand)
    {
        Lock();
        int ret = *src;
        if (ret == Comparand) *src = Exchange;
        Unlock();
        return ret;
    }
    
};

But I'm not happy with the NVIC_DisableIRQ(TIMER3_IRQn)call, as it seems like overkill, when all I want is to atomically fetch or set the values.

It looks like the __ldrex and __strex functions might do it, but is that portable?

Anthony Wieser
Wieser Software Ltd

03 Dec 2011

I came across this, "The ARM Compiler now supports the GNU Compiler atomic builtin functions in --gnu mode for atomic memory access." and includes __synch_add_and_fetch

the following code compiles:

    volatile int t;
    __sync_add_and_fetch(&t, 1);       

but when linked for the LPC2368 I get this.

" Undefined symbol __user_cmpxchg_4 (referred from arm_sync_4.o)." in file "/"

Do I need to implement this function, or am I missing a library?

03 Dec 2011

Hi Anthony,

You can certainly use ldrex/strex, but looking at your previous code example, perhaps the portable functions __disable_irq() and __enable_irq() are what you are after?

Simon