1 /* Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
2 Contributed by Richard Henderson <rth@redhat.com>.
4 This file is part of the GNU OpenMP Library (libgomp).
6 Libgomp is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
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 Lesser General Public License for
16 You should have received a copy of the GNU Lesser General Public License
17 along with libgomp; see the file COPYING.LIB. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301, USA. */
21 /* As a special exception, if you link this library with other files, some
22 of which are compiled with GCC, to produce an executable, this library
23 does not by itself cause the resulting executable to be covered by the
24 GNU General Public License. This exception does not however invalidate
25 any other reasons why the executable file might be covered by the GNU
26 General Public License. */
28 /* This file handles the maintainence of threads in response to team
29 creation and termination. */
35 /* This attribute contains PTHREAD_CREATE_DETACHED. */
36 pthread_attr_t gomp_thread_attr
;
38 /* This key is for the thread destructor. */
39 pthread_key_t gomp_thread_destructor
;
42 /* This is the libgomp per-thread data structure. */
44 __thread
struct gomp_thread gomp_tls_data
;
46 pthread_key_t gomp_tls_key
;
50 /* This structure is used to communicate across pthread_create. */
52 struct gomp_thread_start_data
56 struct gomp_team_state ts
;
57 struct gomp_task
*task
;
58 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 *);
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
;
91 thr
->ts
.team
->ordered_release
[thr
->ts
.team_id
] = &thr
->release
;
93 /* Make thread pool local. */
94 pool
= thr
->thread_pool
;
98 struct gomp_team
*team
= thr
->ts
.team
;
99 struct gomp_task
*task
= thr
->task
;
101 gomp_barrier_wait (&team
->barrier
);
103 local_fn (local_data
);
104 gomp_team_barrier_wait (&team
->barrier
);
105 gomp_finish_task (task
);
106 gomp_barrier_wait_last (&team
->barrier
);
110 pool
->threads
[thr
->ts
.team_id
] = thr
;
112 gomp_barrier_wait (&pool
->threads_dock
);
115 struct gomp_team
*team
= thr
->ts
.team
;
116 struct gomp_task
*task
= thr
->task
;
118 local_fn (local_data
);
119 gomp_team_barrier_wait (&team
->barrier
);
120 gomp_finish_task (task
);
122 gomp_barrier_wait (&pool
->threads_dock
);
125 local_data
= thr
->data
;
135 /* Create a new team data structure. */
138 gomp_new_team (unsigned nthreads
)
140 struct gomp_team
*team
;
144 size
= sizeof (*team
) + nthreads
* (sizeof (team
->ordered_release
[0])
145 + sizeof (team
->implicit_task
[0]));
146 team
= gomp_malloc (size
);
148 team
->work_share_chunk
= 8;
149 #ifdef HAVE_SYNC_BUILTINS
150 team
->single_count
= 0;
152 gomp_mutex_init (&team
->work_share_list_free_lock
);
154 gomp_init_work_share (&team
->work_shares
[0], false, nthreads
);
155 team
->work_shares
[0].next_alloc
= NULL
;
156 team
->work_share_list_free
= NULL
;
157 team
->work_share_list_alloc
= &team
->work_shares
[1];
158 for (i
= 1; i
< 7; i
++)
159 team
->work_shares
[i
].next_free
= &team
->work_shares
[i
+ 1];
160 team
->work_shares
[i
].next_free
= NULL
;
162 team
->nthreads
= nthreads
;
163 gomp_barrier_init (&team
->barrier
, nthreads
);
165 gomp_sem_init (&team
->master_release
, 0);
166 team
->ordered_release
= (void *) &team
->implicit_task
[nthreads
];
167 team
->ordered_release
[0] = &team
->master_release
;
169 gomp_mutex_init (&team
->task_lock
);
170 team
->task_queue
= NULL
;
171 team
->task_count
= 0;
172 team
->task_running_count
= 0;
178 /* Free a team data structure. */
181 free_team (struct gomp_team
*team
)
183 gomp_barrier_destroy (&team
->barrier
);
184 gomp_mutex_destroy (&team
->task_lock
);
188 /* Allocate and initialize a thread pool. */
190 static struct gomp_thread_pool
*gomp_new_thread_pool (void)
192 struct gomp_thread_pool
*pool
193 = gomp_malloc (sizeof(struct gomp_thread_pool
));
194 pool
->threads
= NULL
;
195 pool
->threads_size
= 0;
196 pool
->threads_used
= 0;
197 pool
->last_team
= NULL
;
202 gomp_free_pool_helper (void *thread_pool
)
204 struct gomp_thread_pool
*pool
205 = (struct gomp_thread_pool
*) thread_pool
;
206 gomp_barrier_wait_last (&pool
->threads_dock
);
210 /* Free a thread pool and release its threads. */
213 gomp_free_thread (void *arg
__attribute__((unused
)))
215 struct gomp_thread
*thr
= gomp_thread ();
216 struct gomp_thread_pool
*pool
= thr
->thread_pool
;
219 if (pool
->threads_used
> 0)
222 for (i
= 1; i
< pool
->threads_used
; i
++)
224 struct gomp_thread
*nthr
= pool
->threads
[i
];
225 nthr
->fn
= gomp_free_pool_helper
;
228 /* This barrier undocks threads docked on pool->threads_dock. */
229 gomp_barrier_wait (&pool
->threads_dock
);
230 /* And this waits till all threads have called gomp_barrier_wait_last
231 in gomp_free_pool_helper. */
232 gomp_barrier_wait (&pool
->threads_dock
);
233 /* Now it is safe to destroy the barrier and free the pool. */
234 gomp_barrier_destroy (&pool
->threads_dock
);
236 free (pool
->threads
);
238 free_team (pool
->last_team
);
240 thr
->thread_pool
= NULL
;
242 if (thr
->task
!= NULL
)
244 struct gomp_task
*task
= thr
->task
;
253 gomp_team_start (void (*fn
) (void *), void *data
, unsigned nthreads
,
254 struct gomp_team
*team
)
256 struct gomp_thread_start_data
*start_data
;
257 struct gomp_thread
*thr
, *nthr
;
258 struct gomp_task
*task
;
259 struct gomp_task_icv
*icv
;
261 struct gomp_thread_pool
*pool
;
262 unsigned i
, n
, old_threads_used
= 0;
263 pthread_attr_t thread_attr
, *attr
;
265 thr
= gomp_thread ();
266 nested
= thr
->ts
.team
!= NULL
;
267 if (__builtin_expect (thr
->thread_pool
== NULL
, 0))
269 thr
->thread_pool
= gomp_new_thread_pool ();
270 pthread_setspecific (gomp_thread_destructor
, thr
);
272 pool
= thr
->thread_pool
;
274 icv
= task
? &task
->icv
: &gomp_global_icv
;
276 /* Always save the previous state, even if this isn't a nested team.
277 In particular, we should save any work share state from an outer
278 orphaned work share construct. */
279 team
->prev_ts
= thr
->ts
;
285 ++thr
->ts
.active_level
;
286 thr
->ts
.work_share
= &team
->work_shares
[0];
287 thr
->ts
.last_work_share
= NULL
;
288 #ifdef HAVE_SYNC_BUILTINS
289 thr
->ts
.single_count
= 0;
291 thr
->ts
.static_trip
= 0;
292 thr
->task
= &team
->implicit_task
[0];
293 gomp_init_task (thr
->task
, task
, icv
);
300 /* We only allow the reuse of idle threads for non-nested PARALLEL
301 regions. This appears to be implied by the semantics of
302 threadprivate variables, but perhaps that's reading too much into
303 things. Certainly it does prevent any locking problems, since
304 only the initial program thread will modify gomp_threads. */
307 old_threads_used
= pool
->threads_used
;
309 if (nthreads
<= old_threads_used
)
311 else if (old_threads_used
== 0)
314 gomp_barrier_init (&pool
->threads_dock
, nthreads
);
318 n
= old_threads_used
;
320 /* Increase the barrier threshold to make sure all new
321 threads arrive before the team is released. */
322 gomp_barrier_reinit (&pool
->threads_dock
, nthreads
);
325 /* Not true yet, but soon will be. We're going to release all
326 threads from the dock, and those that aren't part of the
328 pool
->threads_used
= nthreads
;
330 /* Release existing idle threads. */
333 nthr
= pool
->threads
[i
];
334 nthr
->ts
.team
= team
;
335 nthr
->ts
.work_share
= &team
->work_shares
[0];
336 nthr
->ts
.last_work_share
= NULL
;
337 nthr
->ts
.team_id
= i
;
338 nthr
->ts
.level
= team
->prev_ts
.level
+ 1;
339 nthr
->ts
.active_level
= thr
->ts
.active_level
;
340 #ifdef HAVE_SYNC_BUILTINS
341 nthr
->ts
.single_count
= 0;
343 nthr
->ts
.static_trip
= 0;
344 nthr
->task
= &team
->implicit_task
[i
];
345 gomp_init_task (nthr
->task
, task
, icv
);
348 team
->ordered_release
[i
] = &nthr
->release
;
354 /* If necessary, expand the size of the gomp_threads array. It is
355 expected that changes in the number of threads are rare, thus we
356 make no effort to expand gomp_threads_size geometrically. */
357 if (nthreads
>= pool
->threads_size
)
359 pool
->threads_size
= nthreads
+ 1;
361 = gomp_realloc (pool
->threads
,
363 * sizeof (struct gomp_thread_data
*));
367 if (__builtin_expect (nthreads
> old_threads_used
, 0))
369 long diff
= (long) nthreads
- (long) old_threads_used
;
371 if (old_threads_used
== 0)
374 #ifdef HAVE_SYNC_BUILTINS
375 __sync_fetch_and_add (&gomp_managed_threads
, diff
);
377 gomp_mutex_lock (&gomp_remaining_threads_lock
);
378 gomp_managed_threads
+= diff
;
379 gomp_mutex_unlock (&gomp_remaining_threads_lock
);
383 attr
= &gomp_thread_attr
;
384 if (__builtin_expect (gomp_cpu_affinity
!= NULL
, 0))
387 pthread_attr_init (&thread_attr
);
388 pthread_attr_setdetachstate (&thread_attr
, PTHREAD_CREATE_DETACHED
);
389 if (! pthread_attr_getstacksize (&gomp_thread_attr
, &stacksize
))
390 pthread_attr_setstacksize (&thread_attr
, stacksize
);
394 start_data
= gomp_alloca (sizeof (struct gomp_thread_start_data
)
397 /* Launch new threads. */
398 for (; i
< nthreads
; ++i
, ++start_data
)
404 start_data
->fn_data
= data
;
405 start_data
->ts
.team
= team
;
406 start_data
->ts
.work_share
= &team
->work_shares
[0];
407 start_data
->ts
.last_work_share
= NULL
;
408 start_data
->ts
.team_id
= i
;
409 start_data
->ts
.level
= team
->prev_ts
.level
+ 1;
410 start_data
->ts
.active_level
= thr
->ts
.active_level
;
411 #ifdef HAVE_SYNC_BUILTINS
412 start_data
->ts
.single_count
= 0;
414 start_data
->ts
.static_trip
= 0;
415 start_data
->task
= &team
->implicit_task
[i
];
416 gomp_init_task (start_data
->task
, task
, icv
);
417 start_data
->thread_pool
= pool
;
418 start_data
->nested
= nested
;
420 if (gomp_cpu_affinity
!= NULL
)
421 gomp_init_thread_affinity (attr
);
423 err
= pthread_create (&pt
, attr
, gomp_thread_start
, start_data
);
425 gomp_fatal ("Thread creation failed: %s", strerror (err
));
428 if (__builtin_expect (gomp_cpu_affinity
!= NULL
, 0))
429 pthread_attr_destroy (&thread_attr
);
432 gomp_barrier_wait (nested
? &team
->barrier
: &pool
->threads_dock
);
434 /* Decrease the barrier threshold to match the number of threads
435 that should arrive back at the end of this team. The extra
436 threads should be exiting. Note that we arrange for this test
437 to never be true for nested teams. */
438 if (__builtin_expect (nthreads
< old_threads_used
, 0))
440 long diff
= (long) nthreads
- (long) old_threads_used
;
442 gomp_barrier_reinit (&pool
->threads_dock
, nthreads
);
444 #ifdef HAVE_SYNC_BUILTINS
445 __sync_fetch_and_add (&gomp_managed_threads
, diff
);
447 gomp_mutex_lock (&gomp_remaining_threads_lock
);
448 gomp_managed_threads
+= diff
;
449 gomp_mutex_unlock (&gomp_remaining_threads_lock
);
455 /* Terminate the current team. This is only to be called by the master
456 thread. We assume that we must wait for the other threads. */
461 struct gomp_thread
*thr
= gomp_thread ();
462 struct gomp_team
*team
= thr
->ts
.team
;
464 /* This barrier handles all pending explicit threads. */
465 gomp_team_barrier_wait (&team
->barrier
);
466 gomp_fini_work_share (thr
->ts
.work_share
);
469 thr
->ts
= team
->prev_ts
;
471 if (__builtin_expect (thr
->ts
.team
!= NULL
, 0))
473 #ifdef HAVE_SYNC_BUILTINS
474 __sync_fetch_and_add (&gomp_managed_threads
, 1L - team
->nthreads
);
476 gomp_mutex_lock (&gomp_remaining_threads_lock
);
477 gomp_managed_threads
-= team
->nthreads
- 1L;
478 gomp_mutex_unlock (&gomp_remaining_threads_lock
);
480 /* This barrier has gomp_barrier_wait_last counterparts
481 and ensures the team can be safely destroyed. */
482 gomp_barrier_wait (&team
->barrier
);
485 if (__builtin_expect (team
->work_shares
[0].next_alloc
!= NULL
, 0))
487 struct gomp_work_share
*ws
= team
->work_shares
[0].next_alloc
;
490 struct gomp_work_share
*next_ws
= ws
->next_alloc
;
496 gomp_sem_destroy (&team
->master_release
);
497 #ifndef HAVE_SYNC_BUILTINS
498 gomp_mutex_destroy (&team
->work_share_list_free_lock
);
501 if (__builtin_expect (thr
->ts
.team
!= NULL
, 0)
502 || __builtin_expect (team
->nthreads
== 1, 0))
506 struct gomp_thread_pool
*pool
= thr
->thread_pool
;
508 free_team (pool
->last_team
);
509 pool
->last_team
= team
;
514 /* Constructors for this file. */
516 static void __attribute__((constructor
))
517 initialize_team (void)
519 struct gomp_thread
*thr
;
522 static struct gomp_thread initial_thread_tls_data
;
524 pthread_key_create (&gomp_tls_key
, NULL
);
525 pthread_setspecific (gomp_tls_key
, &initial_thread_tls_data
);
528 if (pthread_key_create (&gomp_thread_destructor
, gomp_free_thread
) != 0)
529 gomp_fatal ("could not create thread pool destructor.");
532 thr
= &gomp_tls_data
;
534 thr
= &initial_thread_tls_data
;
536 gomp_sem_init (&thr
->release
, 0);
539 static void __attribute__((destructor
))
540 team_destructor (void)
542 /* Without this dlclose on libgomp could lead to subsequent
544 pthread_key_delete (gomp_thread_destructor
);
547 struct gomp_task_icv
*
550 struct gomp_thread
*thr
= gomp_thread ();
551 struct gomp_task
*task
= gomp_malloc (sizeof (struct gomp_task
));
552 gomp_init_task (task
, NULL
, &gomp_global_icv
);
554 pthread_setspecific (gomp_thread_destructor
, thr
);