For archive, here's the diff on top of -current.
diff --git sys/kern/exec_elf.c sys/kern/exec_elf.c
index 24adf0dbed6..ccbbc6eb3a9 100644
--- sys/kern/exec_elf.c
+++ sys/kern/exec_elf.c
@@ -1217,12 +1217,14 @@ coredump_notes_elf(struct proc *p, void *iocookie,
size_t *sizep)
cpi.cpi_sigcatch = pr->ps_sigacts->ps_sigcatch;
cpi.cpi_pid = pr->ps_pid;
+ rw_enter_read(&proctreelk);
cpi.cpi_ppid = pr->ps_pptr->ps_pid;
cpi.cpi_pgrp = pr->ps_pgid;
if (pr->ps_session->s_leader)
cpi.cpi_sid = pr->ps_session->s_leader->ps_pid;
else
cpi.cpi_sid = 0;
+ rw_exit_read(&proctreelk);
cpi.cpi_ruid = p->p_ucred->cr_ruid;
cpi.cpi_euid = p->p_ucred->cr_uid;
diff --git sys/kern/kern_acct.c sys/kern/kern_acct.c
index f46ebf61d88..90f664977cf 100644
--- sys/kern/kern_acct.c
+++ sys/kern/kern_acct.c
@@ -227,11 +227,13 @@ acct_process(struct proc *p)
acct.ac_gid = pr->ps_ucred->cr_rgid;
/* (7) The terminal from which the process was started */
+ rw_enter_read(&proctreelk);
if ((pr->ps_flags & PS_CONTROLT) &&
pr->ps_pgrp->pg_session->s_ttyp)
acct.ac_tty = pr->ps_pgrp->pg_session->s_ttyp->t_dev;
else
acct.ac_tty = NODEV;
+ rw_exit_read(&proctreelk);
/* (8) The boolean flags that tell how the process terminated, etc. */
acct.ac_flag = pr->ps_acflag;
diff --git sys/kern/kern_exec.c sys/kern/kern_exec.c
index b71c8a9843c..4957df1342f 100644
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -514,9 +514,11 @@ sys_execve(struct proc *p, void *v, register_t *retval)
atomic_setbits_int(&pr->ps_flags, PS_EXEC);
if (pr->ps_flags & PS_PPWAIT) {
+ rw_enter_read(&proctreelk);
atomic_clearbits_int(&pr->ps_flags, PS_PPWAIT);
atomic_clearbits_int(&pr->ps_pptr->ps_flags, PS_ISPWAIT);
wakeup(pr->ps_pptr);
+ rw_exit_read(&proctreelk);
}
/*
diff --git sys/kern/kern_exit.c sys/kern/kern_exit.c
index 4c6f30cbdf8..5fff46481ce 100644
--- sys/kern/kern_exit.c
+++ sys/kern/kern_exit.c
@@ -152,6 +152,7 @@ exit1(struct proc *p, int rv, int flags)
* is set; we wake up the parent early to avoid deadlock.
*/
if (pr->ps_flags & PS_PPWAIT) {
+ /* XXXPT `proctreelk` ? */
atomic_clearbits_int(&pr->ps_flags, PS_PPWAIT);
atomic_clearbits_int(&pr->ps_pptr->ps_flags,
PS_ISPWAIT);
@@ -215,6 +216,7 @@ exit1(struct proc *p, int rv, int flags)
* If parent has the SAS_NOCLDWAIT flag set, we're not
* going to become a zombie.
*/
+ /* XXXPT `proctreelk` ? */
if (pr->ps_pptr->ps_sigacts->ps_flags & SAS_NOCLDWAIT)
atomic_setbits_int(&pr->ps_flags, PS_NOZOMBIE);
}
@@ -229,11 +231,7 @@ exit1(struct proc *p, int rv, int flags)
* thread of a process that isn't PS_NOZOMBIE, we'll put
* the process on the zombprocess list below.
*/
- /*
- * NOTE: WE ARE NO LONGER ALLOWED TO SLEEP!
- */
- p->p_stat = SDEAD;
-
+ rw_enter_write(&proctreelk);
LIST_REMOVE(p, p_hash);
LIST_REMOVE(p, p_list);
@@ -281,6 +279,7 @@ exit1(struct proc *p, int rv, int flags)
}
}
}
+ rw_exit_write(&proctreelk);
/* add thread's accumulated rusage into the process's total */
ruadd(rup, &p->p_ru);
@@ -309,9 +308,13 @@ exit1(struct proc *p, int rv, int flags)
* wait4() to return ECHILD.
*/
if (pr->ps_flags & PS_NOZOMBIE) {
- struct process *ppr = pr->ps_pptr;
+ struct process *ppr;
+
+ rw_enter_write(&proctreelk);
+ ppr = pr->ps_pptr;
proc_reparent(pr, initprocess);
wakeup(ppr);
+ rw_exit_write(&proctreelk);
}
/*
@@ -337,6 +340,11 @@ exit1(struct proc *p, int rv, int flags)
lim_free(limit);
}
+ /*
+ * NOTE: WE ARE NO LONGER ALLOWED TO SLEEP!
+ */
+ p->p_stat = SDEAD;
+
/*
* Other substructures are freed from reaper and wait().
*/
@@ -439,6 +447,7 @@ reaper(void *arg)
/* Release the rest of the process's vmspace */
uvm_exit(pr);
+ rw_enter_write(&proctreelk);
if ((pr->ps_flags & PS_NOZOMBIE) == 0) {
/* Process is now a true zombie. */
atomic_setbits_int(&pr->ps_flags, PS_ZOMBIE);
@@ -446,8 +455,14 @@ reaper(void *arg)
/* Wake up the parent so it can get exit
status. */
wakeup(pr->ps_pptr);
+ rw_exit_write(&proctreelk);
} else {
- /* No one will wait for us. Just zap the
process now */
+ /*
+ * No one will wait for us. Just zap the
+ * process now.
+ *
+ * Release `proctreelk' for us.
+ */
process_zap(pr);
}
}
@@ -493,12 +508,12 @@ dowait4(struct proc *q, pid_t pid, int *statusp, int
options,
struct proc *p;
int error;
- if (pid == 0)
- pid = -q->p_p->ps_pgid;
if (options &~ (WUNTRACED|WNOHANG|WCONTINUED))
return (EINVAL);
-
loop:
+ rw_enter_write(&proctreelk);
+ if (pid == 0)
+ pid = -q->p_p->ps_pgid;
nfound = 0;
LIST_FOREACH(pr, &q->p_p->ps_children, ps_sibling) {
if ((pr->ps_flags & PS_NOZOMBIE) ||
@@ -517,6 +532,7 @@ loop:
*statusp = p->p_xstat; /* convert to int */
if (rusage != NULL)
memcpy(rusage, pr->ps_ru, sizeof(*rusage));
+ /* Release `proctreelk' for us */
proc_finish_wait(q, p);
return (0);
}
@@ -524,6 +540,7 @@ loop:
(pr->ps_flags & PS_WAITED) == 0 && pr->ps_single &&
pr->ps_single->p_stat == SSTOP &&
(pr->ps_single->p_flag & P_SUSPSINGLE) == 0) {
+ rw_exit_write(&proctreelk);
single_thread_wait(pr);
atomic_setbits_int(&pr->ps_flags, PS_WAITED);
@@ -547,6 +564,7 @@ loop:
*statusp = W_STOPCODE(p->p_xstat);
if (rusage != NULL)
memset(rusage, 0, sizeof(*rusage));
+ rw_exit_write(&proctreelk);
return (0);
}
if ((options & WCONTINUED) && (p->p_flag & P_CONTINUED)) {
@@ -557,16 +575,21 @@ loop:
*statusp = _WCONTINUED;
if (rusage != NULL)
memset(rusage, 0, sizeof(*rusage));
+ rw_exit_write(&proctreelk);
return (0);
}
}
- if (nfound == 0)
+ if (nfound == 0) {
+ rw_exit_write(&proctreelk);
return (ECHILD);
+ }
if (options & WNOHANG) {
+ rw_exit_write(&proctreelk);
retval[0] = 0;
return (0);
}
- if ((error = tsleep(q->p_p, PWAIT | PCATCH, "wait", 0)) != 0)
+ if ((error = rwsleep(q->p_p, &proctreelk, PWAIT | PCATCH | PNORELOCK,
+ "wait", 0)) != 0)
return (error);
goto loop;
}
@@ -577,6 +600,8 @@ proc_finish_wait(struct proc *waiter, struct proc *p)
struct process *pr, *tr;
struct rusage *rup;
+ rw_assert_wrlock(&proctreelk);
+
/*
* If we got the child via a ptrace 'attach',
* we need to give it back to the old parent.
@@ -588,6 +613,7 @@ proc_finish_wait(struct proc *waiter, struct proc *p)
proc_reparent(pr, tr);
prsignal(tr, SIGCHLD);
wakeup(tr);
+ rw_exit_write(&proctreelk);
} else {
scheduler_wait_hook(waiter, p);
p->p_xstat = 0;
@@ -595,6 +621,7 @@ proc_finish_wait(struct proc *waiter, struct proc *p)
ruadd(rup, pr->ps_ru);
LIST_REMOVE(pr, ps_list); /* off zombprocess */
freepid(pr->ps_pid);
+ /* Release `proctreelk' for us */
process_zap(pr);
}
}
@@ -606,6 +633,7 @@ void
proc_reparent(struct process *child, struct process *parent)
{
+ rw_assert_wrlock(&proctreelk);
if (child->ps_pptr == parent)
return;
@@ -620,12 +648,15 @@ process_zap(struct process *pr)
struct vnode *otvp;
struct proc *p = pr->ps_mainproc;
+ rw_assert_wrlock(&proctreelk);
+
/*
* Finally finished with old proc entry.
* Unlink it from its process group and free it.
*/
leavepgrp(pr);
LIST_REMOVE(pr, ps_sibling);
+ rw_exit_write(&proctreelk);
/*
* Decrement the count of procs running with this uid.
diff --git sys/kern/kern_fork.c sys/kern/kern_fork.c
index 3977a9f2d4f..8cb20d2da6f 100644
--- sys/kern/kern_fork.c
+++ sys/kern/kern_fork.c
@@ -248,8 +248,6 @@ process_new(struct proc *p, struct process *parent, int
flags)
pr->ps_flags = parent->ps_flags &
(PS_SUGID | PS_SUGIDEXEC | PS_PLEDGE | PS_EXECPLEDGE | PS_WXNEEDED);
- if (parent->ps_session->s_ttyvp != NULL)
- pr->ps_flags |= parent->ps_flags & PS_CONTROLT;
/*
* Duplicate sub-structures as needed.
@@ -280,10 +278,11 @@ process_new(struct proc *p, struct process *parent, int
flags)
/* mark as embryo to protect against others */
pr->ps_flags |= PS_EMBRYO;
- /* Force visibility of all of the above changes */
- membar_producer();
-
/* it's sufficiently inited to be globally visible */
+ rw_enter_write(&proctreelk);
+ if (parent->ps_session->s_ttyvp != NULL)
+ pr->ps_flags |= parent->ps_flags & PS_CONTROLT;
+ pr->ps_pid = allocpid();
LIST_INSERT_HEAD(&allprocess, pr, ps_list);
return pr;
@@ -384,6 +383,7 @@ fork1(struct proc *curp, int flags, void (*func)(void *),
void *arg,
/*
* From now on, we're committed to the fork and cannot fail.
+ * process_new() returns with proctreelk held!
*/
p = thread_new(curp, uaddr);
pr = process_new(p, curpr, flags);
@@ -458,6 +458,7 @@ fork1(struct proc *curp, int flags, void (*func)(void *),
void *arg,
pr->ps_ptstat->pe_other_pid = curpr->ps_pid;
}
}
+ rw_exit_write(&proctreelk);
/*
* For new processes, set accounting bits and mark as complete.
diff --git sys/kern/kern_ktrace.c sys/kern/kern_ktrace.c
index 39bd1183d5b..41db0d1ab98 100644
--- sys/kern/kern_ktrace.c
+++ sys/kern/kern_ktrace.c
@@ -454,6 +454,7 @@ doktrace(struct vnode *vp, int ops, int facs, pid_t pid,
struct proc *p)
/*
* do it
*/
+ rw_enter_read(&proctreelk);
if (pid < 0) {
/*
* by process group
@@ -461,7 +462,7 @@ doktrace(struct vnode *vp, int ops, int facs, pid_t pid,
struct proc *p)
pg = pgfind(-pid);
if (pg == NULL) {
error = ESRCH;
- goto done;
+ goto done2;
}
LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
if (descend)
@@ -477,7 +478,7 @@ doktrace(struct vnode *vp, int ops, int facs, pid_t pid,
struct proc *p)
pr = prfind(pid);
if (pr == NULL) {
error = ESRCH;
- goto done;
+ goto done2;
}
if (descend)
ret |= ktrsetchildren(p, pr, ops, facs, vp, cred);
@@ -486,6 +487,8 @@ doktrace(struct vnode *vp, int ops, int facs, pid_t pid,
struct proc *p)
}
if (!ret)
error = EPERM;
+done2:
+ rw_exit_read(&proctreelk);
done:
return (error);
}
@@ -556,6 +559,8 @@ ktrsetchildren(struct proc *curp, struct process *top, int
ops, int facs,
struct process *pr;
int ret = 0;
+ rw_assert_rdlock(&proctreelk);
+
pr = top;
for (;;) {
ret |= ktrops(curp, pr, ops, facs, vp, cred);
diff --git sys/kern/kern_proc.c sys/kern/kern_proc.c
index 934cf455ba1..7ad2913011a 100644
--- sys/kern/kern_proc.c
+++ sys/kern/kern_proc.c
@@ -67,6 +67,7 @@ u_long pgrphash;
struct processlist allprocess;
struct processlist zombprocess;
struct proclist allproc;
+struct rwlock proctreelk;
struct pool proc_pool;
struct pool process_pool;
@@ -79,9 +80,6 @@ void pgdelete(struct pgrp *);
void fixjobc(struct process *, struct pgrp *, int);
static void orphanpg(struct pgrp *);
-#ifdef DEBUG
-void pgrpdump(void);
-#endif
/*
* Initialize global process hashing structures.
@@ -93,6 +91,7 @@ procinit(void)
LIST_INIT(&zombprocess);
LIST_INIT(&allproc);
+ rw_init(&proctreelk, "proctree");
rw_init(&uidinfolk, "uidinfo");
tidhashtbl = hashinit(maxthread / 4, M_PROC, M_NOWAIT, &tidhash);
@@ -180,6 +179,7 @@ int
inferior(struct process *pr, struct process *parent)
{
+ rw_assert_wrlock(&proctreelk);
for (; pr != parent; pr = pr->ps_pptr)
if (pr->ps_pid == 0 || pr->ps_pid == 1)
return (0);
@@ -222,6 +222,7 @@ pgfind(pid_t pgid)
{
struct pgrp *pgrp;
+ rw_assert_anylock(&proctreelk);
LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash)
if (pgrp->pg_id == pgid)
return (pgrp);
@@ -250,6 +251,8 @@ zombiefind(pid_t pid)
void
enternewpgrp(struct process *pr, struct pgrp *pgrp, struct session *newsess)
{
+ rw_assert_wrlock(&proctreelk);
+
#ifdef DIAGNOSTIC
if (SESS_LEADER(pr))
panic("%s: session leader attempted setpgrp", __func__);
@@ -293,6 +296,8 @@ enterthispgrp(struct process *pr, struct pgrp *pgrp)
{
struct pgrp *savepgrp = pr->ps_pgrp;
+ rw_assert_wrlock(&proctreelk);
+
/*
* Adjust eligibility of affected pgrps to participate in job control.
* Increment eligibility counts before decrementing, otherwise we
@@ -303,6 +308,7 @@ enterthispgrp(struct process *pr, struct pgrp *pgrp)
LIST_REMOVE(pr, ps_pglist);
pr->ps_pgrp = pgrp;
+
LIST_INSERT_HEAD(&pgrp->pg_members, pr, ps_pglist);
if (LIST_EMPTY(&savepgrp->pg_members))
pgdelete(savepgrp);
@@ -315,6 +321,7 @@ void
leavepgrp(struct process *pr)
{
+ rw_assert_wrlock(&proctreelk);
if (pr->ps_session->s_verauthppid == pr->ps_pid)
zapverauth(pr->ps_session);
LIST_REMOVE(pr, ps_pglist);
@@ -331,6 +338,7 @@ pgdelete(struct pgrp *pgrp)
{
sigio_freelist(&pgrp->pg_sigiolst);
+ rw_assert_wrlock(&proctreelk);
if (pgrp->pg_session->s_ttyp != NULL &&
pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
pgrp->pg_session->s_ttyp->t_pgrp = NULL;
@@ -343,6 +351,9 @@ void
zapverauth(void *v)
{
struct session *sess = v;
+
+ rw_assert_wrlock(&proctreelk);
+
sess->s_verauthuid = 0;
sess->s_verauthppid = 0;
}
@@ -364,6 +375,8 @@ fixjobc(struct process *pr, struct pgrp *pgrp, int entering)
struct pgrp *hispgrp;
struct session *mysession = pgrp->pg_session;
+ rw_assert_wrlock(&proctreelk);
+
/*
* Check pr's parent to see whether pr qualifies its own process
* group; if so, adjust count for pr's process group.
@@ -395,6 +408,7 @@ fixjobc(struct process *pr, struct pgrp *pgrp, int entering)
void
killjobc(struct process *pr)
{
+ rw_enter_write(&proctreelk);
if (SESS_LEADER(pr)) {
struct session *sp = pr->ps_session;
@@ -410,7 +424,9 @@ killjobc(struct process *pr)
if (sp->s_ttyp->t_session == sp) {
if (sp->s_ttyp->t_pgrp)
pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
+ rw_exit_write(&proctreelk);
ttywait(sp->s_ttyp);
+ rw_enter_write(&proctreelk);
/*
* The tty could have been revoked
* if we blocked.
@@ -432,6 +448,7 @@ killjobc(struct process *pr)
sp->s_leader = NULL;
}
fixjobc(pr, pr->ps_pgrp, 0);
+ rw_exit_write(&proctreelk);
}
/*
@@ -444,6 +461,7 @@ orphanpg(struct pgrp *pg)
{
struct process *pr;
+ rw_assert_wrlock(&proctreelk);
LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
if (pr->ps_mainproc->p_stat == SSTOP) {
LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
@@ -634,29 +652,3 @@ db_show_all_procs(db_expr_t addr, int haddr, db_expr_t
count, char *modif)
}
}
#endif
-
-#ifdef DEBUG
-void
-pgrpdump(void)
-{
- struct pgrp *pgrp;
- struct process *pr;
- int i;
-
- for (i = 0; i <= pgrphash; i++) {
- if (!LIST_EMPTY(&pgrphashtbl[i])) {
- printf("\tindx %d\n", i);
- LIST_FOREACH(pgrp, &pgrphashtbl[i], pg_hash) {
- printf("\tpgrp %p, pgid %d, sess %p, sesscnt
%d, mem %p\n",
- pgrp, pgrp->pg_id, pgrp->pg_session,
- pgrp->pg_session->s_count,
- LIST_FIRST(&pgrp->pg_members));
- LIST_FOREACH(pr, &pgrp->pg_members, ps_pglist) {
- printf("\t\tpid %d addr %p pgrp %p\n",
- pr->ps_pid, pr, pr->ps_pgrp);
- }
- }
- }
- }
-}
-#endif /* DEBUG */
diff --git sys/kern/kern_prot.c sys/kern/kern_prot.c
index 67c6c1020d5..f248b0e1204 100644
--- sys/kern/kern_prot.c
+++ sys/kern/kern_prot.c
@@ -84,7 +84,9 @@ int
sys_getppid(struct proc *p, void *v, register_t *retval)
{
+ rw_enter_read(&proctreelk);
*retval = p->p_p->ps_pptr->ps_pid;
+ rw_exit_read(&proctreelk);
return (0);
}
@@ -93,7 +95,9 @@ int
sys_getpgrp(struct proc *p, void *v, register_t *retval)
{
+ rw_enter_read(&proctreelk);
*retval = p->p_p->ps_pgrp->pg_id;
+ rw_exit_read(&proctreelk);
return (0);
}
@@ -107,16 +111,23 @@ sys_getpgid(struct proc *curp, void *v, register_t
*retval)
syscallarg(pid_t) pid;
} */ *uap = v;
struct process *targpr = curp->p_p;
+ int error = 0;
- if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
- goto found;
+ if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid) {
+ rw_enter_read(&proctreelk);
+ *retval = targpr->ps_pgid;
+ rw_exit_read(&proctreelk);
+ return 0;
+ }
+ rw_enter_read(&proctreelk);
if ((targpr = prfind(SCARG(uap, pid))) == NULL)
- return (ESRCH);
- if (targpr->ps_session != curp->p_p->ps_session)
- return (EPERM);
-found:
- *retval = targpr->ps_pgid;
- return (0);
+ error = ESRCH;
+ else if (targpr->ps_session != curp->p_p->ps_session)
+ error = EPERM;
+ else
+ *retval = targpr->ps_pgid;
+ rw_exit_read(&proctreelk);
+ return error;
}
int
@@ -126,19 +137,28 @@ sys_getsid(struct proc *curp, void *v, register_t *retval)
syscallarg(pid_t) pid;
} */ *uap = v;
struct process *targpr = curp->p_p;
+ int error = 0;
+
+ rw_enter_read(&proctreelk);
+ if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != targpr->ps_pid) {
+ if ((targpr = prfind(SCARG(uap, pid))) == NULL) {
+ error = ESRCH;
+ goto out;
+ }
+ if (targpr->ps_session != curp->p_p->ps_session) {
+ error = EPERM;
+ goto out;
+ }
+ }
- if (SCARG(uap, pid) == 0 || SCARG(uap, pid) == targpr->ps_pid)
- goto found;
- if ((targpr = prfind(SCARG(uap, pid))) == NULL)
- return (ESRCH);
- if (targpr->ps_session != curp->p_p->ps_session)
- return (EPERM);
-found:
/* Skip exiting processes */
if (targpr->ps_pgrp->pg_session->s_leader == NULL)
- return (ESRCH);
- *retval = targpr->ps_pgrp->pg_session->s_leader->ps_pid;
- return (0);
+ error = ESRCH;
+ else
+ *retval = targpr->ps_pgrp->pg_session->s_leader->ps_pid;
+out:
+ rw_exit_read(&proctreelk);
+ return error;
}
int
@@ -225,12 +245,15 @@ sys_setsid(struct proc *p, void *v, register_t *retval)
newsess = pool_get(&session_pool, PR_WAITOK);
newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
+ rw_enter_write(&proctreelk);
if (pr->ps_pgid == pid || pgfind(pid) != NULL) {
+ rw_exit_write(&proctreelk);
pool_put(&pgrp_pool, newpgrp);
pool_put(&session_pool, newsess);
return (EPERM);
} else {
enternewpgrp(pr, newpgrp, newsess);
+ rw_exit_write(&proctreelk);
*retval = pid;
return (0);
}
@@ -270,6 +293,7 @@ sys_setpgid(struct proc *curp, void *v, register_t *retval)
newpgrp = pool_get(&pgrp_pool, PR_WAITOK);
+ rw_enter_write(&proctreelk);
if (pid != 0 && pid != curpr->ps_pid) {
if ((targpr = prfind(pid)) == 0 || !inferior(targpr, curpr)) {
error = ESRCH;
@@ -308,7 +332,8 @@ sys_setpgid(struct proc *curp, void *v, register_t *retval)
else
enterthispgrp(targpr, pgrp);
}
- out:
+out:
+ rw_exit_write(&proctreelk);
if (newpgrp != NULL)
pool_put(&pgrp_pool, newpgrp);
return (error);
@@ -966,7 +991,6 @@ crhold(struct ucred *cr)
void
crfree(struct ucred *cr)
{
-
if (atomic_dec_int_nv(&cr->cr_ref) == 0)
pool_put(&ucred_pool, cr);
}
@@ -1030,12 +1054,17 @@ sys_getlogin_r(struct proc *p, void *v, register_t
*retval)
syscallarg(size_t) namelen;
} */ *uap = v;
size_t namelen = SCARG(uap, namelen);
- struct session *s = p->p_p->ps_pgrp->pg_session;
+ struct session *s;
+ char buf[sizeof(s->s_login)];
int error;
+ rw_enter_read(&proctreelk);
+ s = p->p_p->ps_pgrp->pg_session;
if (namelen > sizeof(s->s_login))
namelen = sizeof(s->s_login);
- error = copyoutstr(s->s_login, SCARG(uap, namebuf), namelen, NULL);
+ namelen = strlcpy(buf, s->s_login, namelen) + 1;
+ rw_exit_read(&proctreelk);
+ error = copyoutstr(buf, SCARG(uap, namebuf), namelen, NULL);
if (error == ENAMETOOLONG)
error = ERANGE;
*retval = error;
@@ -1051,15 +1080,19 @@ sys_setlogin(struct proc *p, void *v, register_t
*retval)
struct sys_setlogin_args /* {
syscallarg(const char *) namebuf;
} */ *uap = v;
- struct session *s = p->p_p->ps_pgrp->pg_session;
+ struct session *s;
char buf[sizeof(s->s_login)];
int error;
if ((error = suser(p)) != 0)
return (error);
error = copyinstr(SCARG(uap, namebuf), buf, sizeof(buf), NULL);
- if (error == 0)
+ if (error == 0) {
+ rw_enter_write(&proctreelk);
+ s = p->p_p->ps_pgrp->pg_session;
strlcpy(s->s_login, buf, sizeof(s->s_login));
+ rw_exit_write(&proctreelk);
+ }
else if (error == ENAMETOOLONG)
error = EINVAL;
return (error);
diff --git sys/kern/kern_resource.c sys/kern/kern_resource.c
index 341315d03e0..e8bcb7cc7b3 100644
--- sys/kern/kern_resource.c
+++ sys/kern/kern_resource.c
@@ -108,13 +108,17 @@ sys_getpriority(struct proc *curp, void *v, register_t
*retval)
case PRIO_PGRP: {
struct pgrp *pg;
+ rw_enter_read(&proctreelk);
if (SCARG(uap, who) == 0)
pg = curp->p_p->ps_pgrp;
- else if ((pg = pgfind(SCARG(uap, who))) == NULL)
+ else if ((pg = pgfind(SCARG(uap, who))) == NULL) {
+ rw_exit_read(&proctreelk);
break;
+ }
LIST_FOREACH(pr, &pg->pg_members, ps_pglist)
if (pr->ps_nice < low)
low = pr->ps_nice;
+ rw_exit_read(&proctreelk);
break;
}
@@ -163,14 +167,18 @@ sys_setpriority(struct proc *curp, void *v, register_t
*retval)
case PRIO_PGRP: {
struct pgrp *pg;
+ rw_enter_read(&proctreelk);
if (SCARG(uap, who) == 0)
pg = curp->p_p->ps_pgrp;
- else if ((pg = pgfind(SCARG(uap, who))) == NULL)
+ else if ((pg = pgfind(SCARG(uap, who))) == NULL) {
+ rw_exit_read(&proctreelk);
break;
+ }
LIST_FOREACH(pr, &pg->pg_members, ps_pglist) {
error = donice(curp, pr, SCARG(uap, prio));
found++;
}
+ rw_exit_read(&proctreelk);
break;
}
diff --git sys/kern/kern_sig.c sys/kern/kern_sig.c
index 2b93e41fac7..36f961ef13d 100644
--- sys/kern/kern_sig.c
+++ sys/kern/kern_sig.c
@@ -111,6 +111,7 @@ cansignal(struct proc *p, struct process *qr, int signum)
if (uc == quc)
return (1);
+ rw_assert_rdlock(&proctreelk);
if (signum == SIGCONT && qr->ps_session == pr->ps_session)
return (1); /* SIGCONT in session */
@@ -579,7 +580,7 @@ sys_kill(struct proc *cp, void *v, register_t *retval)
struct process *pr;
int pid = SCARG(uap, pid);
int signum = SCARG(uap, signum);
- int error;
+ int error, cansig;
int zombie = 0;
if ((error = pledge_kill(cp, pid)) != 0)
@@ -593,7 +594,10 @@ sys_kill(struct proc *cp, void *v, register_t *retval)
else
zombie = 1;
}
- if (!cansignal(cp, pr, signum))
+ rw_enter_read(&proctreelk);
+ cansig = cansignal(cp, pr, signum);
+ rw_exit_read(&proctreelk);
+ if (!cansig)
return (EPERM);
/* kill single process */
@@ -663,6 +667,7 @@ killpg1(struct proc *cp, int signum, int pgid, int all)
/*
* broadcast
*/
+ rw_enter_read(&proctreelk);
LIST_FOREACH(pr, &allprocess, ps_list) {
if (pr->ps_pid <= 1 ||
pr->ps_flags & (PS_SYSTEM | PS_NOBROADCASTKILL) ||
@@ -672,7 +677,9 @@ killpg1(struct proc *cp, int signum, int pgid, int all)
if (signum)
prsignal(pr, signum);
}
+ rw_exit_read(&proctreelk);
} else {
+ rw_enter_read(&proctreelk);
if (pgid == 0)
/*
* zero pgid means send to my process group.
@@ -680,8 +687,10 @@ killpg1(struct proc *cp, int signum, int pgid, int all)
pgrp = cp->p_p->ps_pgrp;
else {
pgrp = pgfind(pgid);
- if (pgrp == NULL)
+ if (pgrp == NULL) {
+ rw_exit_read(&proctreelk);
return (ESRCH);
+ }
}
LIST_FOREACH(pr, &pgrp->pg_members, ps_pglist) {
if (pr->ps_pid <= 1 || pr->ps_flags & PS_SYSTEM ||
@@ -691,6 +700,7 @@ killpg1(struct proc *cp, int signum, int pgid, int all)
if (signum)
prsignal(pr, signum);
}
+ rw_exit_read(&proctreelk);
}
return (nfound ? 0 : ESRCH);
}
@@ -717,6 +727,12 @@ csignal(pid_t pgid, int signum, uid_t uid, uid_t euid)
struct pgrp *pgrp;
struct process *pr;
+ /*
+ * XXXPT `pg_members' needs to be protected but this can be called
+ * from interrupt context.
+ */
+ //rw_assert_wrlock(&proctreelk)
+
if (pgid == 0)
return;
if (pgid < 0) {
@@ -743,6 +759,12 @@ pgsignal(struct pgrp *pgrp, int signum, int checkctty)
{
struct process *pr;
+ /*
+ * XXXPT `pg_members' needs to be protected but this can be called
+ * from interrupt context.
+ */
+ //rw_assert_wrlock(&proctreelk)
+
if (pgrp)
LIST_FOREACH(pr, &pgrp->pg_members, ps_pglist)
if (checkctty == 0 || pr->ps_flags & PS_CONTROLT)
@@ -1371,6 +1393,7 @@ proc_stop_sweep(void *v)
{
struct process *pr;
+ rw_enter_read(&proctreelk);
LIST_FOREACH(pr, &allprocess, ps_list) {
if ((pr->ps_flags & PS_STOPPED) == 0)
continue;
@@ -1380,6 +1403,7 @@ proc_stop_sweep(void *v)
prsignal(pr->ps_pptr, SIGCHLD);
wakeup(pr->ps_pptr);
}
+ rw_exit_read(&proctreelk);
}
/*
diff --git sys/kern/kern_sysctl.c sys/kern/kern_sysctl.c
index 45a339feb81..12340cbb7bd 100644
--- sys/kern/kern_sysctl.c
+++ sys/kern/kern_sysctl.c
@@ -1510,6 +1510,7 @@ sysctl_doproc(int *name, u_int namelen, char *where,
size_t *sizep)
if (where != NULL)
kproc = malloc(sizeof(*kproc), M_TEMP, M_WAITOK);
+ rw_enter_read(&proctreelk);
pr = LIST_FIRST(&allprocess);
doingzomb = 0;
again:
@@ -1548,6 +1549,7 @@ again:
break;
case KERN_PROC_TTY:
+ /* XXXPT proctreelk? */
if ((pr->ps_flags & PS_CONTROLT) == 0 ||
pr->ps_session->s_ttyp == NULL ||
pr->ps_session->s_ttyp->t_dev != (dev_t)arg)
@@ -1611,6 +1613,7 @@ again:
doingzomb++;
goto again;
}
+ rw_exit_read(&proctreelk);
if (where != NULL) {
*sizep = dp - where;
if (needed > *sizep) {
@@ -1640,6 +1643,8 @@ fill_kproc(struct process *pr, struct kinfo_proc *ki,
struct proc *p,
struct timespec booted, st, ut, utc;
int isthread;
+ rw_assert_rdlock(&proctreelk);
+
isthread = p != NULL;
if (!isthread)
p = pr->ps_mainproc; /* XXX */
diff --git sys/kern/subr_prf.c sys/kern/subr_prf.c
index 9047e83f2a7..9eabedc6b15 100644
--- sys/kern/subr_prf.c
+++ sys/kern/subr_prf.c
@@ -362,6 +362,7 @@ uprintf(const char *fmt, ...)
struct process *pr = curproc->p_p;
va_list ap;
+ /* XXXPT proctreelk? */
if (pr->ps_flags & PS_CONTROLT && pr->ps_session->s_ttyvp) {
va_start(ap, fmt);
kprintf(fmt, TOTTY, pr->ps_session->s_ttyp, NULL, ap);
diff --git sys/kern/sys_process.c sys/kern/sys_process.c
index 08bfb73bf5f..14bedae5d5b 100644
--- sys/kern/sys_process.c
+++ sys/kern/sys_process.c
@@ -276,13 +276,19 @@ ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t
addr, int data)
struct proc *t; /* target thread */
struct process *tr; /* target process */
int error = 0;
+ int proctree_locked;
int s;
+ /* Lock proctree before looking up the process. */
+ rw_enter_write(&proctreelk);
+ proctree_locked = 1;
+
switch (req) {
case PT_TRACE_ME:
/* Just set the trace flag. */
tr = p->p_p;
atomic_setbits_int(&tr->ps_flags, PS_TRACED);
+ rw_exit_write(&proctreelk);
tr->ps_oppid = tr->ps_pptr->ps_pid;
if (tr->ps_ptstat == NULL)
tr->ps_ptstat = malloc(sizeof(*tr->ps_ptstat),
@@ -447,6 +453,8 @@ ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t
addr, int data)
if (error)
goto fail;
#endif
+ proctree_locked = 0;
+ rw_exit_write(&proctreelk);
goto sendsig;
case PT_DETACH:
@@ -486,7 +494,11 @@ ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t
addr, int data)
tr->ps_oppid = 0;
atomic_clearbits_int(&tr->ps_flags, PS_TRACED|PS_WAITED);
+ proctree_locked = 0;
+ rw_exit_write(&proctreelk);
sendsig:
+ KASSERT(proctree_locked == 0);
+
memset(tr->ps_ptstat, 0, sizeof(*tr->ps_ptstat));
/* Finally, deliver the requested signal (or none). */
@@ -507,6 +519,8 @@ ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t
addr, int data)
/* just send the process a KILL signal. */
data = SIGKILL;
+ proctree_locked = 0;
+ rw_exit_write(&proctreelk);
goto sendsig; /* in PT_CONTINUE, above. */
case PT_ATTACH:
@@ -523,6 +537,8 @@ ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t
addr, int data)
tr->ps_oppid = tr->ps_pptr->ps_pid;
if (tr->ps_pptr != p->p_p)
proc_reparent(tr, p->p_p);
+ proctree_locked = 0;
+ rw_exit_write(&proctreelk);
if (tr->ps_ptstat == NULL)
tr->ps_ptstat = malloc(sizeof(*tr->ps_ptstat),
M_SUBPROC, M_WAITOK);
@@ -534,6 +550,8 @@ ptrace_ctrl(struct proc *p, int req, pid_t pid, caddr_t
addr, int data)
}
fail:
+ if (proctree_locked)
+ rw_exit_write(&proctreelk);
return error;
}
diff --git sys/kern/syscalls.master sys/kern/syscalls.master
index 13b44d159b9..f9eca1a449a 100644
--- sys/kern/syscalls.master
+++ sys/kern/syscalls.master
@@ -107,7 +107,7 @@
36 STD { void sys_sync(void); }
37 STD { int sys_msyscall(void *addr, size_t len); }
38 STD { int sys_stat(const char *path, struct stat *ub); }
-39 STD { pid_t sys_getppid(void); }
+39 STD NOLOCK { pid_t sys_getppid(void); }
40 STD { int sys_lstat(const char *path, struct stat *ub); }
41 STD { int sys_dup(int fd); }
42 STD { int sys_fstatat(int fd, const char *path, \
@@ -127,7 +127,7 @@
47 STD NOLOCK { gid_t sys_getgid(void); }
48 STD NOLOCK { int sys_sigprocmask(int how, sigset_t mask); }
49 OBSOL ogetlogin
-50 STD { int sys_setlogin(const char *namebuf); }
+50 STD NOLOCK { int sys_setlogin(const char *namebuf); }
#ifdef ACCOUNTING
51 STD { int sys_acct(const char *path); }
#else
@@ -184,7 +184,7 @@
gid_t *gidset); }
80 STD { int sys_setgroups(int gidsetsize, \
const gid_t *gidset); }
-81 STD { int sys_getpgrp(void); }
+81 STD NOLOCK { int sys_getpgrp(void); }
82 STD { int sys_setpgid(pid_t pid, pid_t pgid); }
83 STD NOLOCK { int sys_futex(uint32_t *f, int op, int val, \
const struct timespec *timeout, uint32_t *g); }
@@ -274,7 +274,7 @@
139 OBSOL 4.2 sigreturn
140 STD NOLOCK { int sys_adjtime(const struct timeval *delta, \
struct timeval *olddelta); }
-141 STD { int sys_getlogin_r(char *namebuf, u_int namelen); }
+141 STD NOLOCK { int sys_getlogin_r(char *namebuf, u_int namelen); }
142 OBSOL ogethostid
143 OBSOL osethostid
144 OBSOL ogetrlimit
diff --git sys/kern/tty.c sys/kern/tty.c
index a21f7f2741f..c2c946f1930 100644
--- sys/kern/tty.c
+++ sys/kern/tty.c
@@ -837,7 +837,9 @@ ttioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
struct proc *p)
case TIOCGSID: /* get sid of tty */
if (!isctty(pr, tp))
return (ENOTTY);
+ rw_enter_read(&proctreelk);
*(int *)data = tp->t_session->s_leader->ps_pid;
+ rw_exit_read(&proctreelk);
break;
#ifdef TIOCHPCL
case TIOCHPCL: /* hang up on last close */
@@ -893,10 +895,12 @@ ttioctl(struct tty *tp, u_long cmd, caddr_t data, int
flag, struct proc *p)
tp->t_cflag = t->c_cflag;
tp->t_ispeed = t->c_ispeed;
tp->t_ospeed = t->c_ospeed;
+ rw_enter_read(&proctreelk);
if (t->c_ospeed == 0 && tp->t_session &&
tp->t_session->s_leader)
prsignal(tp->t_session->s_leader,
SIGHUP);
+ rw_exit_read(&proctreelk);
}
ttsetwater(tp);
}
@@ -971,10 +975,13 @@ ttioctl(struct tty *tp, u_long cmd, caddr_t data, int
flag, struct proc *p)
break;
case TIOCSCTTY: /* become controlling tty */
/* Session ctty vnode pointer set in vnode layer. */
+ rw_enter_write(&proctreelk);
if (!SESS_LEADER(pr) ||
((pr->ps_session->s_ttyvp || tp->t_session) &&
- (tp->t_session != pr->ps_session)))
+ (tp->t_session != pr->ps_session))) {
+ rw_exit_write(&proctreelk);
return (EPERM);
+ }
if (tp->t_session)
SESSRELE(tp->t_session);
SESSHOLD(pr->ps_session);
@@ -982,17 +989,25 @@ ttioctl(struct tty *tp, u_long cmd, caddr_t data, int
flag, struct proc *p)
tp->t_pgrp = pr->ps_pgrp;
pr->ps_session->s_ttyp = tp;
atomic_setbits_int(&pr->ps_flags, PS_CONTROLT);
+ rw_exit_write(&proctreelk);
break;
case TIOCSPGRP: { /* set pgrp of tty */
- struct pgrp *pgrp = pgfind(*(int *)data);
+ struct pgrp *pgrp;
+ rw_enter_write(&proctreelk);
+ pgrp = pgfind(*(int *)data);
if (!isctty(pr, tp))
- return (ENOTTY);
+ error = ENOTTY;
else if (pgrp == NULL)
- return (EINVAL);
+ error = EINVAL;
else if (pgrp->pg_session != pr->ps_session)
- return (EPERM);
- tp->t_pgrp = pgrp;
+ error = EPERM;
+ else {
+ tp->t_pgrp = pgrp;
+ error = 0;
+ }
+ rw_exit_write(&proctreelk);
+ return (error);
break;
}
case TIOCSTAT: /* get load avg stats */
@@ -1383,6 +1398,11 @@ ttymodem(struct tty *tp, int flag)
CLR(tp->t_state, TS_CARR_ON);
if (ISSET(tp->t_state, TS_ISOPEN) &&
!ISSET(tp->t_cflag, CLOCAL)) {
+ /*
+ * XXXPT `s_leader' needs to be protected but this
+ * can be called from interrupt context.
+ */
+ //rw_assert_wrlock(&proctreelk)
if (tp->t_session && tp->t_session->s_leader)
prsignal(tp->t_session->s_leader, SIGHUP);
ttyflush(tp, FREAD | FWRITE);
@@ -1412,6 +1432,11 @@ nullmodem(struct tty *tp, int flag)
CLR(tp->t_state, TS_CARR_ON);
if (ISSET(tp->t_state, TS_ISOPEN) &&
!ISSET(tp->t_cflag, CLOCAL)) {
+ /*
+ * XXXPT `s_leader' needs to be protected but this
+ * can be called from interrupt context.
+ */
+ //rw_assert_wrlock(&proctreelk)
if (tp->t_session && tp->t_session->s_leader)
prsignal(tp->t_session->s_leader, SIGHUP);
ttyflush(tp, FREAD | FWRITE);
@@ -2129,6 +2154,12 @@ ttyinfo(struct tty *tp)
if (ttycheckoutq(tp,0) == 0)
return;
+ /*
+ * XXXPT `pg_members' needs to be protected but this can be called
+ * from interrupt context.
+ */
+ //rw_assert_wrlock(&proctreelk)
+
/* Print load average. */
tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;
ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);
diff --git sys/kern/tty_tty.c sys/kern/tty_tty.c
index da4bb63e13e..4ea28450670 100644
--- sys/kern/tty_tty.c
+++ sys/kern/tty_tty.c
@@ -45,6 +45,9 @@
#include <sys/fcntl.h>
+/*
+ * XXXPT Must hold `proctreelk' to dereference `ps_session'.
+ */
#define cttyvp(p) \
((p)->p_p->ps_flags & PS_CONTROLT ? \
(p)->p_p->ps_session->s_ttyvp : NULL)
@@ -103,11 +106,14 @@ cttyioctl(dev_t dev, u_long cmd, caddr_t addr, int flag,
struct proc *p)
if (cmd == TIOCSCTTY) /* XXX */
return (EINVAL);
if (cmd == TIOCNOTTY) {
+ rw_enter_read(&proctreelk);
if (!SESS_LEADER(p->p_p)) {
atomic_clearbits_int(&p->p_p->ps_flags, PS_CONTROLT);
- return (0);
+ error = 0;
} else
- return (EINVAL);
+ error = EINVAL;
+ rw_exit_read(&proctreelk);
+ return error;
}
switch (cmd) {
case TIOCSETVERAUTH:
@@ -116,15 +122,19 @@ cttyioctl(dev_t dev, u_long cmd, caddr_t addr, int flag,
struct proc *p)
secs = *(int *)addr;
if (secs < 1 || secs > 3600)
return EINVAL;
+ rw_enter_write(&proctreelk);
sess = p->p_p->ps_pgrp->pg_session;
sess->s_verauthuid = p->p_ucred->cr_ruid;
sess->s_verauthppid = p->p_p->ps_pptr->ps_pid;
timeout_add_sec(&sess->s_verauthto, secs);
+ rw_exit_write(&proctreelk);
return 0;
case TIOCCLRVERAUTH:
+ rw_enter_write(&proctreelk);
sess = p->p_p->ps_pgrp->pg_session;
timeout_del(&sess->s_verauthto);
zapverauth(sess);
+ rw_exit_write(&proctreelk);
return 0;
case TIOCCHKVERAUTH:
/*
@@ -134,11 +144,15 @@ cttyioctl(dev_t dev, u_long cmd, caddr_t addr, int flag,
struct proc *p)
* Nevertheless, the checks reflect the original intention;
* namely, that it be the same user using the same shell.
*/
+ rw_enter_read(&proctreelk);
sess = p->p_p->ps_pgrp->pg_session;
if (sess->s_verauthuid == p->p_ucred->cr_ruid &&
sess->s_verauthppid == p->p_p->ps_pptr->ps_pid)
- return 0;
- return EPERM;
+ error = 0;
+ else
+ error = EPERM;
+ rw_exit_read(&proctreelk);
+ return error;
}
return (VOP_IOCTL(ttyvp, cmd, addr, flag, NOCRED, p));
}
diff --git sys/sys/proc.h sys/sys/proc.h
index 846d1946a92..41c8103a1a7 100644
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -44,6 +44,7 @@
#include <sys/selinfo.h> /* For struct selinfo */
#include <sys/syslimits.h> /* For LOGIN_NAME_MAX */
#include <sys/queue.h>
+#include <sys/rwlock.h> /* For struct rwlock */
#include <sys/timeout.h> /* For struct timeout */
#include <sys/event.h> /* For struct klist */
#include <sys/mutex.h> /* For struct mutex */
@@ -57,17 +58,26 @@
#define __need_process
#endif
+/*
+ * Locks used to protect struct members in this file:
+ * I immutable after creation
+ * t proctreelk
+ *
+ * If multiple locks are listed then all are required for writes,
+ * but any one of them is sufficient for reads.
+ */
+
/*
* One structure allocated per session.
*/
struct process;
struct session {
int s_count; /* Ref cnt; pgrps in session. */
- struct process *s_leader; /* Session leader. */
+ struct process *s_leader; /* [t] Session leader. */
struct vnode *s_ttyvp; /* Vnode of controlling terminal. */
- struct tty *s_ttyp; /* Controlling terminal. */
- char s_login[LOGIN_NAME_MAX]; /* Setlogin() name. */
- pid_t s_verauthppid;
+ struct tty *s_ttyp; /* [t] Controlling terminal. */
+ char s_login[LOGIN_NAME_MAX];/* [t] setlogin() name. */
+ pid_t s_verauthppid; /* TIOCSETVERAUTH info */
uid_t s_verauthuid;
struct timeout s_verauthto;
};
@@ -78,11 +88,11 @@ void zapverauth(/* struct session */ void *);
* One structure allocated per process group.
*/
struct pgrp {
- LIST_ENTRY(pgrp) pg_hash; /* Hash chain. */
- LIST_HEAD(, process) pg_members;/* Pointer to pgrp members. */
- struct session *pg_session; /* Pointer to session. */
+ LIST_ENTRY(pgrp) pg_hash; /* [t] Hash chain. */
+ LIST_HEAD(, process) pg_members;/* [t] Pointer to pgrp members. */
+ struct session *pg_session; /* [I] Pointer to session. */
struct sigiolst pg_sigiolst; /* List of sigio structures. */
- pid_t pg_id; /* Pgrp id. */
+ pid_t pg_id; /* [I] Pgrp id. */
int pg_jobc; /* # procs qualifying pgrp for job control */
};
@@ -172,10 +182,10 @@ struct process {
LIST_ENTRY(process) ps_list; /* List of all processes. */
TAILQ_HEAD(,proc) ps_threads; /* Threads in this process. */
- LIST_ENTRY(process) ps_pglist; /* List of processes in pgrp. */
- struct process *ps_pptr; /* Pointer to parent process. */
- LIST_ENTRY(process) ps_sibling; /* List of sibling processes. */
- LIST_HEAD(, process) ps_children;/* Pointer to list of children. */
+ LIST_ENTRY(process) ps_pglist; /* [t] List of processes in pgrp. */
+ struct process *ps_pptr; /* [t] Pointer to parent process. */
+ LIST_ENTRY(process) ps_sibling; /* [t] List of sibling processes. */
+ LIST_HEAD(, process) ps_children;/* [t] Pointer to list of children. */
LIST_ENTRY(process) ps_hash; /* Hash chain. */
struct sigiolst ps_sigiolst; /* List of sigio structures. */
@@ -183,7 +193,7 @@ struct process {
struct vnode *ps_textvp; /* Vnode of executable. */
struct filedesc *ps_fd; /* Ptr to open files structure */
struct vmspace *ps_vmspace; /* Address space */
- pid_t ps_pid; /* Process identifier. */
+ pid_t ps_pid; /* [I] Process identifier. */
struct futex_list ps_ftlist; /* futexes attached to this process */
LIST_HEAD(, kqueue) ps_kqlist; /* kqueues attached to this process */
@@ -202,7 +212,7 @@ struct process {
struct vnode *ps_tracevp; /* Trace to vnode. */
struct ucred *ps_tracecred; /* Creds for writing trace */
- pid_t ps_oppid; /* Save parent pid during ptrace. */
+ pid_t ps_oppid; /* [t] Save parent pid during ptrace. */
int ps_ptmask; /* Ptrace event mask */
struct ptrace_state *ps_ptstat;/* Ptrace state */
@@ -229,7 +239,7 @@ struct process {
/* The following fields are all copied upon creation in process_new. */
#define ps_startcopy ps_limit
struct plimit *ps_limit; /* [m,r] Process limits. */
- struct pgrp *ps_pgrp; /* Pointer to process group. */
+ struct pgrp *ps_pgrp; /* [t] Pointer to process group. */
struct emul *ps_emul; /* Emulation information */
char ps_comm[MAXCOMLEN+1];
@@ -533,6 +543,7 @@ LIST_HEAD(processlist, process);
extern struct processlist allprocess; /* List of all processes. */
extern struct processlist zombprocess; /* List of zombie processes. */
extern struct proclist allproc; /* List of all threads. */
+extern struct rwlock proctreelk; /* parent/child, pgrp, session */
extern struct process *initprocess; /* Process slot for init. */
extern struct proc *reaperproc; /* Thread slot for reaper. */