summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2007-05-08 11:16:32 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2007-05-08 11:16:32 +0000
commit4f657a2ee6148cfc1f2d3d12f424f7d3ebea8ff5 (patch)
tree66215566c5becd1c610f1780110c6cd044c8cd2a /sys/kern
parent12d317cd9a85d467c3fe66ff1b061421fc738441 (diff)
First step in making the SCHED_LOCK not recursive.
- Defer the sending of SIGCHLD and waking the parent when a process goes to sleep. We set a flag in the process "P_STOPPED" and schedule a timeout that checks all processes for this flag and sends SIGCHLD and wakes the parent on those processes that have this flag set. - Delay the waking of the parent in psignal on SIGCONT until we've released the SCHED_LOCK at the end. - In issignal, check for P_SINTR as a way to see we were called from the tsleep path with SCHED_LOCK locked and don't skip locking in that case. (This is slightly ugly, but it works until we have some better way). miod@ ok (after finding and fixing an MD bug on sgi)
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_sig.c80
1 files changed, 60 insertions, 20 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 5cc41b4c702..dd05dc6ed53 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sig.c,v 1.89 2007/04/03 08:05:43 art Exp $ */
+/* $OpenBSD: kern_sig.c,v 1.90 2007/05/08 11:16:31 art Exp $ */
/* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */
/*
@@ -78,7 +78,10 @@ int filt_signal(struct knote *kn, long hint);
struct filterops sig_filtops =
{ 0, filt_sigattach, filt_sigdetach, filt_signal };
-void proc_stop(struct proc *p);
+void proc_stop(struct proc *p, int);
+void proc_stop_sweep(void *);
+struct timeout proc_stop_to;
+
int cansignal(struct proc *, struct pcred *, struct proc *, int);
struct pool sigacts_pool; /* memory pool for sigacts structures */
@@ -146,13 +149,14 @@ cansignal(struct proc *p, struct pcred *pc, struct proc *q, int signum)
return (0);
}
-
/*
* Initialize signal-related data structures.
*/
void
signal_init(void)
{
+ timeout_set(&proc_stop_to, proc_stop_sweep, NULL);
+
pool_init(&sigacts_pool, sizeof(struct sigacts), 0, 0, 0, "sigapl",
&pool_allocator_nointr);
}
@@ -777,6 +781,7 @@ psignal(struct proc *p, int signum)
#ifdef RTHREADS
struct proc *q;
#endif
+ int wakeparent = 0;
#ifdef DIAGNOSTIC
if ((u_int)signum >= NSIG || signum == 0)
@@ -913,9 +918,7 @@ psignal(struct proc *p, int signum)
goto out;
atomic_clearbits_int(&p->p_siglist, mask);
p->p_xstat = signum;
- if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
- psignal(p->p_pptr, SIGCHLD);
- proc_stop(p);
+ proc_stop(p, 0);
goto out;
}
/*
@@ -951,7 +954,7 @@ psignal(struct proc *p, int signum)
* Otherwise, process goes back to sleep state.
*/
atomic_setbits_int(&p->p_flag, P_CONTINUED);
- wakeup(p->p_pptr);
+ wakeparent = 1;
if (action == SIG_DFL)
atomic_clearbits_int(&p->p_siglist, mask);
if (action == SIG_CATCH)
@@ -1004,6 +1007,8 @@ run:
setrunnable(p);
out:
SCHED_UNLOCK(s);
+ if (wakeparent)
+ wakeup(p->p_pptr);
}
/*
@@ -1022,6 +1027,7 @@ int
issignal(struct proc *p)
{
int signum, mask, prop;
+ int dolock = (p->p_flag & P_SINTR) == 0;
int s;
for (;;) {
@@ -1048,11 +1054,11 @@ issignal(struct proc *p)
*/
p->p_xstat = signum;
- SCHED_LOCK(s); /* protect mi_switch */
- psignal(p->p_pptr, SIGCHLD);
- proc_stop(p);
- mi_switch();
- SCHED_UNLOCK(s);
+ if (dolock)
+ SCHED_LOCK(s);
+ proc_stop(p, 1);
+ if (dolock)
+ SCHED_UNLOCK(s);
/*
* If we are no longer being traced, or the parent
@@ -1111,12 +1117,11 @@ issignal(struct proc *p)
prop & SA_TTYSTOP))
break; /* == ignore */
p->p_xstat = signum;
- if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
- psignal(p->p_pptr, SIGCHLD);
- SCHED_LOCK(s);
- proc_stop(p);
- mi_switch();
- SCHED_UNLOCK(s);
+ if (dolock)
+ SCHED_LOCK(s);
+ proc_stop(p, 1);
+ if (dolock)
+ SCHED_UNLOCK(s);
break;
} else if (prop & SA_IGNORE) {
/*
@@ -1160,7 +1165,7 @@ keep:
* on the run queue.
*/
void
-proc_stop(struct proc *p)
+proc_stop(struct proc *p, int sw)
{
#ifdef MULTIPROCESSOR
SCHED_ASSERT_LOCKED();
@@ -1168,7 +1173,42 @@ proc_stop(struct proc *p)
p->p_stat = SSTOP;
atomic_clearbits_int(&p->p_flag, P_WAITED);
- wakeup(p->p_pptr);
+ atomic_setbits_int(&p->p_flag, P_STOPPED);
+ if (!timeout_pending(&proc_stop_to)) {
+ timeout_add(&proc_stop_to, 0);
+ /*
+ * We need this soft interrupt to be handled fast.
+ * Extra calls to softclock don't hurt.
+ */
+#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
+ softintr_schedule(softclock_si);
+#else
+ setsoftclock();
+#endif
+ }
+ if (sw)
+ mi_switch();
+}
+
+/*
+ * Called from a timeout to send signals to the parents of stopped processes.
+ * We can't do this in proc_stop because it's called with nasty locks held
+ * and we would need recursive scheduler lock to deal with that.
+ */
+void
+proc_stop_sweep(void *v)
+{
+ struct proc *p;
+
+ LIST_FOREACH(p, &allproc, p_list) {
+ if ((p->p_flag & P_STOPPED) == 0)
+ continue;
+ atomic_clearbits_int(&p->p_flag, P_STOPPED);
+
+ if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
+ psignal(p->p_pptr, SIGCHLD);
+ wakeup(p->p_pptr);
+ }
}
/*