summaryrefslogtreecommitdiff
path: root/lib/libpthread
diff options
context:
space:
mode:
authornathanw <nathanw@NetBSD.org>2003-01-30 01:12:42 +0000
committernathanw <nathanw@NetBSD.org>2003-01-30 01:12:42 +0000
commitf66d2f37f760c96d2e0e834d068ec4f791dbfc71 (patch)
treeb7994cf2ed127453f41d3b13706c49ec644479b0 /lib/libpthread
parenta8773f45f88d5bf9095c85a8f358fb6d34d6410d (diff)
More rototilling:
* Implement pthread_kill(). * Return the old thread mask, not the old process mask, in our interpositioned sigaction call. * Refer to _NSIG, not NSIG. * Gut pthread_sigmask(). It was handling a lot of corner cases that weren't legal anyway. Handle unblocked signals with a new pthread__kill_self() routine (also used by pthread_kill()). * Be more consistent with locking around pt_sigacts[].
Diffstat (limited to 'lib/libpthread')
-rw-r--r--lib/libpthread/pthread_sig.c294
1 files changed, 165 insertions, 129 deletions
diff --git a/lib/libpthread/pthread_sig.c b/lib/libpthread/pthread_sig.c
index b74f5b5215d..f6c10147440 100644
--- a/lib/libpthread/pthread_sig.c
+++ b/lib/libpthread/pthread_sig.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread_sig.c,v 1.6 2003/01/28 21:04:37 jdolecek Exp $ */
+/* $NetBSD: pthread_sig.c,v 1.7 2003/01/30 01:12:42 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -89,6 +89,9 @@ static pthread_spin_t pt_sigsuspended_lock;
static pthread_cond_t pt_sigsuspended_cond = PTHREAD_COND_INITIALIZER;
+static void pthread__kill(pthread_t, pthread_t, int, int);
+static void pthread__kill_self(pthread_t, int, int);
+
static void
pthread__signal_tramp(int, int, void (*)(int, int, struct sigcontext *),
ucontext_t *, sigset_t *);
@@ -103,17 +106,44 @@ pthread__signal_init(void)
}
int
-/*ARGSUSED*/
pthread_kill(pthread_t thread, int sig)
{
+ pthread_t self;
+ void (*handler)(int);
+
+ self = pthread__self();
+
+ SDPRINTF(("(pthread_kill %p) kill %p sig %d\n", self, thread, sig));
+
+ if ((sig < 0) || (sig >= _NSIG))
+ return EINVAL;
+ if (pthread__find(self, thread) != 0)
+ return ESRCH;
- /* We only let the thread handle this signal if the action for
+ /*
+ * We only let the thread handle this signal if the action for
* the signal is an explicit handler. Otherwise we feed it to
* the kernel so that it can affect the whole process.
*/
+ pthread_spinlock(self, &pt_sigacts_lock);
+ handler = pt_sigacts[sig].sa_handler;
+ pthread_spinunlock(self, &pt_sigacts_lock);
+
+ if (handler == SIG_IGN) {
+ SDPRINTF(("(pthread_kill %p) do nothing\n", self, thread, sig));
+ /* Do nothing */
+ } else if ((sig == SIGKILL) || (sig == SIGSTOP) ||
+ (handler == SIG_DFL)) {
+ /* Let the kernel do the work */
+ SDPRINTF(("(pthread_kill %p) kernel kill\n", self, thread, sig));
+ kill(getpid(), sig);
+ } else {
+ pthread_spinlock(self, &thread->pt_siglock);
+ pthread__kill(self, thread, sig, 0);
+ pthread_spinunlock(self, &thread->pt_siglock);
+ }
- /* XXX implement me */
- return -1;
+ return 0;
}
@@ -125,16 +155,19 @@ pthread_kill(pthread_t thread, int sig)
int
__sigaction14(int sig, const struct sigaction *act, struct sigaction *oact)
{
- pthread_t self;
struct sigaction realact;
-
+ sigset_t oldmask;
+ pthread_t self;
+ int retval;
+
+ if ((sig <= 0) || (sig >= _NSIG))
+ return EINVAL;
+
self = pthread__self();
if (act != NULL) {
- if (sig <= 0 || sig >= _NSIG)
- return (EINVAL);
-
/* Save the information for our internal dispatch. */
pthread_spinlock(self, &pt_sigacts_lock);
+ oldmask = pt_sigacts[sig].sa_mask;
pt_sigacts[sig] = *act;
pthread_spinunlock(self, &pt_sigacts_lock);
/*
@@ -150,7 +183,11 @@ __sigaction14(int sig, const struct sigaction *act, struct sigaction *oact)
act = &realact;
}
- return (__libc_sigaction14(sig, act, oact));
+ retval = __libc_sigaction14(sig, act, oact);
+ if (oact && (retval == 0))
+ oact->sa_mask = oldmask;
+
+ return retval;
}
int
@@ -204,17 +241,17 @@ firstsig(const sigset_t *ss)
sig = ffs((int)ss->__bits[0]);
if (sig != 0)
return (sig);
-#if NSIG > 33
+#if _NSIG > 33
sig = ffs((int)ss->__bits[1]);
if (sig != 0)
return (sig + 32);
#endif
-#if NSIG > 65
+#if _NSIG > 65
sig = ffs((int)ss->__bits[2]);
if (sig != 0)
return (sig + 64);
#endif
-#if NSIG > 97
+#if _NSIG > 97
sig = ffs((int)ss->__bits[3]);
if (sig != 0)
return (sig + 96);
@@ -225,127 +262,75 @@ firstsig(const sigset_t *ss)
int
pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
+ sigset_t tmp, takelist;
pthread_t self;
- sigset_t tmp;
- int i, retval, unblocked, procmaskset;
- void (*handler)(int, int, struct sigcontext *);
- struct sigaction *act;
- struct sigcontext xxxsc;
- sigset_t oldmask, takelist;
+ int i;
self = pthread__self();
+ /*
+ * While other threads may read a process's sigmask,
+ * they won't write it, so we don't need to lock our reads of it.
+ */
+ if (oset != NULL)
+ *oset = self->pt_sigmask;
+
+ if (set == NULL)
+ return 0;
- retval = 0;
- unblocked = 0;
- if (set != NULL) {
- pthread_spinlock(self, &self->pt_siglock);
- if (how == SIG_BLOCK) {
- __sigplusset(set, &self->pt_sigmask);
- /*
- * Blocking of signals that are now
- * blocked by all threads will be done
- * lazily, at signal delivery time.
- */
- } else if (how == SIG_UNBLOCK) {
- pthread_spinlock(self, &pt_process_siglock);
- __sigminusset(set, &self->pt_sigmask);
- /*
- * Unblock any signals that were blocked
- * process-wide before this.
- */
- tmp = pt_process_sigmask;
- __sigminusset(set, &tmp);
- if (!__sigsetequal(&tmp, &pt_process_sigmask))
- pt_process_sigmask = tmp;
- unblocked = 1;
- } else if (how == SIG_SETMASK) {
- pthread_spinlock(self, &pt_process_siglock);
- self->pt_sigmask = *set;
- SDPRINTF(("(pt_sigmask %p) (set) set thread mask to "
- "%08x\n", self, self->pt_sigmask.__bits[0]));
- /*
- * Unblock any signals that were blocked
- * process-wide before this.
- */
- tmp = pt_process_sigmask;
- __sigandset(set, &tmp);
- if (!__sigsetequal(&tmp, &pt_process_sigmask))
- pt_process_sigmask = tmp;
- unblocked = 1; /* Well, maybe */
- } else
- retval = EINVAL;
+ pthread_spinlock(self, &self->pt_siglock);
+ if (how == SIG_BLOCK) {
+ __sigplusset(set, &self->pt_sigmask);
+ /*
+ * Blocking of signals that are now
+ * blocked by all threads will be done
+ * lazily, at signal delivery time.
+ */
+ pthread_spinunlock(self, &self->pt_siglock);
+ return 0;
+ } else if (how == SIG_UNBLOCK)
+ __sigminusset(set, &self->pt_sigmask);
+ else if (how == SIG_SETMASK)
+ self->pt_sigmask = *set;
+ else {
+ pthread_spinunlock(self, &self->pt_siglock);
+ return EINVAL;
}
- if (unblocked) {
- SDPRINTF(("(pt_sigmask %p) Process mask was changed to %08x\n",
- self, pt_process_sigmask.__bits[0]));
- /* See if there are any signals to take */
- __sigemptyset14(&takelist);
- while ((i = firstsig(&self->pt_siglist)) != 0) {
- if (!__sigismember14(&self->pt_sigmask, i)) {
- __sigaddset14(&takelist, i);
- __sigdelset14(&self->pt_siglist, i);
- }
- }
- while ((i = firstsig(&pt_process_siglist)) != 0) {
- if (!__sigismember14(&self->pt_sigmask, i)) {
- __sigaddset14(&takelist, i);
- __sigdelset14(&pt_process_siglist, i);
- }
- }
-
- procmaskset = 0;
- while ((i = firstsig(&takelist)) != 0) {
- if (!__sigismember14(&self->pt_sigmask, i)) {
- /* Take the signal */
- act = &pt_sigacts[i];
- oldmask = self->pt_sigmask;
- __sigplusset(&self->pt_sigmask,
- &act->sa_mask);
- __sigaddset14(&self->pt_sigmask, i);
- pthread_spinunlock(self, &pt_process_siglock);
- pthread_spinunlock(self, &self->pt_siglock);
- SDPRINTF(("(pt_sigmask %p) taking unblocked signal %d\n", self, i));
- handler =
- (void (*)(int, int, struct sigcontext *))
- act->sa_handler;
- handler(i, 0, &xxxsc);
- pthread_spinlock(self, &self->pt_siglock);
- pthread_spinlock(self, &pt_process_siglock);
- __sigdelset14(&takelist, i);
- /* Reset masks */
- self->pt_sigmask = oldmask;
- tmp = pt_process_sigmask;
- __sigandset(&oldmask, &tmp);
- if (!__sigsetequal(&tmp, &pt_process_sigmask)){
- pt_process_sigmask = tmp;
- SDPRINTF(("(pt_sigmask %p) setting proc sigmask to %08x\n", pt_process_sigmask.__bits[0]));
- __sigprocmask14(SIG_SETMASK,
- &pt_process_sigmask, NULL);
- procmaskset = 1;
- }
- }
+ /* See if there are any signals to take */
+ __sigemptyset14(&takelist);
+ while ((i = firstsig(&self->pt_siglist)) != 0) {
+ if (!__sigismember14(&self->pt_sigmask, i)) {
+ __sigaddset14(&takelist, i);
+ __sigdelset14(&self->pt_siglist, i);
}
- if (!procmaskset) {
- SDPRINTF(("(pt_sigmask %p) setting proc sigmask to %08x\n", self, pt_process_sigmask.__bits[0]));
- __sigprocmask14(SIG_SETMASK, &pt_process_sigmask, NULL);
+ }
+ pthread_spinlock(self, &pt_process_siglock);
+ while ((i = firstsig(&pt_process_siglist)) != 0) {
+ if (!__sigismember14(&self->pt_sigmask, i)) {
+ __sigaddset14(&takelist, i);
+ __sigdelset14(&pt_process_siglist, i);
}
- }
- if (set != NULL) {
- if ((how == SIG_UNBLOCK) || (how == SIG_SETMASK))
- pthread_spinunlock(self, &pt_process_siglock);
- pthread_spinunlock(self, &self->pt_siglock);
}
+ /* Unblock any signals that were blocked process-wide before this. */
+ tmp = pt_process_sigmask;
+ __sigandset(&self->pt_sigmask, &tmp);
+ if (!__sigsetequal(&tmp, &pt_process_sigmask)) {
+ pt_process_sigmask = tmp;
+ __sigprocmask14(SIG_SETMASK, &pt_process_sigmask, NULL);
+ }
+ pthread_spinunlock(self, &pt_process_siglock);
- /*
- * While other threads may read a process's sigmask,
- * they won't write it, so we don't need to lock our reads of it.
- */
- if (oset != NULL) {
- *oset = self->pt_sigmask;
+ while ((i = firstsig(&takelist)) != 0) {
+ /* Take the signal */
+ SDPRINTF(("(pt_sigmask %p) taking unblocked signal %d\n",
+ self, i));
+ pthread__kill_self(self, i, 0);
+ __sigdelset14(&takelist, i);
}
- return retval;
+ pthread_spinunlock(self, &self->pt_siglock);
+
+ return 0;
}
@@ -438,10 +423,58 @@ pthread__signal(pthread_t self, pthread_t t, int sig, int code)
__sigprocmask14(SIG_SETMASK, &pt_process_sigmask, NULL);
pthread_spinunlock(self, &pt_process_siglock);
- if (t && __sigismember14(&target->pt_sigmask, sig)) {
+ pthread__kill(self, target, sig, code);
+ pthread_spinunlock(self, &target->pt_siglock);
+}
+
+/*
+ * Call the signal handler in the context of this thread. Not quite as
+ * suicidal as it sounds.
+ * Must be called with target's siglock held.
+ */
+static void
+pthread__kill_self(pthread_t self, int sig, int code)
+{
+ struct sigcontext xxxsc;
+ sigset_t oldmask;
+ struct sigaction act;
+ void (*handler)(int, int, struct sigcontext *);
+
+ pthread_spinlock(self, &pt_sigacts_lock);
+ act = pt_sigacts[sig];
+ pthread_spinunlock(self, &pt_sigacts_lock);
+
+ SDPRINTF(("(pthread__kill_self %p) sig %d code %d\n", self, sig, code));
+
+ oldmask = self->pt_sigmask;
+ __sigplusset(&self->pt_sigmask, &act.sa_mask);
+ if ((act.sa_flags & SA_NODEFER) == 0)
+ __sigaddset14(&self->pt_sigmask, sig);
+
+ handler = (void (*)(int, int, struct sigcontext *)) act.sa_handler;
+
+ pthread_spinunlock(self, &self->pt_siglock);
+ handler(sig, code, &xxxsc);
+ pthread_spinlock(self, &self->pt_siglock);
+
+ self->pt_sigmask = oldmask;
+}
+
+/* Must be called with target's siglock held */
+static void
+pthread__kill(pthread_t self, pthread_t target, int sig, int code)
+{
+
+ SDPRINTF(("(pthread__kill %p) target %p sig %d code %d\n", self, target, sig, code));
+
+ if (__sigismember14(&target->pt_sigmask, sig)) {
/* Record the signal for later delivery. */
__sigaddset14(&target->pt_siglist, sig);
- pthread_spinunlock(self, &target->pt_siglock);
+ return;
+ }
+
+ if (self == target) {
+ pthread__kill_self(self, sig, code);
return;
}
@@ -479,7 +512,6 @@ pthread__signal(pthread_t self, pthread_t t, int sig, int code)
__sigaddset14(&target->pt_sigblocked, sig);
__sigaddset14(&target->pt_sigmask, sig);
target->pt_flags |= PT_FLAG_SIGDEFERRED;
- pthread_spinunlock(self, &target->pt_siglock);
pthread_spinunlock(self, &target->pt_statelock);
_lwp_wakeup(target->pt_blockedlwp);
return;
@@ -498,15 +530,19 @@ pthread__deliver_signal(pthread_t self, pthread_t target, int sig, int code)
{
sigset_t oldmask, *maskp;
ucontext_t *uc;
+ struct sigaction act;
+ pthread_spinlock(self, &pt_sigacts_lock);
+ act = pt_sigacts[sig];
+ pthread_spinunlock(self, &pt_sigacts_lock);
+
/*
* Prevent anyone else from considering this thread for handling
* more instances of this signal.
*/
oldmask = target->pt_sigmask;
- __sigplusset(&target->pt_sigmask, &pt_sigacts[sig].sa_mask);
+ __sigplusset(&target->pt_sigmask, &act.sa_mask);
__sigaddset14(&target->pt_sigmask, sig);
- pthread_spinunlock(self, &target->pt_siglock);
/*
* We'd like to just pass oldmask to the
@@ -537,7 +573,7 @@ pthread__deliver_signal(pthread_t self, pthread_t target, int sig, int code)
SDPRINTF(("(makecontext %p): target %p: sig: %d %d uc: %p oldmask: %08x\n",
self, target, sig, code, target->pt_uc, maskp->__bits[0]));
makecontext(uc, pthread__signal_tramp, 5,
- sig, code, pt_sigacts[sig].sa_handler, target->pt_uc, maskp);
+ sig, code, act.sa_handler, target->pt_uc, maskp);
target->pt_uc = uc;
}