summaryrefslogtreecommitdiffstats
path: root/lib/libthr
diff options
context:
space:
mode:
authormtm <mtm@FreeBSD.org>2003-05-27 21:48:42 +0000
committermtm <mtm@FreeBSD.org>2003-05-27 21:48:42 +0000
commitf36826da252195aa5d378f4a53351b191fc6d531 (patch)
tree4f75318788f96bf41ebf286bfc73efad47a0ea14 /lib/libthr
parent3f6c2641b4f70913825502f0cc91dfd37fb08754 (diff)
downloadFreeBSD-src-f36826da252195aa5d378f4a53351b191fc6d531.zip
FreeBSD-src-f36826da252195aa5d378f4a53351b191fc6d531.tar.gz
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
Diffstat (limited to 'lib/libthr')
-rw-r--r--lib/libthr/thread/thr_exit.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c
index 8c4a060..dd510b1 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);
OpenPOWER on IntegriCloud