summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_proc.c')
-rw-r--r--sys/kern/kern_proc.c290
1 files changed, 211 insertions, 79 deletions
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index b11c23b..27222fa 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -55,14 +55,18 @@
#include <vm/vm_map.h>
#include <vm/vm_zone.h>
-static MALLOC_DEFINE(M_PGRP, "pgrp", "process group header");
+MALLOC_DEFINE(M_PGRP, "pgrp", "process group header");
MALLOC_DEFINE(M_SESSION, "session", "session header");
static MALLOC_DEFINE(M_PROC, "proc", "Proc structures");
MALLOC_DEFINE(M_SUBPROC, "subproc", "Proc sub-structures");
+static struct proc *dopfind __P((register pid_t));
+
+static void doenterpgrp __P((struct proc *, struct pgrp *));
+
static void pgdelete __P((struct pgrp *));
-static void orphanpg __P((struct pgrp *pg));
+static void orphanpg __P((struct pgrp *pg));
/*
* Other process lists
@@ -75,6 +79,7 @@ struct proclist allproc;
struct proclist zombproc;
struct sx allproc_lock;
struct sx proctree_lock;
+struct sx pgrpsess_lock;
vm_zone_t proc_zone;
vm_zone_t ithread_zone;
@@ -88,6 +93,7 @@ procinit()
sx_init(&allproc_lock, "allproc");
sx_init(&proctree_lock, "proctree");
+ sx_init(&pgrpsess_lock, "pgrpsess");
LIST_INIT(&allproc);
LIST_INIT(&zombproc);
pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
@@ -265,17 +271,30 @@ pfind(pid)
register struct proc *p;
sx_slock(&allproc_lock);
+ p = dopfind(pid);
+ sx_sunlock(&allproc_lock);
+ return (p);
+}
+
+static struct proc *
+dopfind(pid)
+ register pid_t pid;
+{
+ register struct proc *p;
+
+ sx_assert(&allproc_lock, SX_LOCKED);
+
LIST_FOREACH(p, PIDHASH(pid), p_hash)
if (p->p_pid == pid) {
PROC_LOCK(p);
break;
}
- sx_sunlock(&allproc_lock);
return (p);
}
/*
- * Locate a process group by number
+ * Locate a process group by number.
+ * The caller must hold pgrpsess_lock.
*/
struct pgrp *
pgfind(pgid)
@@ -283,77 +302,132 @@ pgfind(pgid)
{
register struct pgrp *pgrp;
- LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash)
- if (pgrp->pg_id == pgid)
+ PGRPSESS_LOCK_ASSERT(SX_LOCKED);
+
+ LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) {
+ if (pgrp->pg_id == pgid) {
+ PGRP_LOCK(pgrp);
return (pgrp);
+ }
+ }
return (NULL);
}
/*
- * Move p to a new or existing process group (and session)
+ * Create a new process group.
+ * pgid must be equal to the pid of p.
+ * Begin a new session if required.
*/
int
-enterpgrp(p, pgid, mksess)
+enterpgrp(p, pgid, pgrp, sess)
register struct proc *p;
pid_t pgid;
- int mksess;
+ struct pgrp *pgrp;
+ struct session *sess;
{
- register struct pgrp *pgrp = pgfind(pgid);
- struct pgrp *savegrp;
+ struct pgrp *pgrp2;
- KASSERT(pgrp == NULL || !mksess,
- ("enterpgrp: setsid into non-empty pgrp"));
+ PGRPSESS_LOCK_ASSERT(SX_XLOCKED);
+
+ KASSERT(pgrp != NULL, ("enterpgrp: pgrp == NULL"));
+ KASSERT(p->p_pid == pgid,
+ ("enterpgrp: new pgrp and pid != pgid"));
+
+ pgrp2 = pgfind(pgid);
+
+ KASSERT(pgrp2 == NULL,
+ ("enterpgrp: pgrp with pgid exists"));
KASSERT(!SESS_LEADER(p),
("enterpgrp: session leader attempted setpgrp"));
- if (pgrp == NULL) {
- pid_t savepid = p->p_pid;
- struct proc *np;
+ mtx_init(&pgrp->pg_mtx, "process group", MTX_DEF);
+
+ if (sess != NULL) {
/*
- * new process group
+ * new session
*/
- KASSERT(p->p_pid == pgid,
- ("enterpgrp: new pgrp and pid != pgid"));
- if ((np = pfind(savepid)) == NULL || np != p) {
- if (np != NULL)
- PROC_UNLOCK(np);
- return (ESRCH);
- }
- PROC_UNLOCK(np);
- MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
- M_WAITOK);
- if (mksess) {
- register struct session *sess;
-
- /*
- * new session
- */
- MALLOC(sess, struct session *, sizeof(struct session),
- M_SESSION, M_WAITOK);
- sess->s_leader = p;
- sess->s_sid = p->p_pid;
- sess->s_count = 1;
- sess->s_ttyvp = NULL;
- sess->s_ttyp = NULL;
- bcopy(p->p_session->s_login, sess->s_login,
+ mtx_init(&sess->s_mtx, "session", MTX_DEF);
+ PROC_LOCK(p);
+ p->p_flag &= ~P_CONTROLT;
+ PROC_UNLOCK(p);
+ PGRP_LOCK(pgrp);
+ sess->s_leader = p;
+ sess->s_sid = p->p_pid;
+ sess->s_count = 1;
+ sess->s_ttyvp = NULL;
+ sess->s_ttyp = NULL;
+ bcopy(p->p_session->s_login, sess->s_login,
sizeof(sess->s_login));
- PROC_LOCK(p);
- p->p_flag &= ~P_CONTROLT;
- PROC_UNLOCK(p);
- pgrp->pg_session = sess;
- KASSERT(p == curproc,
- ("enterpgrp: mksession and p != curproc"));
- } else {
- pgrp->pg_session = p->p_session;
- pgrp->pg_session->s_count++;
- }
- pgrp->pg_id = pgid;
- LIST_INIT(&pgrp->pg_members);
- LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
- pgrp->pg_jobc = 0;
- SLIST_INIT(&pgrp->pg_sigiolst);
- } else if (pgrp == p->p_pgrp)
- return (0);
+ pgrp->pg_session = sess;
+ KASSERT(p == curproc,
+ ("enterpgrp: mksession and p != curproc"));
+ } else {
+ pgrp->pg_session = p->p_session;
+ SESS_LOCK(pgrp->pg_session);
+ pgrp->pg_session->s_count++;
+ SESS_UNLOCK(pgrp->pg_session);
+ PGRP_LOCK(pgrp);
+ }
+ pgrp->pg_id = pgid;
+ LIST_INIT(&pgrp->pg_members);
+
+ /*
+ * As we have an exclusive lock of pgrpsess_lock,
+ * this should not deadlock.
+ */
+ LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
+ pgrp->pg_jobc = 0;
+ SLIST_INIT(&pgrp->pg_sigiolst);
+ PGRP_UNLOCK(pgrp);
+
+ doenterpgrp(p, pgrp);
+
+ return (0);
+}
+
+/*
+ * Move p to an existing process group
+ */
+int
+enterthispgrp(p, pgrp)
+ register struct proc *p;
+ struct pgrp *pgrp;
+{
+ PGRPSESS_LOCK_ASSERT(SX_XLOCKED);
+ PROC_LOCK_ASSERT(p, MA_NOTOWNED);
+ PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
+ PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED);
+ SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED);
+ KASSERT(pgrp->pg_session == p->p_session,
+ ("%s: pgrp's session %p, p->p_session %p.\n",
+ __func__,
+ pgrp->pg_session,
+ p->p_session));
+ KASSERT(pgrp != p->p_pgrp,
+ ("%s: p belongs to pgrp.", __func__));
+
+ doenterpgrp(p, pgrp);
+
+ return (0);
+}
+
+/*
+ * Move p to a process group
+ */
+static void
+doenterpgrp(p, pgrp)
+ struct proc *p;
+ struct pgrp *pgrp;
+{
+ struct pgrp *savepgrp;
+
+ PGRPSESS_LOCK_ASSERT(SX_XLOCKED);
+ PROC_LOCK_ASSERT(p, MA_NOTOWNED);
+ PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
+ PGRP_LOCK_ASSERT(p->p_pgrp, MA_NOTOWNED);
+ SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED);
+
+ savepgrp = p->p_pgrp;
/*
* Adjust eligibility of affected pgrps to participate in job control.
@@ -363,15 +437,17 @@ enterpgrp(p, pgid, mksess)
fixjobc(p, pgrp, 1);
fixjobc(p, p->p_pgrp, 0);
+ PGRP_LOCK(pgrp);
+ PGRP_LOCK(savepgrp);
PROC_LOCK(p);
LIST_REMOVE(p, p_pglist);
- savegrp = p->p_pgrp;
p->p_pgrp = pgrp;
- LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
PROC_UNLOCK(p);
- if (LIST_EMPTY(&savegrp->pg_members))
- pgdelete(savegrp);
- return (0);
+ LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
+ PGRP_UNLOCK(savepgrp);
+ PGRP_UNLOCK(pgrp);
+ if (LIST_EMPTY(&savepgrp->pg_members))
+ pgdelete(savepgrp);
}
/*
@@ -381,15 +457,19 @@ int
leavepgrp(p)
register struct proc *p;
{
- struct pgrp *savegrp;
+ struct pgrp *savepgrp;
+ PGRPSESS_XLOCK();
+ savepgrp = p->p_pgrp;
+ PGRP_LOCK(savepgrp);
PROC_LOCK(p);
LIST_REMOVE(p, p_pglist);
- savegrp = p->p_pgrp;
p->p_pgrp = NULL;
PROC_UNLOCK(p);
- if (LIST_EMPTY(&savegrp->pg_members))
- pgdelete(savegrp);
+ PGRP_UNLOCK(savepgrp);
+ if (LIST_EMPTY(&savepgrp->pg_members))
+ pgdelete(savepgrp);
+ PGRPSESS_XUNLOCK();
return (0);
}
@@ -400,6 +480,13 @@ static void
pgdelete(pgrp)
register struct pgrp *pgrp;
{
+ struct session *savesess;
+
+ PGRPSESS_LOCK_ASSERT(SX_XLOCKED);
+ PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
+ SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED);
+
+ PGRP_LOCK(pgrp);
/*
* Reset any sigio structures pointing to us as a result of
@@ -411,8 +498,16 @@ pgdelete(pgrp)
pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
pgrp->pg_session->s_ttyp->t_pgrp = NULL;
LIST_REMOVE(pgrp, pg_hash);
- if (--pgrp->pg_session->s_count == 0)
+ savesess = pgrp->pg_session;
+ SESS_LOCK(savesess);
+ savesess->s_count--;
+ SESS_UNLOCK(savesess);
+ PGRP_UNLOCK(pgrp);
+ if (savesess->s_count == 0) {
+ mtx_destroy(&savesess->s_mtx);
FREE(pgrp->pg_session, M_SESSION);
+ }
+ mtx_destroy(&pgrp->pg_mtx);
FREE(pgrp, M_PGRP);
}
@@ -433,19 +528,30 @@ fixjobc(p, pgrp, entering)
int entering;
{
register struct pgrp *hispgrp;
- register struct session *mysession = pgrp->pg_session;
+ register struct session *mysession;
+
+ PGRPSESS_LOCK_ASSERT(SX_LOCKED);
+ PROC_LOCK_ASSERT(p, MA_NOTOWNED);
+ PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
+ SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED);
/*
* Check p's parent to see whether p qualifies its own process
* group; if so, adjust count for p's process group.
*/
+ mysession = pgrp->pg_session;
sx_slock(&proctree_lock);
if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
hispgrp->pg_session == mysession) {
+ PGRP_LOCK(pgrp);
if (entering)
pgrp->pg_jobc++;
- else if (--pgrp->pg_jobc == 0)
- orphanpg(pgrp);
+ else {
+ --pgrp->pg_jobc;
+ if (pgrp->pg_jobc == 0)
+ orphanpg(pgrp);
+ }
+ PGRP_UNLOCK(pgrp);
}
/*
@@ -453,15 +559,21 @@ fixjobc(p, pgrp, entering)
* their process groups; if so, adjust counts for children's
* process groups.
*/
- LIST_FOREACH(p, &p->p_children, p_sibling)
+ LIST_FOREACH(p, &p->p_children, p_sibling) {
if ((hispgrp = p->p_pgrp) != pgrp &&
hispgrp->pg_session == mysession &&
p->p_stat != SZOMB) {
+ PGRP_LOCK(hispgrp);
if (entering)
hispgrp->pg_jobc++;
- else if (--hispgrp->pg_jobc == 0)
- orphanpg(hispgrp);
+ else {
+ --hispgrp->pg_jobc;
+ if (hispgrp->pg_jobc == 0)
+ orphanpg(hispgrp);
+ }
+ PGRP_UNLOCK(hispgrp);
}
+ }
sx_sunlock(&proctree_lock);
}
@@ -476,6 +588,8 @@ orphanpg(pg)
{
register struct proc *p;
+ PGRP_LOCK_ASSERT(pg, MA_OWNED);
+
mtx_lock_spin(&sched_lock);
LIST_FOREACH(p, &pg->pg_members, p_pglist) {
if (p->p_stat == SSTOP) {
@@ -619,6 +733,7 @@ fill_kinfo_proc(p, kp)
/* ^^^ XXXKSE */
mtx_unlock_spin(&sched_lock);
sp = NULL;
+ tp = NULL;
if (p->p_pgrp) {
kp->ki_pgid = p->p_pgrp->pg_id;
kp->ki_jobc = p->p_pgrp->pg_jobc;
@@ -626,15 +741,18 @@ fill_kinfo_proc(p, kp)
if (sp != NULL) {
kp->ki_sid = sp->s_sid;
+ SESS_LOCK(sp);
strncpy(kp->ki_login, sp->s_login,
sizeof(kp->ki_login) - 1);
if (sp->s_ttyvp)
kp->ki_kiflag |= KI_CTTY;
if (SESS_LEADER(p))
kp->ki_kiflag |= KI_SLEADER;
+ tp = sp->s_ttyp;
+ SESS_UNLOCK(sp);
}
}
- if ((p->p_flag & P_CONTROLT) && sp && ((tp = sp->s_ttyp) != NULL)) {
+ if ((p->p_flag & P_CONTROLT) && tp != NULL) {
kp->ki_tdev = dev2udev(tp->t_dev);
kp->ki_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
if (tp->t_session)
@@ -768,18 +886,32 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
case KERN_PROC_PGRP:
/* could do this by traversing pgrp */
+ PROC_LOCK(p);
if (p->p_pgrp == NULL ||
- p->p_pgrp->pg_id != (pid_t)name[0])
+ p->p_pgrp->pg_id != (pid_t)name[0]) {
+ PROC_UNLOCK(p);
continue;
+ }
+ PROC_UNLOCK(p);
break;
case KERN_PROC_TTY:
+ PROC_LOCK(p);
if ((p->p_flag & P_CONTROLT) == 0 ||
- p->p_session == NULL ||
- p->p_session->s_ttyp == NULL ||
+ p->p_session == NULL) {
+ PROC_UNLOCK(p);
+ continue;
+ }
+ SESS_LOCK(p->p_session);
+ if (p->p_session->s_ttyp == NULL ||
dev2udev(p->p_session->s_ttyp->t_dev) !=
- (udev_t)name[0])
+ (udev_t)name[0]) {
+ SESS_UNLOCK(p->p_session);
+ PROC_UNLOCK(p);
continue;
+ }
+ SESS_UNLOCK(p->p_session);
+ PROC_UNLOCK(p);
break;
case KERN_PROC_UID:
OpenPOWER on IntegriCloud