Bladeren bron

- alpha, armv6 and mip isa2+ atomic_add and atomic_cmpxchg (armv6 & alpha not
tested at all due to lacking hardware or emulators)

Andrei Pelinescu-Onciul 18 jaren geleden
bovenliggende
commit
35f127eeed
3 gewijzigde bestanden met toevoegingen van 106 en 3 verwijderingen
  1. 29 1
      atomic/atomic_alpha.h
  2. 50 2
      atomic/atomic_arm.h
  3. 27 0
      atomic/atomic_mips2.h

+ 29 - 1
atomic/atomic_alpha.h

@@ -36,6 +36,7 @@
  * History:
  * --------
  *  2006-03-31  created by andrei
+ *  2007-05-10  added atomic_add & atomic_cmpxchg (andrei)
  */
 
 
@@ -125,7 +126,7 @@
 		P_TYPE ret; \
 		asm volatile( \
 			ATOMIC_ASM_OP01_##P_TYPE(OP) \
-			: "=&r"(ret), "=r"(v), "=m"(*var), "0"(v)  : "m"(*var) \
+			: "=&r"(ret), "=r"(v), "=m"(*var)  : "m"(*var), "1"(v) \
 			); \
 		return RET_EXPR; \
 	}
@@ -170,6 +171,26 @@
 		return RET_EXPR; \
 	}
 
+/* input in %0 and %3 (param), output in %0 */
+/* cmpxchg var in %1, old in %0, new_v in %
+ * makes the xchg if old==*var
+ * returns initial *var (so if ret==old => new_v was written into var)*/
+#define ATOMIC_CMPXCHG_DECL(NAME,  P_TYPE) \
+	inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+														P_TYPE old, \
+														P_TYPE new_v) \
+	{ \
+		P_TYPE ret; \
+		P_TYPE tmp; \
+		asm volatile( \
+			ATOMIC_ASM_OP01_##P_TYPE("subq  %0, %5, %2 \n\t bne %2, 3f")\
+			"3:    \n\t" \
+			: "=&r"(ret), "=&r"(new_v), "=r"(tmp), "=m"(*var)  :\
+				"m"(*var), "r"(old), "1"(new_v) :"cc" \
+			); \
+		return ret; \
+	}
+
 
 ATOMIC_FUNC_DECL0_0(inc, "addl %0, 1, %0", int, void, /* no return */ )
 ATOMIC_FUNC_DECL0_0(dec, "subl %0, 1, %0", int, void, /* no return */ )
@@ -178,6 +199,8 @@ ATOMIC_FUNC_DECL03_0(or,  "bis %0, %3, %0", int, void, /* no return */ )
 ATOMIC_FUNC_DECL0_1(inc_and_test, "addl %0, 1, %1", int, int, (ret+1)==0 )
 ATOMIC_FUNC_DECL0_1(dec_and_test, "subl %0, 1, %1", int, int, (ret-1)==0 )
 ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, int, int, ret )
+ATOMIC_CMPXCHG_DECL(cmpxchg, int )
+ATOMIC_FUNC_DECL01_1(add, "addl %1, %0, %1", int, int, ret+v)
 
 ATOMIC_FUNC_DECL0_0(inc, "addq %0, 1, %0", long, void, /* no return */ )
 ATOMIC_FUNC_DECL0_0(dec, "subq %0, 1, %0", long, void, /* no return */ )
@@ -186,6 +209,8 @@ ATOMIC_FUNC_DECL03_0(or,  "bis %0, %3, %0", long, void, /* no return */ )
 ATOMIC_FUNC_DECL0_1(inc_and_test, "addq %0, 1, %1", long, long, (ret+1)==0 )
 ATOMIC_FUNC_DECL0_1(dec_and_test, "subq %0, 1, %1", long, long, (ret-1)==0 )
 ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, long, long, ret )
+ATOMIC_CMPXCHG_DECL(cmpxchg, long )
+ATOMIC_FUNC_DECL01_1(add, "addq %1, %0, %1", long, long, ret+v)
 
 
 #define atomic_inc(var) atomic_inc_int(&(var)->val)
@@ -195,6 +220,9 @@ ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, 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_cmpxchg(var, old, new_v) \
+		atomic_cmpxchg_int(&(var)->val, old, new_v)
+#define atomic_add(var, v) atomic_add_int(&(var)->val, (v))
 
 
 /* with integrated membar */

+ 50 - 2
atomic/atomic_arm.h

@@ -37,6 +37,7 @@
  * History:
  * --------
  *  2006-03-31  created by andrei
+ *  2007-05-10  added atomic_add and atomic_cmpxchg (andrei)
  */
 
 
@@ -126,6 +127,44 @@
 	}
 
 
+#define ATOMIC_XCHG_DECL(NAME, P_TYPE) \
+	inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+														P_TYPE v ) \
+	{ \
+		P_TYPE ret; \
+		asm volatile( \
+			"     swp %0, %2, [%3] \n\t" \
+			: "=&r"(ret),  "=m"(*var) :\
+				"r"(v), "r"(var) \
+			); \
+		return ret; \
+	}
+
+
+/* cmpxchg: %5=old, %4=new_v, %3=var
+ * if (*var==old) *var=new_v
+ * returns the original *var (can be used to check if it succeeded: 
+ *  if old==cmpxchg(var, old, new_v) -> success
+ */
+#define ATOMIC_CMPXCHG_DECL(NAME, P_TYPE) \
+	inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+														P_TYPE old, \
+														P_TYPE new_v) \
+	{ \
+		P_TYPE ret, tmp; \
+		asm volatile( \
+			"1:   ldrex %0, [%3] \n\t" \
+			"     cmp %0, %5 \n\t" \
+			"     strexeq %1, %4, [%3] \n\t" \
+			"     cmp %1, #0 \n\t" \
+			"     bne 1b \n\t" \
+			: "=&r"(ret), "=&r"(tmp), "=m"(*var) :\
+				"r"(var), "r"(new_v), "r"(old) : "cc" \
+			); \
+		return ret; \
+	}
+
+
 
 ATOMIC_FUNC_DECL(inc,      "add  %1, %0, #1", int, void, /* no return */ )
 ATOMIC_FUNC_DECL(dec,      "sub  %1, %0, #1", int, void, /* no return */ )
@@ -133,7 +172,10 @@ ATOMIC_FUNC_DECL1(and,     "and  %1, %0, %4", int, void, /* no return */ )
 ATOMIC_FUNC_DECL1(or,      "orr  %1, %0, %4", int, void, /* no return */ )
 ATOMIC_FUNC_DECL(inc_and_test, "add  %1, %0, #1", int, int, ret )
 ATOMIC_FUNC_DECL(dec_and_test, "sub  %1, %0, #1", int, int, ret )
-ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , int, int,  ret)
+//ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , int, int,  ret)
+ATOMIC_XCHG_DECL(get_and_set, int)
+ATOMIC_CMPXCHG_DECL(cmpxchg, int)
+ATOMIC_FUNC_DECL1(add,     "add  %1, %0, %4", int, int, ret )
 
 ATOMIC_FUNC_DECL(inc,      "add  %1, %0, #1", long, void, /* no return */ )
 ATOMIC_FUNC_DECL(dec,      "sub  %1, %0, #1", long, void, /* no return */ )
@@ -141,7 +183,10 @@ ATOMIC_FUNC_DECL1(and,     "and  %1, %0, %4", long, void, /* no return */ )
 ATOMIC_FUNC_DECL1(or,      "orr  %1, %0, %4", long, void, /* no return */ )
 ATOMIC_FUNC_DECL(inc_and_test, "add  %1, %0, #1", long, long, ret )
 ATOMIC_FUNC_DECL(dec_and_test, "sub  %1, %0, #1", long, long, ret )
-ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , long, long,  ret)
+//ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , long, long,  ret)
+ATOMIC_XCHG_DECL(get_and_set, long)
+ATOMIC_CMPXCHG_DECL(cmpxchg, long)
+ATOMIC_FUNC_DECL1(add,     "add  %1, %0, %4", long, long, ret )
 
 #define atomic_inc(var) atomic_inc_int(&(var)->val)
 #define atomic_dec(var) atomic_dec_int(&(var)->val)
@@ -150,6 +195,9 @@ ATOMIC_FUNC_DECL2(get_and_set, /* no extra op needed */ , 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_cmpxchg(var, old, new_v) \
+	atomic_cmpxchg_int(&(var)->val, old, new_v)
+#define atomic_add(var, v) atomic_add_int(&(var)->val, (v))
 
 
 /* with integrated membar */

+ 27 - 0
atomic/atomic_mips2.h

@@ -42,6 +42,7 @@
  * History:
  * --------
  *  2006-03-08  created by andrei
+ *  2007-05-10  added atomic_add & atomic_cmpxchg (andrei)
  */
 
 
@@ -167,6 +168,23 @@
 	}
 
 
+/* %0=var, %1=*var, %2=new, %3=old :
+ * ret=*var; if *var==old  then *var=new; return ret
+ * => if succesfull (changed var to new)  ret==old */
+#define ATOMIC_CMPXCHG_DECL(NAME, P_TYPE) \
+	inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+														P_TYPE old, \
+														P_TYPE new_v) \
+	{ \
+		asm volatile( \
+			ATOMIC_ASM_OP_##P_TYPE("bne %1, %3, 2f \n\t nop") \
+			"2:    \n\t" \
+			: "=m"(*var), "=&r"(old), "=r"(new_v)  \
+			: "r"(old), "m"(*var), "2"(new_v) \
+			 \
+			); \
+		return old; \
+	}
 
 ATOMIC_FUNC_DECL(inc,      "addiu %2, %1, 1", int, void, /* no return */ )
 ATOMIC_FUNC_DECL_CT(dec,   "subu %2, %1, %3", 1,  int, void, /* no return */ )
@@ -175,6 +193,8 @@ ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", int, void,  /* no return */ )
 ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", int, int, (ret+1)==0 )
 ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1, int, int, (ret-1)==0 )
 ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, int, int, ret )
+ATOMIC_CMPXCHG_DECL(cmpxchg, int)
+ATOMIC_FUNC_DECL1(add, "addu %2, %1, %3 \n\t move %1, %2", int, int, ret )
 
 #ifdef __CPU_mips64
 
@@ -185,6 +205,8 @@ ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", long, void,  /* no return */ )
 ATOMIC_FUNC_DECL(inc_and_test, "daddiu %2, %1, 1", long, long, (ret+1)==0 )
 ATOMIC_FUNC_DECL_CT(dec_and_test, "dsubu %2, %1, %3", 1,long, long, (ret-1)==0 )
 ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
+ATOMIC_CMPXCHG_DECL(cmpxchg, long)
+ATOMIC_FUNC_DECL1(add, "daddu %2, %1, %3 \n\t move %1, %2", long, long, ret )
 
 #else /* ! __CPU_mips64 => __CPU_mips2 or __CPU_mips */
 
@@ -195,6 +217,8 @@ ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", long, void,  /* no return */ )
 ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", long, long, (ret+1)==0 )
 ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1,long, long, (ret-1)==0 )
 ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
+ATOMIC_CMPXCHG_DECL(cmpxchg, long)
+ATOMIC_FUNC_DECL1(add, "addu %2, %1, %3 \n\t move %1, %2", long, long, ret )
 
 #endif /* __CPU_mips64 */
 
@@ -205,6 +229,9 @@ ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, 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 */