1 /* Copyright (C) 2005-2015 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU Offloading and Multi Processing Library
7 Libgomp is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 /* This file handles the maintainence of threads in response to team
27 creation and termination. */
34 /* This attribute contains PTHREAD_CREATE_DETACHED. */
35 pthread_attr_t gomp_thread_attr
;
37 /* This key is for the thread destructor. */
38 pthread_key_t gomp_thread_destructor
;
41 /* This is the libgomp per-thread data structure. */
42 #if defined HAVE_TLS || defined USE_EMUTLS
43 __thread
struct gomp_thread gomp_tls_data
;
45 pthread_key_t gomp_tls_key
;
49 /* This structure is used to communicate across pthread_create. */
51 struct gomp_thread_start_data
55 struct gomp_team_state ts
;
56 struct gomp_task
*task
;
57 struct gomp_thread_pool
*thread_pool
;
63 /* This function is a pthread_create entry point. This contains the idle
64 loop in which a thread waits to be called up to become part of a team. */
67 gomp_thread_start (void *xdata
)
69 struct gomp_thread_start_data
*data
= xdata
;
70 struct gomp_thread
*thr
;
71 struct gomp_thread_pool
*pool
;
72 void (*local_fn
) (void *);
75 #if defined HAVE_TLS || defined USE_EMUTLS
78 struct gomp_thread local_thr
;
80 pthread_setspecific (gomp_tls_key
, thr
);
82 gomp_sem_init (&thr
->release
, 0);
84 /* Extract what we need from data. */
86 local_data
= data
->fn_data
;
87 thr
->thread_pool
= data
->thread_pool
;
89 thr
->task
= data
->task
;
90 thr
->place
= data
->place
;
92 thr
->ts
.team
->ordered_release
[thr
->ts
.team_id
] = &thr
->release
;
94 /* Make thread pool local. */
95 pool
= thr
->thread_pool
;
99 struct gomp_team
*team
= thr
->ts
.team
;
100 struct gomp_task
*task
= thr
->task
;
102 gomp_barrier_wait (&team
->barrier
);
104 local_fn (local_data
);
105 gomp_team_barrier_wait_final (&team
->barrier
);
106 gomp_finish_task (task
);
107 gomp_barrier_wait_last (&team
->barrier
);
111 pool
->threads
[thr
->ts
.team_id
] = thr
;
113 gomp_barrier_wait (&pool
->threads_dock
);
116 struct gomp_team
*team
= thr
->ts
.team
;
117 struct gomp_task
*task
= thr
->task
;
119 local_fn (local_data
);
120 gomp_team_barrier_wait_final (&team
->barrier
);
121 gomp_finish_task (task
);
123 gomp_barrier_wait (&pool
->threads_dock
);
126 local_data
= thr
->data
;
132 gomp_sem_destroy (&thr
->release
);
133 thr
->thread_pool
= NULL
;
138 static inline struct gomp_team
*
139 get_last_team (unsigned nthreads
)
141 struct gomp_thread
*thr
= gomp_thread ();
142 if (thr
->ts
.team
== NULL
)
144 struct gomp_thread_pool
*pool
= gomp_get_thread_pool (thr
, nthreads
);
145 struct gomp_team
*last_team
= pool
->last_team
;
146 if (last_team
!= NULL
&& last_team
->nthreads
== nthreads
)
148 pool
->last_team
= NULL
;
155 /* Create a new team data structure. */
158 gomp_new_team (unsigned nthreads
)
160 struct gomp_team
*team
;
163 team
= get_last_team (nthreads
);
166 size_t extra
= sizeof (team
->ordered_release
[0])
167 + sizeof (team
->implicit_task
[0]);
168 team
= gomp_malloc (sizeof (*team
) + nthreads
* extra
);
170 #ifndef HAVE_SYNC_BUILTINS
171 gomp_mutex_init (&team
->work_share_list_free_lock
);
173 gomp_barrier_init (&team
->barrier
, nthreads
);
174 gomp_mutex_init (&team
->task_lock
);
176 team
->nthreads
= nthreads
;
179 team
->work_share_chunk
= 8;
180 #ifdef HAVE_SYNC_BUILTINS
181 team
->single_count
= 0;
183 team
->work_shares_to_free
= &team
->work_shares
[0];
184 gomp_init_work_share (&team
->work_shares
[0], false, nthreads
);
185 team
->work_shares
[0].next_alloc
= NULL
;
186 team
->work_share_list_free
= NULL
;
187 team
->work_share_list_alloc
= &team
->work_shares
[1];
188 for (i
= 1; i
< 7; i
++)
189 team
->work_shares
[i
].next_free
= &team
->work_shares
[i
+ 1];
190 team
->work_shares
[i
].next_free
= NULL
;
192 gomp_sem_init (&team
->master_release
, 0);
193 team
->ordered_release
= (void *) &team
->implicit_task
[nthreads
];
194 team
->ordered_release
[0] = &team
->master_release
;
196 team
->task_queue
= NULL
;
197 team
->task_count
= 0;
198 team
->task_queued_count
= 0;
199 team
->task_running_count
= 0;
200 team
->work_share_cancelled
= 0;
201 team
->team_cancelled
= 0;
207 /* Free a team data structure. */
210 free_team (struct gomp_team
*team
)
212 #ifndef HAVE_SYNC_BUILTINS
213 gomp_mutex_destroy (&team
->work_share_list_free_lock
);
215 gomp_barrier_destroy (&team
->barrier
);
216 gomp_mutex_destroy (&team
->task_lock
);
221 gomp_free_pool_helper (void *thread_pool
)
223 struct gomp_thread
*thr
= gomp_thread ();
224 struct gomp_thread_pool
*pool
225 = (struct gomp_thread_pool
*) thread_pool
;
226 gomp_barrier_wait_last (&pool
->threads_dock
);
227 gomp_sem_destroy (&thr
->release
);
228 thr
->thread_pool
= NULL
;
233 /* Free a thread pool and release its threads. */
236 gomp_free_thread (void *arg
__attribute__((unused
)))
238 struct gomp_thread
*thr
= gomp_thread ();
239 struct gomp_thread_pool
*pool
= thr
->thread_pool
;
242 if (pool
->threads_used
> 0)
245 for (i
= 1; i
< pool
->threads_used
; i
++)
247 struct gomp_thread
*nthr
= pool
->threads
[i
];
248 nthr
->fn
= gomp_free_pool_helper
;
251 /* This barrier undocks threads docked on pool->threads_dock. */
252 gomp_barrier_wait (&pool
->threads_dock
);
253 /* And this waits till all threads have called gomp_barrier_wait_last
254 in gomp_free_pool_helper. */
255 gomp_barrier_wait (&pool
->threads_dock
);
256 /* Now it is safe to destroy the barrier and free the pool. */
257 gomp_barrier_destroy (&pool
->threads_dock
);
259 #ifdef HAVE_SYNC_BUILTINS
260 __sync_fetch_and_add (&gomp_managed_threads
,
261 1L - pool
->threads_used
);
263 gomp_mutex_lock (&gomp_managed_threads_lock
);
264 gomp_managed_threads
-= pool
->threads_used
- 1L;
265 gomp_mutex_unlock (&gomp_managed_threads_lock
);
268 free (pool
->threads
);
270 free_team (pool
->last_team
);
272 thr
->thread_pool
= NULL
;
274 if (thr
->task
!= NULL
)
276 struct gomp_task
*task
= thr
->task
;
285 gomp_team_start (void (*fn
) (void *), void *data
, unsigned nthreads
,
286 unsigned flags
, struct gomp_team
*team
)
288 struct gomp_thread_start_data
*start_data
;
289 struct gomp_thread
*thr
, *nthr
;
290 struct gomp_task
*task
;
291 struct gomp_task_icv
*icv
;
293 struct gomp_thread_pool
*pool
;
294 unsigned i
, n
, old_threads_used
= 0;
295 pthread_attr_t thread_attr
, *attr
;
296 unsigned long nthreads_var
;
298 unsigned int s
= 0, rest
= 0, p
= 0, k
= 0;
299 unsigned int affinity_count
= 0;
300 struct gomp_thread
**affinity_thr
= NULL
;
302 thr
= gomp_thread ();
303 nested
= thr
->ts
.team
!= NULL
;
304 pool
= thr
->thread_pool
;
306 icv
= task
? &task
->icv
: &gomp_global_icv
;
307 if (__builtin_expect (gomp_places_list
!= NULL
, 0) && thr
->place
== 0)
308 gomp_init_affinity ();
310 /* Always save the previous state, even if this isn't a nested team.
311 In particular, we should save any work share state from an outer
312 orphaned work share construct. */
313 team
->prev_ts
= thr
->ts
;
319 ++thr
->ts
.active_level
;
320 thr
->ts
.work_share
= &team
->work_shares
[0];
321 thr
->ts
.last_work_share
= NULL
;
322 #ifdef HAVE_SYNC_BUILTINS
323 thr
->ts
.single_count
= 0;
325 thr
->ts
.static_trip
= 0;
326 thr
->task
= &team
->implicit_task
[0];
327 nthreads_var
= icv
->nthreads_var
;
328 if (__builtin_expect (gomp_nthreads_var_list
!= NULL
, 0)
329 && thr
->ts
.level
< gomp_nthreads_var_list_len
)
330 nthreads_var
= gomp_nthreads_var_list
[thr
->ts
.level
];
331 bind_var
= icv
->bind_var
;
332 if (bind_var
!= omp_proc_bind_false
&& (flags
& 7) != omp_proc_bind_false
)
333 bind_var
= flags
& 7;
335 if (__builtin_expect (gomp_bind_var_list
!= NULL
, 0)
336 && thr
->ts
.level
< gomp_bind_var_list_len
)
337 bind_var
= gomp_bind_var_list
[thr
->ts
.level
];
338 gomp_init_task (thr
->task
, task
, icv
);
339 team
->implicit_task
[0].icv
.nthreads_var
= nthreads_var
;
340 team
->implicit_task
[0].icv
.bind_var
= bind_var
;
347 if (__builtin_expect (gomp_places_list
!= NULL
, 0))
349 /* Depending on chosen proc_bind model, set subpartition
350 for the master thread and initialize helper variables
351 P and optionally S, K and/or REST used by later place
352 computation for each additional thread. */
356 case omp_proc_bind_true
:
357 case omp_proc_bind_close
:
358 if (nthreads
> thr
->ts
.place_partition_len
)
360 /* T > P. S threads will be placed in each place,
361 and the final REM threads placed one by one
362 into the already occupied places. */
363 s
= nthreads
/ thr
->ts
.place_partition_len
;
364 rest
= nthreads
% thr
->ts
.place_partition_len
;
370 case omp_proc_bind_master
:
371 /* Each thread will be bound to master's place. */
373 case omp_proc_bind_spread
:
374 if (nthreads
<= thr
->ts
.place_partition_len
)
376 /* T <= P. Each subpartition will have in between s
377 and s+1 places (subpartitions starting at or
378 after rest will have s places, earlier s+1 places),
379 each thread will be bound to the first place in
380 its subpartition (except for the master thread
381 that can be bound to another place in its
383 s
= thr
->ts
.place_partition_len
/ nthreads
;
384 rest
= thr
->ts
.place_partition_len
% nthreads
;
385 rest
= (s
+ 1) * rest
+ thr
->ts
.place_partition_off
;
388 p
-= (p
- thr
->ts
.place_partition_off
) % (s
+ 1);
389 thr
->ts
.place_partition_len
= s
+ 1;
394 thr
->ts
.place_partition_len
= s
;
396 thr
->ts
.place_partition_off
= p
;
400 /* T > P. Each subpartition will have just a single
401 place and we'll place between s and s+1
402 threads into each subpartition. */
403 s
= nthreads
/ thr
->ts
.place_partition_len
;
404 rest
= nthreads
% thr
->ts
.place_partition_len
;
405 thr
->ts
.place_partition_off
= p
;
406 thr
->ts
.place_partition_len
= 1;
413 bind
= omp_proc_bind_false
;
415 /* We only allow the reuse of idle threads for non-nested PARALLEL
416 regions. This appears to be implied by the semantics of
417 threadprivate variables, but perhaps that's reading too much into
418 things. Certainly it does prevent any locking problems, since
419 only the initial program thread will modify gomp_threads. */
422 old_threads_used
= pool
->threads_used
;
424 if (nthreads
<= old_threads_used
)
426 else if (old_threads_used
== 0)
429 gomp_barrier_init (&pool
->threads_dock
, nthreads
);
433 n
= old_threads_used
;
435 /* Increase the barrier threshold to make sure all new
436 threads arrive before the team is released. */
437 gomp_barrier_reinit (&pool
->threads_dock
, nthreads
);
440 /* Not true yet, but soon will be. We're going to release all
441 threads from the dock, and those that aren't part of the
443 pool
->threads_used
= nthreads
;
445 /* If necessary, expand the size of the gomp_threads array. It is
446 expected that changes in the number of threads are rare, thus we
447 make no effort to expand gomp_threads_size geometrically. */
448 if (nthreads
>= pool
->threads_size
)
450 pool
->threads_size
= nthreads
+ 1;
452 = gomp_realloc (pool
->threads
,
454 * sizeof (struct gomp_thread_data
*));
457 /* Release existing idle threads. */
460 unsigned int place_partition_off
= thr
->ts
.place_partition_off
;
461 unsigned int place_partition_len
= thr
->ts
.place_partition_len
;
462 unsigned int place
= 0;
463 if (__builtin_expect (gomp_places_list
!= NULL
, 0))
467 case omp_proc_bind_true
:
468 case omp_proc_bind_close
:
472 if (p
== (team
->prev_ts
.place_partition_off
473 + team
->prev_ts
.place_partition_len
))
474 p
= team
->prev_ts
.place_partition_off
;
476 if (i
== nthreads
- rest
)
482 case omp_proc_bind_master
:
484 case omp_proc_bind_spread
:
492 if (p
== (team
->prev_ts
.place_partition_off
493 + team
->prev_ts
.place_partition_len
))
494 p
= team
->prev_ts
.place_partition_off
;
495 place_partition_off
= p
;
497 place_partition_len
= s
+ 1;
499 place_partition_len
= s
;
507 if (p
== (team
->prev_ts
.place_partition_off
508 + team
->prev_ts
.place_partition_len
))
509 p
= team
->prev_ts
.place_partition_off
;
511 if (i
== nthreads
- rest
)
516 place_partition_off
= p
;
517 place_partition_len
= 1;
521 if (affinity_thr
!= NULL
522 || (bind
!= omp_proc_bind_true
523 && pool
->threads
[i
]->place
!= p
+ 1)
524 || pool
->threads
[i
]->place
<= place_partition_off
525 || pool
->threads
[i
]->place
> (place_partition_off
526 + place_partition_len
))
529 if (affinity_thr
== NULL
)
533 if (team
->prev_ts
.place_partition_len
> 64)
535 = gomp_malloc (team
->prev_ts
.place_partition_len
536 * sizeof (struct gomp_thread
*));
539 = gomp_alloca (team
->prev_ts
.place_partition_len
540 * sizeof (struct gomp_thread
*));
541 memset (affinity_thr
, '\0',
542 team
->prev_ts
.place_partition_len
543 * sizeof (struct gomp_thread
*));
544 for (j
= i
; j
< old_threads_used
; j
++)
546 if (pool
->threads
[j
]->place
547 > team
->prev_ts
.place_partition_off
548 && (pool
->threads
[j
]->place
549 <= (team
->prev_ts
.place_partition_off
550 + team
->prev_ts
.place_partition_len
)))
552 l
= pool
->threads
[j
]->place
- 1
553 - team
->prev_ts
.place_partition_off
;
554 pool
->threads
[j
]->data
= affinity_thr
[l
];
555 affinity_thr
[l
] = pool
->threads
[j
];
557 pool
->threads
[j
] = NULL
;
559 if (nthreads
> old_threads_used
)
560 memset (&pool
->threads
[old_threads_used
],
561 '\0', ((nthreads
- old_threads_used
)
562 * sizeof (struct gomp_thread
*)));
564 affinity_count
= old_threads_used
- i
;
566 if (affinity_count
== 0)
569 if (affinity_thr
[l
- team
->prev_ts
.place_partition_off
]
572 if (bind
!= omp_proc_bind_true
)
574 for (l
= place_partition_off
;
575 l
< place_partition_off
+ place_partition_len
;
577 if (affinity_thr
[l
- team
->prev_ts
.place_partition_off
]
580 if (l
== place_partition_off
+ place_partition_len
)
583 nthr
= affinity_thr
[l
- team
->prev_ts
.place_partition_off
];
584 affinity_thr
[l
- team
->prev_ts
.place_partition_off
]
585 = (struct gomp_thread
*) nthr
->data
;
587 pool
->threads
[i
] = nthr
;
590 nthr
= pool
->threads
[i
];
594 nthr
= pool
->threads
[i
];
595 nthr
->ts
.team
= team
;
596 nthr
->ts
.work_share
= &team
->work_shares
[0];
597 nthr
->ts
.last_work_share
= NULL
;
598 nthr
->ts
.team_id
= i
;
599 nthr
->ts
.level
= team
->prev_ts
.level
+ 1;
600 nthr
->ts
.active_level
= thr
->ts
.active_level
;
601 nthr
->ts
.place_partition_off
= place_partition_off
;
602 nthr
->ts
.place_partition_len
= place_partition_len
;
603 #ifdef HAVE_SYNC_BUILTINS
604 nthr
->ts
.single_count
= 0;
606 nthr
->ts
.static_trip
= 0;
607 nthr
->task
= &team
->implicit_task
[i
];
609 gomp_init_task (nthr
->task
, task
, icv
);
610 team
->implicit_task
[i
].icv
.nthreads_var
= nthreads_var
;
611 team
->implicit_task
[i
].icv
.bind_var
= bind_var
;
614 team
->ordered_release
[i
] = &nthr
->release
;
617 if (__builtin_expect (affinity_thr
!= NULL
, 0))
619 /* If AFFINITY_THR is non-NULL just because we had to
620 permute some threads in the pool, but we've managed
621 to find exactly as many old threads as we'd find
622 without affinity, we don't need to handle this
623 specially anymore. */
624 if (nthreads
<= old_threads_used
625 ? (affinity_count
== old_threads_used
- nthreads
)
626 : (i
== old_threads_used
))
628 if (team
->prev_ts
.place_partition_len
> 64)
636 /* We are going to compute the places/subpartitions
637 again from the beginning. So, we need to reinitialize
638 vars modified by the switch (bind) above inside
639 of the loop, to the state they had after the initial
643 case omp_proc_bind_true
:
644 case omp_proc_bind_close
:
645 if (nthreads
> thr
->ts
.place_partition_len
)
646 /* T > P. S has been changed, so needs
648 s
= nthreads
/ thr
->ts
.place_partition_len
;
652 case omp_proc_bind_master
:
653 /* No vars have been changed. */
655 case omp_proc_bind_spread
:
656 p
= thr
->ts
.place_partition_off
;
660 s
= nthreads
/ team
->prev_ts
.place_partition_len
;
666 /* Increase the barrier threshold to make sure all new
667 threads and all the threads we're going to let die
668 arrive before the team is released. */
670 gomp_barrier_reinit (&pool
->threads_dock
,
671 nthreads
+ affinity_count
);
680 if (__builtin_expect (nthreads
+ affinity_count
> old_threads_used
, 0))
682 long diff
= (long) (nthreads
+ affinity_count
) - (long) old_threads_used
;
684 if (old_threads_used
== 0)
687 #ifdef HAVE_SYNC_BUILTINS
688 __sync_fetch_and_add (&gomp_managed_threads
, diff
);
690 gomp_mutex_lock (&gomp_managed_threads_lock
);
691 gomp_managed_threads
+= diff
;
692 gomp_mutex_unlock (&gomp_managed_threads_lock
);
696 attr
= &gomp_thread_attr
;
697 if (__builtin_expect (gomp_places_list
!= NULL
, 0))
700 pthread_attr_init (&thread_attr
);
701 pthread_attr_setdetachstate (&thread_attr
, PTHREAD_CREATE_DETACHED
);
702 if (! pthread_attr_getstacksize (&gomp_thread_attr
, &stacksize
))
703 pthread_attr_setstacksize (&thread_attr
, stacksize
);
707 start_data
= gomp_alloca (sizeof (struct gomp_thread_start_data
)
710 /* Launch new threads. */
711 for (; i
< nthreads
; ++i
)
716 start_data
->ts
.place_partition_off
= thr
->ts
.place_partition_off
;
717 start_data
->ts
.place_partition_len
= thr
->ts
.place_partition_len
;
718 start_data
->place
= 0;
719 if (__builtin_expect (gomp_places_list
!= NULL
, 0))
723 case omp_proc_bind_true
:
724 case omp_proc_bind_close
:
728 if (p
== (team
->prev_ts
.place_partition_off
729 + team
->prev_ts
.place_partition_len
))
730 p
= team
->prev_ts
.place_partition_off
;
732 if (i
== nthreads
- rest
)
738 case omp_proc_bind_master
:
740 case omp_proc_bind_spread
:
748 if (p
== (team
->prev_ts
.place_partition_off
749 + team
->prev_ts
.place_partition_len
))
750 p
= team
->prev_ts
.place_partition_off
;
751 start_data
->ts
.place_partition_off
= p
;
753 start_data
->ts
.place_partition_len
= s
+ 1;
755 start_data
->ts
.place_partition_len
= s
;
763 if (p
== (team
->prev_ts
.place_partition_off
764 + team
->prev_ts
.place_partition_len
))
765 p
= team
->prev_ts
.place_partition_off
;
767 if (i
== nthreads
- rest
)
772 start_data
->ts
.place_partition_off
= p
;
773 start_data
->ts
.place_partition_len
= 1;
777 start_data
->place
= p
+ 1;
778 if (affinity_thr
!= NULL
&& pool
->threads
[i
] != NULL
)
780 gomp_init_thread_affinity (attr
, p
);
784 start_data
->fn_data
= data
;
785 start_data
->ts
.team
= team
;
786 start_data
->ts
.work_share
= &team
->work_shares
[0];
787 start_data
->ts
.last_work_share
= NULL
;
788 start_data
->ts
.team_id
= i
;
789 start_data
->ts
.level
= team
->prev_ts
.level
+ 1;
790 start_data
->ts
.active_level
= thr
->ts
.active_level
;
791 #ifdef HAVE_SYNC_BUILTINS
792 start_data
->ts
.single_count
= 0;
794 start_data
->ts
.static_trip
= 0;
795 start_data
->task
= &team
->implicit_task
[i
];
796 gomp_init_task (start_data
->task
, task
, icv
);
797 team
->implicit_task
[i
].icv
.nthreads_var
= nthreads_var
;
798 team
->implicit_task
[i
].icv
.bind_var
= bind_var
;
799 start_data
->thread_pool
= pool
;
800 start_data
->nested
= nested
;
802 attr
= gomp_adjust_thread_attr (attr
, &thread_attr
);
803 err
= pthread_create (&pt
, attr
, gomp_thread_start
, start_data
++);
805 gomp_fatal ("Thread creation failed: %s", strerror (err
));
808 if (__builtin_expect (attr
== &thread_attr
, 0))
809 pthread_attr_destroy (&thread_attr
);
812 gomp_barrier_wait (nested
? &team
->barrier
: &pool
->threads_dock
);
814 /* Decrease the barrier threshold to match the number of threads
815 that should arrive back at the end of this team. The extra
816 threads should be exiting. Note that we arrange for this test
817 to never be true for nested teams. If AFFINITY_COUNT is non-zero,
818 the barrier as well as gomp_managed_threads was temporarily
819 set to NTHREADS + AFFINITY_COUNT. For NTHREADS < OLD_THREADS_COUNT,
820 AFFINITY_COUNT if non-zero will be always at least
821 OLD_THREADS_COUNT - NTHREADS. */
822 if (__builtin_expect (nthreads
< old_threads_used
, 0)
823 || __builtin_expect (affinity_count
, 0))
825 long diff
= (long) nthreads
- (long) old_threads_used
;
828 diff
= -affinity_count
;
830 gomp_barrier_reinit (&pool
->threads_dock
, nthreads
);
832 #ifdef HAVE_SYNC_BUILTINS
833 __sync_fetch_and_add (&gomp_managed_threads
, diff
);
835 gomp_mutex_lock (&gomp_managed_threads_lock
);
836 gomp_managed_threads
+= diff
;
837 gomp_mutex_unlock (&gomp_managed_threads_lock
);
840 if (__builtin_expect (affinity_thr
!= NULL
, 0)
841 && team
->prev_ts
.place_partition_len
> 64)
846 /* Terminate the current team. This is only to be called by the master
847 thread. We assume that we must wait for the other threads. */
852 struct gomp_thread
*thr
= gomp_thread ();
853 struct gomp_team
*team
= thr
->ts
.team
;
855 /* This barrier handles all pending explicit threads.
856 As #pragma omp cancel parallel might get awaited count in
857 team->barrier in a inconsistent state, we need to use a different
859 gomp_team_barrier_wait_final (&team
->barrier
);
860 if (__builtin_expect (team
->team_cancelled
, 0))
862 struct gomp_work_share
*ws
= team
->work_shares_to_free
;
865 struct gomp_work_share
*next_ws
= gomp_ptrlock_get (&ws
->next_ws
);
867 gomp_ptrlock_set (&ws
->next_ws
, ws
);
868 gomp_fini_work_share (ws
);
874 gomp_fini_work_share (thr
->ts
.work_share
);
877 thr
->ts
= team
->prev_ts
;
879 if (__builtin_expect (thr
->ts
.team
!= NULL
, 0))
881 #ifdef HAVE_SYNC_BUILTINS
882 __sync_fetch_and_add (&gomp_managed_threads
, 1L - team
->nthreads
);
884 gomp_mutex_lock (&gomp_managed_threads_lock
);
885 gomp_managed_threads
-= team
->nthreads
- 1L;
886 gomp_mutex_unlock (&gomp_managed_threads_lock
);
888 /* This barrier has gomp_barrier_wait_last counterparts
889 and ensures the team can be safely destroyed. */
890 gomp_barrier_wait (&team
->barrier
);
893 if (__builtin_expect (team
->work_shares
[0].next_alloc
!= NULL
, 0))
895 struct gomp_work_share
*ws
= team
->work_shares
[0].next_alloc
;
898 struct gomp_work_share
*next_ws
= ws
->next_alloc
;
904 gomp_sem_destroy (&team
->master_release
);
906 if (__builtin_expect (thr
->ts
.team
!= NULL
, 0)
907 || __builtin_expect (team
->nthreads
== 1, 0))
911 struct gomp_thread_pool
*pool
= thr
->thread_pool
;
913 free_team (pool
->last_team
);
914 pool
->last_team
= team
;
915 gomp_release_thread_pool (pool
);
920 /* Constructors for this file. */
922 static void __attribute__((constructor
))
923 initialize_team (void)
925 #if !defined HAVE_TLS && !defined USE_EMUTLS
926 static struct gomp_thread initial_thread_tls_data
;
928 pthread_key_create (&gomp_tls_key
, NULL
);
929 pthread_setspecific (gomp_tls_key
, &initial_thread_tls_data
);
932 if (pthread_key_create (&gomp_thread_destructor
, gomp_free_thread
) != 0)
933 gomp_fatal ("could not create thread pool destructor.");
936 static void __attribute__((destructor
))
937 team_destructor (void)
939 /* Without this dlclose on libgomp could lead to subsequent
941 pthread_key_delete (gomp_thread_destructor
);
944 struct gomp_task_icv
*
947 struct gomp_thread
*thr
= gomp_thread ();
948 struct gomp_task
*task
= gomp_malloc (sizeof (struct gomp_task
));
949 gomp_init_task (task
, NULL
, &gomp_global_icv
);
951 pthread_setspecific (gomp_thread_destructor
, thr
);