summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2008-03-04 04:28:59 +0000
committerdavidxu <davidxu@FreeBSD.org>2008-03-04 04:28:59 +0000
commit8ead1ed2f9013c5815c4c1db7a3cfe8ba641cf58 (patch)
tree5a3c84004ac145a232bef7db666578efa5dd21e8
parente0d98325b4da9160dd1e0041c794b99e37ddb7df (diff)
downloadFreeBSD-src-8ead1ed2f9013c5815c4c1db7a3cfe8ba641cf58.zip
FreeBSD-src-8ead1ed2f9013c5815c4c1db7a3cfe8ba641cf58.tar.gz
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
-rw-r--r--lib/libthr/thread/thr_create.c17
-rw-r--r--lib/libthr/thread/thr_private.h6
-rw-r--r--lib/libthr/thread/thr_sig.c2
3 files changed, 24 insertions, 1 deletions
diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c
index 03f0584..3bfd3b3 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 4db3b7a..ff9f52b 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 6da4b90..c8ebc24 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
OpenPOWER on IntegriCloud