On 25-Sep-00 Jan Mikkelsen wrote:
> Kevin Mills <[EMAIL PROTECTED]> wrote:
>>I found the atomic_* functions in <machine/atomic.h>, but noticed that they
>>have no return value. What I need is a function that increments/decrements
>>the given value *and* returns the new value in an atomic operation. I
>>suppose this is possible, yes? How would one modify the assembly to make
>>this work?
>
>
> Atomic decrement, in the Intel style:
>
> long atomic_decrement(volatile long* address)
> {
> asm {
> mov ecx, [address]
> mov eax, -1
> lock xadd [ecx], eax
> dec eax
> }
> /* Return value in EAX */
> }
>
> An untested conversion into the GNU/AT&T style:
>
> long atomic_decrement(volatile long* address)
> {
> asm("movl 8(%ebp),%ecx");
> asm("movl $-1, %eax");
> asm("lock xaddl %eax,(%ecx)");
> asm("decl %eax");
> /* Return value in %eax */
> }
Uh, there is no xaddl instruction in the x86 instruction set. There is
a fetchadd instruction in ia64, but that doesn't help much here. You
can use a loop with the atomic_cmpset_* primitives though to achieve this.
e.g.:
volatile int value;
int save, increment;
value = 3; increment = 4;
do {
save = value;
} while (atomic_cmpset_int(&value, save, save + increment) == 0);
foo = some_array[save + increment];
You can use this to control access to a circular buffer w/o needing a
lock to obtain new entries for example. This will only work with -current
though.
--
John Baldwin <[EMAIL PROTECTED]> -- http://www.FreeBSD.org/~jhb/
PGP Key: http://www.baldwin.cx/~john/pgpkey.asc
"Power Users Use the Power to Serve!" - http://www.FreeBSD.org/
To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message