commit 6d948176bdcfded329e3e4e3097842846bc3491c Author: Nathaniel J. Smith Date: Sun Oct 19 20:23:57 2014 +0100 patch 2 diff --git a/libgomp/team.c b/libgomp/team.c index 19b3cc8..5420881 100644 --- a/libgomp/team.c +++ b/libgomp/team.c @@ -205,42 +205,41 @@ static struct gomp_thread_pool *gomp_new_thread_pool (void) return pool; } +/* Free a thread pool and release its threads. */ + static void gomp_free_pool_helper (void *thread_pool) { - struct gomp_thread *thr = gomp_thread (); struct gomp_thread_pool *pool = (struct gomp_thread_pool *) thread_pool; gomp_barrier_wait_last (&pool->threads_dock); - gomp_sem_destroy (&thr->release); - thr->thread_pool = NULL; - thr->task = NULL; pthread_exit (NULL); } -/* Free a thread pool and release its threads. */ - -void -gomp_free_thread (void *arg __attribute__((unused))) +static void +gomp_free_thread_pool (bool threads_are_running) { struct gomp_thread *thr = gomp_thread (); struct gomp_thread_pool *pool = thr->thread_pool; if (pool) { + int i; if (pool->threads_used > 0) { - int i; - for (i = 1; i < pool->threads_used; i++) + if (threads_are_running) { - struct gomp_thread *nthr = pool->threads[i]; - nthr->fn = gomp_free_pool_helper; - nthr->data = pool; + for (i = 1; i < pool->threads_used; i++) + { + struct gomp_thread *nthr = pool->threads[i]; + nthr->fn = gomp_free_pool_helper; + nthr->data = pool; + } + /* This barrier undocks threads docked on pool->threads_dock. */ + gomp_barrier_wait (&pool->threads_dock); + /* And this waits till all threads have called + gomp_barrier_wait_last in gomp_free_pool_helper. */ + gomp_barrier_wait (&pool->threads_dock); } - /* This barrier undocks threads docked on pool->threads_dock. */ - gomp_barrier_wait (&pool->threads_dock); - /* And this waits till all threads have called gomp_barrier_wait_last - in gomp_free_pool_helper. */ - gomp_barrier_wait (&pool->threads_dock); /* Now it is safe to destroy the barrier and free the pool. */ gomp_barrier_destroy (&pool->threads_dock); @@ -252,6 +251,14 @@ gomp_free_thread (void *arg __attribute__((unused))) gomp_managed_threads -= pool->threads_used - 1L; gomp_mutex_unlock (&gomp_managed_threads_lock); #endif + /* Clean up thread objects */ + for (i = 1; i < pool->threads_used; i++) + { + struct gomp_thread *nthr = pool->threads[i]; + gomp_sem_destroy (&nthr->release); + nthr->thread_pool = NULL; + nthr->task = NULL; + } } free (pool->threads); if (pool->last_team) @@ -267,6 +274,16 @@ gomp_free_thread (void *arg __attribute__((unused))) } } +/* This is called whenever a thread exits which has a non-NULL value for + gomp_thread_destructor. In practice, the only thread for which this occurs + is the one which created the thread pool. +*/ +void +gomp_free_thread (void *arg __attribute__((unused))) +{ + gomp_free_thread_pool (true); +} + /* According to POSIX, if a process which uses threads calls fork(), then there are very few things that the resulting child process can do safely -- mostly just exec(). @@ -349,8 +366,9 @@ gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads, /* There was some parent process who was using OMP, and then called fork(). We are the main thread of the resulting child process. Our thread structure contains stale data referring to the parent thread - who called fork(). Reset it to reflect our new main-thread - status. (This leaks, but that's better than deadlocking.) */ + who called fork(). Do our best to free what we can, and then reset + thr to reflect our new main-thread status. */ + gomp_free_thread_pool (0); memset (thr, 0, sizeof(struct gomp_thread)); } nested = thr->ts.team != NULL;