bar.c revision 1.5 1 1.5 mrg /* Copyright (C) 2005-2015 Free Software Foundation, Inc.
2 1.1 mrg Contributed by Richard Henderson <rth (at) redhat.com>.
3 1.1 mrg
4 1.5 mrg This file is part of the GNU Offloading and Multi Processing Library
5 1.5 mrg (libgomp).
6 1.1 mrg
7 1.1 mrg Libgomp is free software; you can redistribute it and/or modify it
8 1.1 mrg under the terms of the GNU General Public License as published by
9 1.1 mrg the Free Software Foundation; either version 3, or (at your option)
10 1.1 mrg any later version.
11 1.1 mrg
12 1.1 mrg Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13 1.1 mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 1.1 mrg FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 1.1 mrg more details.
16 1.1 mrg
17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
18 1.1 mrg permissions described in the GCC Runtime Library Exception, version
19 1.1 mrg 3.1, as published by the Free Software Foundation.
20 1.1 mrg
21 1.1 mrg You should have received a copy of the GNU General Public License and
22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 1.1 mrg <http://www.gnu.org/licenses/>. */
25 1.1 mrg
26 1.1 mrg /* This is a Linux specific implementation of a barrier synchronization
27 1.1 mrg mechanism for libgomp. This type is private to the library. This
28 1.1 mrg implementation uses atomic instructions and the futex syscall. */
29 1.1 mrg
30 1.1 mrg #include <limits.h>
31 1.1 mrg #include "wait.h"
32 1.1 mrg
33 1.1 mrg
34 1.1 mrg void
35 1.1 mrg gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
36 1.1 mrg {
37 1.5 mrg if (__builtin_expect (state & BAR_WAS_LAST, 0))
38 1.1 mrg {
39 1.1 mrg /* Next time we'll be awaiting TOTAL threads again. */
40 1.1 mrg bar->awaited = bar->total;
41 1.5 mrg __atomic_store_n (&bar->generation, bar->generation + BAR_INCR,
42 1.3 mrg MEMMODEL_RELEASE);
43 1.1 mrg futex_wake ((int *) &bar->generation, INT_MAX);
44 1.1 mrg }
45 1.1 mrg else
46 1.1 mrg {
47 1.1 mrg do
48 1.3 mrg do_wait ((int *) &bar->generation, state);
49 1.3 mrg while (__atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE) == state);
50 1.1 mrg }
51 1.1 mrg }
52 1.1 mrg
53 1.1 mrg void
54 1.1 mrg gomp_barrier_wait (gomp_barrier_t *bar)
55 1.1 mrg {
56 1.1 mrg gomp_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
57 1.1 mrg }
58 1.1 mrg
59 1.1 mrg /* Like gomp_barrier_wait, except that if the encountering thread
60 1.1 mrg is not the last one to hit the barrier, it returns immediately.
61 1.1 mrg The intended usage is that a thread which intends to gomp_barrier_destroy
62 1.1 mrg this barrier calls gomp_barrier_wait, while all other threads
63 1.1 mrg call gomp_barrier_wait_last. When gomp_barrier_wait returns,
64 1.1 mrg the barrier can be safely destroyed. */
65 1.1 mrg
66 1.1 mrg void
67 1.1 mrg gomp_barrier_wait_last (gomp_barrier_t *bar)
68 1.1 mrg {
69 1.1 mrg gomp_barrier_state_t state = gomp_barrier_wait_start (bar);
70 1.5 mrg if (state & BAR_WAS_LAST)
71 1.1 mrg gomp_barrier_wait_end (bar, state);
72 1.1 mrg }
73 1.1 mrg
74 1.1 mrg void
75 1.1 mrg gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
76 1.1 mrg {
77 1.1 mrg futex_wake ((int *) &bar->generation, count == 0 ? INT_MAX : count);
78 1.1 mrg }
79 1.1 mrg
80 1.1 mrg void
81 1.1 mrg gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
82 1.1 mrg {
83 1.3 mrg unsigned int generation, gen;
84 1.1 mrg
85 1.5 mrg if (__builtin_expect (state & BAR_WAS_LAST, 0))
86 1.1 mrg {
87 1.1 mrg /* Next time we'll be awaiting TOTAL threads again. */
88 1.1 mrg struct gomp_thread *thr = gomp_thread ();
89 1.1 mrg struct gomp_team *team = thr->ts.team;
90 1.3 mrg
91 1.1 mrg bar->awaited = bar->total;
92 1.5 mrg team->work_share_cancelled = 0;
93 1.1 mrg if (__builtin_expect (team->task_count, 0))
94 1.1 mrg {
95 1.1 mrg gomp_barrier_handle_tasks (state);
96 1.5 mrg state &= ~BAR_WAS_LAST;
97 1.1 mrg }
98 1.1 mrg else
99 1.1 mrg {
100 1.5 mrg state &= ~BAR_CANCELLED;
101 1.5 mrg state += BAR_INCR - BAR_WAS_LAST;
102 1.5 mrg __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
103 1.1 mrg futex_wake ((int *) &bar->generation, INT_MAX);
104 1.1 mrg return;
105 1.1 mrg }
106 1.1 mrg }
107 1.1 mrg
108 1.1 mrg generation = state;
109 1.5 mrg state &= ~BAR_CANCELLED;
110 1.1 mrg do
111 1.1 mrg {
112 1.1 mrg do_wait ((int *) &bar->generation, generation);
113 1.3 mrg gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
114 1.5 mrg if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
115 1.3 mrg {
116 1.3 mrg gomp_barrier_handle_tasks (state);
117 1.3 mrg gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
118 1.3 mrg }
119 1.5 mrg generation |= gen & BAR_WAITING_FOR_TASK;
120 1.1 mrg }
121 1.5 mrg while (gen != state + BAR_INCR);
122 1.1 mrg }
123 1.1 mrg
124 1.1 mrg void
125 1.1 mrg gomp_team_barrier_wait (gomp_barrier_t *bar)
126 1.1 mrg {
127 1.1 mrg gomp_team_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
128 1.1 mrg }
129 1.5 mrg
130 1.5 mrg void
131 1.5 mrg gomp_team_barrier_wait_final (gomp_barrier_t *bar)
132 1.5 mrg {
133 1.5 mrg gomp_barrier_state_t state = gomp_barrier_wait_final_start (bar);
134 1.5 mrg if (__builtin_expect (state & BAR_WAS_LAST, 0))
135 1.5 mrg bar->awaited_final = bar->total;
136 1.5 mrg gomp_team_barrier_wait_end (bar, state);
137 1.5 mrg }
138 1.5 mrg
139 1.5 mrg bool
140 1.5 mrg gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
141 1.5 mrg gomp_barrier_state_t state)
142 1.5 mrg {
143 1.5 mrg unsigned int generation, gen;
144 1.5 mrg
145 1.5 mrg if (__builtin_expect (state & BAR_WAS_LAST, 0))
146 1.5 mrg {
147 1.5 mrg /* Next time we'll be awaiting TOTAL threads again. */
148 1.5 mrg /* BAR_CANCELLED should never be set in state here, because
149 1.5 mrg cancellation means that at least one of the threads has been
150 1.5 mrg cancelled, thus on a cancellable barrier we should never see
151 1.5 mrg all threads to arrive. */
152 1.5 mrg struct gomp_thread *thr = gomp_thread ();
153 1.5 mrg struct gomp_team *team = thr->ts.team;
154 1.5 mrg
155 1.5 mrg bar->awaited = bar->total;
156 1.5 mrg team->work_share_cancelled = 0;
157 1.5 mrg if (__builtin_expect (team->task_count, 0))
158 1.5 mrg {
159 1.5 mrg gomp_barrier_handle_tasks (state);
160 1.5 mrg state &= ~BAR_WAS_LAST;
161 1.5 mrg }
162 1.5 mrg else
163 1.5 mrg {
164 1.5 mrg state += BAR_INCR - BAR_WAS_LAST;
165 1.5 mrg __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
166 1.5 mrg futex_wake ((int *) &bar->generation, INT_MAX);
167 1.5 mrg return false;
168 1.5 mrg }
169 1.5 mrg }
170 1.5 mrg
171 1.5 mrg if (__builtin_expect (state & BAR_CANCELLED, 0))
172 1.5 mrg return true;
173 1.5 mrg
174 1.5 mrg generation = state;
175 1.5 mrg do
176 1.5 mrg {
177 1.5 mrg do_wait ((int *) &bar->generation, generation);
178 1.5 mrg gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
179 1.5 mrg if (__builtin_expect (gen & BAR_CANCELLED, 0))
180 1.5 mrg return true;
181 1.5 mrg if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
182 1.5 mrg {
183 1.5 mrg gomp_barrier_handle_tasks (state);
184 1.5 mrg gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
185 1.5 mrg }
186 1.5 mrg generation |= gen & BAR_WAITING_FOR_TASK;
187 1.5 mrg }
188 1.5 mrg while (gen != state + BAR_INCR);
189 1.5 mrg
190 1.5 mrg return false;
191 1.5 mrg }
192 1.5 mrg
193 1.5 mrg bool
194 1.5 mrg gomp_team_barrier_wait_cancel (gomp_barrier_t *bar)
195 1.5 mrg {
196 1.5 mrg return gomp_team_barrier_wait_cancel_end (bar, gomp_barrier_wait_start (bar));
197 1.5 mrg }
198 1.5 mrg
199 1.5 mrg void
200 1.5 mrg gomp_team_barrier_cancel (struct gomp_team *team)
201 1.5 mrg {
202 1.5 mrg gomp_mutex_lock (&team->task_lock);
203 1.5 mrg if (team->barrier.generation & BAR_CANCELLED)
204 1.5 mrg {
205 1.5 mrg gomp_mutex_unlock (&team->task_lock);
206 1.5 mrg return;
207 1.5 mrg }
208 1.5 mrg team->barrier.generation |= BAR_CANCELLED;
209 1.5 mrg gomp_mutex_unlock (&team->task_lock);
210 1.5 mrg futex_wake ((int *) &team->barrier.generation, INT_MAX);
211 1.5 mrg }
212