From owner-freebsd-hackers Tue Oct 3 1:22:45 2000 Delivered-To: freebsd-hackers@freebsd.org Received: from fw.wintelcom.net (ns1.wintelcom.net [209.1.153.20]) by hub.freebsd.org (Postfix) with ESMTP id 7E93137B503; Tue, 3 Oct 2000 01:22:41 -0700 (PDT) Received: (from bright@localhost) by fw.wintelcom.net (8.10.0/8.10.0) id e938Mec19063; Tue, 3 Oct 2000 01:22:40 -0700 (PDT) Date: Tue, 3 Oct 2000 01:22:40 -0700 From: Alfred Perlstein To: John Baldwin Cc: Jan Mikkelsen , FreeBSD Hackers , Kevin Mills Subject: Re: atomic operations Message-ID: <20001003012240.G27736@fw.wintelcom.net> References: <00b701c0273b$39f7aaa0$0901a8c0@haym.transactionsite.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.4i In-Reply-To: ; from jhb@FreeBSD.ORG on Tue, Oct 03, 2000 at 12:01:39AM -0700 Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG * John Baldwin [001003 00:01] wrote: > > On 25-Sep-00 Jan Mikkelsen wrote: > > Kevin Mills wrote: > >>I found the atomic_* functions in , 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. Mike Smith and I discussed atomic types and the problem is that not all arches can do all the ops we want, as a compromise we can use macros to wrap the ops as long as we use constructors and destructors for atomic_t. this could use some testing/comments, my gcc+asm is terrible: Index: atomic.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/atomic.h,v retrieving revision 1.12 diff -u -u -r1.12 atomic.h --- atomic.h 2000/09/06 11:21:14 1.12 +++ atomic.h 2000/10/03 07:05:59 @@ -218,6 +218,31 @@ return ( atomic_cmpset_int((volatile u_int *)dst, (u_int)exp, (u_int)src)); } -#endif + +typedef struct { volatile int a; } atomic_t; + +#define atomic_init(p, v) do { p->a = v; } while(0) +#define atomic_destroy(p) do { ; } while(0) +#define atomic_add(p, v) atomic_add_int(&(p->a), v) +#define atomic_sub(p, v) atomic_subtract_int(&(p->a), v) +#define atomic_or(p, v) atomic_set_int(&(p->a), v) +#define atomic_and(p, v) atomic_clear_int(&(p->a), v) +#define atomic_read(p) ((p)->a) +#define atomic_set(p, v) do { (p)->a = (v); } while(0); +/* XXX: maybe use decl/incl ? */ +#define atomic_dec(p) atomic_sub(&(p->a), 1) +#define atomic_inc(p) atomic_add(&(p->a), 1) + +static __inline int +atomic_dec_and_test(volatile atomic_t *v) +{ + unsigned char c; + + __asm __volatile("lock ; decl %0; sete %1" + : "=m" (v->a), "=qm" (c) + : "m" (v->a)); + return (c != 0); +} +#endif /* !WANT_FUNCTIONS */ #endif /* ! _MACHINE_ATOMIC_H_ */ To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message