Atomic operations in assembly

shiningram
shiningram used Ask the Experts™
on
Hi,
I want to write atomic operations (incr, dec, xchg, mod) which should support on almost all architectures.
Can anyone point me to resource available on thsi on net or in EE?

Someone explain what each following line is doing?

int32 func()
{
   int32 val = -1;

    asm volatile ("lock; xaddl %0,%1"
              : "=r" (val), "=m" (*mem)
              : "0" (val), "m" (*mem)
              : "memory", "cc");
 return val;
}

=r
=m
"0"
"m"
"memory"

What all these  above do? Can someone explains all these? I am looking for resource/tutorial to understand these.

Thanks,
Ram
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Top Expert 2005
Commented:
> which should support on almost all architectures.
Assembly, and all architectures? It will not work ;)

The most important thing in Your code is lock; it means, that next instruction will have memory bys locked(that's why it's  atomic operation).

For gcc assembly (the meaning of parameters for asm) refer http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s5
gcc's asm construct is mainly used to enable gcc to generate "glue" code before and after some inline assembly, so C variables can get loaded into input registers, and values in the output registers can be moved back into the C variables.

    asm volatile ("lock; xaddl %0,%1"
              : "=r" (val), "=m" (*mem)
              : "0" (val), "m" (*mem)
              : "memory", "cc");

xadd does the following, in pseudocode:
                temp := dest
                dest := dest + source
                source := temp

The lock instruction ensures that no one else can fiddle with the memory while the next instruction executes.  This prevents something like another processor or a DMA transfer from modifying the memory value while the instruction executes.

"xaddl %0, %1" means that gcc should emit an xadd instruction.  The "l" in xaddl means it should work with 32-bit operands.  The "%0" and "%1" are parameter placeholders, and they mean that the programmer is asking gcc to decide on which registers/memory references to use for this instruction.

After the first colon are the output parameter definitions.  
"=r" (val)
The "=r" means that %0 should be assigned to any register, and it will be written to.  The "(val)" is a C expression that tells gcc what C variable the register value should be placed into after the inline assembly is performed.
"=m" (*mem)
The "=m" means that %1 should be a reference to memory, and it will be written to.  ("mem) tells gcc that the memory address it uses should be the same one that points to (*mem); that is it should be equal to mem.

After the second colon are the input parameter definitions.
              : "0" (val), "m" (*mem)
"0" means that this input corresponds to the same register as %0 above, and this register should be preloaded with the val variable before the inline assembly is performed.
"m" is the same as above, except the lack of a "=" means that it will be read from.  The source is whatever the mem variable is pointing at.

After the third variable comes the clobber list.  What, besides obviously the output registers, will be modified by the inline instructions?
              : "memory", "cc");
"memory" tells gcc that these instructions will modify memory.  So gcc needs to get it's act together and write out anything it has been procrastinating about writing before it emits these inline instructions.
"cc" is the condition code register.  This means that the instructions will modify some processor flag values, so gcc shouldn't make any assumptions about its contents after the inline assembly runs.

The end result is a piece of code that safely decrements a variable, and copies the original value of the  variable into the "val" local variable.

Author

Commented:
Ravenpl you gave a great start and NovaDenizen you are awesome. You will be rewarded points when i close the question.
Can some one help writting increment and decrement atomic operations for linux and windos for 32 and 64 architecture.
Thanks,
Ram
Top Expert 2005
Commented:
unsigned long long volatile p;
            __asm__ __volatile__(
                  "lock; incq %0"
                  :"=m" (p)
                  :"m" (p)
                  :"memory");

use "incl" for 32bit types. USe dec? for decrement.

Author

Commented:
Another question added to get clear suggestion from experts

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial