diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc index 8e119110684d..52d428b51c91 100644 --- a/lib/libthr/thread/Makefile.inc +++ b/lib/libthr/thread/Makefile.inc @@ -19,7 +19,6 @@ SRCS+= \ thr_equal.c \ thr_exit.c \ thr_find_thread.c \ - thr_gc.c \ thr_getprio.c \ thr_info.c \ thr_init.c \ diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c index 32ca69741670..5f1887d4a506 100644 --- a/lib/libthr/thread/thr_create.c +++ b/lib/libthr/thread/thr_create.c @@ -62,9 +62,7 @@ int _pthread_create(pthread_t * thread, const pthread_attr_t * attr, void *(*start_routine) (void *), void *arg) { - int f_gc = 0; int ret = 0; - pthread_t gc_thread; pthread_t new_thread; pthread_attr_t pattr; int flags; @@ -148,12 +146,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, THREAD_LIST_LOCK; - /* - * Check if the garbage collector thread - * needs to be started. - */ - f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); - /* Add the thread to the linked list of all threads: */ TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); @@ -180,13 +172,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, /* Return a pointer to the thread structure: */ (*thread) = new_thread; - /* - * Start a garbage collector thread - * if necessary. - */ - if (f_gc && pthread_create(&gc_thread,NULL, _thread_gc,NULL) != 0) - PANIC("Can't create gc thread"); - return (0); } diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c index 41b1f868d9fc..0455a970906f 100644 --- a/lib/libthr/thread/thr_exit.c +++ b/lib/libthr/thread/thr_exit.c @@ -45,6 +45,8 @@ __weak_reference(_pthread_exit, pthread_exit); /* thr_exit() */ extern int _thr_exit(void); +static void deadlist_free_threads(); + void _thread_exit(char *fname, int lineno, char *string) { @@ -171,9 +173,11 @@ _pthread_exit(void *status) } /* + * Free any memory allocated for dead threads. * Add this thread to the list of dead threads, and * also remove it from the active threads list. */ + deadlist_free_threads(); TAILQ_INSERT_HEAD(&_dead_list, curthread, dle); TAILQ_REMOVE(&_thread_list, curthread, tle); PTHREAD_SET_STATE(curthread, PS_DEAD); @@ -184,20 +188,11 @@ _pthread_exit(void *status) exitNow = 1; THREAD_LIST_UNLOCK; - - /* - * Signal the garbage collector thread that there is something - * to clean up. But don't allow it to free the memory until after - * it is retired by holding on to the dead list lock. - */ - if (pthread_cond_signal(&_gc_cond) != 0) - PANIC("Cannot signal gc cond"); + DEAD_LIST_UNLOCK; if (exitNow) exit(0); - DEAD_LIST_UNLOCK; - /* * This function will not return unless we are the last * thread, which we can't be because we've already checked @@ -208,3 +203,36 @@ _pthread_exit(void *status) /* This point should not be reached. */ PANIC("Dead thread has resumed"); } + +/* + * Note: this function must be called with the dead thread list + * locked. + */ +static void +deadlist_free_threads() +{ + struct pthread *ptd, *ptdTemp; + + TAILQ_FOREACH_SAFE(ptd, &_dead_list, dle, ptdTemp) { + /* Don't destroy the initial thread or non-detached threads. */ + if (ptd == _thread_initial || + (ptd->attr.flags & PTHREAD_DETACHED) == 0) + continue; + TAILQ_REMOVE(&_dead_list, ptd, dle); + deadlist_free_onethread(ptd); + } +} + +void +deadlist_free_onethread(struct pthread *ptd) +{ + + if (ptd->attr.stackaddr_attr == NULL && ptd->stack != NULL) { + STACK_LOCK; + _thread_stack_free(ptd->stack, ptd->attr.stacksize_attr, + ptd->attr.guardsize_attr); + STACK_UNLOCK; + } + _retire_thread(ptd->arch_id); + free(ptd); +} diff --git a/lib/libthr/thread/thr_gc.c b/lib/libthr/thread/thr_gc.c deleted file mode 100644 index 1f6bc6b84133..000000000000 --- a/lib/libthr/thread/thr_gc.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 1998 John Birrell - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by John Birrell. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * - * Garbage collector thread. Frees memory allocated for dead threads. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include "thr_private.h" - -pthread_addr_t -_thread_gc(pthread_addr_t arg) -{ - int f_debug; - int f_done = 0; - int ret; - sigset_t mask; - pthread_t pthread; - pthread_t pthread_cln; - struct timespec abstime; - void *p_stack; - - /* Block all signals */ - sigfillset(&mask); - pthread_sigmask(SIG_BLOCK, &mask, NULL); - - /* Mark this thread as a library thread (not a user thread). */ - curthread->flags |= PTHREAD_FLAGS_PRIVATE; - - /* Set a debug flag based on an environment variable. */ - f_debug = (getenv("LIBC_R_DEBUG") != NULL); - - /* Set the name of this thread. */ - pthread_set_name_np(curthread,"GC"); - - while (!f_done) { - /* Check if debugging this application. */ - if (f_debug) - /* Dump thread info to file. */ - _thread_dump_info(); - - /* - * Lock the list of dead threads which ensures that - * this thread sees another thread exit: - */ - DEAD_LIST_LOCK; - - /* No stack or thread structure to free yet. */ - p_stack = NULL; - pthread_cln = NULL; - - /* Check if this is the last running thread. */ - THREAD_LIST_LOCK; - if (TAILQ_FIRST(&_thread_list) == curthread && - TAILQ_NEXT(curthread, tle) == NULL) - /* - * This is the last thread, so it can exit - * now. - */ - f_done = 1; - THREAD_LIST_UNLOCK; - - /* - * Enter a loop to search for the first dead thread that - * has memory to free. - */ - for (pthread = TAILQ_FIRST(&_dead_list); - p_stack == NULL && pthread_cln == NULL && pthread != NULL; - pthread = TAILQ_NEXT(pthread, dle)) { - /* Don't destroy the initial thread. */ - if (pthread == _thread_initial) - continue; - - UMTX_LOCK(&pthread->lock); - - /* - * Check if the stack was not specified by - * the caller to pthread_create() and has not - * been destroyed yet: - */ - STACK_LOCK; - if (pthread->attr.stackaddr_attr == NULL && - pthread->stack != NULL) { - _thread_stack_free(pthread->stack, - pthread->attr.stacksize_attr, - pthread->attr.guardsize_attr); - pthread->stack = NULL; - } - STACK_UNLOCK; - - /* - * If the thread has not been detached, leave - * it on the dead thread list. - */ - if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { - UMTX_UNLOCK(&pthread->lock); - continue; - } - - /* Remove this thread from the dead list: */ - TAILQ_REMOVE(&_dead_list, pthread, dle); - - /* - * Point to the thread structure that must - * be freed outside the locks: - */ - pthread_cln = pthread; - - UMTX_UNLOCK(&pthread->lock); - - /* - * Retire the architecture specific id so it may be - * used for new threads. - */ - _retire_thread(pthread_cln->arch_id); - - } - - /* - * Check if this is not the last thread and there is no - * memory to free this time around. - */ - if (!f_done && p_stack == NULL && pthread_cln == NULL) { - /* Get the current time. */ - if (clock_gettime(CLOCK_REALTIME,&abstime) != 0) - PANIC("gc cannot get time"); - - /* - * Do a backup poll in 10 seconds if no threads - * die before then. - */ - abstime.tv_sec += 10; - - /* - * Wait for a signal from a dying thread or a - * timeout (for a backup poll). - */ - if ((ret = pthread_cond_timedwait(&_gc_cond, - &dead_list_lock, &abstime)) != 0 && ret != ETIMEDOUT) { - _thread_printf(STDERR_FILENO, "ret = %d", ret); - PANIC("gc cannot wait for a signal"); - } - } - - /* Unlock the garbage collector mutex: */ - DEAD_LIST_UNLOCK; - - /* - * If there is memory to free, do it now. The call to - * free() might block, so this must be done outside the - * locks. - */ - if (p_stack != NULL) - free(p_stack); - if (pthread_cln != NULL) { - if (pthread_cln->name != NULL) { - /* Free the thread name string. */ - free(pthread_cln->name); - } - /* - * Free the memory allocated for the thread - * structure. - */ - free(pthread_cln); - } - } - return (NULL); -} diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index 68532f129240..d74ed2d5f4df 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -224,7 +224,6 @@ init_tdlist(struct pthread *td, int reinit) } } _pthread_mutex_destroy(&dead_list_lock); - _pthread_cond_destroy(&_gc_cond); } else { TAILQ_INIT(&_thread_list); TAILQ_INIT(&_dead_list); @@ -235,11 +234,10 @@ init_tdlist(struct pthread *td, int reinit) /* * Initialize the active thread list lock and the - * dead threads list lock & associated condition variable. + * dead threads list lock. */ memset(&thread_list_lock, 0, sizeof(spinlock_t)); - if (_pthread_mutex_init(&dead_list_lock,NULL) != 0 || - _pthread_cond_init(&_gc_cond,NULL) != 0) + if (_pthread_mutex_init(&dead_list_lock,NULL) != 0) PANIC("Failed to initialize garbage collector primitives"); } diff --git a/lib/libthr/thread/thr_join.c b/lib/libthr/thread/thr_join.c index 30acc93dea1a..b96eedc66cca 100644 --- a/lib/libthr/thread/thr_join.c +++ b/lib/libthr/thread/thr_join.c @@ -160,12 +160,12 @@ _pthread_join(pthread_t pthread, void **thread_return) *thread_return = pthread->ret; } - /* Make the thread collectable by the garbage collector. */ + /* Free all remaining memory allocated to the thread. */ pthread->attr.flags |= PTHREAD_DETACHED; UMTX_UNLOCK(&pthread->lock); + TAILQ_REMOVE(&_dead_list, pthread, dle); + deadlist_free_onethread(pthread); THREAD_LIST_UNLOCK; - if (pthread_cond_signal(&_gc_cond) != 0) - PANIC("Cannot signal gc cond"); DEAD_LIST_UNLOCK; } diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h index 081a0eb8f2e0..901c26f22a70 100644 --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -719,13 +719,6 @@ SCLASS int _clock_res_usec /* Clock resolution in usec. */ ; #endif -/* Garbage collector condition variable. */ -SCLASS pthread_cond_t _gc_cond -#ifdef GLOBAL_PTHREAD_PRIVATE -= NULL -#endif -; - /* * Array of signal actions for this process. */ @@ -791,7 +784,6 @@ void _thread_sig_wrapper(int sig, siginfo_t *info, void *context); void _thread_printf(int fd, const char *, ...); void _thread_start(void); void _thread_seterrno(pthread_t, int); -pthread_addr_t _thread_gc(pthread_addr_t); void _thread_enter_cancellation_point(void); void _thread_leave_cancellation_point(void); void _thread_cancellation_point(void); @@ -802,6 +794,7 @@ void _thread_sigblock(); void _thread_sigunblock(); void adjust_prio_inheritance(struct pthread *); void adjust_prio_protection(struct pthread *); +void deadlist_free_onethread(struct pthread *); void init_td_common(struct pthread *, struct pthread_attr *, int); void init_tdlist(struct pthread *, int); void proc_sigact_copyin(int, const struct sigaction *);