diff options
author | davidxu <davidxu@FreeBSD.org> | 2005-11-08 09:09:26 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2005-11-08 09:09:26 +0000 |
commit | 37bb48367998c0be2f8c72d721837dad4be5ae7b (patch) | |
tree | 13693dc8f2ef07d2346275020e67f9f5c512abc9 /sys/kern/kern_exit.c | |
parent | 9349a52f4187301776450d07f77fbf8af30d7c87 (diff) | |
download | FreeBSD-src-37bb48367998c0be2f8c72d721837dad4be5ae7b.zip FreeBSD-src-37bb48367998c0be2f8c72d721837dad4be5ae7b.tar.gz |
Add support for queueing SIGCHLD same as other UNIX systems did.
For each child process whose status has been changed, a SIGCHLD instance
is queued, if the signal is stilling pending, and process changed status
several times, signal information is updated to reflect latest process
status. If wait() returns because the status of a child process is
available, pending SIGCHLD signal associated with the child process is
discarded. Any other pending SIGCHLD signals remain pending.
The signal information is allocated at the same time when proc structure
is allocated, if process signal queue is fully filled or there is a memory
shortage, it can still send the signal to process.
There is a booting time tunable kern.sigqueue.queue_sigchild which
can control the behavior, setting it to zero disables the SIGCHLD queueing
feature, the tunable will be removed if the function is proved that it is
stable enough.
Tested on: i386 (SMP and UP)
Diffstat (limited to 'sys/kern/kern_exit.c')
-rw-r--r-- | sys/kern/kern_exit.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 6107a00..191bb7c 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -173,6 +173,11 @@ retry: } p->p_flag |= P_WEXIT; + + PROC_LOCK(p->p_pptr); + sigqueue_take(p->p_ksi); + PROC_UNLOCK(p->p_pptr); + PROC_UNLOCK(p); /* Are we a task leader? */ @@ -480,8 +485,12 @@ retry: if (p->p_pptr == initproc) psignal(p->p_pptr, SIGCHLD); - else if (p->p_sigparent != 0) - psignal(p->p_pptr, p->p_sigparent); + else if (p->p_sigparent != 0) { + if (p->p_sigparent == SIGCHLD) + childproc_exited(p); + else /* LINUX thread */ + psignal(p->p_pptr, p->p_sigparent); + } PROC_UNLOCK(p->p_pptr); /* @@ -659,6 +668,10 @@ loop: calcru(p, &rusage->ru_utime, &rusage->ru_stime); } + PROC_LOCK(q); + sigqueue_take(p->p_ksi); + PROC_UNLOCK(q); + /* * If we got the child via a ptrace 'attach', * we need to give it back to the old parent. @@ -669,7 +682,7 @@ loop: p->p_oppid = 0; proc_reparent(p, t); PROC_UNLOCK(p); - psignal(t, SIGCHLD); + tdsignal(t, NULL, SIGCHLD, p->p_ksi); wakeup(t); PROC_UNLOCK(t); sx_xunlock(&proctree_lock); @@ -751,6 +764,11 @@ loop: if (status) *status = W_STOPCODE(p->p_xstat); PROC_UNLOCK(p); + + PROC_LOCK(q); + sigqueue_take(p->p_ksi); + PROC_UNLOCK(q); + return (0); } mtx_unlock_spin(&sched_lock); @@ -760,6 +778,10 @@ loop: p->p_flag &= ~P_CONTINUED; PROC_UNLOCK(p); + PROC_LOCK(q); + sigqueue_take(p->p_ksi); + PROC_UNLOCK(q); + if (status) *status = SIGCONT; return (0); |