]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgomp/config/rtems/bar.c
Update copyright years.
[thirdparty/gcc.git] / libgomp / config / rtems / bar.c
CommitLineData
818ab71a 1/* Copyright (C) 2005-2016 Free Software Foundation, Inc.
13c41b2e
SH
2 Contributed by Sebastian Huber <sebastian.huber@embedded-brains.de>.
3
4 This file is part of the GNU OpenMP Library (libgomp).
5
6 Libgomp is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
19
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
24
25/* This is the RTEMS implementation of a barrier synchronization
26 mechanism for libgomp. It is identical to the Linux implementation, except
27 that the futex API is slightly different. This type is private to the
28 library. */
29
30#include "libgomp.h"
31#include "bar.h"
32#include <limits.h>
33
34static gomp_barrier_t *
35generation_to_barrier (int *addr)
36{
37 return (gomp_barrier_t *)
38 ((char *) addr - __builtin_offsetof (gomp_barrier_t, generation));
39}
40
41static void
42futex_wait (int *addr, int val)
43{
44 gomp_barrier_t *bar = generation_to_barrier (addr);
45 _Futex_Wait (&bar->futex, addr, val);
46}
47
48static void
49futex_wake (int *addr, int count)
50{
51 gomp_barrier_t *bar = generation_to_barrier (addr);
52 _Futex_Wake (&bar->futex, count);
53}
54
55static int
56do_spin (int *addr, int val)
57{
58 unsigned long long i, count = gomp_spin_count_var;
59
60 if (__builtin_expect (gomp_managed_threads > gomp_available_cpus, 0))
61 count = gomp_throttled_spin_count_var;
62 for (i = 0; i < count; i++)
63 if (__builtin_expect (__atomic_load_n (addr, MEMMODEL_RELAXED) != val, 0))
64 return 0;
65 return 1;
66}
67
68static void
69do_wait (int *addr, int val)
70{
71 if (do_spin (addr, val))
72 futex_wait (addr, val);
73}
74
75/* Everything below this point should be identical to the Linux
76 implementation. */
77
78void
79gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
80{
81 if (__builtin_expect (state & BAR_WAS_LAST, 0))
82 {
83 /* Next time we'll be awaiting TOTAL threads again. */
84 bar->awaited = bar->total;
85 __atomic_store_n (&bar->generation, bar->generation + BAR_INCR,
86 MEMMODEL_RELEASE);
87 futex_wake ((int *) &bar->generation, INT_MAX);
88 }
89 else
90 {
91 do
92 do_wait ((int *) &bar->generation, state);
93 while (__atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE) == state);
94 }
95}
96
97void
98gomp_barrier_wait (gomp_barrier_t *bar)
99{
100 gomp_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
101}
102
103/* Like gomp_barrier_wait, except that if the encountering thread
104 is not the last one to hit the barrier, it returns immediately.
105 The intended usage is that a thread which intends to gomp_barrier_destroy
106 this barrier calls gomp_barrier_wait, while all other threads
107 call gomp_barrier_wait_last. When gomp_barrier_wait returns,
108 the barrier can be safely destroyed. */
109
110void
111gomp_barrier_wait_last (gomp_barrier_t *bar)
112{
113 gomp_barrier_state_t state = gomp_barrier_wait_start (bar);
114 if (state & BAR_WAS_LAST)
115 gomp_barrier_wait_end (bar, state);
116}
117
118void
119gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
120{
121 futex_wake ((int *) &bar->generation, count == 0 ? INT_MAX : count);
122}
123
124void
125gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
126{
127 unsigned int generation, gen;
128
129 if (__builtin_expect (state & BAR_WAS_LAST, 0))
130 {
131 /* Next time we'll be awaiting TOTAL threads again. */
132 struct gomp_thread *thr = gomp_thread ();
133 struct gomp_team *team = thr->ts.team;
134
135 bar->awaited = bar->total;
136 team->work_share_cancelled = 0;
137 if (__builtin_expect (team->task_count, 0))
138 {
139 gomp_barrier_handle_tasks (state);
140 state &= ~BAR_WAS_LAST;
141 }
142 else
143 {
144 state &= ~BAR_CANCELLED;
145 state += BAR_INCR - BAR_WAS_LAST;
146 __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
147 futex_wake ((int *) &bar->generation, INT_MAX);
148 return;
149 }
150 }
151
152 generation = state;
153 state &= ~BAR_CANCELLED;
154 do
155 {
156 do_wait ((int *) &bar->generation, generation);
157 gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
158 if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
159 {
160 gomp_barrier_handle_tasks (state);
161 gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
162 }
163 generation |= gen & BAR_WAITING_FOR_TASK;
164 }
165 while (gen != state + BAR_INCR);
166}
167
168void
169gomp_team_barrier_wait (gomp_barrier_t *bar)
170{
171 gomp_team_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
172}
173
174void
175gomp_team_barrier_wait_final (gomp_barrier_t *bar)
176{
177 gomp_barrier_state_t state = gomp_barrier_wait_final_start (bar);
178 if (__builtin_expect (state & BAR_WAS_LAST, 0))
179 bar->awaited_final = bar->total;
180 gomp_team_barrier_wait_end (bar, state);
181}
182
183bool
184gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
185 gomp_barrier_state_t state)
186{
187 unsigned int generation, gen;
188
189 if (__builtin_expect (state & BAR_WAS_LAST, 0))
190 {
191 /* Next time we'll be awaiting TOTAL threads again. */
192 /* BAR_CANCELLED should never be set in state here, because
193 cancellation means that at least one of the threads has been
194 cancelled, thus on a cancellable barrier we should never see
195 all threads to arrive. */
196 struct gomp_thread *thr = gomp_thread ();
197 struct gomp_team *team = thr->ts.team;
198
199 bar->awaited = bar->total;
200 team->work_share_cancelled = 0;
201 if (__builtin_expect (team->task_count, 0))
202 {
203 gomp_barrier_handle_tasks (state);
204 state &= ~BAR_WAS_LAST;
205 }
206 else
207 {
208 state += BAR_INCR - BAR_WAS_LAST;
209 __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
210 futex_wake ((int *) &bar->generation, INT_MAX);
211 return false;
212 }
213 }
214
215 if (__builtin_expect (state & BAR_CANCELLED, 0))
216 return true;
217
218 generation = state;
219 do
220 {
221 do_wait ((int *) &bar->generation, generation);
222 gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
223 if (__builtin_expect (gen & BAR_CANCELLED, 0))
224 return true;
225 if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
226 {
227 gomp_barrier_handle_tasks (state);
228 gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
229 }
230 generation |= gen & BAR_WAITING_FOR_TASK;
231 }
232 while (gen != state + BAR_INCR);
233
234 return false;
235}
236
237bool
238gomp_team_barrier_wait_cancel (gomp_barrier_t *bar)
239{
240 return gomp_team_barrier_wait_cancel_end (bar, gomp_barrier_wait_start (bar));
241}
242
243void
244gomp_team_barrier_cancel (struct gomp_team *team)
245{
246 gomp_mutex_lock (&team->task_lock);
247 if (team->barrier.generation & BAR_CANCELLED)
248 {
249 gomp_mutex_unlock (&team->task_lock);
250 return;
251 }
252 team->barrier.generation |= BAR_CANCELLED;
253 gomp_mutex_unlock (&team->task_lock);
254 futex_wake ((int *) &team->barrier.generation, INT_MAX);
255}