Page MenuHomeFreeBSD

D26116.diff
No OneTemporary

D26116.diff

Index: head/sys/kern/kern_exit.c
===================================================================
--- head/sys/kern/kern_exit.c
+++ head/sys/kern/kern_exit.c
@@ -391,7 +391,6 @@
}
vmspace_exit(td);
- killjobc();
(void)acct_process(td);
#ifdef KTRACE
@@ -434,6 +433,12 @@
PROC_LOCK(p);
p->p_flag &= ~(P_TRACED | P_PPWAIT | P_PPTRACE);
PROC_UNLOCK(p);
+
+ /*
+ * killjobc() might drop and re-acquire proctree_lock to
+ * revoke control tty if exiting process was a session leader.
+ */
+ killjobc();
/*
* Reparent all children processes:
Index: head/sys/kern/kern_proc.c
===================================================================
--- head/sys/kern/kern_proc.c
+++ head/sys/kern/kern_proc.c
@@ -102,13 +102,14 @@
static MALLOC_DEFINE(M_PROC, "proc", "Proc structures");
MALLOC_DEFINE(M_SUBPROC, "subproc", "Proc sub-structures");
+static void fixjobc_enterpgrp(struct proc *p, struct pgrp *pgrp);
static void doenterpgrp(struct proc *, struct pgrp *);
static void orphanpg(struct pgrp *pg);
static void fill_kinfo_aggregate(struct proc *p, struct kinfo_proc *kp);
static void fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp);
static void fill_kinfo_thread(struct thread *td, struct kinfo_proc *kp,
int preferthread);
-static void pgadjustjobc(struct pgrp *pgrp, int entering);
+static void pgadjustjobc(struct pgrp *pgrp, bool entering);
static void pgdelete(struct pgrp *);
static int proc_ctor(void *mem, int size, void *arg, int flags);
static void proc_dtor(void *mem, int size, void *arg);
@@ -633,6 +634,43 @@
}
/*
+ * If true, any child of q which belongs to group pgrp, qualifies the
+ * process group pgrp as not orphaned.
+ */
+static bool
+isjobproc(struct proc *q, struct pgrp *pgrp)
+{
+ sx_assert(&proctree_lock, SX_LOCKED);
+ return (q->p_pgrp != pgrp &&
+ q->p_pgrp->pg_session == pgrp->pg_session);
+}
+
+#ifdef INVARIANTS
+static void
+check_pgrp_jobc(struct pgrp *pgrp)
+{
+ struct proc *q;
+ int cnt;
+
+ sx_assert(&proctree_lock, SX_LOCKED);
+ PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
+
+ cnt = 0;
+ PGRP_LOCK(pgrp);
+ LIST_FOREACH(q, &pgrp->pg_members, p_pglist) {
+ if ((q->p_treeflag & P_TREE_GRPEXITED) != 0 ||
+ q->p_pptr == NULL)
+ continue;
+ if (isjobproc(q->p_pptr, pgrp))
+ cnt++;
+ }
+ KASSERT(pgrp->pg_jobc == cnt, ("pgrp %d %p pg_jobc %d cnt %d",
+ pgrp->pg_id, pgrp, pgrp->pg_jobc, cnt));
+ PGRP_UNLOCK(pgrp);
+}
+#endif
+
+/*
* Move p to a process group
*/
static void
@@ -648,13 +686,15 @@
savepgrp = p->p_pgrp;
+#ifdef INVARIANTS
+ check_pgrp_jobc(pgrp);
+ check_pgrp_jobc(savepgrp);
+#endif
+
/*
* Adjust eligibility of affected pgrps to participate in job control.
- * Increment eligibility counts before decrementing, otherwise we
- * could reach 0 spuriously during the first call.
*/
- fixjobc(p, pgrp, 1);
- fixjobc(p, p->p_pgrp, 0);
+ fixjobc_enterpgrp(p, pgrp);
PGRP_LOCK(pgrp);
PGRP_LOCK(savepgrp);
@@ -728,19 +768,15 @@
}
static void
-pgadjustjobc(struct pgrp *pgrp, int entering)
+pgadjustjobc(struct pgrp *pgrp, bool entering)
{
PGRP_LOCK(pgrp);
if (entering) {
-#ifdef notyet
MPASS(pgrp->pg_jobc >= 0);
-#endif
pgrp->pg_jobc++;
} else {
-#ifdef notyet
MPASS(pgrp->pg_jobc > 0);
-#endif
--pgrp->pg_jobc;
if (pgrp->pg_jobc == 0)
orphanpg(pgrp);
@@ -755,43 +791,95 @@
* process group of the same session). If that count reaches zero, the
* process group becomes orphaned. Check both the specified process'
* process group and that of its children.
- * entering == 0 => p is leaving specified group.
- * entering == 1 => p is entering specified group.
+ * We increment eligibility counts before decrementing, otherwise we
+ * could reach 0 spuriously during the decrement.
*/
-void
-fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
+static void
+fixjobc_enterpgrp(struct proc *p, struct pgrp *pgrp)
{
- struct pgrp *hispgrp;
- struct session *mysession;
struct proc *q;
+ struct pgrp *childpgrp;
+ bool future_jobc;
sx_assert(&proctree_lock, SX_LOCKED);
PROC_LOCK_ASSERT(p, MA_NOTOWNED);
PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED);
+ if (p->p_pgrp == pgrp)
+ return;
+
+ if (isjobproc(p->p_pptr, pgrp))
+ pgadjustjobc(pgrp, true);
+ LIST_FOREACH(q, &p->p_children, p_sibling) {
+ if ((q->p_treeflag & P_TREE_GRPEXITED) != 0)
+ continue;
+ childpgrp = q->p_pgrp;
+ future_jobc = childpgrp != pgrp &&
+ childpgrp->pg_session == pgrp->pg_session;
+ if (!isjobproc(p, childpgrp) && future_jobc)
+ pgadjustjobc(childpgrp, true);
+ }
+
+ if (isjobproc(p->p_pptr, p->p_pgrp))
+ pgadjustjobc(p->p_pgrp, false);
+ LIST_FOREACH(q, &p->p_children, p_sibling) {
+ if ((q->p_treeflag & P_TREE_GRPEXITED) != 0)
+ continue;
+ childpgrp = q->p_pgrp;
+ future_jobc = childpgrp != pgrp &&
+ childpgrp->pg_session == pgrp->pg_session;
+ if (isjobproc(p, childpgrp) && !future_jobc)
+ pgadjustjobc(childpgrp, false);
+ }
+}
+
+static void
+fixjobc_kill(struct proc *p)
+{
+ struct proc *q;
+ struct pgrp *childpgrp, *pgrp;
+
+ sx_assert(&proctree_lock, SX_LOCKED);
+ PROC_LOCK_ASSERT(p, MA_NOTOWNED);
+ pgrp = p->p_pgrp;
+ PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED);
+ SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED);
+
/*
+ * p no longer affects process group orphanage for children.
+ * It is marked by the flag because p is only physically
+ * removed from its process group on wait(2).
+ */
+ p->p_treeflag |= P_TREE_GRPEXITED;
+
+ /*
* 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;
- if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
- hispgrp->pg_session == mysession)
- pgadjustjobc(pgrp, entering);
+ if (isjobproc(p->p_pptr, pgrp))
+ pgadjustjobc(pgrp, false);
/*
* Check this process' children to see whether they qualify
- * their process groups; if so, adjust counts for children's
- * process groups.
+ * their process groups after reparenting to reaper. If so,
+ * adjust counts for children's process groups.
*/
LIST_FOREACH(q, &p->p_children, p_sibling) {
- hispgrp = q->p_pgrp;
- if (hispgrp == pgrp ||
- hispgrp->pg_session != mysession)
+ if ((q->p_treeflag & P_TREE_GRPEXITED) != 0)
continue;
- if (q->p_state == PRS_ZOMBIE)
+ childpgrp = q->p_pgrp;
+ if (isjobproc(q->p_reaper, childpgrp) &&
+ !isjobproc(p, childpgrp))
+ pgadjustjobc(childpgrp, true);
+ }
+ LIST_FOREACH(q, &p->p_children, p_sibling) {
+ if ((q->p_treeflag & P_TREE_GRPEXITED) != 0)
continue;
- pgadjustjobc(hispgrp, entering);
+ childpgrp = q->p_pgrp;
+ if (!isjobproc(q->p_reaper, childpgrp) &&
+ isjobproc(p, childpgrp))
+ pgadjustjobc(childpgrp, false);
}
}
@@ -805,20 +893,8 @@
p = curproc;
MPASS(p->p_flag & P_WEXIT);
- /*
- * Do a quick check to see if there is anything to do with the
- * proctree_lock held. pgrp and LIST_EMPTY checks are for fixjobc().
- */
- PROC_LOCK(p);
- if (!SESS_LEADER(p) &&
- (p->p_pgrp == p->p_pptr->p_pgrp) &&
- LIST_EMPTY(&p->p_children)) {
- PROC_UNLOCK(p);
- return;
- }
- PROC_UNLOCK(p);
+ sx_assert(&proctree_lock, SX_LOCKED);
- sx_xlock(&proctree_lock);
if (SESS_LEADER(p)) {
sp = p->p_session;
@@ -864,8 +940,7 @@
sx_xlock(&proctree_lock);
}
}
- fixjobc(p, p->p_pgrp, 0);
- sx_xunlock(&proctree_lock);
+ fixjobc_kill(p);
}
/*
Index: head/sys/sys/proc.h
===================================================================
--- head/sys/sys/proc.h
+++ head/sys/sys/proc.h
@@ -790,6 +790,7 @@
#define P_TREE_FIRST_ORPHAN 0x00000002 /* First element of orphan
list */
#define P_TREE_REAPER 0x00000004 /* Reaper of subtree */
+#define P_TREE_GRPEXITED 0x00000008 /* exit1() done with job ctl */
/*
* These were process status values (p_stat), now they are only used in
@@ -1045,7 +1046,6 @@
struct session *sess);
int enterthispgrp(struct proc *p, struct pgrp *pgrp);
void faultin(struct proc *p);
-void fixjobc(struct proc *p, struct pgrp *pgrp, int entering);
int fork1(struct thread *, struct fork_req *);
void fork_rfppwait(struct thread *);
void fork_exit(void (*)(void *, struct trapframe *), void *,

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 16, 5:54 AM (19 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15820943
Default Alt Text
D26116.diff (8 KB)

Event Timeline