From 76a9679f8e8734fcba0d83360290d92ffd5c609d Mon Sep 17 00:00:00 2001 From: David Xu Date: Tue, 4 Mar 2008 04:28:59 +0000 Subject: [PATCH] If a new thread is created, it inherits current thread's signal masks, however if current thread is executing cancellation handler, signal SIGCANCEL may have already been blocked, this is unexpected, unblock the signal in new thread if this happens. MFC after: 1 week --- lib/libthr/thread/thr_create.c | 17 ++++++++++++++++- lib/libthr/thread/thr_private.h | 6 ++++++ lib/libthr/thread/thr_sig.c | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c index 03f0584cff3..3bfd3b3a5e2 100644 --- a/lib/libthr/thread/thr_create.c +++ b/lib/libthr/thread/thr_create.c @@ -123,6 +123,11 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, if (new_thread->attr.flags & PTHREAD_CREATE_DETACHED) new_thread->tlflags |= TLFLAGS_DETACHED; + if (curthread->in_sigcancel_handler) + new_thread->unblock_sigcancel = 1; + else + new_thread->unblock_sigcancel = 0; + /* Add the new thread. */ new_thread->refcount = 1; _thr_link(curthread, new_thread); @@ -172,8 +177,10 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr, ret = EAGAIN; } - if (create_suspended) + if (create_suspended) { __sys_sigprocmask(SIG_SETMASK, &oset, NULL); + SIGDELSET(oset, SIGCANCEL); + } if (ret != 0) { if (!locked) @@ -217,6 +224,14 @@ create_stack(struct pthread_attr *pattr) static void thread_start(struct pthread *curthread) { + if (curthread->unblock_sigcancel) { + sigset_t set; + + SIGEMPTYSET(set); + SIGADDSET(set, SIGCANCEL); + sigprocmask(SIG_UNBLOCK, &set, NULL); + } + if (curthread->attr.suspend == THR_CREATE_SUSPENDED) { sigset_t set = curthread->sigmask; diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h index 4db3b7a0028..ff9f52bedeb 100644 --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -378,6 +378,12 @@ struct pthread { /* Thread temporary signal mask. */ sigset_t sigmask; + /* Thread is in SIGCANCEL handler. */ + int in_sigcancel_handler; + + /* New thread should unblock SIGCANCEL. */ + int unblock_sigcancel; + /* Thread state: */ enum pthread_state state; diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c index 6da4b90538f..c8ebc243a43 100644 --- a/lib/libthr/thread/thr_sig.c +++ b/lib/libthr/thread/thr_sig.c @@ -69,7 +69,9 @@ sigcancel_handler(int sig __unused, if (curthread->cancel_defer && curthread->cancel_pending) thr_wake(curthread->tid); + curthread->in_sigcancel_handler = 1; _thr_ast(curthread); + curthread->in_sigcancel_handler = 0; } void