summaryrefslogtreecommitdiffstats
path: root/lib/libthr
diff options
context:
space:
mode:
authormtm <mtm@FreeBSD.org>2004-03-28 14:05:28 +0000
committermtm <mtm@FreeBSD.org>2004-03-28 14:05:28 +0000
commitc715901410e98c7b0c336278828765e4285964d3 (patch)
treec847bc30278d22c01ea70ac7fbb7c69dc9831151 /lib/libthr
parent1425c998a18db105fcdc560157ebc5bb857ab2e6 (diff)
downloadFreeBSD-src-c715901410e98c7b0c336278828765e4285964d3.zip
FreeBSD-src-c715901410e98c7b0c336278828765e4285964d3.tar.gz
Remove the garbage collector thread. All resources are freed
in-line. If the exiting thread cannot release a resource, then the next thread to exit will release it.
Diffstat (limited to 'lib/libthr')
-rw-r--r--lib/libthr/thread/Makefile.inc1
-rw-r--r--lib/libthr/thread/thr_create.c15
-rw-r--r--lib/libthr/thread/thr_exit.c48
-rw-r--r--lib/libthr/thread/thr_gc.c203
-rw-r--r--lib/libthr/thread/thr_init.c6
-rw-r--r--lib/libthr/thread/thr_join.c6
-rw-r--r--lib/libthr/thread/thr_private.h9
7 files changed, 44 insertions, 244 deletions
diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc
index 8e11911..52d428b 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 32ca697..5f1887d 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 41b1f86..0455a97 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 @@ retry:
}
/*
+ * 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 @@ retry:
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 @@ retry:
/* 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 1f6bc6b..0000000
--- a/lib/libthr/thread/thr_gc.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>
- * 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 <sys/param.h>
-#include <errno.h>
-#include <time.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <pthread.h>
-#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 68532f1..d74ed2d 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 30acc93..b96eedc 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 081a0eb..901c26f 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 *);
OpenPOWER on IntegriCloud