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