diff options
author | jb <jb@FreeBSD.org> | 1998-09-30 06:36:56 +0000 |
---|---|---|
committer | jb <jb@FreeBSD.org> | 1998-09-30 06:36:56 +0000 |
commit | df42f1ac5f49d30528909286a925e0d7492bc337 (patch) | |
tree | f3bf279acabc8ce90e6bbf65e33a722b578cebfb /lib/libkse/thread/thr_exit.c | |
parent | d76ace8cb5de85bc8d0e7bcd29ff688098b1de96 (diff) | |
download | FreeBSD-src-df42f1ac5f49d30528909286a925e0d7492bc337.zip FreeBSD-src-df42f1ac5f49d30528909286a925e0d7492bc337.tar.gz |
Move the cleanup code that frees memory allocated for a dead thread from
the thread kernel into a garbage collector thread which is started when
the fisrt thread is created (other than the initial thread). This
removes the window of opportunity where a context switch will cause a
thread that has locked the malloc spinlock, to enter the thread kernel,
find there is a dead thread and try to free memory, therefore trying
to lock the malloc spinlock against itself.
The garbage collector thread acts just like any other thread, so
instead of having a spinlock to control accesses to the dead thread
list, it uses a mutex and a condition variable so that it can happily
wait to be signalled when a thread exists.
Diffstat (limited to 'lib/libkse/thread/thr_exit.c')
-rw-r--r-- | lib/libkse/thread/thr_exit.c | 61 |
1 files changed, 17 insertions, 44 deletions
diff --git a/lib/libkse/thread/thr_exit.c b/lib/libkse/thread/thr_exit.c index 0083f2b..a5fc400 100644 --- a/lib/libkse/thread/thr_exit.c +++ b/lib/libkse/thread/thr_exit.c @@ -133,56 +133,29 @@ pthread_exit(void *status) PTHREAD_NEW_STATE(pthread,PS_RUNNING); } - /* Lock the thread list: */ - _lock_thread_list(); - - /* Check if the running thread is at the head of the linked list: */ - if (_thread_link_list == _thread_run) { - /* There is no previous thread: */ - _thread_link_list = _thread_run->nxt; - } else { - /* Point to the first thread in the list: */ - pthread = _thread_link_list; - - /* - * Enter a loop to find the thread in the linked list before - * the running thread: - */ - while (pthread != NULL && pthread->nxt != _thread_run) { - /* Point to the next thread: */ - pthread = pthread->nxt; - } - - /* Check that a previous thread was found: */ - if (pthread != NULL) { - /* - * Point the previous thread to the one after the - * running thread: - */ - pthread->nxt = _thread_run->nxt; - } - } - - /* Unlock the thread list: */ - _unlock_thread_list(); - - /* Lock the dead thread list: */ - _lock_dead_thread_list(); - /* - * This thread will never run again. Add it to the list of dead - * threads: + * Lock the garbage collector mutex to ensure that the garbage + * collector is not using the dead thread list. */ - _thread_run->nxt = _thread_dead; - _thread_dead = _thread_run; + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); - /* Unlock the dead thread list: */ - _unlock_dead_thread_list(); + /* Add this thread to the list of dead threads. */ + _thread_run->nxt_dead = _thread_dead; + _thread_dead = _thread_run; /* - * The running thread is no longer in the thread link list so it will - * now die: + * Signal the garbage collector thread that there is something + * to clean up. */ + if (pthread_cond_signal(&_gc_cond) != 0) + PANIC("Cannot signal gc cond"); + + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* This this thread will never be re-scheduled. */ _thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__); /* This point should not be reached. */ |