Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_exit.c
Show First 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | |||||
#ifdef KDTRACE_HOOKS | #ifdef KDTRACE_HOOKS | ||||
#include <sys/dtrace_bsd.h> | #include <sys/dtrace_bsd.h> | ||||
dtrace_execexit_func_t dtrace_fasttrap_exit; | dtrace_execexit_func_t dtrace_fasttrap_exit; | ||||
#endif | #endif | ||||
SDT_PROVIDER_DECLARE(proc); | SDT_PROVIDER_DECLARE(proc); | ||||
SDT_PROBE_DEFINE1(proc, , , exit, "int"); | SDT_PROBE_DEFINE1(proc, , , exit, "int"); | ||||
#ifdef VIMAGE | |||||
VPS_DECLARE(int, vrebooting); /* kern_reboot() has been called. */ | |||||
#define V_vrebooting VPS(vrebooting) | |||||
#endif | |||||
/* Hook for NFS teardown procedure. */ | /* Hook for NFS teardown procedure. */ | ||||
void (*nlminfo_release_p)(struct proc *p); | void (*nlminfo_release_p)(struct proc *p); | ||||
EVENTHANDLER_LIST_DECLARE(process_exit); | EVENTHANDLER_LIST_DECLARE(process_exit); | ||||
struct proc * | struct proc * | ||||
proc_realparent(struct proc *child) | proc_realparent(struct proc *child) | ||||
{ | { | ||||
struct proc *p, *parent; | struct proc *p, *parent; | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
if ((child->p_treeflag & P_TREE_ORPHANED) == 0) { | if ((child->p_treeflag & P_TREE_ORPHANED) == 0) { | ||||
if (child->p_oppid == 0 || | if (child->p_oppid == 0 || | ||||
child->p_pptr->p_pid == child->p_oppid) | child->p_pptr->p_pid == child->p_oppid) | ||||
parent = child->p_pptr; | parent = child->p_pptr; | ||||
else | else | ||||
parent = initproc; | parent = V_initproc; | ||||
return (parent); | return (parent); | ||||
} | } | ||||
for (p = child; (p->p_treeflag & P_TREE_FIRST_ORPHAN) == 0;) { | for (p = child; (p->p_treeflag & P_TREE_FIRST_ORPHAN) == 0;) { | ||||
/* Cannot use LIST_PREV(), since the list head is not known. */ | /* Cannot use LIST_PREV(), since the list head is not known. */ | ||||
p = __containerof(p->p_orphan.le_prev, struct proc, | p = __containerof(p->p_orphan.le_prev, struct proc, | ||||
p_orphan.le_next); | p_orphan.le_next); | ||||
KASSERT((p->p_treeflag & P_TREE_ORPHANED) != 0, | KASSERT((p->p_treeflag & P_TREE_ORPHANED) != 0, | ||||
("missing P_ORPHAN %p", p)); | ("missing P_ORPHAN %p", p)); | ||||
} | } | ||||
parent = __containerof(p->p_orphan.le_prev, struct proc, | parent = __containerof(p->p_orphan.le_prev, struct proc, | ||||
p_orphans.lh_first); | p_orphans.lh_first); | ||||
return (parent); | return (parent); | ||||
} | } | ||||
void | void | ||||
reaper_abandon_children(struct proc *p, bool exiting) | reaper_abandon_children(struct proc *p, bool exiting) | ||||
{ | { | ||||
struct proc *p1, *p2, *ptmp; | struct proc *p1, *p2, *ptmp; | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
KASSERT(p != initproc, ("reaper_abandon_children for initproc")); | /* init inside a vps may die on prison_remove. */ | ||||
if ((p->p_treeflag & P_TREE_REAPER) == 0) | KASSERT(!IS_DEFAULT_VPS(curvps) || p != V_initproc, | ||||
("%s: for initproc %p", __func__, p)); | |||||
if ((p->p_treeflag & P_TREE_REAPER) == 0) { | |||||
KASSERT((p != V_initproc && p->p_pid != 1 && p->p_pid != 0), | |||||
("%s:%d curvps %p p %p pid %d p_treeflag %#x", | |||||
__func__, __LINE__, curvps, p, p->p_pid, p->p_treeflag)); | |||||
return; | return; | ||||
} | |||||
p1 = p->p_reaper; | p1 = p->p_reaper; | ||||
LIST_FOREACH_SAFE(p2, &p->p_reaplist, p_reapsibling, ptmp) { | LIST_FOREACH_SAFE(p2, &p->p_reaplist, p_reapsibling, ptmp) { | ||||
LIST_REMOVE(p2, p_reapsibling); | LIST_REMOVE(p2, p_reapsibling); | ||||
p2->p_reaper = p1; | p2->p_reaper = p1; | ||||
p2->p_reapsubtree = p->p_reapsubtree; | p2->p_reapsubtree = p->p_reapsubtree; | ||||
LIST_INSERT_HEAD(&p1->p_reaplist, p2, p_reapsibling); | LIST_INSERT_HEAD(&p1->p_reaplist, p2, p_reapsibling); | ||||
if (exiting && p2->p_pptr == p) { | if (exiting && p2->p_pptr == p) { | ||||
PROC_LOCK(p2); | PROC_LOCK(p2); | ||||
proc_reparent(p2, p1); | proc_reparent(p2, p1); | ||||
PROC_UNLOCK(p2); | PROC_UNLOCK(p2); | ||||
} | } | ||||
} | } | ||||
KASSERT(LIST_EMPTY(&p->p_reaplist), ("p_reaplist not empty")); | KASSERT(LIST_EMPTY(&p->p_reaplist), | ||||
("%s: p %p p_reaplist not empty", __func__, p)); | |||||
p->p_treeflag &= ~P_TREE_REAPER; | p->p_treeflag &= ~P_TREE_REAPER; | ||||
} | } | ||||
static void | static void | ||||
clear_orphan(struct proc *p) | clear_orphan(struct proc *p) | ||||
{ | { | ||||
struct proc *p1; | struct proc *p1; | ||||
sx_assert(&proctree_lock, SA_XLOCKED); | sx_assert(&V_proctree_lock, SA_XLOCKED); | ||||
if ((p->p_treeflag & P_TREE_ORPHANED) == 0) | if ((p->p_treeflag & P_TREE_ORPHANED) == 0) | ||||
return; | return; | ||||
if ((p->p_treeflag & P_TREE_FIRST_ORPHAN) != 0) { | if ((p->p_treeflag & P_TREE_FIRST_ORPHAN) != 0) { | ||||
p1 = LIST_NEXT(p, p_orphan); | p1 = LIST_NEXT(p, p_orphan); | ||||
if (p1 != NULL) | if (p1 != NULL) | ||||
p1->p_treeflag |= P_TREE_FIRST_ORPHAN; | p1->p_treeflag |= P_TREE_FIRST_ORPHAN; | ||||
p->p_treeflag &= ~P_TREE_FIRST_ORPHAN; | p->p_treeflag &= ~P_TREE_FIRST_ORPHAN; | ||||
} | } | ||||
Show All 29 Lines | exit1(struct thread *td, int rval, int signo) | ||||
KASSERT(rval == 0 || signo == 0, ("exit1 rv %d sig %d", rval, signo)); | KASSERT(rval == 0 || signo == 0, ("exit1 rv %d sig %d", rval, signo)); | ||||
p = td->td_proc; | p = td->td_proc; | ||||
/* | /* | ||||
* XXX in case we're rebooting we just let init die in order to | * XXX in case we're rebooting we just let init die in order to | ||||
* work around an unsolved stack overflow seen very late during | * work around an unsolved stack overflow seen very late during | ||||
* shutdown on sparc64 when the gmirror worker process exists. | * shutdown on sparc64 when the gmirror worker process exists. | ||||
*/ | */ | ||||
if (p == initproc && rebooting == 0) { | if (p == V_initproc && (rebooting == 0 | ||||
#ifdef VIMAGE | |||||
|| V_vrebooting | |||||
#endif | |||||
)) { | |||||
printf("init died (signal %d, exit %d)\n", signo, rval); | printf("init died (signal %d, exit %d)\n", signo, rval); | ||||
panic("Going nowhere without my init!"); | #ifdef VIMAGE | ||||
if (!IS_DEFAULT_VPS(TD_TO_VPS(td))) | |||||
/* XXX-BZ make this jail go away. */ ; | |||||
else | |||||
#endif | |||||
panic("%s: Going nowhere without my init! td %p", | |||||
__func__, td); | |||||
} | } | ||||
/* | /* | ||||
* Deref SU mp, since the thread does not return to userspace. | * Deref SU mp, since the thread does not return to userspace. | ||||
*/ | */ | ||||
td_softdep_cleanup(td); | td_softdep_cleanup(td); | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | #ifdef AUDIT | ||||
* what the return value is. | * what the return value is. | ||||
*/ | */ | ||||
AUDIT_ARG_EXIT(rval, 0); | AUDIT_ARG_EXIT(rval, 0); | ||||
AUDIT_SYSCALL_EXIT(0, td); | AUDIT_SYSCALL_EXIT(0, td); | ||||
#endif | #endif | ||||
/* Are we a task leader with peers? */ | /* Are we a task leader with peers? */ | ||||
if (p->p_peers != NULL && p == p->p_leader) { | if (p->p_peers != NULL && p == p->p_leader) { | ||||
mtx_lock(&ppeers_lock); | mtx_lock(&V_ppeers_lock); | ||||
q = p->p_peers; | q = p->p_peers; | ||||
while (q != NULL) { | while (q != NULL) { | ||||
PROC_LOCK(q); | PROC_LOCK(q); | ||||
kern_psignal(q, SIGKILL); | kern_psignal(q, SIGKILL); | ||||
PROC_UNLOCK(q); | PROC_UNLOCK(q); | ||||
q = q->p_peers; | q = q->p_peers; | ||||
} | } | ||||
while (p->p_peers != NULL) | while (p->p_peers != NULL) | ||||
msleep(p, &ppeers_lock, PWAIT, "exit1", 0); | msleep(p, &V_ppeers_lock, PWAIT, "exit1", 0); | ||||
mtx_unlock(&ppeers_lock); | mtx_unlock(&V_ppeers_lock); | ||||
} | } | ||||
/* | /* | ||||
* Check if any loadable modules need anything done at process exit. | * Check if any loadable modules need anything done at process exit. | ||||
* E.g. SYSV IPC stuff. | * E.g. SYSV IPC stuff. | ||||
* Event handler could change exit status. | * Event handler could change exit status. | ||||
* XXX what if one of these generates an error? | * XXX what if one of these generates an error? | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
if (td->td_pflags & TDP_GEOM) | if (td->td_pflags & TDP_GEOM) | ||||
g_waitidle(); | g_waitidle(); | ||||
/* | /* | ||||
* Remove ourself from our leader's peer list and wake our leader. | * Remove ourself from our leader's peer list and wake our leader. | ||||
*/ | */ | ||||
if (p->p_leader->p_peers != NULL) { | if (p->p_leader->p_peers != NULL) { | ||||
mtx_lock(&ppeers_lock); | mtx_lock(&V_ppeers_lock); | ||||
if (p->p_leader->p_peers != NULL) { | if (p->p_leader->p_peers != NULL) { | ||||
q = p->p_leader; | q = p->p_leader; | ||||
while (q->p_peers != p) | while (q->p_peers != p) | ||||
q = q->p_peers; | q = q->p_peers; | ||||
q->p_peers = p->p_peers; | q->p_peers = p->p_peers; | ||||
wakeup(p->p_leader); | wakeup(p->p_leader); | ||||
} | } | ||||
mtx_unlock(&ppeers_lock); | mtx_unlock(&V_ppeers_lock); | ||||
} | } | ||||
vmspace_exit(td); | vmspace_exit(td); | ||||
killjobc(); | killjobc(); | ||||
(void)acct_process(td); | (void)acct_process(td); | ||||
#ifdef KTRACE | #ifdef KTRACE | ||||
ktrprocexit(td); | ktrprocexit(td); | ||||
Show All 19 Lines | #endif | ||||
* machine-dependent resources other than the address space. | * machine-dependent resources other than the address space. | ||||
* The address space is released by "vmspace_exitfree(p)" in | * The address space is released by "vmspace_exitfree(p)" in | ||||
* vm_waitproc(). | * vm_waitproc(). | ||||
*/ | */ | ||||
cpu_exit(td); | cpu_exit(td); | ||||
WITNESS_WARN(WARN_PANIC, NULL, "process (pid %d) exiting", p->p_pid); | WITNESS_WARN(WARN_PANIC, NULL, "process (pid %d) exiting", p->p_pid); | ||||
sx_xlock(&proctree_lock); | sx_xlock(&V_proctree_lock); | ||||
/* | /* | ||||
* Remove proc from allproc queue and pidhash chain. | * Remove proc from allproc queue and pidhash chain. | ||||
* Place onto zombproc. Unlink from parent's child list. | * Place onto zombproc. Unlink from parent's child list. | ||||
*/ | */ | ||||
sx_xlock(&allproc_lock); | /* Operate on current vps instance only. */ | ||||
sx_xlock(&V_allproc_lock); | |||||
LIST_REMOVE(p, p_list); | LIST_REMOVE(p, p_list); | ||||
LIST_INSERT_HEAD(&zombproc, p, p_list); | LIST_INSERT_HEAD(&V_zombproc, p, p_list); | ||||
LIST_REMOVE(p, p_hash); | LIST_REMOVE(p, p_hash); | ||||
sx_xunlock(&allproc_lock); | sx_xunlock(&V_allproc_lock); | ||||
/* | /* | ||||
* Reparent all children processes: | * Reparent all children processes: | ||||
* - traced ones to the original parent (or init if we are that parent) | * - traced ones to the original parent (or init if we are that parent) | ||||
* - the rest to init | * - the rest to init | ||||
*/ | */ | ||||
q = LIST_FIRST(&p->p_children); | q = LIST_FIRST(&p->p_children); | ||||
if (q != NULL) /* only need this if any child is S_ZOMB */ | if (q != NULL) /* only need this if any child is S_ZOMB */ | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | if (p->p_pptr->p_sigacts->ps_flag & | ||||
* Notify parent, so in case he was wait(2)ing or | * Notify parent, so in case he was wait(2)ing or | ||||
* executing waitpid(2) with our pid, he will | * executing waitpid(2) with our pid, he will | ||||
* continue. | * continue. | ||||
*/ | */ | ||||
wakeup(pp); | wakeup(pp); | ||||
} else | } else | ||||
mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx); | mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx); | ||||
if (p->p_pptr == p->p_reaper || p->p_pptr == initproc) { | if (p->p_pptr == p->p_reaper || p->p_pptr == V_initproc) { | ||||
signal_parent = 1; | signal_parent = 1; | ||||
} else if (p->p_sigparent != 0) { | } else if (p->p_sigparent != 0) { | ||||
if (p->p_sigparent == SIGCHLD) { | if (p->p_sigparent == SIGCHLD) { | ||||
signal_parent = 1; | signal_parent = 1; | ||||
} else { /* LINUX thread */ | } else { /* LINUX thread */ | ||||
signal_parent = 2; | signal_parent = 2; | ||||
} | } | ||||
} | } | ||||
} else | } else | ||||
PROC_LOCK(p->p_pptr); | PROC_LOCK(p->p_pptr); | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
if (signal_parent == 1) { | if (signal_parent == 1) { | ||||
childproc_exited(p); | childproc_exited(p); | ||||
} else if (signal_parent == 2) { | } else if (signal_parent == 2) { | ||||
kern_psignal(p->p_pptr, p->p_sigparent); | kern_psignal(p->p_pptr, p->p_sigparent); | ||||
} | } | ||||
/* Tell the prison that we are gone. */ | /* Tell the prison that we are gone. */ | ||||
▲ Show 20 Lines • Show All 197 Lines • ▼ Show 20 Lines | |||||
* rusage. Asserts and will release both the proctree_lock and the process | * rusage. Asserts and will release both the proctree_lock and the process | ||||
* lock as part of its work. | * lock as part of its work. | ||||
*/ | */ | ||||
void | void | ||||
proc_reap(struct thread *td, struct proc *p, int *status, int options) | proc_reap(struct thread *td, struct proc *p, int *status, int options) | ||||
{ | { | ||||
struct proc *q, *t; | struct proc *q, *t; | ||||
sx_assert(&proctree_lock, SA_XLOCKED); | sx_assert(&V_proctree_lock, SA_XLOCKED); | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
KASSERT(p->p_state == PRS_ZOMBIE, ("proc_reap: !PRS_ZOMBIE")); | KASSERT(p->p_state == PRS_ZOMBIE, ("%s: !PRS_ZOMBIE", __func__)); | ||||
mtx_spin_wait_unlocked(&p->p_slock); | mtx_spin_wait_unlocked(&p->p_slock); | ||||
q = td->td_proc; | q = td->td_proc; | ||||
if (status) | if (status) | ||||
*status = KW_EXITCODE(p->p_xexit, p->p_xsig); | *status = KW_EXITCODE(p->p_xexit, p->p_xsig); | ||||
if (options & WNOWAIT) { | if (options & WNOWAIT) { | ||||
/* | /* | ||||
* Only poll, returning the status. Caller does not wish to | * Only poll, returning the status. Caller does not wish to | ||||
* release the proc struct just yet. | * release the proc struct just yet. | ||||
*/ | */ | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
return; | return; | ||||
} | } | ||||
PROC_LOCK(q); | PROC_LOCK(q); | ||||
sigqueue_take(p->p_ksi); | sigqueue_take(p->p_ksi); | ||||
PROC_UNLOCK(q); | PROC_UNLOCK(q); | ||||
/* | /* | ||||
Show All 10 Lines | CTR2(KTR_PTRACE, | ||||
t->p_pid); | t->p_pid); | ||||
proc_reparent(p, t); | proc_reparent(p, t); | ||||
p->p_oppid = 0; | p->p_oppid = 0; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
pksignal(t, SIGCHLD, p->p_ksi); | pksignal(t, SIGCHLD, p->p_ksi); | ||||
wakeup(t); | wakeup(t); | ||||
cv_broadcast(&p->p_pwait); | cv_broadcast(&p->p_pwait); | ||||
PROC_UNLOCK(t); | PROC_UNLOCK(t); | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
return; | return; | ||||
} | } | ||||
p->p_oppid = 0; | p->p_oppid = 0; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
/* | /* | ||||
* Remove other references to this process to ensure we have an | * Remove other references to this process to ensure we have an | ||||
* exclusive reference. | * exclusive reference. | ||||
*/ | */ | ||||
sx_xlock(&allproc_lock); | sx_xlock(&V_allproc_lock); | ||||
LIST_REMOVE(p, p_list); /* off zombproc */ | LIST_REMOVE(p, p_list); /* off zombproc */ | ||||
sx_xunlock(&allproc_lock); | sx_xunlock(&V_allproc_lock); | ||||
LIST_REMOVE(p, p_sibling); | LIST_REMOVE(p, p_sibling); | ||||
reaper_abandon_children(p, true); | reaper_abandon_children(p, true); | ||||
LIST_REMOVE(p, p_reapsibling); | LIST_REMOVE(p, p_reapsibling); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
clear_orphan(p); | clear_orphan(p); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
leavepgrp(p); | leavepgrp(p); | ||||
if (p->p_procdesc != NULL) | if (p->p_procdesc != NULL) | ||||
procdesc_reap(p); | procdesc_reap(p); | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
knlist_detach(p->p_klist); | knlist_detach(p->p_klist); | ||||
p->p_klist = NULL; | p->p_klist = NULL; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
/* | /* | ||||
* Removal from allproc list and process group list paired with | * Removal from allproc list and process group list paired with | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | #endif | ||||
* cpu_exit couldn't release while still running in process context. | * cpu_exit couldn't release while still running in process context. | ||||
*/ | */ | ||||
vm_waitproc(p); | vm_waitproc(p); | ||||
#ifdef MAC | #ifdef MAC | ||||
mac_proc_destroy(p); | mac_proc_destroy(p); | ||||
#endif | #endif | ||||
KASSERT(FIRST_THREAD_IN_PROC(p), | KASSERT(FIRST_THREAD_IN_PROC(p), | ||||
("proc_reap: no residual thread!")); | ("%s: no residual thread!", __func__)); | ||||
uma_zfree(proc_zone, p); | uma_zfree(proc_zone, p); | ||||
atomic_add_int(&nprocs, -1); | atomic_add_int(&V_nprocs, -1); | ||||
} | } | ||||
static int | static int | ||||
proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id, | proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id, | ||||
int *status, int options, struct __wrusage *wrusage, siginfo_t *siginfo, | int *status, int options, struct __wrusage *wrusage, siginfo_t *siginfo, | ||||
int check_only) | int check_only) | ||||
{ | { | ||||
struct rusage *rup; | struct rusage *rup; | ||||
sx_assert(&proctree_lock, SA_XLOCKED); | sx_assert(&V_proctree_lock, SA_XLOCKED); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
switch (idtype) { | switch (idtype) { | ||||
case P_ALL: | case P_ALL: | ||||
if (p->p_procdesc != NULL) { | if (p->p_procdesc != NULL) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
report_alive_proc(struct thread *td, struct proc *p, siginfo_t *siginfo, | report_alive_proc(struct thread *td, struct proc *p, siginfo_t *siginfo, | ||||
int *status, int options, int si_code) | int *status, int options, int si_code) | ||||
{ | { | ||||
bool cont; | bool cont; | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
sx_assert(&proctree_lock, SA_XLOCKED); | sx_assert(&V_proctree_lock, SA_XLOCKED); | ||||
MPASS(si_code == CLD_TRAPPED || si_code == CLD_STOPPED || | MPASS(si_code == CLD_TRAPPED || si_code == CLD_STOPPED || | ||||
si_code == CLD_CONTINUED); | si_code == CLD_CONTINUED); | ||||
cont = si_code == CLD_CONTINUED; | cont = si_code == CLD_CONTINUED; | ||||
if ((options & WNOWAIT) == 0) { | if ((options & WNOWAIT) == 0) { | ||||
if (cont) | if (cont) | ||||
p->p_flag &= ~P_CONTINUED; | p->p_flag &= ~P_CONTINUED; | ||||
else | else | ||||
p->p_flag |= P_WAITED; | p->p_flag |= P_WAITED; | ||||
PROC_LOCK(td->td_proc); | PROC_LOCK(td->td_proc); | ||||
sigqueue_take(p->p_ksi); | sigqueue_take(p->p_ksi); | ||||
PROC_UNLOCK(td->td_proc); | PROC_UNLOCK(td->td_proc); | ||||
} | } | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
if (siginfo != NULL) { | if (siginfo != NULL) { | ||||
siginfo->si_code = si_code; | siginfo->si_code = si_code; | ||||
siginfo->si_status = cont ? SIGCONT : p->p_xsig; | siginfo->si_status = cont ? SIGCONT : p->p_xsig; | ||||
} | } | ||||
if (status != NULL) | if (status != NULL) | ||||
*status = cont ? SIGCONT : W_STOPCODE(p->p_xsig); | *status = cont ? SIGCONT : W_STOPCODE(p->p_xsig); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
td->td_retval[0] = p->p_pid; | td->td_retval[0] = p->p_pid; | ||||
Show All 36 Lines | kern_wait6(struct thread *td, idtype_t idtype, id_t id, int *status, | ||||
} | } | ||||
loop: | loop: | ||||
if (q->p_flag & P_STATCHILD) { | if (q->p_flag & P_STATCHILD) { | ||||
PROC_LOCK(q); | PROC_LOCK(q); | ||||
q->p_flag &= ~P_STATCHILD; | q->p_flag &= ~P_STATCHILD; | ||||
PROC_UNLOCK(q); | PROC_UNLOCK(q); | ||||
} | } | ||||
sx_xlock(&proctree_lock); | sx_xlock(&V_proctree_lock); | ||||
loop_locked: | loop_locked: | ||||
nfound = 0; | nfound = 0; | ||||
LIST_FOREACH(p, &q->p_children, p_sibling) { | LIST_FOREACH(p, &q->p_children, p_sibling) { | ||||
pid = p->p_pid; | pid = p->p_pid; | ||||
ret = proc_to_reap(td, p, idtype, id, status, options, | ret = proc_to_reap(td, p, idtype, id, status, options, | ||||
wrusage, siginfo, 0); | wrusage, siginfo, 0); | ||||
if (ret == 0) | if (ret == 0) | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | LIST_FOREACH(p, &q->p_orphans, p_orphan) { | ||||
(int)td->td_retval[0])); | (int)td->td_retval[0])); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
nfound++; | nfound++; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (nfound == 0) { | if (nfound == 0) { | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
return (ECHILD); | return (ECHILD); | ||||
} | } | ||||
if (options & WNOHANG) { | if (options & WNOHANG) { | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
td->td_retval[0] = 0; | td->td_retval[0] = 0; | ||||
return (0); | return (0); | ||||
} | } | ||||
PROC_LOCK(q); | PROC_LOCK(q); | ||||
if (q->p_flag & P_STATCHILD) { | if (q->p_flag & P_STATCHILD) { | ||||
q->p_flag &= ~P_STATCHILD; | q->p_flag &= ~P_STATCHILD; | ||||
PROC_UNLOCK(q); | PROC_UNLOCK(q); | ||||
goto loop_locked; | goto loop_locked; | ||||
} | } | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
error = msleep(q, &q->p_mtx, PWAIT | PCATCH | PDROP, "wait", 0); | error = msleep(q, &q->p_mtx, PWAIT | PCATCH | PDROP, "wait", 0); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
goto loop; | goto loop; | ||||
} | } | ||||
/* | /* | ||||
* Make process 'parent' the new parent of process 'child'. | * Make process 'parent' the new parent of process 'child'. | ||||
* Must be called with an exclusive hold of proctree lock. | * Must be called with an exclusive hold of proctree lock. | ||||
*/ | */ | ||||
void | void | ||||
proc_reparent(struct proc *child, struct proc *parent) | proc_reparent(struct proc *child, struct proc *parent) | ||||
{ | { | ||||
sx_assert(&proctree_lock, SX_XLOCKED); | sx_assert(&V_proctree_lock, SX_XLOCKED); | ||||
PROC_LOCK_ASSERT(child, MA_OWNED); | PROC_LOCK_ASSERT(child, MA_OWNED); | ||||
if (child->p_pptr == parent) | if (child->p_pptr == parent) | ||||
return; | return; | ||||
PROC_LOCK(child->p_pptr); | PROC_LOCK(child->p_pptr); | ||||
sigqueue_take(child->p_ksi); | sigqueue_take(child->p_ksi); | ||||
PROC_UNLOCK(child->p_pptr); | PROC_UNLOCK(child->p_pptr); | ||||
LIST_REMOVE(child, p_sibling); | LIST_REMOVE(child, p_sibling); | ||||
Show All 17 Lines |