diff mbox

Fixed back-to-back barrier bug

Message ID 1395148387-8912-1-git-send-email-petri.savolainen@linaro.org
State Superseded, archived
Headers show

Commit Message

Petri Savolainen March 18, 2014, 1:13 p.m. UTC
There was a race condition with the "in" variable. This patch
uses more robust barrier exit synchronization to avoid the race.

Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>
---
 include/odp_barrier.h                       |  5 ++-
 platform/linux-generic/source/odp_barrier.c | 52 +++++++++++++++++++++--------
 test/example/odp_example.c                  |  4 +++
 3 files changed, 47 insertions(+), 14 deletions(-)

Comments

Maxim Uvarov March 18, 2014, 1:31 p.m. UTC | #1
On 03/18/2014 05:13 PM, Petri Savolainen wrote:
> There was a race condition with the "in" variable. This patch
> uses more robust barrier exit synchronization to avoid the race.
>
> Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>
> ---
>   include/odp_barrier.h                       |  5 ++-
>   platform/linux-generic/source/odp_barrier.c | 52 +++++++++++++++++++++--------
>   test/example/odp_example.c                  |  4 +++
>   3 files changed, 47 insertions(+), 14 deletions(-)
>
> diff --git a/include/odp_barrier.h b/include/odp_barrier.h
> index bb4a6c5..19dfc06 100644
> --- a/include/odp_barrier.h
> +++ b/include/odp_barrier.h
> @@ -28,8 +28,11 @@ extern "C" {
>    */
>   typedef struct odp_barrier_t {
>   	int              count;
> +	volatile int     wait;
> +	volatile int     wait_exit;
is there any reason to use volatile int instead of odp_atomic_int_t ?


Please also run ./scripts/cleanfile to remove DOS endings in the patch. 
And do clean ups
./scripts/checkpatch.pl warnings.
>   	odp_atomic_int_t in;
> -	odp_atomic_int_t out;
> +	odp_atomic_int_t waiting;
> +	odp_atomic_int_t waiting_exit;
>   } odp_barrier_t;
>   
>   
> diff --git a/platform/linux-generic/source/odp_barrier.c b/platform/linux-generic/source/odp_barrier.c
> index 64fbdb9..b27afc7 100644
> --- a/platform/linux-generic/source/odp_barrier.c
> +++ b/platform/linux-generic/source/odp_barrier.c
> @@ -10,9 +10,13 @@
>   
>   void odp_barrier_init_count(odp_barrier_t *barrier, int count)
>   {
> -	barrier->count = count;
> -	barrier->in    = 0;
> -	barrier->out   = count - 1;
> +	barrier->count        = count;
> +	barrier->wait         = 1;
> +	barrier->wait_exit    = 0;
> +	barrier->in           = 0;
> +	barrier->waiting      = 0;
> +	barrier->waiting_exit = 0;
> +
>   	odp_sync_stores();
>   }
>   
> @@ -26,25 +30,47 @@ void odp_barrier_sync(odp_barrier_t *barrier)
>   	count = odp_atomic_fetch_inc_int(&barrier->in);
>   
>   	if (count == barrier->count - 1) {
> -		/* If last thread, release others */
> -		barrier->in = 0;
> +		/*
> +		 * This is the last thread.
> +		 * Spin until other threads are waiting.
> +		 */
> +		while (barrier->waiting != barrier->count-1)
> +			odp_spin();
> +
> +		/* Reset barrier entry */
> +		barrier->wait_exit    = 1;
> +		barrier->in           = 0;
> +		barrier->waiting      = 0;
> +		barrier->waiting_exit = 0;
>   		odp_sync_stores();
>   
> -		/* Wait for others to exit */
> -		while (barrier->out)
> +		/* Move other threads to wait for exit */
> +		barrier->wait = 0;
> +
> +		/* Spin until other threads are waiting for exit */
> +		while (barrier->waiting_exit != barrier->count-1)
>   			odp_spin();
>   
> -		/* Ready, reset out counter */
> -		barrier->out = barrier->count - 1;
> +		/* Reset barrier exit */
> +		barrier->waiting_exit = 0;
> +		barrier->wait         = 1;
>   		odp_sync_stores();
>   
> +		/* Let other threads to exit */
> +		barrier->wait_exit = 0;
> +
> +		odp_sync_stores();
>   	} else {
> -		/* Wait for the last thread*/
> -		while (barrier->in)
> +		odp_atomic_inc_int(&barrier->waiting);
> +
> +		while (barrier->wait)
> +			odp_spin();
> +
> +		odp_atomic_inc_int(&barrier->waiting_exit);
> +
> +		while (barrier->wait_exit)
>   			odp_spin();
>   
> -		/* Ready */
> -		odp_atomic_dec_int(&barrier->out);
>   		odp_mem_barrier();
>   	}
>   }
> diff --git a/test/example/odp_example.c b/test/example/odp_example.c
> index 4764657..a6ab89e 100644
> --- a/test/example/odp_example.c
> +++ b/test/example/odp_example.c
> @@ -507,6 +507,10 @@ static void *run_thread(void *arg)
>   	odp_barrier_sync(&test_barrier);
>   	odp_barrier_sync(&test_barrier);
>   	odp_barrier_sync(&test_barrier);
> +	odp_barrier_sync(&test_barrier);
> +	odp_barrier_sync(&test_barrier);
> +	odp_barrier_sync(&test_barrier);
> +	odp_barrier_sync(&test_barrier);
>   
>   	/*
>   	 * Find the buffer pool
Petri Savolainen March 18, 2014, 1:46 p.m. UTC | #2
On Tuesday, 18 March 2014 15:31:06 UTC+2, Maxim Uvarov wrote:

> On 03/18/2014 05:13 PM, Petri Savolainen wrote: 
> > There was a race condition with the "in" variable. This patch 
> > uses more robust barrier exit synchronization to avoid the race. 
> > 
> > Signed-off-by: Petri Savolainen <petri.sa...@linaro.org <javascript:>> 
> > --- 
> >   include/odp_barrier.h                       |  5 ++- 
> >   platform/linux-generic/source/odp_barrier.c | 52 
> +++++++++++++++++++++-------- 
> >   test/example/odp_example.c                  |  4 +++ 
> >   3 files changed, 47 insertions(+), 14 deletions(-) 
> > 
> > diff --git a/include/odp_barrier.h b/include/odp_barrier.h 
> > index bb4a6c5..19dfc06 100644 
> > --- a/include/odp_barrier.h 
> > +++ b/include/odp_barrier.h 
> > @@ -28,8 +28,11 @@ extern "C" { 
> >    */ 
> >   typedef struct odp_barrier_t { 
> >           int              count; 
> > +        volatile int     wait; 
> > +        volatile int     wait_exit; 
> is there any reason to use volatile int instead of odp_atomic_int_t ? 
>
>  
Because those are not atomic counters, but status variables.
 

>
> Please also run ./scripts/cleanfile to remove DOS endings in the patch. 
> And do clean ups 
> ./scripts/checkpatch.pl warnings. 
>

What DOS endings? Checkpatch didn't show other warnings than volatiles.

-Petri
Maxim Uvarov March 18, 2014, 2:02 p.m. UTC | #3
On 03/18/2014 05:46 PM, Petri Savolainen wrote:
>
>
> On Tuesday, 18 March 2014 15:31:06 UTC+2, Maxim Uvarov wrote:
>
>     On 03/18/2014 05:13 PM, Petri Savolainen wrote:
>     > There was a race condition with the "in" variable. This patch
>     > uses more robust barrier exit synchronization to avoid the race.
>     >
>     > Signed-off-by: Petri Savolainen <petri.sa...@linaro.org
>     <javascript:>>
>     > ---
>     >   include/odp_barrier.h                       |  5 ++-
>     >   platform/linux-generic/source/odp_barrier.c | 52
>     +++++++++++++++++++++--------
>     >   test/example/odp_example.c                  |  4 +++
>     >   3 files changed, 47 insertions(+), 14 deletions(-)
>     >
>     > diff --git a/include/odp_barrier.h b/include/odp_barrier.h
>     > index bb4a6c5..19dfc06 100644
>     > --- a/include/odp_barrier.h
>     > +++ b/include/odp_barrier.h
>     > @@ -28,8 +28,11 @@ extern "C" {
>     >    */
>     >   typedef struct odp_barrier_t {
>     >           int              count;
>     > +        volatile int     wait;
>     > +        volatile int     wait_exit;
>     is there any reason to use volatile int instead of odp_atomic_int_t ?
>
> Because those are not atomic counters, but status variables.
>
>
>     Please also run ./scripts/cleanfile to remove DOS endings in the
>     patch.
>     And do clean ups
>     ./scripts/checkpatch.pl <http://checkpatch.pl> warnings.
>
>
> What DOS endings? Checkpatch didn't show other warnings than volatiles.
>
> -Petri
I don't know why but this email has ^M at the end of the lines. However 
git am cleanly removes them. Don't worry about that.

Best regards,
Maxim.

> -- 
> You received this message because you are subscribed to the Google 
> Groups "LNG ODP Sub-team - lng-odp@linaro.org" group.
> To unsubscribe from this group and stop receiving emails from it, send 
> an email to lng-odp+unsubscribe@linaro.org 
> <mailto:lng-odp+unsubscribe@linaro.org>.
> To post to this group, send email to lng-odp@linaro.org 
> <mailto:lng-odp@linaro.org>.
> Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/.
> To view this discussion on the web visit 
> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/964440bc-af68-4841-aa1b-3752170f66f7%40linaro.org 
> <https://groups.google.com/a/linaro.org/d/msgid/lng-odp/964440bc-af68-4841-aa1b-3752170f66f7%40linaro.org?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/a/linaro.org/d/optout.
Anders Roxell March 18, 2014, 2:07 p.m. UTC | #4
On 18 March 2014 15:02, Maxim Uvarov <maxim.uvarov@linaro.org> wrote:

> On 03/18/2014 05:46 PM, Petri Savolainen wrote:
>
>>
>>
>> On Tuesday, 18 March 2014 15:31:06 UTC+2, Maxim Uvarov wrote:
>>
>>     On 03/18/2014 05:13 PM, Petri Savolainen wrote:
>>     > There was a race condition with the "in" variable. This patch
>>     > uses more robust barrier exit synchronization to avoid the race.
>>     >
>>     > Signed-off-by: Petri Savolainen <petri.sa...@linaro.org
>>     <javascript:>>
>>
>>     > ---
>>     >   include/odp_barrier.h                       |  5 ++-
>>     >   platform/linux-generic/source/odp_barrier.c | 52
>>     +++++++++++++++++++++--------
>>     >   test/example/odp_example.c                  |  4 +++
>>     >   3 files changed, 47 insertions(+), 14 deletions(-)
>>     >
>>     > diff --git a/include/odp_barrier.h b/include/odp_barrier.h
>>     > index bb4a6c5..19dfc06 100644
>>     > --- a/include/odp_barrier.h
>>     > +++ b/include/odp_barrier.h
>>     > @@ -28,8 +28,11 @@ extern "C" {
>>     >    */
>>     >   typedef struct odp_barrier_t {
>>     >           int              count;
>>     > +        volatile int     wait;
>>     > +        volatile int     wait_exit;
>>     is there any reason to use volatile int instead of odp_atomic_int_t ?
>>
>> Because those are not atomic counters, but status variables.
>>
>>
>>     Please also run ./scripts/cleanfile to remove DOS endings in the
>>     patch.
>>     And do clean ups
>>     ./scripts/checkpatch.pl <http://checkpatch.pl> warnings.
>>
>>
>>
>> What DOS endings? Checkpatch didn't show other warnings than volatiles.
>>
>> -Petri
>>
> I don't know why but this email has ^M at the end of the lines. However
> git am cleanly removes them. Don't worry about that.
>

where did you see them?
specify the lines please, I could not see any ^M...

Cheers,
Anders


>
> Best regards,
> Maxim.
>
>  --
>> You received this message because you are subscribed to the Google Groups
>> "LNG ODP Sub-team - lng-odp@linaro.org" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to lng-odp+unsubscribe@linaro.org <mailto:lng-odp+unsubscribe@
>> linaro.org>.
>> To post to this group, send email to lng-odp@linaro.org <mailto:
>> lng-odp@linaro.org>.
>>
>> Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/.
>> To view this discussion on the web visit https://groups.google.com/a/
>> linaro.org/d/msgid/lng-odp/964440bc-af68-4841-aa1b-
>> 3752170f66f7%40linaro.org <https://groups.google.com/a/
>> linaro.org/d/msgid/lng-odp/964440bc-af68-4841-aa1b-
>> 3752170f66f7%40linaro.org?utm_medium=email&utm_source=footer>.
>>
>> For more options, visit https://groups.google.com/a/linaro.org/d/optout.
>>
>
> --
> You received this message because you are subscribed to the Google Groups
> "LNG ODP Sub-team - lng-odp@linaro.org" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to lng-odp+unsubscribe@linaro.org.
> To post to this group, send email to lng-odp@linaro.org.
> Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/.
> To view this discussion on the web visit https://groups.google.com/a/
> linaro.org/d/msgid/lng-odp/53285207.40704%40linaro.org.
>
> For more options, visit https://groups.google.com/a/linaro.org/d/optout.
>
Maxim Uvarov March 18, 2014, 2:12 p.m. UTC | #5
On 03/18/2014 06:07 PM, Anders Roxell wrote:
>
>
>
> On 18 March 2014 15:02, Maxim Uvarov <maxim.uvarov@linaro.org 
> <mailto:maxim.uvarov@linaro.org>> wrote:
>
>     On 03/18/2014 05:46 PM, Petri Savolainen wrote:
>
>
>
>         On Tuesday, 18 March 2014 15:31:06 UTC+2, Maxim Uvarov wrote:
>
>             On 03/18/2014 05:13 PM, Petri Savolainen wrote:
>             > There was a race condition with the "in" variable. This
>         patch
>             > uses more robust barrier exit synchronization to avoid
>         the race.
>             >
>             > Signed-off-by: Petri Savolainen <petri.sa...@linaro.org
>         <mailto:petri.sa...@linaro.org>
>             <javascript:>>
>
>             > ---
>             >   include/odp_barrier.h |  5 ++-
>             >   platform/linux-generic/source/odp_barrier.c | 52
>             +++++++++++++++++++++--------
>             >   test/example/odp_example.c  |  4 +++
>             >   3 files changed, 47 insertions(+), 14 deletions(-)
>             >
>             > diff --git a/include/odp_barrier.h b/include/odp_barrier.h
>             > index bb4a6c5..19dfc06 100644
>             > --- a/include/odp_barrier.h
>             > +++ b/include/odp_barrier.h
>             > @@ -28,8 +28,11 @@ extern "C" {
>             >    */
>             >   typedef struct odp_barrier_t {
>             >           int              count;
>             > +        volatile int     wait;
>             > +        volatile int     wait_exit;
>             is there any reason to use volatile int instead of
>         odp_atomic_int_t ?
>
>         Because those are not atomic counters, but status variables.
>
>
>             Please also run ./scripts/cleanfile to remove DOS endings
>         in the
>             patch.
>             And do clean ups
>             ./scripts/checkpatch.pl <http://checkpatch.pl>
>         <http://checkpatch.pl> warnings.
>
>
>
>         What DOS endings? Checkpatch didn't show other warnings than
>         volatiles.
>
>         -Petri
>
>     I don't know why but this email has ^M at the end of the lines.
>     However git am cleanly removes them. Don't worry about that.
>
>
> where did you see them?
> specify the lines please, I could not see any ^M...
>
> Cheers,
> Anders

bunch of places. But after I git am this patch and do git format-patch 
again ending ^M disappear. So that is not the problem:

ERROR: DOS line endings
#190: FILE: test/example/odp_example.c:510:
+^Iodp_barrier_sync(&test_barrier);^M$

ERROR: DOS line endings
#191: FILE: test/example/odp_example.c:511:
+^Iodp_barrier_sync(&test_barrier);^M$

ERROR: DOS line endings
#192: FILE: test/example/odp_example.c:512:
+^Iodp_barrier_sync(&test_barrier);^M$


>
>     Best regards,
>     Maxim.
>
>         -- 
>         You received this message because you are subscribed to the
>         Google Groups "LNG ODP Sub-team - lng-odp@linaro.org
>         <mailto:lng-odp@linaro.org>" group.
>         To unsubscribe from this group and stop receiving emails from
>         it, send an email to lng-odp+unsubscribe@linaro.org
>         <mailto:lng-odp%2Bunsubscribe@linaro.org>
>         <mailto:lng-odp+unsubscribe@linaro.org
>         <mailto:lng-odp%2Bunsubscribe@linaro.org>>.
>         To post to this group, send email to lng-odp@linaro.org
>         <mailto:lng-odp@linaro.org> <mailto:lng-odp@linaro.org
>         <mailto:lng-odp@linaro.org>>.
>
>         Visit this group at
>         http://groups.google.com/a/linaro.org/group/lng-odp/.
>         To view this discussion on the web visit
>         https://groups.google.com/a/linaro.org/d/msgid/lng-odp/964440bc-af68-4841-aa1b-3752170f66f7%40linaro.org
>         <https://groups.google.com/a/linaro.org/d/msgid/lng-odp/964440bc-af68-4841-aa1b-3752170f66f7%40linaro.org?utm_medium=email&utm_source=footer>.
>
>
>         For more options, visit
>         https://groups.google.com/a/linaro.org/d/optout.
>
>
>     -- 
>     You received this message because you are subscribed to the Google
>     Groups "LNG ODP Sub-team - lng-odp@linaro.org
>     <mailto:lng-odp@linaro.org>" group.
>     To unsubscribe from this group and stop receiving emails from it,
>     send an email to lng-odp+unsubscribe@linaro.org
>     <mailto:lng-odp%2Bunsubscribe@linaro.org>.
>     To post to this group, send email to lng-odp@linaro.org
>     <mailto:lng-odp@linaro.org>.
>     Visit this group at
>     http://groups.google.com/a/linaro.org/group/lng-odp/.
>     To view this discussion on the web visit
>     https://groups.google.com/a/linaro.org/d/msgid/lng-odp/53285207.40704%40linaro.org.
>
>
>     For more options, visit
>     https://groups.google.com/a/linaro.org/d/optout.
>
>
Stuart Haslam March 18, 2014, 7:09 p.m. UTC | #6
On Tue, Mar 18, 2014 at 01:13:07PM +0000, Petri Savolainen wrote:
> There was a race condition with the "in" variable. This patch
> uses more robust barrier exit synchronization to avoid the race.
> 

This patch does seem to fix the race, but it feels a little over
engineered, some comments below..

> Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>
> ---
>  include/odp_barrier.h                       |  5 ++-
>  platform/linux-generic/source/odp_barrier.c | 52 +++++++++++++++++++++--------
>  test/example/odp_example.c                  |  4 +++
>  3 files changed, 47 insertions(+), 14 deletions(-)
> 
> diff --git a/include/odp_barrier.h b/include/odp_barrier.h
> index bb4a6c5..19dfc06 100644
> --- a/include/odp_barrier.h
> +++ b/include/odp_barrier.h
> @@ -28,8 +28,11 @@ extern "C" {
>   */
>  typedef struct odp_barrier_t {
>  	int              count;
> +	volatile int     wait;
> +	volatile int     wait_exit;
>  	odp_atomic_int_t in;
> -	odp_atomic_int_t out;
> +	odp_atomic_int_t waiting;
> +	odp_atomic_int_t waiting_exit;
>  } odp_barrier_t;
>  

This is quite complicated and specific given that it's part of the
external API.

>  
> diff --git a/platform/linux-generic/source/odp_barrier.c b/platform/linux-generic/source/odp_barrier.c
> index 64fbdb9..b27afc7 100644
> --- a/platform/linux-generic/source/odp_barrier.c
> +++ b/platform/linux-generic/source/odp_barrier.c
> @@ -10,9 +10,13 @@
>  
>  void odp_barrier_init_count(odp_barrier_t *barrier, int count)
>  {
> -	barrier->count = count;
> -	barrier->in    = 0;
> -	barrier->out   = count - 1;
> +	barrier->count        = count;
> +	barrier->wait         = 1;
> +	barrier->wait_exit    = 0;
> +	barrier->in           = 0;
> +	barrier->waiting      = 0;
> +	barrier->waiting_exit = 0;
> +
>  	odp_sync_stores();
>  }
>  
> @@ -26,25 +30,47 @@ void odp_barrier_sync(odp_barrier_t *barrier)
>  	count = odp_atomic_fetch_inc_int(&barrier->in);
>  
>  	if (count == barrier->count - 1) {
> -		/* If last thread, release others */
> -		barrier->in = 0;
> +		/*
> +		 * This is the last thread.
> +		 * Spin until other threads are waiting.
> +		 */
> +		while (barrier->waiting != barrier->count-1)
> +			odp_spin();

I don't think barrier->waiting is needed at all, how would you reach
here without the other threads already waiting?

> +
> +		/* Reset barrier entry */
> +		barrier->wait_exit    = 1;
> +		barrier->in           = 0;
> +		barrier->waiting      = 0;
> +		barrier->waiting_exit = 0;
>  		odp_sync_stores();
>  
> -		/* Wait for others to exit */
> -		while (barrier->out)
> +		/* Move other threads to wait for exit */
> +		barrier->wait = 0;
> +
> +		/* Spin until other threads are waiting for exit */
> +		while (barrier->waiting_exit != barrier->count-1)
>  			odp_spin();

Also not sure why this is needed, why not decrement ->in where you're
currently incrementing ->waiting_exit and check here for ->in != 1?

>  
> -		/* Ready, reset out counter */
> -		barrier->out = barrier->count - 1;
> +		/* Reset barrier exit */
> +		barrier->waiting_exit = 0;
> +		barrier->wait         = 1;
>  		odp_sync_stores();
>  
> +		/* Let other threads to exit */
> +		barrier->wait_exit = 0;
> +
> +		odp_sync_stores();
>  	} else {
> -		/* Wait for the last thread*/
> -		while (barrier->in)
> +		odp_atomic_inc_int(&barrier->waiting);
> +
> +		while (barrier->wait)
> +			odp_spin();
> +
> +		odp_atomic_inc_int(&barrier->waiting_exit);
> +
> +		while (barrier->wait_exit)
>  			odp_spin();
>  
> -		/* Ready */
> -		odp_atomic_dec_int(&barrier->out);
>  		odp_mem_barrier();
>  	}
>  }
> diff --git a/test/example/odp_example.c b/test/example/odp_example.c
> index 4764657..a6ab89e 100644
> --- a/test/example/odp_example.c
> +++ b/test/example/odp_example.c
> @@ -507,6 +507,10 @@ static void *run_thread(void *arg)
>  	odp_barrier_sync(&test_barrier);
>  	odp_barrier_sync(&test_barrier);
>  	odp_barrier_sync(&test_barrier);
> +	odp_barrier_sync(&test_barrier);
> +	odp_barrier_sync(&test_barrier);
> +	odp_barrier_sync(&test_barrier);
> +	odp_barrier_sync(&test_barrier);
>  
>  	/*
>  	 * Find the buffer pool
> -- 
> 1.8.5.3
>
Bill Fischofer March 18, 2014, 11:04 p.m. UTC | #7
I've submitted alternate fix for the reported bug which is also simpler and
more efficient.  It should be used instead of this patch.

Bill


On Tue, Mar 18, 2014 at 2:09 PM, Stuart Haslam <stuart.haslam@arm.com>wrote:

> On Tue, Mar 18, 2014 at 01:13:07PM +0000, Petri Savolainen wrote:
> > There was a race condition with the "in" variable. This patch
> > uses more robust barrier exit synchronization to avoid the race.
> >
>
> This patch does seem to fix the race, but it feels a little over
> engineered, some comments below..
>
> > Signed-off-by: Petri Savolainen <petri.savolainen@linaro.org>
> > ---
> >  include/odp_barrier.h                       |  5 ++-
> >  platform/linux-generic/source/odp_barrier.c | 52
> +++++++++++++++++++++--------
> >  test/example/odp_example.c                  |  4 +++
> >  3 files changed, 47 insertions(+), 14 deletions(-)
> >
> > diff --git a/include/odp_barrier.h b/include/odp_barrier.h
> > index bb4a6c5..19dfc06 100644
> > --- a/include/odp_barrier.h
> > +++ b/include/odp_barrier.h
> > @@ -28,8 +28,11 @@ extern "C" {
> >   */
> >  typedef struct odp_barrier_t {
> >       int              count;
> > +     volatile int     wait;
> > +     volatile int     wait_exit;
> >       odp_atomic_int_t in;
> > -     odp_atomic_int_t out;
> > +     odp_atomic_int_t waiting;
> > +     odp_atomic_int_t waiting_exit;
> >  } odp_barrier_t;
> >
>
> This is quite complicated and specific given that it's part of the
> external API.
>
> >
> > diff --git a/platform/linux-generic/source/odp_barrier.c
> b/platform/linux-generic/source/odp_barrier.c
> > index 64fbdb9..b27afc7 100644
> > --- a/platform/linux-generic/source/odp_barrier.c
> > +++ b/platform/linux-generic/source/odp_barrier.c
> > @@ -10,9 +10,13 @@
> >
> >  void odp_barrier_init_count(odp_barrier_t *barrier, int count)
> >  {
> > -     barrier->count = count;
> > -     barrier->in    = 0;
> > -     barrier->out   = count - 1;
> > +     barrier->count        = count;
> > +     barrier->wait         = 1;
> > +     barrier->wait_exit    = 0;
> > +     barrier->in           = 0;
> > +     barrier->waiting      = 0;
> > +     barrier->waiting_exit = 0;
> > +
> >       odp_sync_stores();
> >  }
> >
> > @@ -26,25 +30,47 @@ void odp_barrier_sync(odp_barrier_t *barrier)
> >       count = odp_atomic_fetch_inc_int(&barrier->in);
> >
> >       if (count == barrier->count - 1) {
> > -             /* If last thread, release others */
> > -             barrier->in = 0;
> > +             /*
> > +              * This is the last thread.
> > +              * Spin until other threads are waiting.
> > +              */
> > +             while (barrier->waiting != barrier->count-1)
> > +                     odp_spin();
>
> I don't think barrier->waiting is needed at all, how would you reach
> here without the other threads already waiting?
>
> > +
> > +             /* Reset barrier entry */
> > +             barrier->wait_exit    = 1;
> > +             barrier->in           = 0;
> > +             barrier->waiting      = 0;
> > +             barrier->waiting_exit = 0;
> >               odp_sync_stores();
> >
> > -             /* Wait for others to exit */
> > -             while (barrier->out)
> > +             /* Move other threads to wait for exit */
> > +             barrier->wait = 0;
> > +
> > +             /* Spin until other threads are waiting for exit */
> > +             while (barrier->waiting_exit != barrier->count-1)
> >                       odp_spin();
>
> Also not sure why this is needed, why not decrement ->in where you're
> currently incrementing ->waiting_exit and check here for ->in != 1?
>
> >
> > -             /* Ready, reset out counter */
> > -             barrier->out = barrier->count - 1;
> > +             /* Reset barrier exit */
> > +             barrier->waiting_exit = 0;
> > +             barrier->wait         = 1;
> >               odp_sync_stores();
> >
> > +             /* Let other threads to exit */
> > +             barrier->wait_exit = 0;
> > +
> > +             odp_sync_stores();
> >       } else {
> > -             /* Wait for the last thread*/
> > -             while (barrier->in)
> > +             odp_atomic_inc_int(&barrier->waiting);
> > +
> > +             while (barrier->wait)
> > +                     odp_spin();
> > +
> > +             odp_atomic_inc_int(&barrier->waiting_exit);
> > +
> > +             while (barrier->wait_exit)
> >                       odp_spin();
> >
> > -             /* Ready */
> > -             odp_atomic_dec_int(&barrier->out);
> >               odp_mem_barrier();
> >       }
> >  }
> > diff --git a/test/example/odp_example.c b/test/example/odp_example.c
> > index 4764657..a6ab89e 100644
> > --- a/test/example/odp_example.c
> > +++ b/test/example/odp_example.c
> > @@ -507,6 +507,10 @@ static void *run_thread(void *arg)
> >       odp_barrier_sync(&test_barrier);
> >       odp_barrier_sync(&test_barrier);
> >       odp_barrier_sync(&test_barrier);
> > +     odp_barrier_sync(&test_barrier);
> > +     odp_barrier_sync(&test_barrier);
> > +     odp_barrier_sync(&test_barrier);
> > +     odp_barrier_sync(&test_barrier);
> >
> >       /*
> >        * Find the buffer pool
> > --
> > 1.8.5.3
> >
>
> --
> Stuart.
>
> --
> You received this message because you are subscribed to the Google Groups
> "LNG ODP Sub-team - lng-odp@linaro.org" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to lng-odp+unsubscribe@linaro.org.
> To post to this group, send email to lng-odp@linaro.org.
> Visit this group at http://groups.google.com/a/linaro.org/group/lng-odp/.
> To view this discussion on the web visit
> https://groups.google.com/a/linaro.org/d/msgid/lng-odp/20140318190951.GA28006%40e106441
> .
> For more options, visit https://groups.google.com/a/linaro.org/d/optout.
>
diff mbox

Patch

diff --git a/include/odp_barrier.h b/include/odp_barrier.h
index bb4a6c5..19dfc06 100644
--- a/include/odp_barrier.h
+++ b/include/odp_barrier.h
@@ -28,8 +28,11 @@  extern "C" {
  */
 typedef struct odp_barrier_t {
 	int              count;
+	volatile int     wait;
+	volatile int     wait_exit;
 	odp_atomic_int_t in;
-	odp_atomic_int_t out;
+	odp_atomic_int_t waiting;
+	odp_atomic_int_t waiting_exit;
 } odp_barrier_t;
 
 
diff --git a/platform/linux-generic/source/odp_barrier.c b/platform/linux-generic/source/odp_barrier.c
index 64fbdb9..b27afc7 100644
--- a/platform/linux-generic/source/odp_barrier.c
+++ b/platform/linux-generic/source/odp_barrier.c
@@ -10,9 +10,13 @@ 
 
 void odp_barrier_init_count(odp_barrier_t *barrier, int count)
 {
-	barrier->count = count;
-	barrier->in    = 0;
-	barrier->out   = count - 1;
+	barrier->count        = count;
+	barrier->wait         = 1;
+	barrier->wait_exit    = 0;
+	barrier->in           = 0;
+	barrier->waiting      = 0;
+	barrier->waiting_exit = 0;
+
 	odp_sync_stores();
 }
 
@@ -26,25 +30,47 @@  void odp_barrier_sync(odp_barrier_t *barrier)
 	count = odp_atomic_fetch_inc_int(&barrier->in);
 
 	if (count == barrier->count - 1) {
-		/* If last thread, release others */
-		barrier->in = 0;
+		/*
+		 * This is the last thread.
+		 * Spin until other threads are waiting.
+		 */
+		while (barrier->waiting != barrier->count-1)
+			odp_spin();
+
+		/* Reset barrier entry */
+		barrier->wait_exit    = 1;
+		barrier->in           = 0;
+		barrier->waiting      = 0;
+		barrier->waiting_exit = 0;
 		odp_sync_stores();
 
-		/* Wait for others to exit */
-		while (barrier->out)
+		/* Move other threads to wait for exit */
+		barrier->wait = 0;
+
+		/* Spin until other threads are waiting for exit */
+		while (barrier->waiting_exit != barrier->count-1)
 			odp_spin();
 
-		/* Ready, reset out counter */
-		barrier->out = barrier->count - 1;
+		/* Reset barrier exit */
+		barrier->waiting_exit = 0;
+		barrier->wait         = 1;
 		odp_sync_stores();
 
+		/* Let other threads to exit */
+		barrier->wait_exit = 0;
+
+		odp_sync_stores();
 	} else {
-		/* Wait for the last thread*/
-		while (barrier->in)
+		odp_atomic_inc_int(&barrier->waiting);
+
+		while (barrier->wait)
+			odp_spin();
+
+		odp_atomic_inc_int(&barrier->waiting_exit);
+
+		while (barrier->wait_exit)
 			odp_spin();
 
-		/* Ready */
-		odp_atomic_dec_int(&barrier->out);
 		odp_mem_barrier();
 	}
 }
diff --git a/test/example/odp_example.c b/test/example/odp_example.c
index 4764657..a6ab89e 100644
--- a/test/example/odp_example.c
+++ b/test/example/odp_example.c
@@ -507,6 +507,10 @@  static void *run_thread(void *arg)
 	odp_barrier_sync(&test_barrier);
 	odp_barrier_sync(&test_barrier);
 	odp_barrier_sync(&test_barrier);
+	odp_barrier_sync(&test_barrier);
+	odp_barrier_sync(&test_barrier);
+	odp_barrier_sync(&test_barrier);
+	odp_barrier_sync(&test_barrier);
 
 	/*
 	 * Find the buffer pool