From a09d02f780d6aac0bdd6d86cb0cce6e91198b407 Mon Sep 17 00:00:00 2001 From: Mike Makonnen Date: Tue, 27 May 2003 21:48:42 +0000 Subject: [PATCH] Minimize the potential for deadlocks between an exiting thread and it's joiner by making sure all locks and unlocks occur in the same order. For the record the lock order is: DEAD_LIST, THREAD_LIST, exiting thread, joiner thread. Approved by: re/rwatson --- lib/libthr/thread/thr_exit.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c index 8c4a0601f78..dd510b15523 100644 --- a/lib/libthr/thread/thr_exit.c +++ b/lib/libthr/thread/thr_exit.c @@ -94,7 +94,7 @@ _thread_exit_cleanup(void) void _pthread_exit(void *status) { - pthread_t pthread; + pthread_t pthread, joiner; int exitNow = 0; /* Check if this thread is already in the process of exiting: */ @@ -122,10 +122,27 @@ _pthread_exit(void *status) _thread_cleanupspecific(); } +retry: + /* + * Proper lock order, to minimize deadlocks, between joining + * and exiting threads is: DEAD_LIST, THREAD_LIST, exiting, joiner. + * In order to do this *and* protect from races, we must resort + * this test-and-retry loop. + */ + joiner = curthread->joiner; + /* Lock the dead list first to maintain correct lock order */ DEAD_LIST_LOCK; + THREAD_LIST_LOCK; _thread_critical_enter(curthread); + if (joiner != curthread->joiner) { + _thread_critical_exit(curthread); + THREAD_LIST_UNLOCK; + DEAD_LIST_UNLOCK; + goto retry; + } + /* Check if there is a thread joining this one: */ if (curthread->joiner != NULL) { pthread = curthread->joiner; @@ -151,7 +168,6 @@ _pthread_exit(void *status) * Add this thread to the list of dead threads, and * also remove it from the active threads list. */ - THREAD_LIST_LOCK; TAILQ_INSERT_HEAD(&_dead_list, curthread, dle); TAILQ_REMOVE(&_thread_list, curthread, tle); PTHREAD_SET_STATE(curthread, PS_DEAD);