Browse Source

- s/atomic_ops_destroy/destroy_atomic_ops
- fixed membar w/ locks (should be unlock; lock)
- added a separate lock for membar w/ locks (unkown arch).

Andrei Pelinescu-Onciul 19 years ago
parent
commit
f146bed01f
3 changed files with 89 additions and 28 deletions
  1. 24 11
      atomic/atomic_unknown.h
  2. 37 12
      atomic_ops.c
  3. 28 5
      test/atomic_test2.c

+ 24 - 11
atomic/atomic_unknown.h

@@ -49,17 +49,10 @@
 
 #include "../lock_ops.h"
 
-extern gen_lock_t* _atomic_lock; /* declared and init in ../atomic.c */
-
-#define atomic_lock    lock_get(_atomic_lock)
-#define atomic_unlock  lock_release(_atomic_lock)
 
 
 #ifndef HAVE_ASM_INLINE_MEMBAR
 
-#define ATOMIC_OPS_USE_LOCK
-
-
 #ifdef NOSMP
 #define membar()
 #else /* SMP */
@@ -67,13 +60,27 @@ extern gen_lock_t* _atomic_lock; /* declared and init in ../atomic.c */
 #warning no native memory barrier implementations, falling back to slow lock \
 	       based workarround
 
+#define MEMBAR_USES_LOCK
+
+extern gen_lock_t* __membar_lock; /* init in atomic_ops.c */
+#define _membar_lock    lock_get(__membar_lock)
+#define _membar_unlock  lock_release(__membar_lock)
+
 /* memory barriers 
- *  not a known cpu -> fall back lock/unlock: safe but costly  (it should 
- *  include a memory barrier effect) */
+ *  not a known cpu -> fall back unlock/lock: safe but costly  (it should 
+ *  include a memory barrier effect)
+ *  lock/unlock does not imply a full memory barrier effect (it allows mixing
+ *   operations from before the lock with operations after the lock _inside_
+ *  the lock & unlock block; however in most implementations it is equivalent
+ *  with at least membar StoreStore | StoreLoad | LoadStore => only LoadLoad
+ *  is missing). On the other hand and unlock/lock will always be equivalent
+ *  with a full memory barrier
+ *  => to be safe we must use either unlock; lock or lock; unlock; lock; unlock
+ *  --andrei*/
 #define membar() \
 	do{\
-		atomic_lock; \
-		atomic_unlock; \
+		_membar_unlock; \
+		_membar_lock; \
 	} while(0)
 #endif /* NOSMP */
 
@@ -91,6 +98,12 @@ extern gen_lock_t* _atomic_lock; /* declared and init in ../atomic.c */
 #define ATOMIC_OPS_USE_LOCK
 #endif
 
+extern gen_lock_t* _atomic_lock; /* declared and init in ../atomic_ops.c */
+
+#define atomic_lock    lock_get(_atomic_lock)
+#define atomic_unlock  lock_release(_atomic_lock)
+
+
 /* atomic ops */
 
 

+ 37 - 12
atomic_ops.c

@@ -36,39 +36,64 @@
 #include "atomic_ops_init.h"
 #include "atomic_ops.h"
 
-#ifdef ATOMIC_OPS_USE_LOCK
-
+#if defined ATOMIC_OPS_USE_LOCK  || defines MEMBAR_USES_LOCK
 #include "locking.h"
+#endif
 
-gen_lock_t* _atomic_lock;
+#ifdef MEMBAR_USES_LOCK
+gen_lock_t* __membar_lock=0; /* init in atomic_ops.c */
+#endif
+
+#ifdef ATOMIC_OPS_USE_LOCK
+gen_lock_t* _atomic_lock=0;
 #endif
 
 
 /* returns 0 on success, -1 on error */
 int init_atomic_ops()
 {
-	int ret;
 	
-	ret=0;
+#ifdef MEMBAR_USES_LOCK
+	if ((__membar_lock=lock_alloc())==0){
+		goto error;
+	}
+	if (lock_init(__membar_lock)==0){
+		lock_dealloc(__membar_lock);
+		__membar_lock=0;
+		goto error;
+	}
+	_membar_lock; /* start with the lock "taken" so that we can safely use
+					 unlock/lock sequences on it later */
+#endif
 #ifdef ATOMIC_OPS_USE_LOCK
 	if ((_atomic_lock=lock_alloc())==0){
-		ret=-1;
-		goto end;
+		goto error;
 	}
 	if (lock_init(_atomic_lock)==0){
-		ret=-1;
-		atomic_ops_destroy();
-		goto end;
+		lock_dealloc(_atomic_lock);
+		_atomic_lock=0;
+		goto error;
 	}
-end:
 #endif
-	return ret;
+	return 0;
+#if defined MEMBAR_USES_LOCK || defined ATOMIC_OPS_USE_LOCK
+error:
+	destroy_atomic_ops();
+	return -1;
+#endif
 }
 
 
 
 void destroy_atomic_ops()
 {
+#ifdef MEMBAR_USES_LOCK
+	if (__membar_lock!=0){
+		lock_destroy(__membar_lock);
+		lock_dealloc(__membar_lock);
+		__membar_lock=0;
+	}
+#endif
 #ifdef ATOMIC_OPS_USE_LOCK
 	if (_atomic_lock!=0){
 		lock_destroy(_atomic_lock);

+ 28 - 5
test/atomic_test2.c

@@ -41,13 +41,19 @@
 
 #include "../atomic_ops.h"
 
-#ifdef ATOMIC_OPS_USE_LOCK 
+#if defined ATOMIC_OPS_USE_LOCK  || defined MEMBAR_USES_LOCK
 /* hack to make lock work */
 #include "../lock_ops.h"
+#endif
 
-gen_lock_t* _atomic_lock;
+#ifdef MEMBAR_USES_LOCK
+gen_lock_t* __membar_lock=0; /* init in atomic_ops.c */
+gen_lock_t dummy_membar_lock;
+#endif
 
-gen_lock_t dummy_lock;
+#ifdef ATOMIC_OPS_USE_LOCK
+gen_lock_t* _atomic_lock=0;
+gen_lock_t dummy_atomic_lock;
 
 #endif
 
@@ -152,11 +158,21 @@ int main(int argc, char** argv)
 	v=&var;
 	
 	
+#ifdef MEMBAR_USES_LOCK
+	__membar_lock=&dummy_membar_lock;
+	if (lock_init(__membar_lock)==0){
+		fprintf(stderr, "ERROR: failed to initialize membar_lock\n");
+		__membar_lock=0;
+		goto error;
+	}
+	_membar_lock; /* start with the lock "taken" so that we can safely use
+					 unlock/lock sequences on it later */
+#endif
 #ifdef ATOMIC_OPS_USE_LOCK
 	/* init the lock (emulate atomic_ops.c) */
-	_atomic_lock=&dummy_lock;
+	_atomic_lock=&dummy_atomic_lock;
 	if (lock_init(_atomic_lock)==0){
-		fprintf(stderr, "ERROR: failed to initialize the lock\n");
+		fprintf(stderr, "ERROR: failed to initialize atomic_lock\n");
 		_atomic_lock=0;
 		goto error;
 	}
@@ -204,11 +220,18 @@ int main(int argc, char** argv)
 
 	
 	printf("\ndone.\n");
+#ifdef MEMBAR_USES_LOCK
+	lock_destroy(__membar_lock);
+#endif
 #ifdef ATOMIC_OPS_USE_LOCK
 	lock_destroy(_atomic_lock);
 #endif
 	return 0;
 error:
+#ifdef MEMBAR_USES_LOCK
+	if (__membar_lock)
+		lock_destroy(__membar_lock);
+#endif
 #ifdef ATOMIC_OPS_USE_LOCK
 	if (_atomic_lock)
 		lock_destroy(_atomic_lock);