diff mbox

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

Message ID 1395322632-9139-1-git-send-email-bill.fischofer@linaro.org
State Accepted, archived
Headers show

Commit Message

Bill Fischofer March 20, 2014, 1:37 p.m. UTC
Add odp_mem_barrier() before exit from odp_barrier_sync()

Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
---
 include/odp_barrier.h                       |  3 +-
 platform/linux-generic/source/odp_barrier.c | 44 ++++++++++++++---------------
 2 files changed, 22 insertions(+), 25 deletions(-)

Comments

Maxim Uvarov March 24, 2014, 9:49 a.m. UTC | #1
applied!

thanks,
Maxim.
On 03/20/2014 05:37 PM, Bill Fischofer wrote:
> Add odp_mem_barrier() before exit from odp_barrier_sync()
>
> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org>
> ---
>   include/odp_barrier.h                       |  3 +-
>   platform/linux-generic/source/odp_barrier.c | 44 ++++++++++++++---------------
>   2 files changed, 22 insertions(+), 25 deletions(-)
>
> 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..a82b294 100644
> --- a/platform/linux-generic/source/odp_barrier.c
> +++ b/platform/linux-generic/source/odp_barrier.c
> @@ -11,40 +11,38 @@
>   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();
>   	}
> +
> +	odp_mem_barrier();
>   }
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..a82b294 100644
--- a/platform/linux-generic/source/odp_barrier.c
+++ b/platform/linux-generic/source/odp_barrier.c
@@ -11,40 +11,38 @@ 
 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();
 	}
+
+	odp_mem_barrier();
 }