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