This is the mail archive of the
libc-ports@sources.redhat.com
mailing list for the libc-ports project.
Update ARM atomic operations question
- From: Dominique Fober <fober at grame dot fr>
- To: libc-ports at sources dot redhat dot com
- Date: Fri, 9 Dec 2005 11:13:40 +0100
- Subject: Update ARM atomic operations question
This is a question regarding the patch posted on Wed, 5 Oct 2005 and
entitled "Update ARM atomic operations". I'm puzzling about the 2
versions of the compare_and_swap primitive included in the patch:
- with the first version (inline function), 'result' indicates
success (1) or failure (0), with the macro version, 'result' seems to
always hold the memory value whatever the result of the operation: is
it right? and if yes, why? (I've commented the assembly code below
with pseudo code and comments to give my understanding of the code)
- I guess there is a strong rationale behind the two step approach:
a) getting the actual value, comparing with the expected value b)
trying to swap, but why not directly doing the swap? is it to avoid
the race condition in 6) as much as possible?
- and finally, why moving from an inline typed function
implementation to a raw untyped macro?
Thanks in advance for your reply,
Dominique Fober
static inline int
__attribute__ ((unused))
compare_and_swap (volatile long int *p, long int oldval, long int
newval)
{
int result, tmp;
__asm__ ("\n"
"0:\tldr\t%1,[%2]\n\t" a) tmp = *p load *p into tmp
"mov\t%0,#0\n\t" b) result=0 clear result (0=failure)
"cmp\t%1,%4\n\t" c) if (tmp != oldval) compare tmp and
oldval
"bne\t1f\n\t" d) goto 1 if not equal, branch to end)
"swp\t%0,%3,[%2]\n\t" e| result=*p swap newval and p content -
> result
e| *p= newval
"cmp\t%1,%0\n\t" f) if (result != tmp) compare result and
tmp
"swpne\t%1,%0,[%2]\n\t" g| tmp=*p if not equal, swap result
and p content -> tmp (cc flags not affected)
g| *p=result
"bne\t0b\n\t" h) goto 0 if not equal, loop to a)
"mov\t%0,#1\n" i) result=1 set result (1=success)
"1:"
: "=&r" (result), "=&r" (tmp)
: "r" (p), "r" (newval), "r" (oldval)
: "cc", "memory");
return result;
}
#define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
({ __typeof (oldval) result, tmp; \
__asm__ ("\n" \
"0:\tldr\t%1,[%2]\n\t" \ 1) tmp = *mem load *mem into tmp
"cmp\t%1,%4\n\t" \ 2) if (tmp != oldval) compare tmp
and oldval
"movne\t%0,%1\n\t" \ 3) result=tmp if not equal,
move tmp to result (cc flags not affected)
"bne\t1f\n\t" \ 4) goto 1 if not equal,
branch to end)
"swp\t%0,%3,[%2]\n\t" \ 5| result=*mem swap newval and
mem content -> result
5| *mem= newval
"cmp\t%1,%0\n\t" \ 6) if (result != tmp) compare
result and tmp
"swpne\t%1,%0,[%2]\n\t" \ 7| tmp=*mem if not equal,
swap result and mem content -> tmp (cc flags not affected)
7| *mem=result
"bne\t0b\n\t" \ 8) goto 0 if not equal, loop
to 1)
"1:" \ end)
: "=&r" (result), "=&r" (tmp) \
: "r" (mem), "r" (newval), "r" (oldval) \
: "cc", "memory"); \
result; })