This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

InterlockedExchangeAdd equivalent

Note: This was originally posted on 11th February 2013 at http://forums.arm.com

I'm porting a Windows application to an ARM® Cortex-A9 based system running Ubuntu 12.04 and I need something equivalent the Windows function InterlockedExchangeAdd().  Is there a function like this available for ARM?  If not, can anyone provide some equivalent assembly code?
  • Note: This was originally posted on 11th February 2013 at http://forums.arm.com

    Hello DKP and welcome,
    I believe this function is to do atomic add.

    Here is an example of code for atomic increment you might be interested in from an old thread here.
    There are also a number of external blogs discussing about this.
    For instance Jon Masters has an example of atomic add halway through the page.

    Please when you see the code examples, keep in mind you are using an ARMv7 architecture (and not ARMv6 some examples can be for).

    Cheers,
    Alban
  • Note: This was originally posted on 11th February 2013 at http://forums.arm.com

    Thanks for the quick reply.  The second example you referenced looks like what I need.   Do you know where I can find a v7 assembly reference / programmer's guide so that I can make any necessary modifications from v6?  I'm having a rather difficult time locating what I need in the online documentation.
  • Note: This was originally posted on 11th February 2013 at http://forums.arm.com

    There is an electronic book you can get. It's called the ARM Cortex-A Programmers' Guide, you need to be logged in but it's free.
    Generally speaking, all ARM documentation is under ARM Infocenter and is kept up to date there.
    LDREX and STREX are both supported in the ARMv7 ARM Cortex-A9 processor: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0388i/CBBDIIFI.html
  • Note: This was originally posted on 11th February 2013 at http://forums.arm.com

    Thanks so much for your help.  For anyone else that may be interested, here's what I came up with.

    long myExchangeAdd( volatile long *pTarget, long nValue )
    {
    #if defined( _WIN32 )
    return InterlockedExchangeAdd( pTarget, nValue );
    #else
    int nResult, nModified;

    asm volatile
    (
         "1:"                               "\t@ loop label"   "\n\t"
         "LDREX %0,[%2]"        "\t@ load value"  "\n\t"
         "ADD   %0,%0,%3"   "\t@ increment it"   "\n\t"
         "STREX %1,%0,[%2]" "\t@ attempt store" "\n\t"
         "CMP   %1,#0"           "\t@ if not atomic"  "\n\t"
         "BNE   1b"                   "\t@ then repeat"   "\n\t"
         : "=&r" (nResult), "=&r" (nModified)
         : "r" (pTarget), "r" (nValue)
         : "cc", "memory"
    );

    return nResult;
    #endif
    }
  • Note: This was originally posted on 12th February 2013 at http://forums.arm.com

    Hmm, depending what you are doing with them you are probably missing a barrier which ensures ordering relative to other instructions in the instruction stream. See http://infocenter.ar...ookbook_A08.pdf
  • Note: This was originally posted on 13th February 2013 at http://forums.arm.com

    Here's a slight modification since InterlockedExchangeAdd actually returns the previous value

    long myExchangeAdd( volatile long *pTarget, long nValue )
    {
    #if defined( _WIN32 )
    return InterlockedExchangeAdd( pTarget, nValue );
    #else
    int nOldValue, nNewValue, nModified;

    asm volatile
    (
         "1: LDREX %0,[%3]     @load value\n"
         " ADD   %1,%0,%4   @increment it\n"
         " STREX %2,%1,[%3] @attempt store\n"
         " CMP   %2,#0           @if not atomic\n"
         " BNE   1b                   @then repeat\n"
         : "=&r" (nOldValue), "=&r" (nNewValue), "=&r" (nModified)
         : "r" (pTarget), "r" (nValue)
         : "cc", "memory"
    );

    return nOldValue;
    #endif
    }
  • Note: This was originally posted on 13th February 2013 at http://forums.arm.com


    Hmm, depending what you are doing with them you are probably missing a barrier which ensures ordering relative to other instructions in the instruction stream. See http://infocenter.ar...ookbook_A08.pdf


    So if I understand you correctly, per section 7.2.1 of the document, in order to preserve ordering I need to add a "DMB" after the "BNE" command, right?  Sorry if that's a seemingly obvious question, but I'm somewhat new to ARM assembly language programming.
  • Note: This was originally posted on 13th February 2013 at http://forums.arm.com

    It depends what you are using it for TBH. If you are using it like a spinlock (e.g., incref to lock, decref to unlock) then you need barriers after the lock before you touch the memory it is protecting (ensure that the lock is committed before other instructions in the instruction stream can touch the memory) and before the unlock (ensure you've committed data it is protecting to memory before you release the lock). If you don't then you risk race conditions and trampled data (and much painful debugging - trust me).

    If you are just using it like a reference count then you might get away with it ;)
  • Note: This was originally posted on 14th February 2013 at http://forums.arm.com


    It depends what you are using it for TBH. If you are using it like a spinlock (e.g., incref to lock, decref to unlock) then you need barriers after the lock before you touch the memory it is protecting (ensure that the lock is committed before other instructions in the instruction stream can touch the memory) and before the unlock (ensure you've committed data it is protecting to memory before you release the lock). If you don't then you risk race conditions and trampled data (and much painful debugging - trust me).

    If you are just using it like a reference count then you might get away with it ;)


    The purpose is to provide a multi-thread safe increment / decrement of an integer value.  It's primary use is for reference counting, but it may also be used for other "counting" operations.  Based on your second comment then, it sounds like I can eliminate the use of barriers altogether.