Browse Source

- x86: atomic_add
- sparc64: atomic_cmpxchg, atomic_add

Andrei Pelinescu-Onciul 18 năm trước cách đây
mục cha
commit
15e8d3faab
3 tập tin đã thay đổi với 71 bổ sung2 xóa
  1. 44 1
      atomic/atomic_sparc64.h
  2. 17 0
      atomic/atomic_x86.h
  3. 10 1
      test/atomic_test2.c

+ 44 - 1
atomic/atomic_sparc64.h

@@ -38,6 +38,7 @@
  * History:
  * --------
  *  2006-03-28  created by andrei
+ *  2007-05-08 added atomic_add and atomic_cmpxchg (andrei)
  */
 
 
@@ -121,6 +122,34 @@
 		return RET_EXPR; \
 	}
 
+/* same as above, but uses a short 1 op sequence 
+ * %2 (or %1) is var, %0 is  v and return (ret)*/
+#define ATOMIC_FUNC_DECL1_RAW(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+															P_TYPE v) \
+	{ \
+		P_TYPE ret; \
+		asm volatile( \
+			OP "\n\t" \
+			: "=&r"(ret), "=m"(*var) : "r"(var), "0"(v) : "cc" \
+			); \
+		return RET_EXPR; \
+	}
+
+/* same as above, but takes two extra params, v, which goes in %4
+ * and uses a short 1 op sequence:
+ * %2 (or %1) is var, %3 is v1 and %0 is v2 & result (ret) */
+#define ATOMIC_FUNC_DECL2_CAS(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+													P_TYPE v1, P_TYPE v2) \
+	{ \
+		P_TYPE ret; \
+		asm volatile( \
+			OP "\n\t" \
+			: "=&r"(ret), "=m"(*var) : "r"(var), "r"(v1), "0"(v2) : "cc" \
+			); \
+		return RET_EXPR; \
+	}
 
 
 
@@ -130,7 +159,11 @@ ATOMIC_FUNC_DECL1(and,     "and  %0, %4, %1", int, void, /* no return */ )
 ATOMIC_FUNC_DECL1(or,      "or   %0, %4, %1", int, void, /* no return */ )
 ATOMIC_FUNC_DECL(inc_and_test, "add   %0, 1, %1", int, int, ((ret+1)==0) )
 ATOMIC_FUNC_DECL(dec_and_test, "sub   %0, 1, %1", int, int, ((ret-1)==0) )
-ATOMIC_FUNC_DECL1(get_and_set, "mov %4, %1" , int, int,  ret)
+/* deprecated but probably better then CAS for futexes */
+ATOMIC_FUNC_DECL1_RAW(get_and_set, "swap [%2], %0", int, int, ret)
+/*ATOMIC_FUNC_DECL1(get_and_set, "mov %4, %1" , int, int,  ret)*/
+ATOMIC_FUNC_DECL1(add,     "add  %0, %4, %1", int, int,  ret+v)
+ATOMIC_FUNC_DECL2_CAS(cmpxchg, "cas  [%2], %3, %0", int, int,  ret)
 
 
 ATOMIC_FUNC_DECL(inc,      "add  %0,  1, %1", long, void, /* no return */ )
@@ -140,6 +173,12 @@ ATOMIC_FUNC_DECL1(or,      "or   %0, %4, %1", long, void, /* no return */ )
 ATOMIC_FUNC_DECL(inc_and_test, "add   %0, 1, %1", long, long, ((ret+1)==0) )
 ATOMIC_FUNC_DECL(dec_and_test, "sub   %0, 1, %1", long, long, ((ret-1)==0) )
 ATOMIC_FUNC_DECL1(get_and_set, "mov %4, %1" , long, long,  ret)
+ATOMIC_FUNC_DECL1(add,     "add  %0, %4, %1", long, long,  ret+v)
+#ifdef SPARC64_MODE
+ATOMIC_FUNC_DECL2_CAS(cmpxchg, "casx  [%2], %3, %0", long, long,  ret)
+#else
+ATOMIC_FUNC_DECL2_CAS(cmpxchg, "cas   [%2], %3, %0", long, long,  ret)
+#endif
 
 
 #define atomic_inc(var) atomic_inc_int(&(var)->val)
@@ -149,6 +188,10 @@ ATOMIC_FUNC_DECL1(get_and_set, "mov %4, %1" , long, long,  ret)
 #define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
 #define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
 #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
+#define atomic_add(var, i) atomic_add_int(&(var)->val, i)
+#define atomic_cmpxchg(var, old, new_v) \
+	atomic_cmpxchg_int(&(var)->val, old, new_v)
+
 
 
 /* with integrated membar */

+ 17 - 0
atomic/atomic_x86.h

@@ -43,6 +43,7 @@
  * --------
  *  2006-03-08  created by andrei
  *  2007-05-07  added cmpxchg (andrei)
+ *  2007-05-08  added atomic_add (andrei)
  */
 
 #ifndef _atomic_x86_h
@@ -184,6 +185,18 @@
 		return ret; \
 	}
 
+/* similar w/ XCHG but with LOCK prefix, relaxed constraints & diff. return */
+#define ATOMIC_FUNC_XADD(NAME, OP, TYPE) \
+	inline static TYPE atomic_##NAME##_##TYPE(volatile TYPE* var, TYPE v) \
+{ \
+	TYPE ret; \
+	asm volatile( \
+			__LOCK_PREF " " OP " \n\t" \
+			: "=r"(ret), "=m"(*var) :"m"(*var), "0"(v) : "cc", "memory" \
+			); \
+	return ret+v; \
+}
+
 ATOMIC_FUNC_DECL1(inc, "incl %0", int)
 ATOMIC_FUNC_DECL1(dec, "decl %0", int)
 ATOMIC_FUNC_DECL2(and, "andl %1, %0", int)
@@ -192,6 +205,7 @@ ATOMIC_FUNC_TEST(inc_and_test, "incl %0", int, int)
 ATOMIC_FUNC_TEST(dec_and_test, "decl %0", int, int)
 ATOMIC_FUNC_XCHG(get_and_set,  "xchgl %1, %0", int)
 ATOMIC_FUNC_CMPXCHG(cmpxchg, "cmpxchgl %2, %1", int , int)
+ATOMIC_FUNC_XADD(add, "xaddl %0, %1", int) 
 #ifdef __CPU_x86_64
 ATOMIC_FUNC_DECL1(inc, "incq %0", long)
 ATOMIC_FUNC_DECL1(dec, "decq %0", long)
@@ -201,6 +215,7 @@ ATOMIC_FUNC_TEST(inc_and_test, "incq %0", long, int)
 ATOMIC_FUNC_TEST(dec_and_test, "decq %0", long, int)
 ATOMIC_FUNC_XCHG(get_and_set,  "xchgq %1, %0", long)
 ATOMIC_FUNC_CMPXCHG(cmpxchg, "cmpxchgq %2, %1", long , long)
+ATOMIC_FUNC_XADD(add, "xaddq %0, %1",long) 
 #else
 ATOMIC_FUNC_DECL1(inc, "incl %0", long)
 ATOMIC_FUNC_DECL1(dec, "decl %0", long)
@@ -210,6 +225,7 @@ ATOMIC_FUNC_TEST(inc_and_test, "incl %0", long, int)
 ATOMIC_FUNC_TEST(dec_and_test, "decl %0", long, int)
 ATOMIC_FUNC_XCHG(get_and_set,  "xchgl %1, %0", long)
 ATOMIC_FUNC_CMPXCHG(cmpxchg, "cmpxchgl %2, %1", long , long)
+ATOMIC_FUNC_XADD(add, "xaddl %0, %1",long) 
 #endif
 
 #define atomic_inc(var) atomic_inc_int(&(var)->val)
@@ -221,6 +237,7 @@ ATOMIC_FUNC_CMPXCHG(cmpxchg, "cmpxchgl %2, %1", long , long)
 #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
 #define atomic_cmpxchg(var, old, newv) \
 		atomic_cmpxchg_int(&(var)->val, old, newv)
+#define atomic_add(var, v) atomic_add_int(&(var)->val, v)
 
 
 #ifdef NOSMP

+ 10 - 1
test/atomic_test2.c

@@ -134,6 +134,7 @@ static char* flags=
 #define at_or	AT_DECL(or)
 #define at_get_and_set	AT_DECL(get_and_set)
 #define at_cmpxchg	AT_DECL(cmpxchg)
+#define at_add	AT_DECL(add)
 
 
 #define CHECK_ERR(txt, x, y) \
@@ -215,7 +216,7 @@ int main(int argc, char** argv)
 	printf(" atomic_and, v should be 2 ............. %2d\n", (int)at_get(v));
 	
 	VERIFY(at_or(v, 5), 7);
-	printf(" atomic_or,  v should be 7 ............. %2d\n", (int)r);
+	printf(" atomic_or,  v should be 7 ............. %2d\n", (int)at_get(v));
 	VERIFY(r=at_get_and_set(v, 0), 0);
 	printf(" atomic_get_and_set, v should be 0 ..... %2d\n", (int)at_get(v));
 	VERIFY(r=at_cmpxchg(v, 0, 7), 7);
@@ -226,6 +227,14 @@ int main(int argc, char** argv)
 	CHECK_ERR(cmpxchg, r, 7);
 	printf(" atomic_cmpxchg (fail), v should be 7 .. %2d\n", (int)at_get(v));
 	printf("                        r should be 7 .. %2d\n", (int)r);
+	VERIFY(r=at_add(v, 2), 9);
+	CHECK_ERR(atomic_add, r, 9);
+	printf(" atomic_add, v should be 9 ............. %2d\n", (int)at_get(v));
+	printf("             r should be 9 ............. %2d\n", (int)r);
+	VERIFY(r=at_add(v, -10), -1);
+	CHECK_ERR(atomic_add, r, -1);
+	printf(" atomic_add, v should be -1 ............ %2d\n", (int)at_get(v));
+	printf("             r should be -1 ............ %2d\n", (int)r);
 
 	
 	printf("\ndone.\n");