diff mbox

[ODP/PATCH,v5] Correct race condition and simplify barrier implementation

Message ID 1395317034-7456-1-git-send-email-bill.fischofer@linaro.org
State Superseded, archived
Headers show

Commit Message

Bill Fischofer March 20, 2014, 12:03 p.m. UTC
Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
---
 include/odp_barrier.h                       |  3 +--
 platform/linux-generic/source/odp_barrier.c | 42 +++++++++++++----------------
 2 files changed, 20 insertions(+), 25 deletions(-)
diff mbox

Patch

diff --git a/include/odp_barrier.h b/include/odp_barrier.h
index bb4a6c5..0a1404b 100644
--- a/include/odp_barrier.h
+++ b/include/odp_barrier.h
@@ -28,8 +28,7 @@  extern "C" {
  */
 typedef struct odp_barrier_t {
 	int              count;
-	odp_atomic_int_t in;
-	odp_atomic_int_t out;
+	odp_atomic_int_t bar;
 } odp_barrier_t;
 
 
diff --git a/platform/linux-generic/source/odp_barrier.c b/platform/linux-generic/source/odp_barrier.c
index 64fbdb9..c78e802 100644
--- a/platform/linux-generic/source/odp_barrier.c
+++ b/platform/linux-generic/source/odp_barrier.c
@@ -11,40 +11,36 @@ 
 void odp_barrier_init_count(odp_barrier_t *barrier, int count)
 {
 	barrier->count = count;
-	barrier->in    = 0;
-	barrier->out   = count - 1;
+	barrier->bar = 0;
 	odp_sync_stores();
 }
 
+/*
+ * Efficient barrier_sync -
+ *
+ *   Barriers are initialized with a count of the number of callers
+ *   that must sync on the barrier before any may proceed.
+ *
+ *   To avoid race conditions and to permit the barrier to be fully
+ *   reusable, the barrier value cycles between 0..2*count-1. When
+ *   synchronizing the wasless variable simply tracks which half of
+ *   the cycle the barrier was in upon entry.  Exit is when the
+ *   barrier crosses to the other half of the cycle.
+ */
 
 void odp_barrier_sync(odp_barrier_t *barrier)
 {
 	int count;
+	int wasless;
 
 	odp_sync_stores();
+	wasless = barrier->bar < barrier->count;
+	count = odp_atomic_fetch_inc_int(&barrier->bar);
 
-	count = odp_atomic_fetch_inc_int(&barrier->in);
-
-	if (count == barrier->count - 1) {
-		/* If last thread, release others */
-		barrier->in = 0;
-		odp_sync_stores();
-
-		/* Wait for others to exit */
-		while (barrier->out)
-			odp_spin();
-
-		/* Ready, reset out counter */
-		barrier->out = barrier->count - 1;
-		odp_sync_stores();
-
+	if (count == 2*barrier->count-1) {
+		barrier->bar = 0;
 	} else {
-		/* Wait for the last thread*/
-		while (barrier->in)
+		while ((barrier->bar < barrier->count) == wasless)
 			odp_spin();
-
-		/* Ready */
-		odp_atomic_dec_int(&barrier->out);
-		odp_mem_barrier();
 	}
 }