team.c revision 1.1.1.12 1 1.1.1.12 mrg /* Copyright (C) 2005-2024 Free Software Foundation, Inc.
2 1.1 mrg Contributed by Richard Henderson <rth (at) redhat.com>.
3 1.1 mrg
4 1.1.1.3 mrg This file is part of the GNU Offloading and Multi Processing Library
5 1.1.1.3 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.1.10 mrg /* This file handles the maintenance of threads in response to team
27 1.1 mrg creation and termination. */
28 1.1 mrg
29 1.1 mrg #include "libgomp.h"
30 1.1.1.4 mrg #include "pool.h"
31 1.1 mrg #include <stdlib.h>
32 1.1 mrg #include <string.h>
33 1.1 mrg
34 1.1.1.5 mrg #ifdef LIBGOMP_USE_PTHREADS
35 1.1 mrg pthread_attr_t gomp_thread_attr;
36 1.1 mrg
37 1.1 mrg /* This key is for the thread destructor. */
38 1.1 mrg pthread_key_t gomp_thread_destructor;
39 1.1 mrg
40 1.1 mrg
41 1.1 mrg /* This is the libgomp per-thread data structure. */
42 1.1.1.3 mrg #if defined HAVE_TLS || defined USE_EMUTLS
43 1.1 mrg __thread struct gomp_thread gomp_tls_data;
44 1.1 mrg #else
45 1.1 mrg pthread_key_t gomp_tls_key;
46 1.1 mrg #endif
47 1.1 mrg
48 1.1 mrg
49 1.1 mrg /* This structure is used to communicate across pthread_create. */
50 1.1 mrg
51 1.1 mrg struct gomp_thread_start_data
52 1.1 mrg {
53 1.1 mrg void (*fn) (void *);
54 1.1 mrg void *fn_data;
55 1.1 mrg struct gomp_team_state ts;
56 1.1 mrg struct gomp_task *task;
57 1.1 mrg struct gomp_thread_pool *thread_pool;
58 1.1.1.3 mrg unsigned int place;
59 1.1.1.11 mrg unsigned int num_teams;
60 1.1.1.11 mrg unsigned int team_num;
61 1.1 mrg bool nested;
62 1.1.1.9 mrg pthread_t handle;
63 1.1 mrg };
64 1.1 mrg
65 1.1 mrg
66 1.1 mrg /* This function is a pthread_create entry point. This contains the idle
67 1.1 mrg loop in which a thread waits to be called up to become part of a team. */
68 1.1 mrg
69 1.1 mrg static void *
70 1.1 mrg gomp_thread_start (void *xdata)
71 1.1 mrg {
72 1.1 mrg struct gomp_thread_start_data *data = xdata;
73 1.1 mrg struct gomp_thread *thr;
74 1.1 mrg struct gomp_thread_pool *pool;
75 1.1 mrg void (*local_fn) (void *);
76 1.1 mrg void *local_data;
77 1.1 mrg
78 1.1.1.3 mrg #if defined HAVE_TLS || defined USE_EMUTLS
79 1.1 mrg thr = &gomp_tls_data;
80 1.1 mrg #else
81 1.1 mrg struct gomp_thread local_thr;
82 1.1 mrg thr = &local_thr;
83 1.1 mrg #endif
84 1.1 mrg gomp_sem_init (&thr->release, 0);
85 1.1 mrg
86 1.1 mrg /* Extract what we need from data. */
87 1.1 mrg local_fn = data->fn;
88 1.1 mrg local_data = data->fn_data;
89 1.1 mrg thr->thread_pool = data->thread_pool;
90 1.1 mrg thr->ts = data->ts;
91 1.1 mrg thr->task = data->task;
92 1.1.1.3 mrg thr->place = data->place;
93 1.1.1.11 mrg thr->num_teams = data->num_teams;
94 1.1.1.11 mrg thr->team_num = data->team_num;
95 1.1.1.9 mrg #ifdef GOMP_NEEDS_THREAD_HANDLE
96 1.1.1.9 mrg thr->handle = data->handle;
97 1.1.1.9 mrg #endif
98 1.1.1.11 mrg #if !(defined HAVE_TLS || defined USE_EMUTLS)
99 1.1.1.11 mrg pthread_setspecific (gomp_tls_key, thr);
100 1.1.1.11 mrg #endif
101 1.1 mrg
102 1.1 mrg thr->ts.team->ordered_release[thr->ts.team_id] = &thr->release;
103 1.1 mrg
104 1.1 mrg /* Make thread pool local. */
105 1.1 mrg pool = thr->thread_pool;
106 1.1 mrg
107 1.1 mrg if (data->nested)
108 1.1 mrg {
109 1.1 mrg struct gomp_team *team = thr->ts.team;
110 1.1 mrg struct gomp_task *task = thr->task;
111 1.1 mrg
112 1.1 mrg gomp_barrier_wait (&team->barrier);
113 1.1 mrg
114 1.1 mrg local_fn (local_data);
115 1.1.1.3 mrg gomp_team_barrier_wait_final (&team->barrier);
116 1.1 mrg gomp_finish_task (task);
117 1.1 mrg gomp_barrier_wait_last (&team->barrier);
118 1.1 mrg }
119 1.1 mrg else
120 1.1 mrg {
121 1.1 mrg pool->threads[thr->ts.team_id] = thr;
122 1.1 mrg
123 1.1.1.5 mrg gomp_simple_barrier_wait (&pool->threads_dock);
124 1.1 mrg do
125 1.1 mrg {
126 1.1 mrg struct gomp_team *team = thr->ts.team;
127 1.1 mrg struct gomp_task *task = thr->task;
128 1.1 mrg
129 1.1 mrg local_fn (local_data);
130 1.1.1.3 mrg gomp_team_barrier_wait_final (&team->barrier);
131 1.1 mrg gomp_finish_task (task);
132 1.1 mrg
133 1.1.1.5 mrg gomp_simple_barrier_wait (&pool->threads_dock);
134 1.1 mrg
135 1.1 mrg local_fn = thr->fn;
136 1.1 mrg local_data = thr->data;
137 1.1 mrg thr->fn = NULL;
138 1.1 mrg }
139 1.1 mrg while (local_fn);
140 1.1 mrg }
141 1.1 mrg
142 1.1 mrg gomp_sem_destroy (&thr->release);
143 1.1.1.9 mrg pthread_detach (pthread_self ());
144 1.1.1.3 mrg thr->thread_pool = NULL;
145 1.1.1.3 mrg thr->task = NULL;
146 1.1 mrg return NULL;
147 1.1 mrg }
148 1.1.1.5 mrg #endif
149 1.1 mrg
150 1.1.1.4 mrg static inline struct gomp_team *
151 1.1.1.4 mrg get_last_team (unsigned nthreads)
152 1.1.1.4 mrg {
153 1.1.1.4 mrg struct gomp_thread *thr = gomp_thread ();
154 1.1.1.4 mrg if (thr->ts.team == NULL)
155 1.1.1.4 mrg {
156 1.1.1.4 mrg struct gomp_thread_pool *pool = gomp_get_thread_pool (thr, nthreads);
157 1.1.1.4 mrg struct gomp_team *last_team = pool->last_team;
158 1.1.1.4 mrg if (last_team != NULL && last_team->nthreads == nthreads)
159 1.1.1.4 mrg {
160 1.1.1.4 mrg pool->last_team = NULL;
161 1.1.1.4 mrg return last_team;
162 1.1.1.4 mrg }
163 1.1.1.4 mrg }
164 1.1.1.4 mrg return NULL;
165 1.1.1.4 mrg }
166 1.1 mrg
167 1.1 mrg /* Create a new team data structure. */
168 1.1 mrg
169 1.1 mrg struct gomp_team *
170 1.1 mrg gomp_new_team (unsigned nthreads)
171 1.1 mrg {
172 1.1 mrg struct gomp_team *team;
173 1.1 mrg int i;
174 1.1 mrg
175 1.1.1.4 mrg team = get_last_team (nthreads);
176 1.1.1.4 mrg if (team == NULL)
177 1.1.1.4 mrg {
178 1.1.1.4 mrg size_t extra = sizeof (team->ordered_release[0])
179 1.1.1.4 mrg + sizeof (team->implicit_task[0]);
180 1.1.1.11 mrg #ifdef GOMP_USE_ALIGNED_WORK_SHARES
181 1.1.1.11 mrg team = gomp_aligned_alloc (__alignof (struct gomp_team),
182 1.1.1.11 mrg sizeof (*team) + nthreads * extra);
183 1.1.1.11 mrg #else
184 1.1.1.10 mrg team = team_malloc (sizeof (*team) + nthreads * extra);
185 1.1.1.11 mrg #endif
186 1.1.1.4 mrg
187 1.1.1.4 mrg #ifndef HAVE_SYNC_BUILTINS
188 1.1.1.4 mrg gomp_mutex_init (&team->work_share_list_free_lock);
189 1.1.1.4 mrg #endif
190 1.1.1.4 mrg gomp_barrier_init (&team->barrier, nthreads);
191 1.1.1.4 mrg gomp_mutex_init (&team->task_lock);
192 1.1.1.4 mrg
193 1.1.1.4 mrg team->nthreads = nthreads;
194 1.1.1.4 mrg }
195 1.1 mrg
196 1.1 mrg team->work_share_chunk = 8;
197 1.1 mrg #ifdef HAVE_SYNC_BUILTINS
198 1.1 mrg team->single_count = 0;
199 1.1 mrg #endif
200 1.1.1.3 mrg team->work_shares_to_free = &team->work_shares[0];
201 1.1.1.9 mrg gomp_init_work_share (&team->work_shares[0], 0, nthreads);
202 1.1 mrg team->work_shares[0].next_alloc = NULL;
203 1.1 mrg team->work_share_list_free = NULL;
204 1.1 mrg team->work_share_list_alloc = &team->work_shares[1];
205 1.1 mrg for (i = 1; i < 7; i++)
206 1.1 mrg team->work_shares[i].next_free = &team->work_shares[i + 1];
207 1.1 mrg team->work_shares[i].next_free = NULL;
208 1.1 mrg
209 1.1 mrg gomp_sem_init (&team->master_release, 0);
210 1.1 mrg team->ordered_release = (void *) &team->implicit_task[nthreads];
211 1.1 mrg team->ordered_release[0] = &team->master_release;
212 1.1 mrg
213 1.1.1.4 mrg priority_queue_init (&team->task_queue);
214 1.1 mrg team->task_count = 0;
215 1.1.1.3 mrg team->task_queued_count = 0;
216 1.1 mrg team->task_running_count = 0;
217 1.1.1.3 mrg team->work_share_cancelled = 0;
218 1.1.1.3 mrg team->team_cancelled = 0;
219 1.1 mrg
220 1.1.1.11 mrg team->task_detach_count = 0;
221 1.1.1.11 mrg
222 1.1 mrg return team;
223 1.1 mrg }
224 1.1 mrg
225 1.1 mrg
226 1.1 mrg /* Free a team data structure. */
227 1.1 mrg
228 1.1 mrg static void
229 1.1 mrg free_team (struct gomp_team *team)
230 1.1 mrg {
231 1.1.1.4 mrg #ifndef HAVE_SYNC_BUILTINS
232 1.1.1.4 mrg gomp_mutex_destroy (&team->work_share_list_free_lock);
233 1.1.1.4 mrg #endif
234 1.1 mrg gomp_barrier_destroy (&team->barrier);
235 1.1 mrg gomp_mutex_destroy (&team->task_lock);
236 1.1.1.4 mrg priority_queue_free (&team->task_queue);
237 1.1.1.10 mrg team_free (team);
238 1.1 mrg }
239 1.1 mrg
240 1.1 mrg static void
241 1.1 mrg gomp_free_pool_helper (void *thread_pool)
242 1.1 mrg {
243 1.1.1.3 mrg struct gomp_thread *thr = gomp_thread ();
244 1.1 mrg struct gomp_thread_pool *pool
245 1.1 mrg = (struct gomp_thread_pool *) thread_pool;
246 1.1.1.5 mrg gomp_simple_barrier_wait_last (&pool->threads_dock);
247 1.1.1.3 mrg gomp_sem_destroy (&thr->release);
248 1.1.1.3 mrg thr->thread_pool = NULL;
249 1.1.1.3 mrg thr->task = NULL;
250 1.1.1.5 mrg #ifdef LIBGOMP_USE_PTHREADS
251 1.1.1.9 mrg pthread_detach (pthread_self ());
252 1.1 mrg pthread_exit (NULL);
253 1.1.1.5 mrg #elif defined(__nvptx__)
254 1.1.1.5 mrg asm ("exit;");
255 1.1.1.10 mrg #elif defined(__AMDGCN__)
256 1.1.1.12 mrg asm ("s_endpgm");
257 1.1.1.5 mrg #else
258 1.1.1.5 mrg #error gomp_free_pool_helper must terminate the thread
259 1.1.1.5 mrg #endif
260 1.1 mrg }
261 1.1 mrg
262 1.1 mrg /* Free a thread pool and release its threads. */
263 1.1 mrg
264 1.1.1.3 mrg void
265 1.1 mrg gomp_free_thread (void *arg __attribute__((unused)))
266 1.1 mrg {
267 1.1 mrg struct gomp_thread *thr = gomp_thread ();
268 1.1 mrg struct gomp_thread_pool *pool = thr->thread_pool;
269 1.1 mrg if (pool)
270 1.1 mrg {
271 1.1 mrg if (pool->threads_used > 0)
272 1.1 mrg {
273 1.1 mrg int i;
274 1.1 mrg for (i = 1; i < pool->threads_used; i++)
275 1.1 mrg {
276 1.1 mrg struct gomp_thread *nthr = pool->threads[i];
277 1.1 mrg nthr->fn = gomp_free_pool_helper;
278 1.1 mrg nthr->data = pool;
279 1.1 mrg }
280 1.1 mrg /* This barrier undocks threads docked on pool->threads_dock. */
281 1.1.1.5 mrg gomp_simple_barrier_wait (&pool->threads_dock);
282 1.1 mrg /* And this waits till all threads have called gomp_barrier_wait_last
283 1.1 mrg in gomp_free_pool_helper. */
284 1.1.1.5 mrg gomp_simple_barrier_wait (&pool->threads_dock);
285 1.1 mrg /* Now it is safe to destroy the barrier and free the pool. */
286 1.1.1.5 mrg gomp_simple_barrier_destroy (&pool->threads_dock);
287 1.1.1.2 mrg
288 1.1.1.2 mrg #ifdef HAVE_SYNC_BUILTINS
289 1.1.1.2 mrg __sync_fetch_and_add (&gomp_managed_threads,
290 1.1.1.2 mrg 1L - pool->threads_used);
291 1.1.1.2 mrg #else
292 1.1.1.3 mrg gomp_mutex_lock (&gomp_managed_threads_lock);
293 1.1.1.2 mrg gomp_managed_threads -= pool->threads_used - 1L;
294 1.1.1.3 mrg gomp_mutex_unlock (&gomp_managed_threads_lock);
295 1.1.1.2 mrg #endif
296 1.1 mrg }
297 1.1 mrg if (pool->last_team)
298 1.1 mrg free_team (pool->last_team);
299 1.1.1.5 mrg #ifndef __nvptx__
300 1.1.1.10 mrg team_free (pool->threads);
301 1.1.1.10 mrg team_free (pool);
302 1.1.1.5 mrg #endif
303 1.1 mrg thr->thread_pool = NULL;
304 1.1 mrg }
305 1.1.1.4 mrg if (thr->ts.level == 0 && __builtin_expect (thr->ts.team != NULL, 0))
306 1.1.1.4 mrg gomp_team_end ();
307 1.1 mrg if (thr->task != NULL)
308 1.1 mrg {
309 1.1 mrg struct gomp_task *task = thr->task;
310 1.1 mrg gomp_end_task ();
311 1.1 mrg free (task);
312 1.1 mrg }
313 1.1 mrg }
314 1.1 mrg
315 1.1 mrg /* Launch a team. */
316 1.1 mrg
317 1.1.1.5 mrg #ifdef LIBGOMP_USE_PTHREADS
318 1.1 mrg void
319 1.1 mrg gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
320 1.1.1.9 mrg unsigned flags, struct gomp_team *team,
321 1.1.1.9 mrg struct gomp_taskgroup *taskgroup)
322 1.1 mrg {
323 1.1.1.11 mrg struct gomp_thread_start_data *start_data = NULL;
324 1.1 mrg struct gomp_thread *thr, *nthr;
325 1.1 mrg struct gomp_task *task;
326 1.1 mrg struct gomp_task_icv *icv;
327 1.1 mrg bool nested;
328 1.1 mrg struct gomp_thread_pool *pool;
329 1.1 mrg unsigned i, n, old_threads_used = 0;
330 1.1 mrg pthread_attr_t thread_attr, *attr;
331 1.1.1.2 mrg unsigned long nthreads_var;
332 1.1.1.3 mrg char bind, bind_var;
333 1.1.1.3 mrg unsigned int s = 0, rest = 0, p = 0, k = 0;
334 1.1.1.3 mrg unsigned int affinity_count = 0;
335 1.1.1.3 mrg struct gomp_thread **affinity_thr = NULL;
336 1.1.1.9 mrg bool force_display = false;
337 1.1 mrg
338 1.1 mrg thr = gomp_thread ();
339 1.1.1.4 mrg nested = thr->ts.level;
340 1.1 mrg pool = thr->thread_pool;
341 1.1 mrg task = thr->task;
342 1.1 mrg icv = task ? &task->icv : &gomp_global_icv;
343 1.1.1.3 mrg if (__builtin_expect (gomp_places_list != NULL, 0) && thr->place == 0)
344 1.1.1.9 mrg {
345 1.1.1.9 mrg gomp_init_affinity ();
346 1.1.1.9 mrg if (__builtin_expect (gomp_display_affinity_var, 0) && nthreads == 1)
347 1.1.1.9 mrg gomp_display_affinity_thread (gomp_thread_self (), &thr->ts,
348 1.1.1.9 mrg thr->place);
349 1.1.1.9 mrg }
350 1.1 mrg
351 1.1 mrg /* Always save the previous state, even if this isn't a nested team.
352 1.1 mrg In particular, we should save any work share state from an outer
353 1.1 mrg orphaned work share construct. */
354 1.1 mrg team->prev_ts = thr->ts;
355 1.1 mrg
356 1.1 mrg thr->ts.team = team;
357 1.1 mrg thr->ts.team_id = 0;
358 1.1 mrg ++thr->ts.level;
359 1.1 mrg if (nthreads > 1)
360 1.1 mrg ++thr->ts.active_level;
361 1.1 mrg thr->ts.work_share = &team->work_shares[0];
362 1.1 mrg thr->ts.last_work_share = NULL;
363 1.1 mrg #ifdef HAVE_SYNC_BUILTINS
364 1.1 mrg thr->ts.single_count = 0;
365 1.1 mrg #endif
366 1.1 mrg thr->ts.static_trip = 0;
367 1.1 mrg thr->task = &team->implicit_task[0];
368 1.1.1.9 mrg #ifdef GOMP_NEEDS_THREAD_HANDLE
369 1.1.1.9 mrg thr->handle = pthread_self ();
370 1.1.1.9 mrg #endif
371 1.1.1.2 mrg nthreads_var = icv->nthreads_var;
372 1.1.1.2 mrg if (__builtin_expect (gomp_nthreads_var_list != NULL, 0)
373 1.1.1.2 mrg && thr->ts.level < gomp_nthreads_var_list_len)
374 1.1.1.2 mrg nthreads_var = gomp_nthreads_var_list[thr->ts.level];
375 1.1.1.3 mrg bind_var = icv->bind_var;
376 1.1.1.3 mrg if (bind_var != omp_proc_bind_false && (flags & 7) != omp_proc_bind_false)
377 1.1.1.3 mrg bind_var = flags & 7;
378 1.1.1.3 mrg bind = bind_var;
379 1.1.1.3 mrg if (__builtin_expect (gomp_bind_var_list != NULL, 0)
380 1.1.1.3 mrg && thr->ts.level < gomp_bind_var_list_len)
381 1.1.1.3 mrg bind_var = gomp_bind_var_list[thr->ts.level];
382 1.1 mrg gomp_init_task (thr->task, task, icv);
383 1.1.1.9 mrg thr->task->taskgroup = taskgroup;
384 1.1.1.2 mrg team->implicit_task[0].icv.nthreads_var = nthreads_var;
385 1.1.1.3 mrg team->implicit_task[0].icv.bind_var = bind_var;
386 1.1 mrg
387 1.1 mrg if (nthreads == 1)
388 1.1 mrg return;
389 1.1 mrg
390 1.1 mrg i = 1;
391 1.1 mrg
392 1.1.1.3 mrg if (__builtin_expect (gomp_places_list != NULL, 0))
393 1.1.1.3 mrg {
394 1.1.1.3 mrg /* Depending on chosen proc_bind model, set subpartition
395 1.1.1.3 mrg for the master thread and initialize helper variables
396 1.1.1.3 mrg P and optionally S, K and/or REST used by later place
397 1.1.1.3 mrg computation for each additional thread. */
398 1.1.1.3 mrg p = thr->place - 1;
399 1.1.1.3 mrg switch (bind)
400 1.1.1.3 mrg {
401 1.1.1.3 mrg case omp_proc_bind_true:
402 1.1.1.3 mrg case omp_proc_bind_close:
403 1.1.1.3 mrg if (nthreads > thr->ts.place_partition_len)
404 1.1.1.3 mrg {
405 1.1.1.3 mrg /* T > P. S threads will be placed in each place,
406 1.1.1.3 mrg and the final REM threads placed one by one
407 1.1.1.3 mrg into the already occupied places. */
408 1.1.1.3 mrg s = nthreads / thr->ts.place_partition_len;
409 1.1.1.3 mrg rest = nthreads % thr->ts.place_partition_len;
410 1.1.1.3 mrg }
411 1.1.1.3 mrg else
412 1.1.1.3 mrg s = 1;
413 1.1.1.3 mrg k = 1;
414 1.1.1.3 mrg break;
415 1.1.1.3 mrg case omp_proc_bind_master:
416 1.1.1.3 mrg /* Each thread will be bound to master's place. */
417 1.1.1.3 mrg break;
418 1.1.1.3 mrg case omp_proc_bind_spread:
419 1.1.1.3 mrg if (nthreads <= thr->ts.place_partition_len)
420 1.1.1.3 mrg {
421 1.1.1.3 mrg /* T <= P. Each subpartition will have in between s
422 1.1.1.3 mrg and s+1 places (subpartitions starting at or
423 1.1.1.3 mrg after rest will have s places, earlier s+1 places),
424 1.1.1.3 mrg each thread will be bound to the first place in
425 1.1.1.3 mrg its subpartition (except for the master thread
426 1.1.1.3 mrg that can be bound to another place in its
427 1.1.1.3 mrg subpartition). */
428 1.1.1.3 mrg s = thr->ts.place_partition_len / nthreads;
429 1.1.1.3 mrg rest = thr->ts.place_partition_len % nthreads;
430 1.1.1.3 mrg rest = (s + 1) * rest + thr->ts.place_partition_off;
431 1.1.1.3 mrg if (p < rest)
432 1.1.1.3 mrg {
433 1.1.1.3 mrg p -= (p - thr->ts.place_partition_off) % (s + 1);
434 1.1.1.3 mrg thr->ts.place_partition_len = s + 1;
435 1.1.1.3 mrg }
436 1.1.1.3 mrg else
437 1.1.1.3 mrg {
438 1.1.1.3 mrg p -= (p - rest) % s;
439 1.1.1.3 mrg thr->ts.place_partition_len = s;
440 1.1.1.3 mrg }
441 1.1.1.3 mrg thr->ts.place_partition_off = p;
442 1.1.1.3 mrg }
443 1.1.1.3 mrg else
444 1.1.1.3 mrg {
445 1.1.1.3 mrg /* T > P. Each subpartition will have just a single
446 1.1.1.3 mrg place and we'll place between s and s+1
447 1.1.1.3 mrg threads into each subpartition. */
448 1.1.1.3 mrg s = nthreads / thr->ts.place_partition_len;
449 1.1.1.3 mrg rest = nthreads % thr->ts.place_partition_len;
450 1.1.1.3 mrg thr->ts.place_partition_off = p;
451 1.1.1.3 mrg thr->ts.place_partition_len = 1;
452 1.1.1.3 mrg k = 1;
453 1.1.1.3 mrg }
454 1.1.1.3 mrg break;
455 1.1.1.3 mrg }
456 1.1.1.3 mrg }
457 1.1.1.3 mrg else
458 1.1.1.3 mrg bind = omp_proc_bind_false;
459 1.1.1.3 mrg
460 1.1 mrg /* We only allow the reuse of idle threads for non-nested PARALLEL
461 1.1 mrg regions. This appears to be implied by the semantics of
462 1.1 mrg threadprivate variables, but perhaps that's reading too much into
463 1.1 mrg things. Certainly it does prevent any locking problems, since
464 1.1 mrg only the initial program thread will modify gomp_threads. */
465 1.1 mrg if (!nested)
466 1.1 mrg {
467 1.1 mrg old_threads_used = pool->threads_used;
468 1.1 mrg
469 1.1 mrg if (nthreads <= old_threads_used)
470 1.1 mrg n = nthreads;
471 1.1 mrg else if (old_threads_used == 0)
472 1.1 mrg {
473 1.1 mrg n = 0;
474 1.1.1.5 mrg gomp_simple_barrier_init (&pool->threads_dock, nthreads);
475 1.1 mrg }
476 1.1 mrg else
477 1.1 mrg {
478 1.1 mrg n = old_threads_used;
479 1.1 mrg
480 1.1 mrg /* Increase the barrier threshold to make sure all new
481 1.1 mrg threads arrive before the team is released. */
482 1.1.1.5 mrg gomp_simple_barrier_reinit (&pool->threads_dock, nthreads);
483 1.1 mrg }
484 1.1 mrg
485 1.1 mrg /* Not true yet, but soon will be. We're going to release all
486 1.1 mrg threads from the dock, and those that aren't part of the
487 1.1 mrg team will exit. */
488 1.1 mrg pool->threads_used = nthreads;
489 1.1 mrg
490 1.1.1.3 mrg /* If necessary, expand the size of the gomp_threads array. It is
491 1.1.1.3 mrg expected that changes in the number of threads are rare, thus we
492 1.1.1.3 mrg make no effort to expand gomp_threads_size geometrically. */
493 1.1.1.3 mrg if (nthreads >= pool->threads_size)
494 1.1.1.3 mrg {
495 1.1.1.3 mrg pool->threads_size = nthreads + 1;
496 1.1.1.3 mrg pool->threads
497 1.1.1.3 mrg = gomp_realloc (pool->threads,
498 1.1.1.3 mrg pool->threads_size
499 1.1.1.9 mrg * sizeof (struct gomp_thread *));
500 1.1.1.9 mrg /* Add current (master) thread to threads[]. */
501 1.1.1.9 mrg pool->threads[0] = thr;
502 1.1.1.3 mrg }
503 1.1.1.3 mrg
504 1.1 mrg /* Release existing idle threads. */
505 1.1 mrg for (; i < n; ++i)
506 1.1 mrg {
507 1.1.1.3 mrg unsigned int place_partition_off = thr->ts.place_partition_off;
508 1.1.1.3 mrg unsigned int place_partition_len = thr->ts.place_partition_len;
509 1.1.1.3 mrg unsigned int place = 0;
510 1.1.1.3 mrg if (__builtin_expect (gomp_places_list != NULL, 0))
511 1.1.1.3 mrg {
512 1.1.1.3 mrg switch (bind)
513 1.1.1.3 mrg {
514 1.1.1.3 mrg case omp_proc_bind_true:
515 1.1.1.3 mrg case omp_proc_bind_close:
516 1.1.1.3 mrg if (k == s)
517 1.1.1.3 mrg {
518 1.1.1.3 mrg ++p;
519 1.1.1.3 mrg if (p == (team->prev_ts.place_partition_off
520 1.1.1.3 mrg + team->prev_ts.place_partition_len))
521 1.1.1.3 mrg p = team->prev_ts.place_partition_off;
522 1.1.1.3 mrg k = 1;
523 1.1.1.3 mrg if (i == nthreads - rest)
524 1.1.1.3 mrg s = 1;
525 1.1.1.3 mrg }
526 1.1.1.3 mrg else
527 1.1.1.3 mrg ++k;
528 1.1.1.3 mrg break;
529 1.1.1.3 mrg case omp_proc_bind_master:
530 1.1.1.3 mrg break;
531 1.1.1.3 mrg case omp_proc_bind_spread:
532 1.1.1.3 mrg if (k == 0)
533 1.1.1.3 mrg {
534 1.1.1.3 mrg /* T <= P. */
535 1.1.1.3 mrg if (p < rest)
536 1.1.1.3 mrg p += s + 1;
537 1.1.1.3 mrg else
538 1.1.1.3 mrg p += s;
539 1.1.1.3 mrg if (p == (team->prev_ts.place_partition_off
540 1.1.1.3 mrg + team->prev_ts.place_partition_len))
541 1.1.1.3 mrg p = team->prev_ts.place_partition_off;
542 1.1.1.3 mrg place_partition_off = p;
543 1.1.1.3 mrg if (p < rest)
544 1.1.1.3 mrg place_partition_len = s + 1;
545 1.1.1.3 mrg else
546 1.1.1.3 mrg place_partition_len = s;
547 1.1.1.3 mrg }
548 1.1.1.3 mrg else
549 1.1.1.3 mrg {
550 1.1.1.3 mrg /* T > P. */
551 1.1.1.3 mrg if (k == s)
552 1.1.1.3 mrg {
553 1.1.1.3 mrg ++p;
554 1.1.1.3 mrg if (p == (team->prev_ts.place_partition_off
555 1.1.1.3 mrg + team->prev_ts.place_partition_len))
556 1.1.1.3 mrg p = team->prev_ts.place_partition_off;
557 1.1.1.3 mrg k = 1;
558 1.1.1.3 mrg if (i == nthreads - rest)
559 1.1.1.3 mrg s = 1;
560 1.1.1.3 mrg }
561 1.1.1.3 mrg else
562 1.1.1.3 mrg ++k;
563 1.1.1.3 mrg place_partition_off = p;
564 1.1.1.3 mrg place_partition_len = 1;
565 1.1.1.3 mrg }
566 1.1.1.3 mrg break;
567 1.1.1.3 mrg }
568 1.1.1.3 mrg if (affinity_thr != NULL
569 1.1.1.3 mrg || (bind != omp_proc_bind_true
570 1.1.1.3 mrg && pool->threads[i]->place != p + 1)
571 1.1.1.3 mrg || pool->threads[i]->place <= place_partition_off
572 1.1.1.3 mrg || pool->threads[i]->place > (place_partition_off
573 1.1.1.3 mrg + place_partition_len))
574 1.1.1.3 mrg {
575 1.1.1.3 mrg unsigned int l;
576 1.1.1.9 mrg force_display = true;
577 1.1.1.3 mrg if (affinity_thr == NULL)
578 1.1.1.3 mrg {
579 1.1.1.3 mrg unsigned int j;
580 1.1.1.3 mrg
581 1.1.1.3 mrg if (team->prev_ts.place_partition_len > 64)
582 1.1.1.3 mrg affinity_thr
583 1.1.1.3 mrg = gomp_malloc (team->prev_ts.place_partition_len
584 1.1.1.3 mrg * sizeof (struct gomp_thread *));
585 1.1.1.3 mrg else
586 1.1.1.3 mrg affinity_thr
587 1.1.1.3 mrg = gomp_alloca (team->prev_ts.place_partition_len
588 1.1.1.3 mrg * sizeof (struct gomp_thread *));
589 1.1.1.3 mrg memset (affinity_thr, '\0',
590 1.1.1.3 mrg team->prev_ts.place_partition_len
591 1.1.1.3 mrg * sizeof (struct gomp_thread *));
592 1.1.1.3 mrg for (j = i; j < old_threads_used; j++)
593 1.1.1.3 mrg {
594 1.1.1.3 mrg if (pool->threads[j]->place
595 1.1.1.3 mrg > team->prev_ts.place_partition_off
596 1.1.1.3 mrg && (pool->threads[j]->place
597 1.1.1.3 mrg <= (team->prev_ts.place_partition_off
598 1.1.1.3 mrg + team->prev_ts.place_partition_len)))
599 1.1.1.3 mrg {
600 1.1.1.3 mrg l = pool->threads[j]->place - 1
601 1.1.1.3 mrg - team->prev_ts.place_partition_off;
602 1.1.1.3 mrg pool->threads[j]->data = affinity_thr[l];
603 1.1.1.3 mrg affinity_thr[l] = pool->threads[j];
604 1.1.1.3 mrg }
605 1.1.1.3 mrg pool->threads[j] = NULL;
606 1.1.1.3 mrg }
607 1.1.1.3 mrg if (nthreads > old_threads_used)
608 1.1.1.3 mrg memset (&pool->threads[old_threads_used],
609 1.1.1.3 mrg '\0', ((nthreads - old_threads_used)
610 1.1.1.3 mrg * sizeof (struct gomp_thread *)));
611 1.1.1.3 mrg n = nthreads;
612 1.1.1.3 mrg affinity_count = old_threads_used - i;
613 1.1.1.3 mrg }
614 1.1.1.3 mrg if (affinity_count == 0)
615 1.1.1.3 mrg break;
616 1.1.1.3 mrg l = p;
617 1.1.1.3 mrg if (affinity_thr[l - team->prev_ts.place_partition_off]
618 1.1.1.3 mrg == NULL)
619 1.1.1.3 mrg {
620 1.1.1.3 mrg if (bind != omp_proc_bind_true)
621 1.1.1.3 mrg continue;
622 1.1.1.3 mrg for (l = place_partition_off;
623 1.1.1.3 mrg l < place_partition_off + place_partition_len;
624 1.1.1.3 mrg l++)
625 1.1.1.3 mrg if (affinity_thr[l - team->prev_ts.place_partition_off]
626 1.1.1.3 mrg != NULL)
627 1.1.1.3 mrg break;
628 1.1.1.3 mrg if (l == place_partition_off + place_partition_len)
629 1.1.1.3 mrg continue;
630 1.1.1.3 mrg }
631 1.1.1.3 mrg nthr = affinity_thr[l - team->prev_ts.place_partition_off];
632 1.1.1.3 mrg affinity_thr[l - team->prev_ts.place_partition_off]
633 1.1.1.3 mrg = (struct gomp_thread *) nthr->data;
634 1.1.1.3 mrg affinity_count--;
635 1.1.1.3 mrg pool->threads[i] = nthr;
636 1.1.1.3 mrg }
637 1.1.1.3 mrg else
638 1.1.1.3 mrg nthr = pool->threads[i];
639 1.1.1.3 mrg place = p + 1;
640 1.1.1.3 mrg }
641 1.1.1.3 mrg else
642 1.1.1.3 mrg nthr = pool->threads[i];
643 1.1 mrg nthr->ts.team = team;
644 1.1 mrg nthr->ts.work_share = &team->work_shares[0];
645 1.1 mrg nthr->ts.last_work_share = NULL;
646 1.1 mrg nthr->ts.team_id = i;
647 1.1 mrg nthr->ts.level = team->prev_ts.level + 1;
648 1.1 mrg nthr->ts.active_level = thr->ts.active_level;
649 1.1.1.3 mrg nthr->ts.place_partition_off = place_partition_off;
650 1.1.1.3 mrg nthr->ts.place_partition_len = place_partition_len;
651 1.1.1.11 mrg nthr->ts.def_allocator = thr->ts.def_allocator;
652 1.1 mrg #ifdef HAVE_SYNC_BUILTINS
653 1.1 mrg nthr->ts.single_count = 0;
654 1.1 mrg #endif
655 1.1 mrg nthr->ts.static_trip = 0;
656 1.1.1.11 mrg nthr->num_teams = thr->num_teams;
657 1.1.1.11 mrg nthr->team_num = thr->team_num;
658 1.1 mrg nthr->task = &team->implicit_task[i];
659 1.1.1.3 mrg nthr->place = place;
660 1.1 mrg gomp_init_task (nthr->task, task, icv);
661 1.1.1.2 mrg team->implicit_task[i].icv.nthreads_var = nthreads_var;
662 1.1.1.3 mrg team->implicit_task[i].icv.bind_var = bind_var;
663 1.1.1.9 mrg nthr->task->taskgroup = taskgroup;
664 1.1 mrg nthr->fn = fn;
665 1.1 mrg nthr->data = data;
666 1.1 mrg team->ordered_release[i] = &nthr->release;
667 1.1 mrg }
668 1.1 mrg
669 1.1.1.3 mrg if (__builtin_expect (affinity_thr != NULL, 0))
670 1.1.1.3 mrg {
671 1.1.1.3 mrg /* If AFFINITY_THR is non-NULL just because we had to
672 1.1.1.3 mrg permute some threads in the pool, but we've managed
673 1.1.1.3 mrg to find exactly as many old threads as we'd find
674 1.1.1.3 mrg without affinity, we don't need to handle this
675 1.1.1.3 mrg specially anymore. */
676 1.1.1.3 mrg if (nthreads <= old_threads_used
677 1.1.1.3 mrg ? (affinity_count == old_threads_used - nthreads)
678 1.1.1.3 mrg : (i == old_threads_used))
679 1.1.1.3 mrg {
680 1.1.1.3 mrg if (team->prev_ts.place_partition_len > 64)
681 1.1.1.3 mrg free (affinity_thr);
682 1.1.1.3 mrg affinity_thr = NULL;
683 1.1.1.3 mrg affinity_count = 0;
684 1.1.1.3 mrg }
685 1.1.1.3 mrg else
686 1.1.1.3 mrg {
687 1.1.1.3 mrg i = 1;
688 1.1.1.3 mrg /* We are going to compute the places/subpartitions
689 1.1.1.3 mrg again from the beginning. So, we need to reinitialize
690 1.1.1.3 mrg vars modified by the switch (bind) above inside
691 1.1.1.3 mrg of the loop, to the state they had after the initial
692 1.1.1.3 mrg switch (bind). */
693 1.1.1.3 mrg switch (bind)
694 1.1.1.3 mrg {
695 1.1.1.3 mrg case omp_proc_bind_true:
696 1.1.1.3 mrg case omp_proc_bind_close:
697 1.1.1.3 mrg if (nthreads > thr->ts.place_partition_len)
698 1.1.1.3 mrg /* T > P. S has been changed, so needs
699 1.1.1.3 mrg to be recomputed. */
700 1.1.1.3 mrg s = nthreads / thr->ts.place_partition_len;
701 1.1.1.3 mrg k = 1;
702 1.1.1.3 mrg p = thr->place - 1;
703 1.1.1.3 mrg break;
704 1.1.1.3 mrg case omp_proc_bind_master:
705 1.1.1.3 mrg /* No vars have been changed. */
706 1.1.1.3 mrg break;
707 1.1.1.3 mrg case omp_proc_bind_spread:
708 1.1.1.3 mrg p = thr->ts.place_partition_off;
709 1.1.1.3 mrg if (k != 0)
710 1.1.1.3 mrg {
711 1.1.1.3 mrg /* T > P. */
712 1.1.1.3 mrg s = nthreads / team->prev_ts.place_partition_len;
713 1.1.1.3 mrg k = 1;
714 1.1.1.3 mrg }
715 1.1.1.3 mrg break;
716 1.1.1.3 mrg }
717 1.1.1.3 mrg
718 1.1.1.3 mrg /* Increase the barrier threshold to make sure all new
719 1.1.1.3 mrg threads and all the threads we're going to let die
720 1.1.1.3 mrg arrive before the team is released. */
721 1.1.1.3 mrg if (affinity_count)
722 1.1.1.5 mrg gomp_simple_barrier_reinit (&pool->threads_dock,
723 1.1.1.5 mrg nthreads + affinity_count);
724 1.1.1.3 mrg }
725 1.1.1.3 mrg }
726 1.1.1.3 mrg
727 1.1 mrg if (i == nthreads)
728 1.1 mrg goto do_release;
729 1.1 mrg
730 1.1 mrg }
731 1.1 mrg
732 1.1.1.3 mrg if (__builtin_expect (nthreads + affinity_count > old_threads_used, 0))
733 1.1 mrg {
734 1.1.1.3 mrg long diff = (long) (nthreads + affinity_count) - (long) old_threads_used;
735 1.1 mrg
736 1.1 mrg if (old_threads_used == 0)
737 1.1 mrg --diff;
738 1.1 mrg
739 1.1 mrg #ifdef HAVE_SYNC_BUILTINS
740 1.1 mrg __sync_fetch_and_add (&gomp_managed_threads, diff);
741 1.1 mrg #else
742 1.1.1.3 mrg gomp_mutex_lock (&gomp_managed_threads_lock);
743 1.1 mrg gomp_managed_threads += diff;
744 1.1.1.3 mrg gomp_mutex_unlock (&gomp_managed_threads_lock);
745 1.1 mrg #endif
746 1.1 mrg }
747 1.1 mrg
748 1.1 mrg attr = &gomp_thread_attr;
749 1.1.1.3 mrg if (__builtin_expect (gomp_places_list != NULL, 0))
750 1.1 mrg {
751 1.1 mrg size_t stacksize;
752 1.1 mrg pthread_attr_init (&thread_attr);
753 1.1 mrg if (! pthread_attr_getstacksize (&gomp_thread_attr, &stacksize))
754 1.1 mrg pthread_attr_setstacksize (&thread_attr, stacksize);
755 1.1 mrg attr = &thread_attr;
756 1.1 mrg }
757 1.1 mrg
758 1.1.1.12 mrg if (i >= nthreads)
759 1.1.1.12 mrg __builtin_unreachable ();
760 1.1 mrg start_data = gomp_alloca (sizeof (struct gomp_thread_start_data)
761 1.1.1.9 mrg * (nthreads - i));
762 1.1 mrg
763 1.1 mrg /* Launch new threads. */
764 1.1.1.3 mrg for (; i < nthreads; ++i)
765 1.1 mrg {
766 1.1 mrg int err;
767 1.1 mrg
768 1.1.1.3 mrg start_data->ts.place_partition_off = thr->ts.place_partition_off;
769 1.1.1.3 mrg start_data->ts.place_partition_len = thr->ts.place_partition_len;
770 1.1.1.3 mrg start_data->place = 0;
771 1.1.1.3 mrg if (__builtin_expect (gomp_places_list != NULL, 0))
772 1.1.1.3 mrg {
773 1.1.1.3 mrg switch (bind)
774 1.1.1.3 mrg {
775 1.1.1.3 mrg case omp_proc_bind_true:
776 1.1.1.3 mrg case omp_proc_bind_close:
777 1.1.1.3 mrg if (k == s)
778 1.1.1.3 mrg {
779 1.1.1.3 mrg ++p;
780 1.1.1.3 mrg if (p == (team->prev_ts.place_partition_off
781 1.1.1.3 mrg + team->prev_ts.place_partition_len))
782 1.1.1.3 mrg p = team->prev_ts.place_partition_off;
783 1.1.1.3 mrg k = 1;
784 1.1.1.3 mrg if (i == nthreads - rest)
785 1.1.1.3 mrg s = 1;
786 1.1.1.3 mrg }
787 1.1.1.3 mrg else
788 1.1.1.3 mrg ++k;
789 1.1.1.3 mrg break;
790 1.1.1.3 mrg case omp_proc_bind_master:
791 1.1.1.3 mrg break;
792 1.1.1.3 mrg case omp_proc_bind_spread:
793 1.1.1.3 mrg if (k == 0)
794 1.1.1.3 mrg {
795 1.1.1.3 mrg /* T <= P. */
796 1.1.1.3 mrg if (p < rest)
797 1.1.1.3 mrg p += s + 1;
798 1.1.1.3 mrg else
799 1.1.1.3 mrg p += s;
800 1.1.1.3 mrg if (p == (team->prev_ts.place_partition_off
801 1.1.1.3 mrg + team->prev_ts.place_partition_len))
802 1.1.1.3 mrg p = team->prev_ts.place_partition_off;
803 1.1.1.3 mrg start_data->ts.place_partition_off = p;
804 1.1.1.3 mrg if (p < rest)
805 1.1.1.3 mrg start_data->ts.place_partition_len = s + 1;
806 1.1.1.3 mrg else
807 1.1.1.3 mrg start_data->ts.place_partition_len = s;
808 1.1.1.3 mrg }
809 1.1.1.3 mrg else
810 1.1.1.3 mrg {
811 1.1.1.3 mrg /* T > P. */
812 1.1.1.3 mrg if (k == s)
813 1.1.1.3 mrg {
814 1.1.1.3 mrg ++p;
815 1.1.1.3 mrg if (p == (team->prev_ts.place_partition_off
816 1.1.1.3 mrg + team->prev_ts.place_partition_len))
817 1.1.1.3 mrg p = team->prev_ts.place_partition_off;
818 1.1.1.3 mrg k = 1;
819 1.1.1.3 mrg if (i == nthreads - rest)
820 1.1.1.3 mrg s = 1;
821 1.1.1.3 mrg }
822 1.1.1.3 mrg else
823 1.1.1.3 mrg ++k;
824 1.1.1.3 mrg start_data->ts.place_partition_off = p;
825 1.1.1.3 mrg start_data->ts.place_partition_len = 1;
826 1.1.1.3 mrg }
827 1.1.1.3 mrg break;
828 1.1.1.3 mrg }
829 1.1.1.3 mrg start_data->place = p + 1;
830 1.1.1.3 mrg if (affinity_thr != NULL && pool->threads[i] != NULL)
831 1.1.1.3 mrg continue;
832 1.1.1.3 mrg gomp_init_thread_affinity (attr, p);
833 1.1.1.3 mrg }
834 1.1.1.3 mrg
835 1.1 mrg start_data->fn = fn;
836 1.1 mrg start_data->fn_data = data;
837 1.1 mrg start_data->ts.team = team;
838 1.1 mrg start_data->ts.work_share = &team->work_shares[0];
839 1.1 mrg start_data->ts.last_work_share = NULL;
840 1.1 mrg start_data->ts.team_id = i;
841 1.1 mrg start_data->ts.level = team->prev_ts.level + 1;
842 1.1 mrg start_data->ts.active_level = thr->ts.active_level;
843 1.1.1.11 mrg start_data->ts.def_allocator = thr->ts.def_allocator;
844 1.1 mrg #ifdef HAVE_SYNC_BUILTINS
845 1.1 mrg start_data->ts.single_count = 0;
846 1.1 mrg #endif
847 1.1 mrg start_data->ts.static_trip = 0;
848 1.1.1.11 mrg start_data->num_teams = thr->num_teams;
849 1.1.1.11 mrg start_data->team_num = thr->team_num;
850 1.1 mrg start_data->task = &team->implicit_task[i];
851 1.1 mrg gomp_init_task (start_data->task, task, icv);
852 1.1.1.2 mrg team->implicit_task[i].icv.nthreads_var = nthreads_var;
853 1.1.1.3 mrg team->implicit_task[i].icv.bind_var = bind_var;
854 1.1.1.9 mrg start_data->task->taskgroup = taskgroup;
855 1.1 mrg start_data->thread_pool = pool;
856 1.1 mrg start_data->nested = nested;
857 1.1 mrg
858 1.1.1.4 mrg attr = gomp_adjust_thread_attr (attr, &thread_attr);
859 1.1.1.9 mrg err = pthread_create (&start_data->handle, attr, gomp_thread_start,
860 1.1.1.9 mrg start_data);
861 1.1.1.9 mrg start_data++;
862 1.1 mrg if (err != 0)
863 1.1 mrg gomp_fatal ("Thread creation failed: %s", strerror (err));
864 1.1 mrg }
865 1.1 mrg
866 1.1.1.4 mrg if (__builtin_expect (attr == &thread_attr, 0))
867 1.1 mrg pthread_attr_destroy (&thread_attr);
868 1.1 mrg
869 1.1 mrg do_release:
870 1.1.1.5 mrg if (nested)
871 1.1.1.5 mrg gomp_barrier_wait (&team->barrier);
872 1.1.1.5 mrg else
873 1.1.1.5 mrg gomp_simple_barrier_wait (&pool->threads_dock);
874 1.1 mrg
875 1.1 mrg /* Decrease the barrier threshold to match the number of threads
876 1.1 mrg that should arrive back at the end of this team. The extra
877 1.1 mrg threads should be exiting. Note that we arrange for this test
878 1.1.1.3 mrg to never be true for nested teams. If AFFINITY_COUNT is non-zero,
879 1.1.1.3 mrg the barrier as well as gomp_managed_threads was temporarily
880 1.1.1.3 mrg set to NTHREADS + AFFINITY_COUNT. For NTHREADS < OLD_THREADS_COUNT,
881 1.1.1.3 mrg AFFINITY_COUNT if non-zero will be always at least
882 1.1.1.3 mrg OLD_THREADS_COUNT - NTHREADS. */
883 1.1.1.3 mrg if (__builtin_expect (nthreads < old_threads_used, 0)
884 1.1.1.3 mrg || __builtin_expect (affinity_count, 0))
885 1.1 mrg {
886 1.1 mrg long diff = (long) nthreads - (long) old_threads_used;
887 1.1 mrg
888 1.1.1.3 mrg if (affinity_count)
889 1.1.1.3 mrg diff = -affinity_count;
890 1.1.1.3 mrg
891 1.1.1.5 mrg gomp_simple_barrier_reinit (&pool->threads_dock, nthreads);
892 1.1 mrg
893 1.1 mrg #ifdef HAVE_SYNC_BUILTINS
894 1.1 mrg __sync_fetch_and_add (&gomp_managed_threads, diff);
895 1.1 mrg #else
896 1.1.1.3 mrg gomp_mutex_lock (&gomp_managed_threads_lock);
897 1.1 mrg gomp_managed_threads += diff;
898 1.1.1.3 mrg gomp_mutex_unlock (&gomp_managed_threads_lock);
899 1.1 mrg #endif
900 1.1 mrg }
901 1.1.1.9 mrg if (__builtin_expect (gomp_display_affinity_var, 0))
902 1.1.1.9 mrg {
903 1.1.1.9 mrg if (nested
904 1.1.1.9 mrg || nthreads != old_threads_used
905 1.1.1.9 mrg || force_display)
906 1.1.1.9 mrg {
907 1.1.1.9 mrg gomp_display_affinity_thread (gomp_thread_self (), &thr->ts,
908 1.1.1.9 mrg thr->place);
909 1.1.1.9 mrg if (nested)
910 1.1.1.9 mrg {
911 1.1.1.9 mrg start_data -= nthreads - 1;
912 1.1.1.9 mrg for (i = 1; i < nthreads; ++i)
913 1.1.1.9 mrg {
914 1.1.1.9 mrg gomp_display_affinity_thread (
915 1.1.1.9 mrg #ifdef LIBGOMP_USE_PTHREADS
916 1.1.1.9 mrg start_data->handle,
917 1.1.1.9 mrg #else
918 1.1.1.9 mrg gomp_thread_self (),
919 1.1.1.9 mrg #endif
920 1.1.1.9 mrg &start_data->ts,
921 1.1.1.9 mrg start_data->place);
922 1.1.1.9 mrg start_data++;
923 1.1.1.9 mrg }
924 1.1.1.9 mrg }
925 1.1.1.9 mrg else
926 1.1.1.9 mrg {
927 1.1.1.9 mrg for (i = 1; i < nthreads; ++i)
928 1.1.1.9 mrg {
929 1.1.1.9 mrg gomp_thread_handle handle
930 1.1.1.9 mrg = gomp_thread_to_pthread_t (pool->threads[i]);
931 1.1.1.9 mrg gomp_display_affinity_thread (handle, &pool->threads[i]->ts,
932 1.1.1.9 mrg pool->threads[i]->place);
933 1.1.1.9 mrg }
934 1.1.1.9 mrg }
935 1.1.1.9 mrg }
936 1.1.1.9 mrg }
937 1.1.1.3 mrg if (__builtin_expect (affinity_thr != NULL, 0)
938 1.1.1.3 mrg && team->prev_ts.place_partition_len > 64)
939 1.1.1.3 mrg free (affinity_thr);
940 1.1 mrg }
941 1.1.1.5 mrg #endif
942 1.1 mrg
943 1.1 mrg
944 1.1 mrg /* Terminate the current team. This is only to be called by the master
945 1.1 mrg thread. We assume that we must wait for the other threads. */
946 1.1 mrg
947 1.1 mrg void
948 1.1 mrg gomp_team_end (void)
949 1.1 mrg {
950 1.1 mrg struct gomp_thread *thr = gomp_thread ();
951 1.1 mrg struct gomp_team *team = thr->ts.team;
952 1.1 mrg
953 1.1.1.3 mrg /* This barrier handles all pending explicit threads.
954 1.1.1.3 mrg As #pragma omp cancel parallel might get awaited count in
955 1.1.1.3 mrg team->barrier in a inconsistent state, we need to use a different
956 1.1.1.3 mrg counter here. */
957 1.1.1.3 mrg gomp_team_barrier_wait_final (&team->barrier);
958 1.1.1.3 mrg if (__builtin_expect (team->team_cancelled, 0))
959 1.1.1.3 mrg {
960 1.1.1.3 mrg struct gomp_work_share *ws = team->work_shares_to_free;
961 1.1.1.3 mrg do
962 1.1.1.3 mrg {
963 1.1.1.3 mrg struct gomp_work_share *next_ws = gomp_ptrlock_get (&ws->next_ws);
964 1.1.1.3 mrg if (next_ws == NULL)
965 1.1.1.3 mrg gomp_ptrlock_set (&ws->next_ws, ws);
966 1.1.1.3 mrg gomp_fini_work_share (ws);
967 1.1.1.3 mrg ws = next_ws;
968 1.1.1.3 mrg }
969 1.1.1.3 mrg while (ws != NULL);
970 1.1.1.3 mrg }
971 1.1.1.3 mrg else
972 1.1.1.3 mrg gomp_fini_work_share (thr->ts.work_share);
973 1.1 mrg
974 1.1 mrg gomp_end_task ();
975 1.1 mrg thr->ts = team->prev_ts;
976 1.1 mrg
977 1.1.1.9 mrg if (__builtin_expect (thr->ts.level != 0, 0))
978 1.1 mrg {
979 1.1 mrg #ifdef HAVE_SYNC_BUILTINS
980 1.1 mrg __sync_fetch_and_add (&gomp_managed_threads, 1L - team->nthreads);
981 1.1 mrg #else
982 1.1.1.3 mrg gomp_mutex_lock (&gomp_managed_threads_lock);
983 1.1 mrg gomp_managed_threads -= team->nthreads - 1L;
984 1.1.1.3 mrg gomp_mutex_unlock (&gomp_managed_threads_lock);
985 1.1 mrg #endif
986 1.1 mrg /* This barrier has gomp_barrier_wait_last counterparts
987 1.1 mrg and ensures the team can be safely destroyed. */
988 1.1 mrg gomp_barrier_wait (&team->barrier);
989 1.1 mrg }
990 1.1 mrg
991 1.1 mrg if (__builtin_expect (team->work_shares[0].next_alloc != NULL, 0))
992 1.1 mrg {
993 1.1 mrg struct gomp_work_share *ws = team->work_shares[0].next_alloc;
994 1.1 mrg do
995 1.1 mrg {
996 1.1 mrg struct gomp_work_share *next_ws = ws->next_alloc;
997 1.1 mrg free (ws);
998 1.1 mrg ws = next_ws;
999 1.1 mrg }
1000 1.1 mrg while (ws != NULL);
1001 1.1 mrg }
1002 1.1 mrg gomp_sem_destroy (&team->master_release);
1003 1.1 mrg
1004 1.1 mrg if (__builtin_expect (thr->ts.team != NULL, 0)
1005 1.1 mrg || __builtin_expect (team->nthreads == 1, 0))
1006 1.1 mrg free_team (team);
1007 1.1 mrg else
1008 1.1 mrg {
1009 1.1 mrg struct gomp_thread_pool *pool = thr->thread_pool;
1010 1.1 mrg if (pool->last_team)
1011 1.1 mrg free_team (pool->last_team);
1012 1.1 mrg pool->last_team = team;
1013 1.1.1.4 mrg gomp_release_thread_pool (pool);
1014 1.1 mrg }
1015 1.1 mrg }
1016 1.1 mrg
1017 1.1.1.5 mrg #ifdef LIBGOMP_USE_PTHREADS
1018 1.1 mrg
1019 1.1 mrg /* Constructors for this file. */
1020 1.1 mrg
1021 1.1 mrg static void __attribute__((constructor))
1022 1.1 mrg initialize_team (void)
1023 1.1 mrg {
1024 1.1.1.3 mrg #if !defined HAVE_TLS && !defined USE_EMUTLS
1025 1.1 mrg static struct gomp_thread initial_thread_tls_data;
1026 1.1 mrg
1027 1.1 mrg pthread_key_create (&gomp_tls_key, NULL);
1028 1.1 mrg pthread_setspecific (gomp_tls_key, &initial_thread_tls_data);
1029 1.1 mrg #endif
1030 1.1 mrg
1031 1.1 mrg if (pthread_key_create (&gomp_thread_destructor, gomp_free_thread) != 0)
1032 1.1 mrg gomp_fatal ("could not create thread pool destructor.");
1033 1.1 mrg }
1034 1.1 mrg
1035 1.1 mrg static void __attribute__((destructor))
1036 1.1 mrg team_destructor (void)
1037 1.1 mrg {
1038 1.1 mrg /* Without this dlclose on libgomp could lead to subsequent
1039 1.1 mrg crashes. */
1040 1.1 mrg pthread_key_delete (gomp_thread_destructor);
1041 1.1 mrg }
1042 1.1.1.9 mrg
1043 1.1.1.9 mrg /* Similar to gomp_free_pool_helper, but don't detach itself,
1044 1.1.1.9 mrg gomp_pause_host will pthread_join those threads. */
1045 1.1.1.9 mrg
1046 1.1.1.9 mrg static void
1047 1.1.1.9 mrg gomp_pause_pool_helper (void *thread_pool)
1048 1.1.1.9 mrg {
1049 1.1.1.9 mrg struct gomp_thread *thr = gomp_thread ();
1050 1.1.1.9 mrg struct gomp_thread_pool *pool
1051 1.1.1.9 mrg = (struct gomp_thread_pool *) thread_pool;
1052 1.1.1.9 mrg gomp_simple_barrier_wait_last (&pool->threads_dock);
1053 1.1.1.9 mrg gomp_sem_destroy (&thr->release);
1054 1.1.1.9 mrg thr->thread_pool = NULL;
1055 1.1.1.9 mrg thr->task = NULL;
1056 1.1.1.9 mrg pthread_exit (NULL);
1057 1.1.1.9 mrg }
1058 1.1.1.9 mrg
1059 1.1.1.9 mrg /* Free a thread pool and release its threads. Return non-zero on
1060 1.1.1.9 mrg failure. */
1061 1.1.1.9 mrg
1062 1.1.1.9 mrg int
1063 1.1.1.9 mrg gomp_pause_host (void)
1064 1.1.1.9 mrg {
1065 1.1.1.9 mrg struct gomp_thread *thr = gomp_thread ();
1066 1.1.1.9 mrg struct gomp_thread_pool *pool = thr->thread_pool;
1067 1.1.1.9 mrg if (thr->ts.level)
1068 1.1.1.9 mrg return -1;
1069 1.1.1.9 mrg if (pool)
1070 1.1.1.9 mrg {
1071 1.1.1.9 mrg if (pool->threads_used > 0)
1072 1.1.1.9 mrg {
1073 1.1.1.9 mrg int i;
1074 1.1.1.9 mrg pthread_t *thrs
1075 1.1.1.9 mrg = gomp_alloca (sizeof (pthread_t) * pool->threads_used);
1076 1.1.1.9 mrg for (i = 1; i < pool->threads_used; i++)
1077 1.1.1.9 mrg {
1078 1.1.1.9 mrg struct gomp_thread *nthr = pool->threads[i];
1079 1.1.1.9 mrg nthr->fn = gomp_pause_pool_helper;
1080 1.1.1.9 mrg nthr->data = pool;
1081 1.1.1.9 mrg thrs[i] = gomp_thread_to_pthread_t (nthr);
1082 1.1.1.9 mrg }
1083 1.1.1.9 mrg /* This barrier undocks threads docked on pool->threads_dock. */
1084 1.1.1.9 mrg gomp_simple_barrier_wait (&pool->threads_dock);
1085 1.1.1.9 mrg /* And this waits till all threads have called gomp_barrier_wait_last
1086 1.1.1.9 mrg in gomp_pause_pool_helper. */
1087 1.1.1.9 mrg gomp_simple_barrier_wait (&pool->threads_dock);
1088 1.1.1.9 mrg /* Now it is safe to destroy the barrier and free the pool. */
1089 1.1.1.9 mrg gomp_simple_barrier_destroy (&pool->threads_dock);
1090 1.1.1.9 mrg
1091 1.1.1.9 mrg #ifdef HAVE_SYNC_BUILTINS
1092 1.1.1.9 mrg __sync_fetch_and_add (&gomp_managed_threads,
1093 1.1.1.9 mrg 1L - pool->threads_used);
1094 1.1.1.9 mrg #else
1095 1.1.1.9 mrg gomp_mutex_lock (&gomp_managed_threads_lock);
1096 1.1.1.9 mrg gomp_managed_threads -= pool->threads_used - 1L;
1097 1.1.1.9 mrg gomp_mutex_unlock (&gomp_managed_threads_lock);
1098 1.1.1.9 mrg #endif
1099 1.1.1.9 mrg for (i = 1; i < pool->threads_used; i++)
1100 1.1.1.9 mrg pthread_join (thrs[i], NULL);
1101 1.1.1.9 mrg }
1102 1.1.1.9 mrg if (pool->last_team)
1103 1.1.1.9 mrg free_team (pool->last_team);
1104 1.1.1.9 mrg #ifndef __nvptx__
1105 1.1.1.10 mrg team_free (pool->threads);
1106 1.1.1.10 mrg team_free (pool);
1107 1.1.1.9 mrg #endif
1108 1.1.1.9 mrg thr->thread_pool = NULL;
1109 1.1.1.9 mrg }
1110 1.1.1.9 mrg return 0;
1111 1.1.1.9 mrg }
1112 1.1.1.5 mrg #endif
1113 1.1 mrg
1114 1.1 mrg struct gomp_task_icv *
1115 1.1 mrg gomp_new_icv (void)
1116 1.1 mrg {
1117 1.1 mrg struct gomp_thread *thr = gomp_thread ();
1118 1.1 mrg struct gomp_task *task = gomp_malloc (sizeof (struct gomp_task));
1119 1.1 mrg gomp_init_task (task, NULL, &gomp_global_icv);
1120 1.1 mrg thr->task = task;
1121 1.1.1.5 mrg #ifdef LIBGOMP_USE_PTHREADS
1122 1.1 mrg pthread_setspecific (gomp_thread_destructor, thr);
1123 1.1.1.5 mrg #endif
1124 1.1 mrg return &task->icv;
1125 1.1 mrg }
1126