From d67355bbb5c570cac6fe866113d79ce9de9b51a7 Mon Sep 17 00:00:00 2001 From: Nikodemus Siivola Date: Mon, 7 Nov 2011 14:49:57 +0200 Subject: [PATCH] pthread_cond_broadcast is not asynch signal safe AKA /less/ GC deadlocks on Darwin. To be specific, it can cause our GC to deadlock on Darwin, with all lisp threads spinning on the same global spinlock in the bowels of the pthread_cond_wait implementation. That was fun to figure out. The test (:interrupt-thread :interrupt-consing-child) is a good one for catching this: try to run it repeatedly under an earlier SBCL under Darwin, and sooner or later it will hang. ...with this commit, we're still using pthread_cond_broadcast, but blocking signals around the relevant bits, which --experimentally-- makes the aforementioned test pass "somewhat more consistently". It can still hang, but those hangs seem to be related to deferrable signals being indefinitely blocked in one of the threads -- no idea as of yet why. Summa Summarum: this is a bit of a sorry bandaid, waiting for a better solution. (Probably using realtime semaphores, which /should/ be signal-handler safe.) --- src/runtime/thread.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/runtime/thread.h b/src/runtime/thread.h index 249d226..e62cb2b 100644 --- a/src/runtime/thread.h +++ b/src/runtime/thread.h @@ -30,28 +30,37 @@ static inline lispobj thread_state(struct thread *thread) { lispobj state; + sigset_t old; + block_blockable_signals(0, &old); pthread_mutex_lock(thread->state_lock); state = thread->state; pthread_mutex_unlock(thread->state_lock); + thread_sigmask(SIG_SETMASK,&old,0); return state; } static inline void set_thread_state(struct thread *thread, lispobj state) { + sigset_t old; + block_blockable_signals(0, &old); pthread_mutex_lock(thread->state_lock); thread->state = state; pthread_cond_broadcast(thread->state_cond); pthread_mutex_unlock(thread->state_lock); + thread_sigmask(SIG_SETMASK,&old,0); } static inline void wait_for_thread_state_change(struct thread *thread, lispobj state) { + sigset_t old; + block_blockable_signals(0, &old); pthread_mutex_lock(thread->state_lock); while (thread->state == state) pthread_cond_wait(thread->state_cond, thread->state_lock); pthread_mutex_unlock(thread->state_lock); + thread_sigmask(SIG_SETMASK,&old,0); } extern pthread_key_t lisp_thread; -- 1.7.10.4