summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authornathanw <nathanw@NetBSD.org>2003-02-07 21:43:18 +0000
committernathanw <nathanw@NetBSD.org>2003-02-07 21:43:18 +0000
commit4c99df7fccc7fbbe9f96e6f74b51eaa3aafc5efb (patch)
tree804640a2d4113057c0bbec7f8cd5c40f9e7b17dd /sys
parent610dbac2ccc25badb819c49854edff0085d61662 (diff)
Two fixes:
* Change the semantics of proc_unstop() slightly, so that it is responsible for making all stopped LWPs runnable, instead of all-but-one. Return value is a LWP that can be interrupted if doing so is necessary to take a signal. Adjust callers of proc_stop() to the new, simpler semantics. * When a non-continue signal is delivered to a stopped process and there is a LWP sleeping interruptably, call setrunnable() (by way of the 'out:' target in psignal1) instead of calling unsleep() so that it becomes LSSTOP in issignal() and continuable by proc_unstop(). Addresses PR kern/19990 by Martin Husemann, with suggestions from enami tsugutomo.
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_sig.c65
1 files changed, 32 insertions, 33 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index a29a49b7b64..919edb0c4ed 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_sig.c,v 1.132 2003/02/07 09:02:14 jdolecek Exp $ */
+/* $NetBSD: kern_sig.c,v 1.133 2003/02/07 21:43:18 nathanw Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
@@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.132 2003/02/07 09:02:14 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.133 2003/02/07 21:43:18 nathanw Exp $");
#include "opt_ktrace.h"
#include "opt_compat_sunos.h"
@@ -973,7 +973,6 @@ psignal1(struct proc *p, int signum,
l = proc_unstop(p);
if (l)
goto runfast;
- /* XXX should this be possible? */
goto out;
}
@@ -996,16 +995,8 @@ psignal1(struct proc *p, int signum,
sigdelset(&p->p_sigctx.ps_siglist,
signum);
l = proc_unstop(p);
- /*
- * XXX see note in proc_unstop(). SIGKILL
- * XXX and SIGCONT have conflicting needs.
- */
- if (l && (l->l_stat == LSSLEEP))
- l = NULL;
if (l && (action == SIG_CATCH))
goto runfast;
- if (l)
- goto run;
goto out;
}
@@ -1019,14 +1010,15 @@ psignal1(struct proc *p, int signum,
}
/*
- * If process is sleeping interruptibly, then
- * simulate a wakeup so that when it is
- * continued, it will be made runnable and can
- * look at the signal. But don't make the
- * process runnable, leave it stopped.
+ * If a lwp is sleeping interruptibly, then
+ * wake it up; it will run until the kernel
+ * boundary, where it will stop in issignal(),
+ * since p->p_stat is still SSTOP. When the
+ * process is continued, it will be made
+ * runnable and can look at the signal.
*/
if (l)
- unsleep(l);
+ goto run;
goto out;
} else {
/* Else what? */
@@ -1364,11 +1356,20 @@ proc_stop(struct proc *p)
sched_wakeup((caddr_t)p->p_pptr);
}
+/*
+ * Given a process in state SSTOP, set the state back to SACTIVE and
+ * move LSSTOP'd LWPs to LSSLEEP or make them runnable.
+ *
+ * If no LWPs ended up runnable (and therefore able to take a signal),
+ * return a LWP that is sleeping interruptably. The caller can wake
+ * that LWP up to take a signal.
+ */
struct lwp *
proc_unstop(p)
struct proc *p;
{
struct lwp *l, *lr = NULL;
+ int cantake = 0;
SCHED_ASSERT_LOCKED();
@@ -1378,28 +1379,26 @@ proc_unstop(p)
*/
p->p_stat = SACTIVE;
- /*
- * For the benefit of SIGKILL, return the idle LWP if there's
- * nothing better (and if there is an idle LWP, there
- * shouldn't be anything better.
- * XXX This is bad for SIGCONT; SIGSTOP/SIGCONT shouldn't
- * XXX noticably affect the state of a process, idling or
- * XXX not. We work around this in the SIGCONT handling in
- * XXX psignal().
- */
- if (p->p_flag & P_SA)
+ if (p->p_flag & P_SA) {
lr = p->p_sa->sa_idle; /* OK if this is NULL. */
+ cantake = 1;
+ }
LIST_FOREACH(l, &p->p_lwps, l_sibling) {
+ if (l->l_stat == LSRUN)
+ cantake = 1;
if (l->l_stat != LSSTOP)
continue;
- if (l->l_wchan == NULL) {
- if (lr == NULL)
- lr = l;
- else if (l != lr)
- setrunnable(l);
- } else
+ if (l->l_wchan != NULL) {
l->l_stat = LSSLEEP;
+ if ((cantake == 0) && (l->l_flag & L_SINTR)) {
+ lr = l;
+ cantake = 1;
+ }
+ } else {
+ setrunnable(l);
+ cantake = 1;
+ }
}
return lr;