summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_exit.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-01-05 03:27:09 +0000
committerkib <kib@FreeBSD.org>2015-01-05 03:27:09 +0000
commit5777edec4a4de6b756dc614129b8c3ac1605481d (patch)
tree6960c9f306d6b65c6d55b3a1dab46a3fe4eb9100 /sys/kern/kern_exit.c
parent6e9fd215c729431fe469e85f7af8fc605988227d (diff)
downloadFreeBSD-src-5777edec4a4de6b756dc614129b8c3ac1605481d.zip
FreeBSD-src-5777edec4a4de6b756dc614129b8c3ac1605481d.tar.gz
Merge reaper facility.
MFC r270443 (by mjg): Properly reparent traced processes when the tracer dies. MFC r273452 (by mjg): Plug unnecessary PRS_NEW check in kern_procctl. MFC 275800: Add a facility for non-init process to declare itself the reaper of the orphaned descendants. MFC r275821: Add missed break. MFC r275846 (by mckusick): Add some additional clarification and fix a few gammer nits. MFC r275847 (by bdrewery): Bump Dd for r275846.
Diffstat (limited to 'sys/kern/kern_exit.c')
-rw-r--r--sys/kern/kern_exit.c68
1 files changed, 53 insertions, 15 deletions
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 3f2b13a..cacb973 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -125,6 +125,31 @@ proc_realparent(struct proc *child)
return (parent);
}
+void
+reaper_abandon_children(struct proc *p, bool exiting)
+{
+ struct proc *p1, *p2, *ptmp;
+
+ sx_assert(&proctree_lock, SX_LOCKED);
+ KASSERT(p != initproc, ("reaper_abandon_children for initproc"));
+ if ((p->p_treeflag & P_TREE_REAPER) == 0)
+ return;
+ p1 = p->p_reaper;
+ LIST_FOREACH_SAFE(p2, &p->p_reaplist, p_reapsibling, ptmp) {
+ LIST_REMOVE(p2, p_reapsibling);
+ p2->p_reaper = p1;
+ p2->p_reapsubtree = p->p_reapsubtree;
+ LIST_INSERT_HEAD(&p1->p_reaplist, p2, p_reapsibling);
+ if (exiting && p2->p_pptr == p) {
+ PROC_LOCK(p2);
+ proc_reparent(p2, p1);
+ PROC_UNLOCK(p2);
+ }
+ }
+ KASSERT(LIST_EMPTY(&p->p_reaplist), ("p_reaplist not empty"));
+ p->p_treeflag &= ~P_TREE_REAPER;
+}
+
static void
clear_orphan(struct proc *p)
{
@@ -162,7 +187,8 @@ sys_sys_exit(struct thread *td, struct sys_exit_args *uap)
void
exit1(struct thread *td, int rv)
{
- struct proc *p, *nq, *q;
+ struct proc *p, *nq, *q, *t;
+ struct thread *tdt;
struct vnode *ttyvp = NULL;
mtx_assert(&Giant, MA_NOTOWNED);
@@ -450,24 +476,34 @@ exit1(struct thread *td, int rv)
WITNESS_WARN(WARN_PANIC, NULL, "process (pid %d) exiting", p->p_pid);
/*
- * Reparent all of our children to init.
+ * Reparent all children processes:
+ * - traced ones to the original parent (or init if we are that parent)
+ * - the rest to init
*/
sx_xlock(&proctree_lock);
q = LIST_FIRST(&p->p_children);
if (q != NULL) /* only need this if any child is S_ZOMB */
- wakeup(initproc);
+ wakeup(q->p_reaper);
for (; q != NULL; q = nq) {
nq = LIST_NEXT(q, p_sibling);
PROC_LOCK(q);
- proc_reparent(q, initproc);
q->p_sigparent = SIGCHLD;
- /*
- * Traced processes are killed
- * since their existence means someone is screwing up.
- */
- if (q->p_flag & P_TRACED) {
- struct thread *temp;
+ if (!(q->p_flag & P_TRACED)) {
+ proc_reparent(q, q->p_reaper);
+ } else {
+ /*
+ * Traced processes are killed since their existence
+ * means someone is screwing up.
+ */
+ t = proc_realparent(q);
+ if (t == p) {
+ proc_reparent(q, q->p_reaper);
+ } else {
+ PROC_LOCK(t);
+ proc_reparent(q, t);
+ PROC_UNLOCK(t);
+ }
/*
* Since q was found on our children list, the
* proc_reparent() call moved q to the orphan
@@ -476,8 +512,8 @@ exit1(struct thread *td, int rv)
*/
clear_orphan(q);
q->p_flag &= ~(P_TRACED | P_STOPPED_TRACE);
- FOREACH_THREAD_IN_PROC(q, temp)
- temp->td_dbgflags &= ~TDB_SUSPEND;
+ FOREACH_THREAD_IN_PROC(q, tdt)
+ tdt->td_dbgflags &= ~TDB_SUSPEND;
kern_psignal(q, SIGKILL);
}
PROC_UNLOCK(q);
@@ -553,7 +589,7 @@ exit1(struct thread *td, int rv)
mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx);
pp = p->p_pptr;
PROC_UNLOCK(pp);
- proc_reparent(p, initproc);
+ proc_reparent(p, p->p_reaper);
p->p_sigparent = SIGCHLD;
PROC_LOCK(p->p_pptr);
@@ -566,8 +602,8 @@ exit1(struct thread *td, int rv)
} else
mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx);
- if (p->p_pptr == initproc)
- kern_psignal(p->p_pptr, SIGCHLD);
+ if (p->p_pptr == p->p_reaper || p->p_pptr == initproc)
+ childproc_exited(p);
else if (p->p_sigparent != 0) {
if (p->p_sigparent == SIGCHLD)
childproc_exited(p);
@@ -840,6 +876,8 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options)
LIST_REMOVE(p, p_list); /* off zombproc */
sx_xunlock(&allproc_lock);
LIST_REMOVE(p, p_sibling);
+ reaper_abandon_children(p, true);
+ LIST_REMOVE(p, p_reapsibling);
PROC_LOCK(p);
clear_orphan(p);
PROC_UNLOCK(p);
OpenPOWER on IntegriCloud