svn commit: r254617 - in head: share/man/man9 sys/amd64/include sys/i386/include

Jung-uk Kim jkim at FreeBSD.org
Wed Aug 21 22:03:07 UTC 2013


Author: jkim
Date: Wed Aug 21 22:03:06 2013
New Revision: 254617
URL: http://svnweb.freebsd.org/changeset/base/254617

Log:
  Implement atomic_swap() and atomic_testandset().
  
  Reviewed by:	arch, bde, jilles, kib

Modified:
  head/share/man/man9/atomic.9
  head/sys/amd64/include/atomic.h
  head/sys/i386/include/atomic.h

Modified: head/share/man/man9/atomic.9
==============================================================================
--- head/share/man/man9/atomic.9	Wed Aug 21 21:47:56 2013	(r254616)
+++ head/share/man/man9/atomic.9	Wed Aug 21 22:03:06 2013	(r254617)
@@ -23,7 +23,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 27, 2005
+.Dd August 20, 2013
 .Dt ATOMIC 9
 .Os
 .Sh NAME
@@ -62,6 +62,10 @@
 .Fn atomic_subtract_[acq_|rel_]<type> "volatile <type> *p" "<type> v"
 .Ft void
 .Fn atomic_store_rel_<type> "volatile <type> *p" "<type> v"
+.Ft <type>
+.Fn atomic_swap_<type> "volatile <type> *p" "<type> v"
+.Ft int
+.Fn atomic_testandset_<type> "volatile <type> *p" "u_int v"
 .Sh DESCRIPTION
 Each of the atomic operations is guaranteed to be atomic in the presence of
 interrupts.
@@ -184,9 +188,9 @@ This section describes the semantics of 
 .Bd -literal -compact
 if (*dst == old) {
 	*dst = new;
-	return 1;
+	return (1);
 } else
-	return 0;
+	return (0);
 .Ed
 .El
 .Pp
@@ -203,7 +207,7 @@ and
 .Bd -literal -compact
 tmp = *p;
 *p += v;
-return tmp;
+return (tmp);
 .Ed
 .El
 .Pp
@@ -216,9 +220,9 @@ and
 .Dq Li 32
 and do not have any variants with memory barriers at this time.
 .Bl -hang
-.It Fn atomic_load addr
+.It Fn atomic_load p
 .Bd -literal -compact
-return (*addr)
+return (*p);
 .Ed
 .El
 .Pp
@@ -226,11 +230,11 @@ The
 .Fn atomic_load
 functions are only provided with acquire memory barriers.
 .Bl -hang
-.It Fn atomic_readandclear addr
+.It Fn atomic_readandclear p
 .Bd -literal -compact
-temp = *addr;
-*addr = 0;
-return (temp);
+tmp = *p;
+*p = 0;
+return (tmp);
 .Ed
 .El
 .Pp
@@ -243,8 +247,7 @@ functions are not implemented for the ty
 .Dq Li 8 ,
 and
 .Dq Li 16
-and do
-not have any variants with memory barriers at this time.
+and do not have any variants with memory barriers at this time.
 .Bl -hang
 .It Fn atomic_set p v
 .Bd -literal -compact
@@ -264,6 +267,44 @@ The
 .Fn atomic_store
 functions are only provided with release memory barriers.
 .Pp
+.Bl -hang
+.It Fn atomic_swap p v
+.Bd -literal -compact
+tmp = *p;
+*p = v;
+return (tmp);
+.Ed
+.El
+.Pp
+The
+.Fn atomic_swap
+functions are not implemented for the types
+.Dq Li char ,
+.Dq Li short ,
+.Dq Li ptr ,
+.Dq Li 8 ,
+and
+.Dq Li 16
+and do not have any variants with memory barriers at this time.
+.Bl -hang
+.It Fn atomic_testandset p v
+.Bd -literal -compact
+bit = 1 << (v % (sizeof(*p) * NBBY));
+tmp = (*p & bit) != 0;
+*p |= bit;
+return (tmp);
+.Ed
+.El
+.Pp
+The
+.Fn atomic_testandset
+functions are only implemented for the types
+.Dq Li int ,
+.Dq Li long
+and
+.Dq Li 32
+and do not have any variants with memory barriers at this time.
+.Pp
 The type
 .Dq Li 64
 is currently not implemented for any of the atomic operations on the
@@ -275,15 +316,17 @@ architectures.
 .Sh RETURN VALUES
 The
 .Fn atomic_cmpset
-function
-returns the result of the compare operation.
+function returns the result of the compare operation.
 The
 .Fn atomic_fetchadd ,
 .Fn atomic_load ,
+.Fn atomic_readandclear ,
 and
-.Fn atomic_readandclear
-functions
-return the value at the specified address.
+.Fn atomic_swap
+functions return the value at the specified address.
+The
+.Fn atomic_testandset
+function returns the result of the test operation.
 .Sh EXAMPLES
 This example uses the
 .Fn atomic_cmpset_acq_ptr
@@ -354,3 +397,9 @@ The
 .Fn atomic_fetchadd
 operations were added in
 .Fx 6.0 .
+The
+.Fn atomic_swap
+and
+.Fn atomic_testandset
+operations were added in
+.Fx 10.0 .

Modified: head/sys/amd64/include/atomic.h
==============================================================================
--- head/sys/amd64/include/atomic.h	Wed Aug 21 21:47:56 2013	(r254616)
+++ head/sys/amd64/include/atomic.h	Wed Aug 21 22:03:06 2013	(r254617)
@@ -54,12 +54,14 @@
  * atomic_clear_int(P, V)	(*(u_int *)(P) &= ~(V))
  * atomic_add_int(P, V)		(*(u_int *)(P) += (V))
  * atomic_subtract_int(P, V)	(*(u_int *)(P) -= (V))
+ * atomic_swap_int(P, V)	(return (*(u_int *)(P)); *(u_int *)(P) = (V);)
  * atomic_readandclear_int(P)	(return (*(u_int *)(P)); *(u_int *)(P) = 0;)
  *
  * atomic_set_long(P, V)	(*(u_long *)(P) |= (V))
  * atomic_clear_long(P, V)	(*(u_long *)(P) &= ~(V))
  * atomic_add_long(P, V)	(*(u_long *)(P) += (V))
  * atomic_subtract_long(P, V)	(*(u_long *)(P) -= (V))
+ * atomic_swap_long(P, V)	(return (*(u_long *)(P)); *(u_long *)(P) = (V);)
  * atomic_readandclear_long(P)	(return (*(u_long *)(P)); *(u_long *)(P) = 0;)
  */
 
@@ -80,6 +82,8 @@ int	atomic_cmpset_int(volatile u_int *ds
 int	atomic_cmpset_long(volatile u_long *dst, u_long expect, u_long src);
 u_int	atomic_fetchadd_int(volatile u_int *p, u_int v);
 u_long	atomic_fetchadd_long(volatile u_long *p, u_long v);
+int	atomic_testandset_int(volatile u_int *p, u_int v);
+int	atomic_testandset_long(volatile u_long *p, u_int v);
 
 #define	ATOMIC_LOAD(TYPE, LOP)					\
 u_##TYPE	atomic_load_acq_##TYPE(volatile u_##TYPE *p)
@@ -205,6 +209,40 @@ atomic_fetchadd_long(volatile u_long *p,
 	return (v);
 }
 
+static __inline int
+atomic_testandset_int(volatile u_int *p, u_int v)
+{
+	u_char res;
+
+	__asm __volatile(
+	"	" MPLOCKED "		"
+	"	btsl	%2,%1 ;		"
+	"	setc	%0 ;		"
+	"# atomic_testandset_int"
+	: "=q" (res),			/* 0 */
+	  "+m" (*p)			/* 1 */
+	: "Ir" (v & 0x1f)		/* 2 */
+	: "cc");
+	return (res);
+}
+
+static __inline int
+atomic_testandset_long(volatile u_long *p, u_int v)
+{
+	u_char res;
+
+	__asm __volatile(
+	"	" MPLOCKED "		"
+	"	btsq	%2,%1 ;		"
+	"	setc	%0 ;		"
+	"# atomic_testandset_long"
+	: "=q" (res),			/* 0 */
+	  "+m" (*p)			/* 1 */
+	: "Jr" ((u_long)(v & 0x3f))	/* 2 */
+	: "cc");
+	return (res);
+}
+
 /*
  * We assume that a = b will do atomic loads and stores.  Due to the
  * IA32 memory model, a simple store guarantees release semantics.
@@ -296,43 +334,39 @@ ATOMIC_STORE(long);
 
 #ifndef WANT_FUNCTIONS
 
-/* Read the current value and store a zero in the destination. */
+/* Read the current value and store a new value in the destination. */
 #ifdef __GNUCLIKE_ASM
 
 static __inline u_int
-atomic_readandclear_int(volatile u_int *p)
+atomic_swap_int(volatile u_int *p, u_int v)
 {
-	u_int res;
 
-	res = 0;
 	__asm __volatile(
 	"	xchgl	%1,%0 ;		"
-	"# atomic_readandclear_int"
-	: "+r" (res),			/* 0 */
+	"# atomic_swap_int"
+	: "+r" (v),			/* 0 */
 	  "+m" (*p));			/* 1 */
 
-	return (res);
+	return (v);
 }
 
 static __inline u_long
-atomic_readandclear_long(volatile u_long *p)
+atomic_swap_long(volatile u_long *p, u_long v)
 {
-	u_long res;
 
-	res = 0;
 	__asm __volatile(
 	"	xchgq	%1,%0 ;		"
-	"# atomic_readandclear_long"
-	: "+r" (res),			/* 0 */
+	"# atomic_swap_long"
+	: "+r" (v),			/* 0 */
 	  "+m" (*p));			/* 1 */
 
-	return (res);
+	return (v);
 }
 
 #else /* !__GNUCLIKE_ASM */
 
-u_int	atomic_readandclear_int(volatile u_int *p);
-u_long	atomic_readandclear_long(volatile u_long *p);
+u_int	atomic_swap_int(volatile u_int *p, u_int v);
+u_long	atomic_swap_long(volatile u_long *p, u_long v);
 
 #endif /* __GNUCLIKE_ASM */
 
@@ -376,6 +410,9 @@ u_long	atomic_readandclear_long(volatile
 #define	atomic_cmpset_acq_long		atomic_cmpset_long
 #define	atomic_cmpset_rel_long		atomic_cmpset_long
 
+#define	atomic_readandclear_int(p)	atomic_swap_int(p, 0)
+#define	atomic_readandclear_long(p)	atomic_swap_long(p, 0)
+
 /* Operations on 8-bit bytes. */
 #define	atomic_set_8		atomic_set_char
 #define	atomic_set_acq_8	atomic_set_acq_char
@@ -426,8 +463,10 @@ u_long	atomic_readandclear_long(volatile
 #define	atomic_cmpset_32	atomic_cmpset_int
 #define	atomic_cmpset_acq_32	atomic_cmpset_acq_int
 #define	atomic_cmpset_rel_32	atomic_cmpset_rel_int
+#define	atomic_swap_32		atomic_swap_int
 #define	atomic_readandclear_32	atomic_readandclear_int
 #define	atomic_fetchadd_32	atomic_fetchadd_int
+#define	atomic_testandset_32	atomic_testandset_int
 
 /* Operations on 64-bit quad words. */
 #define	atomic_set_64		atomic_set_long
@@ -447,7 +486,9 @@ u_long	atomic_readandclear_long(volatile
 #define	atomic_cmpset_64	atomic_cmpset_long
 #define	atomic_cmpset_acq_64	atomic_cmpset_acq_long
 #define	atomic_cmpset_rel_64	atomic_cmpset_rel_long
+#define	atomic_swap_64		atomic_swap_long
 #define	atomic_readandclear_64	atomic_readandclear_long
+#define	atomic_testandset_64	atomic_testandset_long
 
 /* Operations on pointers. */
 #define	atomic_set_ptr		atomic_set_long
@@ -467,6 +508,7 @@ u_long	atomic_readandclear_long(volatile
 #define	atomic_cmpset_ptr	atomic_cmpset_long
 #define	atomic_cmpset_acq_ptr	atomic_cmpset_acq_long
 #define	atomic_cmpset_rel_ptr	atomic_cmpset_rel_long
+#define	atomic_swap_ptr		atomic_swap_long
 #define	atomic_readandclear_ptr	atomic_readandclear_long
 
 #endif /* !WANT_FUNCTIONS */

Modified: head/sys/i386/include/atomic.h
==============================================================================
--- head/sys/i386/include/atomic.h	Wed Aug 21 21:47:56 2013	(r254616)
+++ head/sys/i386/include/atomic.h	Wed Aug 21 22:03:06 2013	(r254617)
@@ -54,12 +54,14 @@
  * atomic_clear_int(P, V)	(*(u_int *)(P) &= ~(V))
  * atomic_add_int(P, V)		(*(u_int *)(P) += (V))
  * atomic_subtract_int(P, V)	(*(u_int *)(P) -= (V))
+ * atomic_swap_int(P, V)	(return (*(u_int *)(P)); *(u_int *)(P) = (V);)
  * atomic_readandclear_int(P)	(return (*(u_int *)(P)); *(u_int *)(P) = 0;)
  *
  * atomic_set_long(P, V)	(*(u_long *)(P) |= (V))
  * atomic_clear_long(P, V)	(*(u_long *)(P) &= ~(V))
  * atomic_add_long(P, V)	(*(u_long *)(P) += (V))
  * atomic_subtract_long(P, V)	(*(u_long *)(P) -= (V))
+ * atomic_swap_long(P, V)	(return (*(u_long *)(P)); *(u_long *)(P) = (V);)
  * atomic_readandclear_long(P)	(return (*(u_long *)(P)); *(u_long *)(P) = 0;)
  */
 
@@ -78,6 +80,7 @@ void atomic_##NAME##_barr_##TYPE(volatil
 
 int	atomic_cmpset_int(volatile u_int *dst, u_int expect, u_int src);
 u_int	atomic_fetchadd_int(volatile u_int *p, u_int v);
+int	atomic_testandset_int(volatile u_int *p, u_int v);
 
 #define	ATOMIC_LOAD(TYPE, LOP)					\
 u_##TYPE	atomic_load_acq_##TYPE(volatile u_##TYPE *p)
@@ -275,6 +278,23 @@ atomic_fetchadd_int(volatile u_int *p, u
 	return (v);
 }
 
+static __inline int
+atomic_testandset_int(volatile u_int *p, u_int v)
+{
+	u_char res;
+
+	__asm __volatile(
+	"	" MPLOCKED "		"
+	"	btsl	%2,%1 ;		"
+	"	setc	%0 ;		"
+	"# atomic_testandset_int"
+	: "=q" (res),			/* 0 */
+	  "+m" (*p)			/* 1 */
+	: "Ir" (v & 0x1f)		/* 2 */
+	: "cc");
+	return (res);
+}
+
 /*
  * We assume that a = b will do atomic loads and stores.  Due to the
  * IA32 memory model, a simple store guarantees release semantics.
@@ -386,43 +406,40 @@ atomic_fetchadd_long(volatile u_long *p,
 	return (atomic_fetchadd_int((volatile u_int *)p, (u_int)v));
 }
 
-/* Read the current value and store a zero in the destination. */
+static __inline int
+atomic_testandset_long(volatile u_long *p, u_int v)
+{
+
+	return (atomic_testandset_int((volatile u_int *)p, v));
+}
+
+/* Read the current value and store a new value in the destination. */
 #ifdef __GNUCLIKE_ASM
 
 static __inline u_int
-atomic_readandclear_int(volatile u_int *p)
+atomic_swap_int(volatile u_int *p, u_int v)
 {
-	u_int res;
 
-	res = 0;
 	__asm __volatile(
 	"	xchgl	%1,%0 ;		"
-	"# atomic_readandclear_int"
-	: "+r" (res),			/* 0 */
+	"# atomic_swap_int"
+	: "+r" (v),			/* 0 */
 	  "+m" (*p));			/* 1 */
 
-	return (res);
+	return (v);
 }
 
 static __inline u_long
-atomic_readandclear_long(volatile u_long *p)
+atomic_swap_long(volatile u_long *p, u_long v)
 {
-	u_long res;
 
-	res = 0;
-	__asm __volatile(
-	"	xchgl	%1,%0 ;		"
-	"# atomic_readandclear_long"
-	: "+r" (res),			/* 0 */
-	  "+m" (*p));			/* 1 */
-
-	return (res);
+	return (atomic_swap_int((volatile u_int *)p, (u_int)v));
 }
 
 #else /* !__GNUCLIKE_ASM */
 
-u_int	atomic_readandclear_int(volatile u_int *p);
-u_long	atomic_readandclear_long(volatile u_long *p);
+u_int	atomic_swap_int(volatile u_int *p, u_int v);
+u_long	atomic_swap_long(volatile u_long *p, u_long v);
 
 #endif /* __GNUCLIKE_ASM */
 
@@ -466,6 +483,9 @@ u_long	atomic_readandclear_long(volatile
 #define	atomic_cmpset_acq_long		atomic_cmpset_long
 #define	atomic_cmpset_rel_long		atomic_cmpset_long
 
+#define	atomic_readandclear_int(p)	atomic_swap_int(p, 0)
+#define	atomic_readandclear_long(p)	atomic_swap_long(p, 0)
+
 /* Operations on 8-bit bytes. */
 #define	atomic_set_8		atomic_set_char
 #define	atomic_set_acq_8	atomic_set_acq_char
@@ -516,8 +536,10 @@ u_long	atomic_readandclear_long(volatile
 #define	atomic_cmpset_32	atomic_cmpset_int
 #define	atomic_cmpset_acq_32	atomic_cmpset_acq_int
 #define	atomic_cmpset_rel_32	atomic_cmpset_rel_int
+#define	atomic_swap_32		atomic_swap_int
 #define	atomic_readandclear_32	atomic_readandclear_int
 #define	atomic_fetchadd_32	atomic_fetchadd_int
+#define	atomic_testandset_32	atomic_testandset_int
 
 /* Operations on pointers. */
 #define	atomic_set_ptr(p, v) \
@@ -556,6 +578,8 @@ u_long	atomic_readandclear_long(volatile
 #define	atomic_cmpset_rel_ptr(dst, old, new) \
 	atomic_cmpset_rel_int((volatile u_int *)(dst), (u_int)(old), \
 	    (u_int)(new))
+#define	atomic_swap_ptr(p, v) \
+	atomic_swap_int((volatile u_int *)(p), (u_int)(v))
 #define	atomic_readandclear_ptr(p) \
 	atomic_readandclear_int((volatile u_int *)(p))
 


More information about the svn-src-head mailing list