summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2008-10-03 04:22:38 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2008-10-03 04:22:38 +0000
commitde488b267d2252ee7bce9afcebd3687ddb07a80c (patch)
tree722e4ec54122d91fef8a58e21dfe2a8c6c719fc8 /sys/kern
parentbc88e179cfce53de0abe82ca519bfa191ea45a16 (diff)
Make sigwait() work correctly. In particular, it'll work when the
signal is already pending in the calling thread or the main thread and there's no longer a race condition where the signal could be diverted but sigwait() would still block. There were some off-by-one errors too. (The checking of the main thread's pending list is just until a pending list for the process can be added to struct process. For now, such signals end up as pending on the main thread.) oks tedu@ and art@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_sig.c53
1 files changed, 47 insertions, 6 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 46c766447c8..7fe57337454 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sig.c,v 1.99 2008/06/10 20:41:52 hshoexer Exp $ */
+/* $OpenBSD: kern_sig.c,v 1.100 2008/10/03 04:22:37 guenther Exp $ */
/* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */
/*
@@ -784,12 +784,13 @@ psignal(struct proc *p, int signum)
if (p->p_flag & P_WEXIT)
return;
+ mask = sigmask(signum);
+
#ifdef RTHREADS
TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) {
if (q == p)
continue;
- if (q->p_sigdivert & (1 << signum)) {
- q->p_sigdivert = 0;
+ if (q->p_sigdivert & mask) {
psignal(q, signum);
return;
}
@@ -798,7 +799,6 @@ psignal(struct proc *p, int signum)
KNOTE(&p->p_klist, NOTE_SIGNAL | signum);
- mask = sigmask(signum);
prop = sigprop[signum];
/*
@@ -806,6 +806,14 @@ psignal(struct proc *p, int signum)
*/
if (p->p_flag & P_TRACED)
action = SIG_DFL;
+#ifdef RTHREADS
+ else if (p->p_sigdivert & mask) {
+ p->p_sigwait = signum;
+ atomic_clearbits_int(&p->p_sigdivert, ~0);
+ action = SIG_CATCH;
+ wakeup(&p->p_sigdivert);
+ }
+#endif
else {
/*
* If the signal is being ignored,
@@ -1459,10 +1467,43 @@ sys_nosys(struct proc *p, void *v, register_t *retval)
int
sys_thrsigdivert(struct proc *p, void *v, register_t *retval)
{
- struct sys_thrsigdivert_args *uap = v;
+ struct sys_thrsigdivert_args /* {
+ syscallarg(sigset_t) sigmask;
+ } */ *uap = v;
+ sigset_t mask;
+ sigset_t *m;
+ int error;
+
+ m = NULL;
+ mask = SCARG(uap, sigmask) &~ sigcantmask;
+
+ /* pending signal for this thread? */
+ if (p->p_siglist & mask)
+ m = &p->p_siglist;
+ else if (p->p_p->ps_mainproc->p_siglist & mask)
+ m = &p->p_p->ps_mainproc->p_siglist;
+ if (m != NULL) {
+ int sig = ffs((long)(*m & mask));
+ atomic_clearbits_int(m, sigmask(sig));
+ *retval = sig;
+ return (0);
+ }
- p->p_sigdivert = SCARG(uap, sigmask);
+ p->p_sigwait = 0;
+ atomic_setbits_int(&p->p_sigdivert, mask);
+ error = tsleep(&p->p_sigdivert, PPAUSE|PCATCH, "sigwait", 0);
+ if (p->p_sigdivert) {
+ /* interrupted */
+ KASSERT(error != 0);
+ atomic_clearbits_int(&p->p_sigdivert, ~0);
+ if (error == ERESTART)
+ error = EINTR;
+ return (error);
+ }
+ KASSERT(error == 0);
+ KASSERT(p->p_sigwait != 0);
+ *retval = p->p_sigwait;
return (0);
}
#endif