Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_proc.c
Show First 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | |||||
static int proc_init(void *mem, int size, int flags); | static int proc_init(void *mem, int size, int flags); | ||||
static void proc_fini(void *mem, int size); | static void proc_fini(void *mem, int size); | ||||
static void pargs_free(struct pargs *pa); | static void pargs_free(struct pargs *pa); | ||||
static struct proc *zpfind_locked(pid_t pid); | static struct proc *zpfind_locked(pid_t pid); | ||||
/* | /* | ||||
* Other process lists | * Other process lists | ||||
*/ | */ | ||||
struct pidhashhead *pidhashtbl; | VPS_DEFINE(struct pidhashhead *, pidhashtbl); | ||||
u_long pidhash; | VPS_DEFINE(u_long, pidhash); | ||||
struct pgrphashhead *pgrphashtbl; | VPS_DEFINE(struct pgrphashhead *, pgrphashtbl); | ||||
u_long pgrphash; | VPS_DEFINE(u_long, pgrphash); | ||||
struct proclist allproc; | VPS_DEFINE(struct proclist, allproc); | ||||
struct proclist zombproc; | VPS_DEFINE(struct proclist, zombproc); | ||||
#ifndef VIMAGE | |||||
struct sx __exclusive_cache_line allproc_lock; | struct sx __exclusive_cache_line allproc_lock; | ||||
struct sx __exclusive_cache_line proctree_lock; | struct sx __exclusive_cache_line proctree_lock; | ||||
struct mtx __exclusive_cache_line ppeers_lock; | struct mtx __exclusive_cache_line ppeers_lock; | ||||
#else | |||||
VPS_DEFINE(struct sx, allproc_lock); | |||||
VPS_DEFINE(struct sx, proctree_lock); | |||||
VPS_DEFINE(struct mtx, ppeers_lock); | |||||
#endif | |||||
uma_zone_t proc_zone; | uma_zone_t proc_zone; | ||||
/* | /* | ||||
* The offset of various fields in struct proc and struct thread. | * The offset of various fields in struct proc and struct thread. | ||||
* These are used by kernel debuggers to enumerate kernel threads and | * These are used by kernel debuggers to enumerate kernel threads and | ||||
* processes. | * processes. | ||||
*/ | */ | ||||
const int proc_off_p_pid = offsetof(struct proc, p_pid); | const int proc_off_p_pid = offsetof(struct proc, p_pid); | ||||
Show All 28 Lines | |||||
CTASSERT(sizeof(struct kinfo_proc) == KINFO_PROC_SIZE); | CTASSERT(sizeof(struct kinfo_proc) == KINFO_PROC_SIZE); | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
CTASSERT(sizeof(struct kinfo_proc32) == KINFO_PROC32_SIZE); | CTASSERT(sizeof(struct kinfo_proc32) == KINFO_PROC32_SIZE); | ||||
#endif | #endif | ||||
/* | /* | ||||
* Initialize global process hashing structures. | * Initialize global process hashing structures. | ||||
*/ | */ | ||||
void | static void | ||||
procinit(void) | procinit(void) | ||||
{ | { | ||||
sx_init(&allproc_lock, "allproc"); | sx_init(&V_allproc_lock, "allproc"); | ||||
sx_init(&proctree_lock, "proctree"); | sx_init(&V_proctree_lock, "proctree"); | ||||
mtx_init(&ppeers_lock, "p_peers", NULL, MTX_DEF); | mtx_init(&V_ppeers_lock, "p_peers", NULL, MTX_DEF); | ||||
LIST_INIT(&allproc); | LIST_INIT(&V_allproc); | ||||
LIST_INIT(&zombproc); | LIST_INIT(&V_zombproc); | ||||
pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); | V_pidhashtbl = hashinit(maxproc / 4, M_PROC, &V_pidhash); | ||||
pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash); | V_pgrphashtbl = hashinit(maxproc / 4, M_PROC, &V_pgrphash); | ||||
if (IS_DEFAULT_VPS(curvps)) { | |||||
proc_zone = uma_zcreate("PROC", sched_sizeof_proc(), | proc_zone = uma_zcreate("PROC", sched_sizeof_proc(), | ||||
proc_ctor, proc_dtor, proc_init, proc_fini, | proc_ctor, proc_dtor, proc_init, proc_fini, | ||||
UMA_ALIGN_PTR, UMA_ZONE_NOFREE); | UMA_ALIGN_PTR, UMA_ZONE_NOFREE); | ||||
uihashinit(); | |||||
} | } | ||||
} | |||||
VPS_SYSINIT(procinit, SI_SUB_INTRINSIC, SI_ORDER_SECOND, procinit, NULL); | |||||
#ifdef VIMAGE | |||||
static void | |||||
procdestroy(void *ident __unused) | |||||
{ | |||||
KASSERT((LIST_EMPTY(&V_allproc)), ("%s: list allproc %p not empty\n", | |||||
__func__, &V_allproc)); | |||||
KASSERT((LIST_EMPTY(&V_zombproc)), ("%s: list zombproc %p not empty\n", | |||||
__func__, &V_zombproc)); | |||||
/* proc_zone */ | |||||
hashdestroy(V_pgrphashtbl, M_PROC, V_pgrphash); | |||||
hashdestroy(V_pidhashtbl, M_PROC, V_pidhash); | |||||
mtx_destroy(&V_ppeers_lock); | |||||
sx_destroy(&V_proctree_lock); | |||||
sx_destroy(&V_allproc_lock); | |||||
} | |||||
VPS_SYSUNINIT(procdestroy, SI_SUB_INTRINSIC, SI_ORDER_SECOND, procdestroy, | |||||
NULL); | |||||
#endif | |||||
/* | /* | ||||
* Prepare a proc for use. | * Prepare a proc for use. | ||||
*/ | */ | ||||
static int | static int | ||||
proc_ctor(void *mem, int size, void *arg, int flags) | proc_ctor(void *mem, int size, void *arg, int flags) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
struct thread *td; | struct thread *td; | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Is p an inferior of the current process? | * Is p an inferior of the current process? | ||||
*/ | */ | ||||
int | int | ||||
inferior(struct proc *p) | inferior(struct proc *p) | ||||
{ | { | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
for (; p != curproc; p = proc_realparent(p)) { | for (; p != curproc; p = proc_realparent(p)) { | ||||
if (p->p_pid == 0) | if (p->p_pid == 0) | ||||
return (0); | return (0); | ||||
} | } | ||||
return (1); | return (1); | ||||
} | } | ||||
struct proc * | struct proc * | ||||
pfind_locked(pid_t pid) | pfind_locked(pid_t pid) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
sx_assert(&allproc_lock, SX_LOCKED); | sx_assert(&V_allproc_lock, SX_LOCKED); | ||||
LIST_FOREACH(p, PIDHASH(pid), p_hash) { | LIST_FOREACH(p, PIDHASH(pid), p_hash) { | ||||
if (p->p_pid == pid) { | if (p->p_pid == pid) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if (p->p_state == PRS_NEW) { | if (p->p_state == PRS_NEW) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
p = NULL; | p = NULL; | ||||
} | } | ||||
break; | break; | ||||
Show All 13 Lines | |||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
p = curproc; | p = curproc; | ||||
if (p->p_pid == pid) { | if (p->p_pid == pid) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
return (p); | return (p); | ||||
} | } | ||||
sx_slock(&allproc_lock); | sx_slock(&V_allproc_lock); | ||||
p = pfind_locked(pid); | p = pfind_locked(pid); | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&V_allproc_lock); | ||||
return (p); | return (p); | ||||
} | } | ||||
/* | /* | ||||
* Same as pfind but allow zombies. | * Same as pfind but allow zombies. | ||||
*/ | */ | ||||
struct proc * | struct proc * | ||||
pfind_any(pid_t pid) | pfind_any(pid_t pid) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
sx_slock(&allproc_lock); | sx_slock(&V_allproc_lock); | ||||
p = pfind_locked(pid); | p = pfind_locked(pid); | ||||
if (p == NULL) | if (p == NULL) | ||||
p = zpfind_locked(pid); | p = zpfind_locked(pid); | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&V_allproc_lock); | ||||
return (p); | return (p); | ||||
} | } | ||||
static struct proc * | static struct proc * | ||||
pfind_tid_locked(pid_t tid) | pfind_tid_locked(pid_t tid) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
struct thread *td; | struct thread *td; | ||||
sx_assert(&allproc_lock, SX_LOCKED); | /* Operate on current vps instance only. */ | ||||
sx_assert(&V_allproc_lock, SX_LOCKED); | |||||
FOREACH_PROC_IN_SYSTEM(p) { | FOREACH_PROC_IN_SYSTEM(p) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if (p->p_state == PRS_NEW) { | if (p->p_state == PRS_NEW) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
continue; | continue; | ||||
} | } | ||||
FOREACH_THREAD_IN_PROC(p, td) { | FOREACH_THREAD_IN_PROC(p, td) { | ||||
if (td->td_tid == tid) | if (td->td_tid == tid) | ||||
Show All 9 Lines | |||||
* Locate a process group by number. | * Locate a process group by number. | ||||
* The caller must hold proctree_lock. | * The caller must hold proctree_lock. | ||||
*/ | */ | ||||
struct pgrp * | struct pgrp * | ||||
pgfind(pid_t pgid) | pgfind(pid_t pgid) | ||||
{ | { | ||||
struct pgrp *pgrp; | struct pgrp *pgrp; | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) { | LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) { | ||||
if (pgrp->pg_id == pgid) { | if (pgrp->pg_id == pgid) { | ||||
PGRP_LOCK(pgrp); | PGRP_LOCK(pgrp); | ||||
return (pgrp); | return (pgrp); | ||||
} | } | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* | /* | ||||
* Locate process and do additional manipulations, depending on flags. | * Locate process and do additional manipulations, depending on flags. | ||||
*/ | */ | ||||
int | int | ||||
pget(pid_t pid, int flags, struct proc **pp) | pget(pid_t pid, int flags, struct proc **pp) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
int error; | int error; | ||||
p = curproc; | p = curproc; | ||||
if (p->p_pid == pid) { | if (p->p_pid == pid) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
} else { | } else { | ||||
sx_slock(&allproc_lock); | sx_slock(&V_allproc_lock); | ||||
if (pid <= PID_MAX) { | if (pid <= PID_MAX) { | ||||
p = pfind_locked(pid); | p = pfind_locked(pid); | ||||
if (p == NULL && (flags & PGET_NOTWEXIT) == 0) | if (p == NULL && (flags & PGET_NOTWEXIT) == 0) | ||||
p = zpfind_locked(pid); | p = zpfind_locked(pid); | ||||
} else if ((flags & PGET_NOTID) == 0) { | } else if ((flags & PGET_NOTID) == 0) { | ||||
p = pfind_tid_locked(pid); | p = pfind_tid_locked(pid); | ||||
} else { | } else { | ||||
p = NULL; | p = NULL; | ||||
} | } | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&V_allproc_lock); | ||||
if (p == NULL) | if (p == NULL) | ||||
return (ESRCH); | return (ESRCH); | ||||
if ((flags & PGET_CANSEE) != 0) { | if ((flags & PGET_CANSEE) != 0) { | ||||
error = p_cansee(curthread, p); | error = p_cansee(curthread, p); | ||||
if (error != 0) | if (error != 0) | ||||
goto errout; | goto errout; | ||||
} | } | ||||
} | } | ||||
Show All 33 Lines | |||||
* Create a new process group. | * Create a new process group. | ||||
* pgid must be equal to the pid of p. | * pgid must be equal to the pid of p. | ||||
* Begin a new session if required. | * Begin a new session if required. | ||||
*/ | */ | ||||
int | int | ||||
enterpgrp(struct proc *p, pid_t pgid, struct pgrp *pgrp, struct session *sess) | enterpgrp(struct proc *p, pid_t pgid, struct pgrp *pgrp, struct session *sess) | ||||
{ | { | ||||
sx_assert(&proctree_lock, SX_XLOCKED); | sx_assert(&V_proctree_lock, SX_XLOCKED); | ||||
KASSERT(pgrp != NULL, ("enterpgrp: pgrp == NULL")); | KASSERT(pgrp != NULL, ("enterpgrp: pgrp == NULL")); | ||||
KASSERT(p->p_pid == pgid, | KASSERT(p->p_pid == pgid, | ||||
("enterpgrp: new pgrp and pid != pgid")); | ("enterpgrp: new pgrp and pid != pgid")); | ||||
KASSERT(pgfind(pgid) == NULL, | KASSERT(pgfind(pgid) == NULL, | ||||
("enterpgrp: pgrp with pgid exists")); | ("enterpgrp: pgrp with pgid exists")); | ||||
KASSERT(!SESS_LEADER(p), | KASSERT(!SESS_LEADER(p), | ||||
("enterpgrp: session leader attempted setpgrp")); | ("enterpgrp: session leader attempted setpgrp")); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Move p to an existing process group | * Move p to an existing process group | ||||
*/ | */ | ||||
int | int | ||||
enterthispgrp(struct proc *p, struct pgrp *pgrp) | enterthispgrp(struct proc *p, struct pgrp *pgrp) | ||||
{ | { | ||||
sx_assert(&proctree_lock, SX_XLOCKED); | sx_assert(&V_proctree_lock, SX_XLOCKED); | ||||
PROC_LOCK_ASSERT(p, MA_NOTOWNED); | PROC_LOCK_ASSERT(p, MA_NOTOWNED); | ||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | ||||
PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); | ||||
SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); | SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); | ||||
KASSERT(pgrp->pg_session == p->p_session, | KASSERT(pgrp->pg_session == p->p_session, | ||||
("%s: pgrp's session %p, p->p_session %p.\n", | ("%s: pgrp's session %p, p->p_session %p.\n", | ||||
__func__, | __func__, | ||||
pgrp->pg_session, | pgrp->pg_session, | ||||
Show All 9 Lines | |||||
/* | /* | ||||
* Move p to a process group | * Move p to a process group | ||||
*/ | */ | ||||
static void | static void | ||||
doenterpgrp(struct proc *p, struct pgrp *pgrp) | doenterpgrp(struct proc *p, struct pgrp *pgrp) | ||||
{ | { | ||||
struct pgrp *savepgrp; | struct pgrp *savepgrp; | ||||
sx_assert(&proctree_lock, SX_XLOCKED); | sx_assert(&V_proctree_lock, SX_XLOCKED); | ||||
PROC_LOCK_ASSERT(p, MA_NOTOWNED); | PROC_LOCK_ASSERT(p, MA_NOTOWNED); | ||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | ||||
PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED); | ||||
SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); | SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); | ||||
savepgrp = p->p_pgrp; | savepgrp = p->p_pgrp; | ||||
/* | /* | ||||
Show All 20 Lines | |||||
/* | /* | ||||
* remove process from process group | * remove process from process group | ||||
*/ | */ | ||||
int | int | ||||
leavepgrp(struct proc *p) | leavepgrp(struct proc *p) | ||||
{ | { | ||||
struct pgrp *savepgrp; | struct pgrp *savepgrp; | ||||
sx_assert(&proctree_lock, SX_XLOCKED); | sx_assert(&V_proctree_lock, SX_XLOCKED); | ||||
savepgrp = p->p_pgrp; | savepgrp = p->p_pgrp; | ||||
PGRP_LOCK(savepgrp); | PGRP_LOCK(savepgrp); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
LIST_REMOVE(p, p_pglist); | LIST_REMOVE(p, p_pglist); | ||||
p->p_pgrp = NULL; | p->p_pgrp = NULL; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
PGRP_UNLOCK(savepgrp); | PGRP_UNLOCK(savepgrp); | ||||
if (LIST_EMPTY(&savepgrp->pg_members)) | if (LIST_EMPTY(&savepgrp->pg_members)) | ||||
pgdelete(savepgrp); | pgdelete(savepgrp); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* delete a process group | * delete a process group | ||||
*/ | */ | ||||
static void | static void | ||||
pgdelete(struct pgrp *pgrp) | pgdelete(struct pgrp *pgrp) | ||||
{ | { | ||||
struct session *savesess; | struct session *savesess; | ||||
struct tty *tp; | struct tty *tp; | ||||
sx_assert(&proctree_lock, SX_XLOCKED); | sx_assert(&V_proctree_lock, SX_XLOCKED); | ||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | ||||
SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); | SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); | ||||
/* | /* | ||||
* Reset any sigio structures pointing to us as a result of | * Reset any sigio structures pointing to us as a result of | ||||
* F_SETOWN with our pgid. | * F_SETOWN with our pgid. | ||||
*/ | */ | ||||
funsetownlst(&pgrp->pg_sigiolst); | funsetownlst(&pgrp->pg_sigiolst); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
void | void | ||||
fixjobc(struct proc *p, struct pgrp *pgrp, int entering) | fixjobc(struct proc *p, struct pgrp *pgrp, int entering) | ||||
{ | { | ||||
struct pgrp *hispgrp; | struct pgrp *hispgrp; | ||||
struct session *mysession; | struct session *mysession; | ||||
struct proc *q; | struct proc *q; | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
PROC_LOCK_ASSERT(p, MA_NOTOWNED); | PROC_LOCK_ASSERT(p, MA_NOTOWNED); | ||||
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); | ||||
SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); | SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); | ||||
/* | /* | ||||
* Check p's parent to see whether p qualifies its own process | * Check p's parent to see whether p qualifies its own process | ||||
* group; if so, adjust count for p's process group. | * group; if so, adjust count for p's process group. | ||||
*/ | */ | ||||
Show All 36 Lines | killjobc(void) | ||||
if (!SESS_LEADER(p) && | if (!SESS_LEADER(p) && | ||||
(p->p_pgrp == p->p_pptr->p_pgrp) && | (p->p_pgrp == p->p_pptr->p_pgrp) && | ||||
LIST_EMPTY(&p->p_children)) { | LIST_EMPTY(&p->p_children)) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
return; | return; | ||||
} | } | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
sx_xlock(&proctree_lock); | sx_xlock(&V_proctree_lock); | ||||
if (SESS_LEADER(p)) { | if (SESS_LEADER(p)) { | ||||
sp = p->p_session; | sp = p->p_session; | ||||
/* | /* | ||||
* s_ttyp is not zero'd; we use this to indicate that | * s_ttyp is not zero'd; we use this to indicate that | ||||
* the session once had a controlling terminal. (for | * the session once had a controlling terminal. (for | ||||
* logging and informational purposes) | * logging and informational purposes) | ||||
*/ | */ | ||||
Show All 20 Lines | if (SESS_LEADER(p)) { | ||||
if (tp != NULL) { | if (tp != NULL) { | ||||
tty_lock(tp); | tty_lock(tp); | ||||
if (tp->t_session == sp) | if (tp->t_session == sp) | ||||
tty_signal_pgrp(tp, SIGHUP); | tty_signal_pgrp(tp, SIGHUP); | ||||
tty_unlock(tp); | tty_unlock(tp); | ||||
} | } | ||||
if (ttyvp != NULL) { | if (ttyvp != NULL) { | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
if (vn_lock(ttyvp, LK_EXCLUSIVE) == 0) { | if (vn_lock(ttyvp, LK_EXCLUSIVE) == 0) { | ||||
VOP_REVOKE(ttyvp, REVOKEALL); | VOP_REVOKE(ttyvp, REVOKEALL); | ||||
VOP_UNLOCK(ttyvp, 0); | VOP_UNLOCK(ttyvp, 0); | ||||
} | } | ||||
vrele(ttyvp); | vrele(ttyvp); | ||||
sx_xlock(&proctree_lock); | sx_xlock(&V_proctree_lock); | ||||
} | } | ||||
} | } | ||||
fixjobc(p, p->p_pgrp, 0); | fixjobc(p, p->p_pgrp, 0); | ||||
sx_xunlock(&proctree_lock); | sx_xunlock(&V_proctree_lock); | ||||
} | } | ||||
/* | /* | ||||
* A process group has become orphaned; | * A process group has become orphaned; | ||||
* if there are any stopped processes in the group, | * if there are any stopped processes in the group, | ||||
* hang-up all process in that group. | * hang-up all process in that group. | ||||
*/ | */ | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
#ifdef DDB | #ifdef DDB | ||||
DB_SHOW_COMMAND(pgrpdump, pgrpdump) | DB_SHOW_COMMAND(pgrpdump, pgrpdump) | ||||
{ | { | ||||
struct pgrp *pgrp; | struct pgrp *pgrp; | ||||
struct proc *p; | struct proc *p; | ||||
int i; | int i; | ||||
for (i = 0; i <= pgrphash; i++) { | for (i = 0; i <= V_pgrphash; i++) { | ||||
if (!LIST_EMPTY(&pgrphashtbl[i])) { | if (!LIST_EMPTY(&V_pgrphashtbl[i])) { | ||||
printf("\tindx %d\n", i); | printf("\tindx %d\n", i); | ||||
LIST_FOREACH(pgrp, &pgrphashtbl[i], pg_hash) { | LIST_FOREACH(pgrp, &V_pgrphashtbl[i], pg_hash) { | ||||
printf( | printf( | ||||
"\tpgrp %p, pgid %ld, sess %p, sesscnt %d, mem %p\n", | "\tpgrp %p, pgid %ld, sess %p, sesscnt %d, mem %p\n", | ||||
(void *)pgrp, (long)pgrp->pg_id, | (void *)pgrp, (long)pgrp->pg_id, | ||||
(void *)pgrp->pg_session, | (void *)pgrp->pg_session, | ||||
pgrp->pg_session->s_count, | pgrp->pg_session->s_count, | ||||
(void *)LIST_FIRST(&pgrp->pg_members)); | (void *)LIST_FIRST(&pgrp->pg_members)); | ||||
LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { | LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { | ||||
printf("\t\tpid %ld addr %p pgrp %p\n", | printf("\t\tpid %ld addr %p pgrp %p\n", | ||||
Show All 39 Lines | fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp) | ||||
struct thread *td0; | struct thread *td0; | ||||
struct tty *tp; | struct tty *tp; | ||||
struct session *sp; | struct session *sp; | ||||
struct ucred *cred; | struct ucred *cred; | ||||
struct sigacts *ps; | struct sigacts *ps; | ||||
struct timeval boottime; | struct timeval boottime; | ||||
/* For proc_realparent. */ | /* For proc_realparent. */ | ||||
sx_assert(&proctree_lock, SX_LOCKED); | sx_assert(&V_proctree_lock, SX_LOCKED); | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
bzero(kp, sizeof(*kp)); | bzero(kp, sizeof(*kp)); | ||||
kp->ki_structsize = sizeof(*kp); | kp->ki_structsize = sizeof(*kp); | ||||
kp->ki_paddr = p; | kp->ki_paddr = p; | ||||
kp->ki_addr =/* p->p_addr; */0; /* XXX */ | kp->ki_addr =/* p->p_addr; */0; /* XXX */ | ||||
kp->ki_args = p->p_args; | kp->ki_args = p->p_args; | ||||
kp->ki_textvp = p->p_textvp; | kp->ki_textvp = p->p_textvp; | ||||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | if (sp != NULL) { | ||||
kp->ki_sid = sp->s_sid; | kp->ki_sid = sp->s_sid; | ||||
SESS_LOCK(sp); | SESS_LOCK(sp); | ||||
strlcpy(kp->ki_login, sp->s_login, | strlcpy(kp->ki_login, sp->s_login, | ||||
sizeof(kp->ki_login)); | sizeof(kp->ki_login)); | ||||
if (sp->s_ttyvp) | if (sp->s_ttyvp) | ||||
kp->ki_kiflag |= KI_CTTY; | kp->ki_kiflag |= KI_CTTY; | ||||
if (SESS_LEADER(p)) | if (SESS_LEADER(p)) | ||||
kp->ki_kiflag |= KI_SLEADER; | kp->ki_kiflag |= KI_SLEADER; | ||||
/* XXX proctree_lock */ | /* XXX V_proctree_lock */ | ||||
tp = sp->s_ttyp; | tp = sp->s_ttyp; | ||||
SESS_UNLOCK(sp); | SESS_UNLOCK(sp); | ||||
} | } | ||||
} | } | ||||
if ((p->p_flag & P_CONTROLT) && tp != NULL) { | if ((p->p_flag & P_CONTROLT) && tp != NULL) { | ||||
kp->ki_tdev = tty_udev(tp); | kp->ki_tdev = tty_udev(tp); | ||||
kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */ | kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */ | ||||
kp->ki_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; | kp->ki_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; | ||||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | pstats_free(struct pstats *ps) | ||||
free(ps, M_SUBPROC); | free(ps, M_SUBPROC); | ||||
} | } | ||||
static struct proc * | static struct proc * | ||||
zpfind_locked(pid_t pid) | zpfind_locked(pid_t pid) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
sx_assert(&allproc_lock, SX_LOCKED); | /* Operate on current vps instance only. */ | ||||
LIST_FOREACH(p, &zombproc, p_list) { | sx_assert(&V_allproc_lock, SX_LOCKED); | ||||
LIST_FOREACH(p, &V_zombproc, p_list) { | |||||
if (p->p_pid == pid) { | if (p->p_pid == pid) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return (p); | return (p); | ||||
} | } | ||||
/* | /* | ||||
* Locate a zombie process by number | * Locate a zombie process by number | ||||
*/ | */ | ||||
struct proc * | struct proc * | ||||
zpfind(pid_t pid) | zpfind(pid_t pid) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
sx_slock(&allproc_lock); | sx_slock(&V_allproc_lock); | ||||
p = zpfind_locked(pid); | p = zpfind_locked(pid); | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&V_allproc_lock); | ||||
return (p); | return (p); | ||||
} | } | ||||
#ifdef COMPAT_FREEBSD32 | #ifdef COMPAT_FREEBSD32 | ||||
/* | /* | ||||
* This function is typically used to copy out the kernel address, so | * This function is typically used to copy out the kernel address, so | ||||
* it can be replaced by assignment of zero. | * it can be replaced by assignment of zero. | ||||
▲ Show 20 Lines • Show All 219 Lines • ▼ Show 20 Lines | if (req->flags & SCTL_MASK32) | ||||
flags |= KERN_PROC_MASK32; | flags |= KERN_PROC_MASK32; | ||||
#endif | #endif | ||||
if (oid_number == KERN_PROC_PID) { | if (oid_number == KERN_PROC_PID) { | ||||
if (namelen != 1) | if (namelen != 1) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = sysctl_wire_old_buffer(req, 0); | error = sysctl_wire_old_buffer(req, 0); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
sx_slock(&proctree_lock); | sx_slock(&V_proctree_lock); | ||||
error = pget((pid_t)name[0], PGET_CANSEE, &p); | error = pget((pid_t)name[0], PGET_CANSEE, &p); | ||||
if (error == 0) | if (error == 0) | ||||
error = sysctl_out_proc(p, req, flags); | error = sysctl_out_proc(p, req, flags); | ||||
sx_sunlock(&proctree_lock); | sx_sunlock(&V_proctree_lock); | ||||
return (error); | return (error); | ||||
} | } | ||||
switch (oid_number) { | switch (oid_number) { | ||||
case KERN_PROC_ALL: | case KERN_PROC_ALL: | ||||
if (namelen != 0) | if (namelen != 0) | ||||
return (EINVAL); | return (EINVAL); | ||||
break; | break; | ||||
Show All 16 Lines | if (req->oldptr == NULL) { | ||||
error = sysctl_wire_old_buffer(req, 0); | error = sysctl_wire_old_buffer(req, 0); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
/* | /* | ||||
* This lock is only needed to safely grab the parent of a | * This lock is only needed to safely grab the parent of a | ||||
* traced process. Only grab it if we are producing any | * traced process. Only grab it if we are producing any | ||||
* data to begin with. | * data to begin with. | ||||
*/ | */ | ||||
sx_slock(&proctree_lock); | sx_slock(&V_proctree_lock); | ||||
} | } | ||||
sx_slock(&allproc_lock); | sx_slock(&V_allproc_lock); | ||||
for (doingzomb=0 ; doingzomb < 2 ; doingzomb++) { | for (doingzomb=0 ; doingzomb < 2 ; doingzomb++) { | ||||
/* Operate on current vps instance only. */ | |||||
if (!doingzomb) | if (!doingzomb) | ||||
p = LIST_FIRST(&allproc); | p = LIST_FIRST(&V_allproc); | ||||
else | else | ||||
p = LIST_FIRST(&zombproc); | p = LIST_FIRST(&V_zombproc); | ||||
for (; p != NULL; p = LIST_NEXT(p, p_list)) { | for (; p != NULL; p = LIST_NEXT(p, p_list)) { | ||||
/* | /* | ||||
* Skip embryonic processes. | * Skip embryonic processes. | ||||
*/ | */ | ||||
if (p->p_state == PRS_NEW) | if (p->p_state == PRS_NEW) | ||||
continue; | continue; | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
KASSERT(p->p_ucred != NULL, | KASSERT(p->p_ucred != NULL, | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | for (; p != NULL; p = LIST_NEXT(p, p_list)) { | ||||
break; | break; | ||||
case KERN_PROC_TTY: | case KERN_PROC_TTY: | ||||
if ((p->p_flag & P_CONTROLT) == 0 || | if ((p->p_flag & P_CONTROLT) == 0 || | ||||
p->p_session == NULL) { | p->p_session == NULL) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
continue; | continue; | ||||
} | } | ||||
/* XXX proctree_lock */ | /* XXX V_proctree_lock */ | ||||
SESS_LOCK(p->p_session); | SESS_LOCK(p->p_session); | ||||
if (p->p_session->s_ttyp == NULL || | if (p->p_session->s_ttyp == NULL || | ||||
tty_udev(p->p_session->s_ttyp) != | tty_udev(p->p_session->s_ttyp) != | ||||
(dev_t)name[0]) { | (dev_t)name[0]) { | ||||
SESS_UNLOCK(p->p_session); | SESS_UNLOCK(p->p_session); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
continue; | continue; | ||||
} | } | ||||
Show All 23 Lines | for (; p != NULL; p = LIST_NEXT(p, p_list)) { | ||||
} | } | ||||
error = sysctl_out_proc(p, req, flags); | error = sysctl_out_proc(p, req, flags); | ||||
if (error) | if (error) | ||||
goto out; | goto out; | ||||
} | } | ||||
} | } | ||||
out: | out: | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&V_allproc_lock); | ||||
if (req->oldptr != NULL) | if (req->oldptr != NULL) | ||||
sx_sunlock(&proctree_lock); | sx_sunlock(&V_proctree_lock); | ||||
return (error); | return (error); | ||||
} | } | ||||
struct pargs * | struct pargs * | ||||
pargs_alloc(int len) | pargs_alloc(int len) | ||||
{ | { | ||||
struct pargs *pa; | struct pargs *pa; | ||||
▲ Show 20 Lines • Show All 1,467 Lines • ▼ Show 20 Lines | |||||
* stop_all_proc() purpose is to stop all process which have usermode, | * stop_all_proc() purpose is to stop all process which have usermode, | ||||
* except current process for obvious reasons. This makes it somewhat | * except current process for obvious reasons. This makes it somewhat | ||||
* unreliable when invoked from multithreaded process. The service | * unreliable when invoked from multithreaded process. The service | ||||
* must not be user-callable anyway. | * must not be user-callable anyway. | ||||
*/ | */ | ||||
void | void | ||||
stop_all_proc(void) | stop_all_proc(void) | ||||
{ | { | ||||
VPS_ITERATOR_DECL(vps_iter); | |||||
struct proc *cp, *p; | struct proc *cp, *p; | ||||
int r, gen; | int r, gen; | ||||
bool restart, seen_stopped, seen_exiting, stopped_some; | bool restart, seen_stopped, seen_exiting, stopped_some; | ||||
KASSERT(IS_DEFAULT_VPS(curvps), | |||||
("%s: called from non vps0 %p: vps %p\n", __func__, vps0, curvps)); | |||||
VPS_LIST_RLOCK(); | |||||
VPS_FOREACH(vps_iter) { | |||||
CURVPS_SET(vps_iter); | |||||
#ifdef VIMAGE | |||||
if (saved_vps != vps_iter) | |||||
cp = NULL; | |||||
else | |||||
#endif | |||||
cp = curproc; | cp = curproc; | ||||
allproc_loop: | allproc_loop: | ||||
sx_xlock(&allproc_lock); | sx_xlock(&V_allproc_lock); | ||||
if (cp == NULL) | |||||
cp = LIST_FIRST(&V_allproc); | |||||
gen = allproc_gen; | gen = allproc_gen; | ||||
seen_exiting = seen_stopped = stopped_some = restart = false; | seen_exiting = seen_stopped = stopped_some = restart = false; | ||||
LIST_REMOVE(cp, p_list); | LIST_REMOVE(cp, p_list); | ||||
LIST_INSERT_HEAD(&allproc, cp, p_list); | LIST_INSERT_HEAD(&V_allproc, cp, p_list); | ||||
for (;;) { | for (;;) { | ||||
p = LIST_NEXT(cp, p_list); | p = LIST_NEXT(cp, p_list); | ||||
if (p == NULL) | if (p == NULL) | ||||
break; | break; | ||||
LIST_REMOVE(cp, p_list); | LIST_REMOVE(cp, p_list); | ||||
LIST_INSERT_AFTER(p, cp, p_list); | LIST_INSERT_AFTER(p, cp, p_list); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if ((p->p_flag & (P_KPROC | P_SYSTEM | P_TOTAL_STOP)) != 0) { | if ((p->p_flag & (P_KPROC | P_SYSTEM | P_TOTAL_STOP)) != 0) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
continue; | continue; | ||||
} | } | ||||
if ((p->p_flag & P_WEXIT) != 0) { | if ((p->p_flag & P_WEXIT) != 0) { | ||||
seen_exiting = true; | seen_exiting = true; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
continue; | continue; | ||||
} | } | ||||
if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { | if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) { | ||||
/* | /* | ||||
* Stopped processes are tolerated when there | * Stopped processes are tolerated when there | ||||
* are no other processes which might continue | * are no other processes which might continue | ||||
* them. P_STOPPED_SINGLE but not | * them. P_STOPPED_SINGLE but not | ||||
* P_TOTAL_STOP process still has at least one | * P_TOTAL_STOP process still has at least one | ||||
* thread running. | * thread running. | ||||
*/ | */ | ||||
seen_stopped = true; | seen_stopped = true; | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
continue; | continue; | ||||
} | } | ||||
_PHOLD(p); | _PHOLD(p); | ||||
sx_xunlock(&allproc_lock); | sx_xunlock(&V_allproc_lock); | ||||
r = thread_single(p, SINGLE_ALLPROC); | r = thread_single(p, SINGLE_ALLPROC); | ||||
if (r != 0) | if (r != 0) | ||||
restart = true; | restart = true; | ||||
else | else | ||||
stopped_some = true; | stopped_some = true; | ||||
_PRELE(p); | _PRELE(p); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
sx_xlock(&allproc_lock); | sx_xlock(&V_allproc_lock); | ||||
} | } | ||||
/* Catch forked children we did not see in iteration. */ | /* Catch forked children we did not see in iteration. */ | ||||
if (gen != allproc_gen) | if (gen != allproc_gen) | ||||
restart = true; | restart = true; | ||||
sx_xunlock(&allproc_lock); | sx_xunlock(&V_allproc_lock); | ||||
if (restart || stopped_some || seen_exiting || seen_stopped) { | if (restart || stopped_some || seen_exiting || seen_stopped) { | ||||
kern_yield(PRI_USER); | kern_yield(PRI_USER); | ||||
goto allproc_loop; | goto allproc_loop; | ||||
} | } | ||||
CURVPS_RESTORE(); | |||||
} | } | ||||
VPS_LIST_RUNLOCK(); | |||||
} | |||||
void | void | ||||
resume_all_proc(void) | resume_all_proc(void) | ||||
{ | { | ||||
VPS_ITERATOR_DECL(vps_iter); | |||||
struct proc *cp, *p; | struct proc *cp, *p; | ||||
KASSERT(IS_DEFAULT_VPS(curvps), | |||||
("%s: called from non vps0 %p: vps %p\n", __func__, vps0, curvps)); | |||||
VPS_LIST_RLOCK(); | |||||
VPS_FOREACH(vps_iter) { | |||||
CURVPS_SET(vps_iter); | |||||
#ifdef VIMAGE | |||||
if (saved_vps != vps_iter) | |||||
cp = NULL; | |||||
else | |||||
#endif | |||||
cp = curproc; | cp = curproc; | ||||
sx_xlock(&allproc_lock); | sx_xlock(&V_allproc_lock); | ||||
again: | again: | ||||
LIST_REMOVE(cp, p_list); | LIST_REMOVE(cp, p_list); | ||||
LIST_INSERT_HEAD(&allproc, cp, p_list); | LIST_INSERT_HEAD(&V_allproc, cp, p_list); | ||||
for (;;) { | for (;;) { | ||||
p = LIST_NEXT(cp, p_list); | p = LIST_NEXT(cp, p_list); | ||||
if (p == NULL) | if (p == NULL) | ||||
break; | break; | ||||
LIST_REMOVE(cp, p_list); | LIST_REMOVE(cp, p_list); | ||||
LIST_INSERT_AFTER(p, cp, p_list); | LIST_INSERT_AFTER(p, cp, p_list); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if ((p->p_flag & P_TOTAL_STOP) != 0) { | if ((p->p_flag & P_TOTAL_STOP) != 0) { | ||||
sx_xunlock(&allproc_lock); | sx_xunlock(&V_allproc_lock); | ||||
_PHOLD(p); | _PHOLD(p); | ||||
thread_single_end(p, SINGLE_ALLPROC); | thread_single_end(p, SINGLE_ALLPROC); | ||||
_PRELE(p); | _PRELE(p); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
sx_xlock(&allproc_lock); | sx_xlock(&V_allproc_lock); | ||||
} else { | } else { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
} | } | ||||
} | } | ||||
/* Did the loop above missed any stopped process ? */ | /* Did the loop above missed any stopped process ? */ | ||||
FOREACH_PROC_IN_SYSTEM(p) { | FOREACH_PROC_IN_SYSTEM(p) { | ||||
/* No need for proc lock. */ | /* No need for proc lock. */ | ||||
if ((p->p_flag & P_TOTAL_STOP) != 0) | if ((p->p_flag & P_TOTAL_STOP) != 0) | ||||
goto again; | goto again; | ||||
} | } | ||||
sx_xunlock(&allproc_lock); | sx_xunlock(&V_allproc_lock); | ||||
CURVPS_RESTORE(); | |||||
} | |||||
VPS_LIST_RUNLOCK(); | |||||
} | } | ||||
/* #define TOTAL_STOP_DEBUG 1 */ | /* #define TOTAL_STOP_DEBUG 1 */ | ||||
#ifdef TOTAL_STOP_DEBUG | #ifdef TOTAL_STOP_DEBUG | ||||
volatile static int ap_resume; | volatile static int ap_resume; | ||||
#include <sys/mount.h> | #include <sys/mount.h> | ||||
static int | static int | ||||
Show All 25 Lines |