Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107510408
D26116.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D26116.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D26116: Fix several issues with process group orphanage.
Attached
Detach File
Event Timeline
Log In to Comment