diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 2007-05-08 11:16:32 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 2007-05-08 11:16:32 +0000 |
commit | 4f657a2ee6148cfc1f2d3d12f424f7d3ebea8ff5 (patch) | |
tree | 66215566c5becd1c610f1780110c6cd044c8cd2a /sys/kern | |
parent | 12d317cd9a85d467c3fe66ff1b061421fc738441 (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.c | 80 |
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); + } } /* |