diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -98,20 +98,18 @@ SDT_PROVIDER_DEFINE(proc); -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 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, bool entering); static void pgdelete(struct pgrp *); +static int pgrp_init(void *mem, int size, int flags); static int proc_ctor(void *mem, int size, void *arg, int flags); static void proc_dtor(void *mem, int size, void *arg); static int proc_init(void *mem, int size, int flags); @@ -133,6 +131,7 @@ struct mtx __exclusive_cache_line ppeers_lock; struct mtx __exclusive_cache_line procid_lock; uma_zone_t proc_zone; +uma_zone_t pgrp_zone; /* * The offset of various fields in struct proc and struct thread. @@ -196,6 +195,8 @@ proc_zone = uma_zcreate("PROC", sched_sizeof_proc(), proc_ctor, proc_dtor, proc_init, proc_fini, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); + pgrp_zone = uma_zcreate("PGRP", sizeof(struct pgrp), NULL, NULL, + pgrp_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE); uihashinit(); } @@ -299,6 +300,16 @@ #endif } +static int +pgrp_init(void *mem, int size, int flags) +{ + struct pgrp *pg; + + pg = mem; + mtx_init(&pg->pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK); + return (0); +} + /* * PID space management. * @@ -570,8 +581,6 @@ KASSERT(!SESS_LEADER(p), ("enterpgrp: session leader attempted setpgrp")); - mtx_init(&pgrp->pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK); - if (sess != NULL) { /* * new session @@ -601,13 +610,13 @@ pgrp->pg_id = pgid; proc_id_set(PROC_ID_GROUP, p->p_pid); LIST_INIT(&pgrp->pg_members); + pgrp->pg_flags = 0; /* * As we have an exclusive lock of proctree_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); @@ -629,12 +638,10 @@ 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)); + ("%s: pgrp's session %p, p->p_session %p proc %p\n", + __func__, pgrp->pg_session, p->p_session, p)); KASSERT(pgrp != p->p_pgrp, - ("%s: p belongs to pgrp.", __func__)); + ("%s: p %p belongs to pgrp %p", __func__, p, pgrp)); doenterpgrp(p, pgrp); @@ -649,6 +656,7 @@ 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); } @@ -658,7 +666,7 @@ { struct proc *pp; - sx_assert(&proctree_lock, SX_LOCKED); + sx_assert(&proctree_lock, SA_LOCKED); for (pp = p;;) { pp = pp->p_reaper; @@ -669,43 +677,40 @@ } static struct proc * -jobc_parent(struct proc *p) +jobc_parent(struct proc *p, struct proc *p_exiting) { struct proc *pp; - sx_assert(&proctree_lock, SX_LOCKED); + sx_assert(&proctree_lock, SA_LOCKED); pp = proc_realparent(p); - if (pp->p_pptr == NULL || + if (pp->p_pptr == NULL || pp == p_exiting || (pp->p_treeflag & P_TREE_GRPEXITED) == 0) return (pp); return (jobc_reaper(pp)); } -#ifdef INVARIANTS -static void -check_pgrp_jobc(struct pgrp *pgrp) +static int +pgrp_calc_jobc(struct pgrp *pgrp) { struct proc *q; int cnt; - sx_assert(&proctree_lock, SX_LOCKED); - PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); +#ifdef INVARIANTS + if (!mtx_owned(&pgrp->pg_mtx)) + sx_assert(&proctree_lock, SA_LOCKED); +#endif 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(jobc_parent(q), pgrp)) + if (isjobproc(jobc_parent(q, NULL), 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); + return (cnt); } -#endif /* * Move p to a process group @@ -714,6 +719,7 @@ doenterpgrp(struct proc *p, struct pgrp *pgrp) { struct pgrp *savepgrp; + struct proc *pp; sx_assert(&proctree_lock, SX_XLOCKED); PROC_LOCK_ASSERT(p, MA_NOTOWNED); @@ -722,24 +728,19 @@ SESS_LOCK_ASSERT(p->p_session, MA_NOTOWNED); 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. - */ - fixjobc_enterpgrp(p, pgrp); + pp = jobc_parent(p, NULL); PGRP_LOCK(pgrp); PGRP_LOCK(savepgrp); + if (isjobproc(pp, savepgrp) && pgrp_calc_jobc(savepgrp) == 1) + orphanpg(savepgrp); PROC_LOCK(p); LIST_REMOVE(p, p_pglist); p->p_pgrp = pgrp; PROC_UNLOCK(p); LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); + if (isjobproc(pp, pgrp)) + pgrp->pg_flags &= ~PGRP_ORPHANED; PGRP_UNLOCK(savepgrp); PGRP_UNLOCK(pgrp); if (LIST_EMPTY(&savepgrp->pg_members)) @@ -800,107 +801,10 @@ } proc_id_clear(PROC_ID_GROUP, pgrp->pg_id); - mtx_destroy(&pgrp->pg_mtx); - free(pgrp, M_PGRP); + uma_zfree(pgrp_zone, pgrp); sess_release(savesess); } -static void -pgadjustjobc(struct pgrp *pgrp, bool entering) -{ - - PGRP_LOCK(pgrp); - if (entering) { - MPASS(pgrp->pg_jobc >= 0); - pgrp->pg_jobc++; - } else { - MPASS(pgrp->pg_jobc > 0); - --pgrp->pg_jobc; - if (pgrp->pg_jobc == 0) - orphanpg(pgrp); - } - PGRP_UNLOCK(pgrp); -} - -static void -fixjobc_enterpgrp_q(struct pgrp *pgrp, struct proc *p, struct proc *q, bool adj) -{ - struct pgrp *childpgrp; - bool future_jobc; - - sx_assert(&proctree_lock, SX_LOCKED); - - if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) - return; - childpgrp = q->p_pgrp; - future_jobc = childpgrp != pgrp && - childpgrp->pg_session == pgrp->pg_session; - - if ((adj && !isjobproc(p, childpgrp) && future_jobc) || - (!adj && isjobproc(p, childpgrp) && !future_jobc)) - pgadjustjobc(childpgrp, adj); -} - -/* - * Adjust pgrp jobc counters when specified process changes process group. - * We count the number of processes in each process group that "qualify" - * the group for terminal job control (those with a parent in a different - * 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. - * We increment eligibility counts before decrementing, otherwise we - * could reach 0 spuriously during the decrement. - */ -static void -fixjobc_enterpgrp(struct proc *p, struct pgrp *pgrp) -{ - struct proc *q; - - 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(jobc_parent(p), pgrp)) - pgadjustjobc(pgrp, true); - LIST_FOREACH(q, &p->p_children, p_sibling) { - if ((q->p_treeflag & P_TREE_ORPHANED) != 0) - continue; - fixjobc_enterpgrp_q(pgrp, p, q, true); - } - LIST_FOREACH(q, &p->p_orphans, p_orphan) - fixjobc_enterpgrp_q(pgrp, p, q, true); - - if (isjobproc(jobc_parent(p), p->p_pgrp)) - pgadjustjobc(p->p_pgrp, false); - LIST_FOREACH(q, &p->p_children, p_sibling) { - if ((q->p_treeflag & P_TREE_ORPHANED) != 0) - continue; - fixjobc_enterpgrp_q(pgrp, p, q, false); - } - LIST_FOREACH(q, &p->p_orphans, p_orphan) - fixjobc_enterpgrp_q(pgrp, p, q, false); -} - -static void -fixjobc_kill_q(struct proc *p, struct proc *q, bool adj) -{ - struct pgrp *childpgrp; - - sx_assert(&proctree_lock, SX_LOCKED); - - if ((q->p_treeflag & P_TREE_GRPEXITED) != 0) - return; - childpgrp = q->p_pgrp; - - if ((adj && isjobproc(jobc_reaper(q), childpgrp) && - !isjobproc(p, childpgrp)) || (!adj && !isjobproc(jobc_reaper(q), - childpgrp) && isjobproc(p, childpgrp))) - pgadjustjobc(childpgrp, adj); -} static void fixjobc_kill(struct proc *p) @@ -913,9 +817,6 @@ pgrp = p->p_pgrp; PGRP_LOCK_ASSERT(pgrp, MA_NOTOWNED); SESS_LOCK_ASSERT(pgrp->pg_session, MA_NOTOWNED); -#ifdef INVARIANTS - check_pgrp_jobc(pgrp); -#endif /* * p no longer affects process group orphanage for children. @@ -926,35 +827,46 @@ 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. + * Check if exiting p orphans its own group. */ - if (isjobproc(jobc_parent(p), pgrp)) - pgadjustjobc(pgrp, false); + pgrp = p->p_pgrp; + if (isjobproc(jobc_parent(p, NULL), pgrp)) { + PGRP_LOCK(pgrp); + if (pgrp_calc_jobc(pgrp) == 0) + orphanpg(pgrp); + PGRP_UNLOCK(pgrp); + } /* * Check this process' children to see whether they qualify - * their process groups after reparenting to reaper. If so, - * adjust counts for children's process groups. + * their process groups after reparenting to reaper. */ LIST_FOREACH(q, &p->p_children, p_sibling) { - if ((q->p_treeflag & P_TREE_ORPHANED) != 0) - continue; - fixjobc_kill_q(p, q, true); + pgrp = q->p_pgrp; + PGRP_LOCK(pgrp); + if (pgrp_calc_jobc(pgrp) == 0) { + /* + * We want to handle exactly the children that + * has p as realparent. Then, when calculating + * jobc_parent for children, we should ignore + * P_TREE_GRPEXITED flag already set on p. + */ + if (jobc_parent(q, p) == p && isjobproc(p, pgrp)) + orphanpg(pgrp); + } else + pgrp->pg_flags &= ~PGRP_ORPHANED; + PGRP_UNLOCK(pgrp); } - LIST_FOREACH(q, &p->p_orphans, p_orphan) - fixjobc_kill_q(p, q, true); - LIST_FOREACH(q, &p->p_children, p_sibling) { - if ((q->p_treeflag & P_TREE_ORPHANED) != 0) - continue; - fixjobc_kill_q(p, q, false); + LIST_FOREACH(q, &p->p_orphans, p_orphan) { + pgrp = q->p_pgrp; + PGRP_LOCK(pgrp); + if (pgrp_calc_jobc(pgrp) == 0) { + if (isjobproc(p, pgrp)) + orphanpg(pgrp); + } else + pgrp->pg_flags &= ~PGRP_ORPHANED; + PGRP_UNLOCK(pgrp); } - LIST_FOREACH(q, &p->p_orphans, p_orphan) - fixjobc_kill_q(p, q, false); - -#ifdef INVARIANTS - check_pgrp_jobc(pgrp); -#endif } void @@ -1018,8 +930,8 @@ } /* - * A process group has become orphaned; - * if there are any stopped processes in the group, + * A process group has become orphaned, mark it as such for signal + * delivery code. If there are any stopped processes in the group, * hang-up all process in that group. */ static void @@ -1029,6 +941,8 @@ PGRP_LOCK_ASSERT(pg, MA_OWNED); + pg->pg_flags |= PGRP_ORPHANED; + LIST_FOREACH(p, &pg->pg_members, p_pglist) { PROC_LOCK(p); if (P_SHOULDSTOP(p) == P_STOPPED_SIG) { @@ -1125,22 +1039,18 @@ } /* - * Clear kinfo_proc and fill in any information that is common - * to all threads in the process. + * Fill in any information that is common to all threads in the process. * Must be called with the target process locked. */ static void fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp) { struct thread *td0; - struct tty *tp; - struct session *sp; struct ucred *cred; struct sigacts *ps; struct timeval boottime; PROC_LOCK_ASSERT(p, MA_OWNED); - bzero(kp, sizeof(*kp)); kp->ki_structsize = sizeof(*kp); kp->ki_paddr = p; @@ -1233,36 +1143,6 @@ FOREACH_THREAD_IN_PROC(p, td0) kp->ki_cow += td0->td_cow; - tp = NULL; - if (p->p_pgrp) { - kp->ki_pgid = p->p_pgrp->pg_id; - kp->ki_jobc = p->p_pgrp->pg_jobc; - sp = p->p_pgrp->pg_session; - - if (sp != NULL) { - kp->ki_sid = sp->s_sid; - SESS_LOCK(sp); - strlcpy(kp->ki_login, sp->s_login, - sizeof(kp->ki_login)); - if (sp->s_ttyvp) - kp->ki_kiflag |= KI_CTTY; - if (SESS_LEADER(p)) - kp->ki_kiflag |= KI_SLEADER; - /* XXX proctree_lock */ - tp = sp->s_ttyp; - SESS_UNLOCK(sp); - } - } - if ((p->p_flag & P_CONTROLT) && tp != NULL) { - kp->ki_tdev = tty_udev(tp); - kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */ - kp->ki_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; - if (tp->t_session) - kp->ki_tsid = tp->t_session->s_sid; - } else { - kp->ki_tdev = NODEV; - kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */ - } if (p->p_comm[0] != '\0') strlcpy(kp->ki_comm, p->p_comm, sizeof(kp->ki_comm)); if (p->p_sysent && p->p_sysent->sv_name != NULL && @@ -1279,6 +1159,53 @@ } } +/* + * Fill job-related process information. + */ +static void +fill_kinfo_proc_pgrp(struct proc *p, struct kinfo_proc *kp) +{ + struct tty *tp; + struct session *sp; + struct pgrp *pgrp; + + sx_assert(&proctree_lock, SA_LOCKED); + PROC_LOCK_ASSERT(p, MA_OWNED); + + pgrp = p->p_pgrp; + if (pgrp == NULL) + return; + + kp->ki_pgid = pgrp->pg_id; + kp->ki_jobc = pgrp_calc_jobc(pgrp); + + sp = pgrp->pg_session; + tp = NULL; + + if (sp != NULL) { + kp->ki_sid = sp->s_sid; + SESS_LOCK(sp); + strlcpy(kp->ki_login, sp->s_login, sizeof(kp->ki_login)); + 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) && tp != NULL) { + kp->ki_tdev = tty_udev(tp); + kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */ + kp->ki_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; + if (tp->t_session) + kp->ki_tsid = tp->t_session->s_sid; + } else { + kp->ki_tdev = NODEV; + kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */ + } +} + /* * Fill in information that is thread specific. Must be called with * target process locked. If 'preferthread' is set, overwrite certain @@ -1398,9 +1325,11 @@ void fill_kinfo_proc(struct proc *p, struct kinfo_proc *kp) { - MPASS(FIRST_THREAD_IN_PROC(p) != NULL); + bzero(kp, sizeof(*kp)); + + fill_kinfo_proc_pgrp(p,kp); fill_kinfo_proc_only(p, kp); fill_kinfo_thread(FIRST_THREAD_IN_PROC(p), kp, 0); fill_kinfo_aggregate(p, kp); @@ -1645,6 +1574,7 @@ int error, i, j; for (i = 0; i < pidhashlock + 1; i++) { + sx_slock(&proctree_lock); sx_slock(&pidhashtbl_lock[i]); for (j = i; j <= pidhash; j += pidhashlock + 1) { LIST_FOREACH(p, &pidhashtbl[j], p_hash) { @@ -1654,11 +1584,13 @@ PROC_LOCK_ASSERT(p, MA_NOTOWNED); if (error != 0) { sx_sunlock(&pidhashtbl_lock[i]); + sx_sunlock(&proctree_lock); return (error); } } } sx_sunlock(&pidhashtbl_lock[i]); + sx_sunlock(&proctree_lock); } return (0); } @@ -1784,9 +1716,11 @@ error = sysctl_wire_old_buffer(req, 0); if (error) return (error); + sx_slock(&proctree_lock); error = pget((pid_t)name[0], PGET_CANSEE, &p); if (error == 0) error = sysctl_out_proc(p, req, flags); + sx_sunlock(&proctree_lock); return (error); } diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -333,7 +333,7 @@ error = 0; pgrp = NULL; - newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); + newpgrp = uma_zalloc(pgrp_zone, M_WAITOK); newsess = malloc(sizeof(struct session), M_SESSION, M_WAITOK | M_ZERO); sx_xlock(&proctree_lock); @@ -351,10 +351,8 @@ sx_xunlock(&proctree_lock); - if (newpgrp != NULL) - free(newpgrp, M_PGRP); - if (newsess != NULL) - free(newsess, M_SESSION); + uma_zfree(pgrp_zone, newpgrp); + free(newsess, M_SESSION); return (error); } @@ -393,7 +391,7 @@ error = 0; - newpgrp = malloc(sizeof(struct pgrp), M_PGRP, M_WAITOK | M_ZERO); + newpgrp = uma_zalloc(pgrp_zone, M_WAITOK); sx_xlock(&proctree_lock); if (uap->pid != 0 && uap->pid != curp->p_pid) { @@ -456,8 +454,7 @@ sx_xunlock(&proctree_lock); KASSERT((error == 0) || (newpgrp != NULL), ("setpgid failed and newpgrp is NULL")); - if (newpgrp != NULL) - free(newpgrp, M_PGRP); + uma_zfree(pgrp_zone, newpgrp); return (error); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -2227,9 +2227,9 @@ * is default; don't stop the process below if sleeping, * and don't clear any pending SIGCONT. */ - if ((prop & SIGPROP_TTYSTOP) && - (p->p_pgrp->pg_jobc == 0) && - (action == SIG_DFL)) { + if ((prop & SIGPROP_TTYSTOP) != 0 && + (p->p_pgrp->pg_flags & PGRP_ORPHANED) != 0 && + action == SIG_DFL) { if (ksi && (ksi->ksi_flags & KSI_INS)) ksiginfo_tryfree(ksi); return (ret); @@ -2984,17 +2984,20 @@ * should ignore tty stops. */ if (prop & SIGPROP_STOP) { - if (p->p_flag & - (P_TRACED | P_WEXIT | P_SINGLE_EXIT) || - (p->p_pgrp->pg_jobc == 0 && - prop & SIGPROP_TTYSTOP)) + mtx_unlock(&ps->ps_mtx); + if ((p->p_flag & (P_TRACED | P_WEXIT | + P_SINGLE_EXIT)) != 0 || ((p->p_pgrp-> + pg_flags & PGRP_ORPHANED) != 0 && + (prop & SIGPROP_TTYSTOP) != 0)) { + mtx_lock(&ps->ps_mtx); break; /* == ignore */ + } if (TD_SBDRY_INTR(td)) { KASSERT((td->td_flags & TDF_SBDRY) != 0, ("lost TDF_SBDRY")); + mtx_lock(&ps->ps_mtx); return (-1); } - mtx_unlock(&ps->ps_mtx); WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &p->p_mtx.lock_object, "Catching SIGSTOP"); sigqueue_delete(&td->td_sigqueue, sig); diff --git a/sys/kern/tty.c b/sys/kern/tty.c --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -423,7 +423,7 @@ int tty_wait_background(struct tty *tp, struct thread *td, int sig) { - struct proc *p = td->td_proc; + struct proc *p; struct pgrp *pg; ksiginfo_t ksi; int error; @@ -431,8 +431,22 @@ MPASS(sig == SIGTTIN || sig == SIGTTOU); tty_assert_locked(tp); + p = td->td_proc; for (;;) { + pg = p->p_pgrp; + PGRP_LOCK(pg); PROC_LOCK(p); + + /* + * pg may no longer be our process group. + * Re-check after locking. + */ + if (p->p_pgrp != pg) { + PROC_UNLOCK(p); + PGRP_UNLOCK(pg); + continue; + } + /* * The process should only sleep, when: * - This terminal is the controlling terminal @@ -445,6 +459,7 @@ if (!tty_is_ctty(tp, p) || p->p_pgrp == tp->t_pgrp) { /* Allow the action to happen. */ PROC_UNLOCK(p); + PGRP_UNLOCK(pg); return (0); } @@ -452,13 +467,15 @@ SIGISMEMBER(td->td_sigmask, sig)) { /* Only allow them in write()/ioctl(). */ PROC_UNLOCK(p); + PGRP_UNLOCK(pg); return (sig == SIGTTOU ? 0 : EIO); } - pg = p->p_pgrp; - if (p->p_flag & P_PPWAIT || pg->pg_jobc == 0) { + if ((p->p_flag & P_PPWAIT) != 0 || + (pg->pg_flags & PGRP_ORPHANED) != 0) { /* Don't allow the action to happen. */ PROC_UNLOCK(p); + PGRP_UNLOCK(pg); return (EIO); } PROC_UNLOCK(p); @@ -473,20 +490,7 @@ ksi.ksi_signo = sig; sig = 0; } - PGRP_LOCK(pg); - - /* - * pg may no longer be our process group. - * Re-check after locking process group. - */ - PROC_LOCK(p); - if (p->p_pgrp != pg) { - PROC_UNLOCK(p); - PGRP_UNLOCK(pg); - continue; - } - PROC_UNLOCK(p); pgsignal(pg, ksi.ksi_signo, 1, &ksi); PGRP_UNLOCK(pg); @@ -2392,9 +2396,8 @@ _db_show_hooks("\t", tp->t_hook); /* Process info. */ - db_printf("\tpgrp: %p gid %d jobc %d\n", tp->t_pgrp, - tp->t_pgrp ? tp->t_pgrp->pg_id : 0, - tp->t_pgrp ? tp->t_pgrp->pg_jobc : 0); + db_printf("\tpgrp: %p gid %d\n", tp->t_pgrp, + tp->t_pgrp ? tp->t_pgrp->pg_id : 0); db_printf("\tsession: %p", tp->t_session); if (tp->t_session != NULL) db_printf(" count %u leader %p tty %p sid %d login %s", diff --git a/sys/sys/proc.h b/sys/sys/proc.h --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -111,10 +111,12 @@ struct session *pg_session; /* (c) Pointer to session. */ struct sigiolst pg_sigiolst; /* (m) List of sigio sources. */ pid_t pg_id; /* (c) Process group id. */ - int pg_jobc; /* (m) Job control process count. */ struct mtx pg_mtx; /* Mutex to protect members */ + int pg_flags; /* (m) PGRP_ flags */ }; +#define PGRP_ORPHANED 0x00000001 /* Group is orphaned */ + /* * pargs, used to hold a copy of the command line, if it had a sane length. */ @@ -864,7 +866,6 @@ #ifdef MALLOC_DECLARE MALLOC_DECLARE(M_PARGS); -MALLOC_DECLARE(M_PGRP); MALLOC_DECLARE(M_SESSION); MALLOC_DECLARE(M_SUBPROC); #endif @@ -1022,6 +1023,7 @@ extern struct proc *initproc, *pageproc; /* Process slots for init, pager. */ extern struct uma_zone *proc_zone; +extern struct uma_zone *pgrp_zone; struct proc *pfind(pid_t); /* Find process by id. */ struct proc *pfind_any(pid_t); /* Find (zombie) process by id. */