bar.c revision 1.3
1168515Sgshapiro/* Copyright (C) 2005-2013 Free Software Foundation, Inc.
2168515Sgshapiro   Contributed by Richard Henderson <rth@redhat.com>.
3168515Sgshapiro
4168515Sgshapiro   This file is part of the GNU OpenMP Library (libgomp).
5168515Sgshapiro
6168515Sgshapiro   Libgomp is free software; you can redistribute it and/or modify it
7168515Sgshapiro   under the terms of the GNU General Public License as published by
8168515Sgshapiro   the Free Software Foundation; either version 3, or (at your option)
9168515Sgshapiro   any later version.
10168515Sgshapiro
11168515Sgshapiro   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12168515Sgshapiro   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13168515Sgshapiro   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14168515Sgshapiro   more details.
15168515Sgshapiro
16168515Sgshapiro   Under Section 7 of GPL version 3, you are granted additional
17168515Sgshapiro   permissions described in the GCC Runtime Library Exception, version
18168515Sgshapiro   3.1, as published by the Free Software Foundation.
19168515Sgshapiro
20168515Sgshapiro   You should have received a copy of the GNU General Public License and
21168515Sgshapiro   a copy of the GCC Runtime Library Exception along with this program;
22168515Sgshapiro   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23168515Sgshapiro   <http://www.gnu.org/licenses/>.  */
24168515Sgshapiro
25168515Sgshapiro/* This is a Linux specific implementation of a barrier synchronization
26168515Sgshapiro   mechanism for libgomp.  This type is private to the library.  This
27168515Sgshapiro   implementation uses atomic instructions and the futex syscall.  */
28168515Sgshapiro
29168515Sgshapiro#include <limits.h>
30168515Sgshapiro#include "wait.h"
31168515Sgshapiro
32168515Sgshapiro
33168515Sgshapirovoid
34168515Sgshapirogomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
35168515Sgshapiro{
36168515Sgshapiro  if (__builtin_expect ((state & 1) != 0, 0))
37168515Sgshapiro    {
38168515Sgshapiro      /* Next time we'll be awaiting TOTAL threads again.  */
39266692Sgshapiro      bar->awaited = bar->total;
40173340Sgshapiro      __atomic_store_n (&bar->generation, bar->generation + 4,
41168515Sgshapiro			MEMMODEL_RELEASE);
42168515Sgshapiro      futex_wake ((int *) &bar->generation, INT_MAX);
43173340Sgshapiro    }
44173340Sgshapiro  else
45168515Sgshapiro    {
46168515Sgshapiro      do
47168515Sgshapiro	do_wait ((int *) &bar->generation, state);
48168515Sgshapiro      while (__atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE) == state);
49168515Sgshapiro    }
50168515Sgshapiro}
51168515Sgshapiro
52168515Sgshapirovoid
53168515Sgshapirogomp_barrier_wait (gomp_barrier_t *bar)
54168515Sgshapiro{
55168515Sgshapiro  gomp_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
56168515Sgshapiro}
57168515Sgshapiro
58168515Sgshapiro/* Like gomp_barrier_wait, except that if the encountering thread
59168515Sgshapiro   is not the last one to hit the barrier, it returns immediately.
60168515Sgshapiro   The intended usage is that a thread which intends to gomp_barrier_destroy
61168515Sgshapiro   this barrier calls gomp_barrier_wait, while all other threads
62168515Sgshapiro   call gomp_barrier_wait_last.  When gomp_barrier_wait returns,
63168515Sgshapiro   the barrier can be safely destroyed.  */
64168515Sgshapiro
65168515Sgshapirovoid
66168515Sgshapirogomp_barrier_wait_last (gomp_barrier_t *bar)
67168515Sgshapiro{
68168515Sgshapiro  gomp_barrier_state_t state = gomp_barrier_wait_start (bar);
69168515Sgshapiro  if (state & 1)
70168515Sgshapiro    gomp_barrier_wait_end (bar, state);
71168515Sgshapiro}
72244833Sgshapiro
73244833Sgshapirovoid
74168515Sgshapirogomp_team_barrier_wake (gomp_barrier_t *bar, int count)
75168515Sgshapiro{
76168515Sgshapiro  futex_wake ((int *) &bar->generation, count == 0 ? INT_MAX : count);
77168515Sgshapiro}
78168515Sgshapiro
79168515Sgshapirovoid
80168515Sgshapirogomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
81168515Sgshapiro{
82168515Sgshapiro  unsigned int generation, gen;
83168515Sgshapiro
84168515Sgshapiro  if (__builtin_expect ((state & 1) != 0, 0))
85168515Sgshapiro    {
86168515Sgshapiro      /* Next time we'll be awaiting TOTAL threads again.  */
87168515Sgshapiro      struct gomp_thread *thr = gomp_thread ();
88168515Sgshapiro      struct gomp_team *team = thr->ts.team;
89168515Sgshapiro
90168515Sgshapiro      bar->awaited = bar->total;
91168515Sgshapiro      if (__builtin_expect (team->task_count, 0))
92168515Sgshapiro	{
93168515Sgshapiro	  gomp_barrier_handle_tasks (state);
94168515Sgshapiro	  state &= ~1;
95168515Sgshapiro	}
96168515Sgshapiro      else
97168515Sgshapiro	{
98168515Sgshapiro	  __atomic_store_n (&bar->generation, state + 3, MEMMODEL_RELEASE);
99168515Sgshapiro	  futex_wake ((int *) &bar->generation, INT_MAX);
100168515Sgshapiro	  return;
101168515Sgshapiro	}
102168515Sgshapiro    }
103168515Sgshapiro
104168515Sgshapiro  generation = state;
105168515Sgshapiro  do
106168515Sgshapiro    {
107168515Sgshapiro      do_wait ((int *) &bar->generation, generation);
108168515Sgshapiro      gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
109168515Sgshapiro      if (__builtin_expect (gen & 1, 0))
110168515Sgshapiro	{
111168515Sgshapiro	  gomp_barrier_handle_tasks (state);
112168515Sgshapiro	  gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
113168515Sgshapiro	}
114168515Sgshapiro      if ((gen & 2) != 0)
115168515Sgshapiro	generation |= 2;
116168515Sgshapiro    }
117168515Sgshapiro  while (gen != state + 4);
118168515Sgshapiro}
119168515Sgshapiro
120168515Sgshapirovoid
121168515Sgshapirogomp_team_barrier_wait (gomp_barrier_t *bar)
122168515Sgshapiro{
123168515Sgshapiro  gomp_team_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
124168515Sgshapiro}
125168515Sgshapiro