Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 3 Oct 2000 01:22:40 -0700
From:      Alfred Perlstein <bright@wintelcom.net>
To:        John Baldwin <jhb@FreeBSD.ORG>
Cc:        Jan Mikkelsen <janm@transactionsite.com>, FreeBSD Hackers <freebsd-hackers@FreeBSD.ORG>, Kevin Mills <kmills@aventail.com>
Subject:   Re: atomic operations
Message-ID:  <20001003012240.G27736@fw.wintelcom.net>
In-Reply-To: <XFMail.001003000139.jhb@FreeBSD.org>; from jhb@FreeBSD.ORG on Tue, Oct 03, 2000 at 12:01:39AM -0700
References:  <00b701c0273b$39f7aaa0$0901a8c0@haym.transactionsite.com> <XFMail.001003000139.jhb@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
* John Baldwin <jhb@FreeBSD.ORG> [001003 00:01] wrote:
> 
> On 25-Sep-00 Jan Mikkelsen wrote:
> > Kevin Mills <kmills@aventail.com> 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.

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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20001003012240.G27736>