diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index c01f4fa0f30c..02af5eebebd9 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -162,11 +162,19 @@ execve(td, uap) PROC_LOCK(p); KASSERT((p->p_flag & P_INEXEC) == 0, ("%s(): process already has P_INEXEC flag", __func__)); - if ((p->p_flag & P_KSES) && thread_single(SNGLE_EXIT)) { - PROC_UNLOCK(p); - return (ERESTART); /* Try again later. */ + if (p->p_flag & P_KSES) { + if (thread_single(SNGLE_EXIT)) { + PROC_UNLOCK(p); + return (ERESTART); /* Try again later. */ + } + /* + * If we get here all other threads are dead, + * so unset the associated flags and lose KSE mode. + */ + p->p_flag &= ~P_KSES; + td->td_flags &= ~TDF_UNBOUND; + thread_single_end(); } - /* If we get here all other threads are dead. */ p->p_flag |= P_INEXEC; PROC_UNLOCK(p); diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index e09e98d8df5f..5f9d1bd374d0 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -767,6 +767,15 @@ fork1(td, flags, procp) msleep(p1, &p2->p_mtx, PWAIT, "ppwait", 0); PROC_UNLOCK(p2); + /* + * If other threads are waiting, let them continue now + */ + if (p1->p_flag & P_KSES) { + PROC_LOCK(p1); + thread_single_end(); + PROC_UNLOCK(p1); + } + /* * Return child proc pointer to parent. */ diff --git a/sys/kern/kern_kse.c b/sys/kern/kern_kse.c index 664dde45405b..0214237a64a0 100644 --- a/sys/kern/kern_kse.c +++ b/sys/kern/kern_kse.c @@ -804,6 +804,21 @@ thread_single_end(void) PROC_LOCK_ASSERT(p, MA_OWNED); p->p_flag &= ~P_STOPPED_SNGL; p->p_singlethread = NULL; - thread_unsuspend(p); + /* + * If there are other threads they mey now run, + * unless of course there is a blanket 'stop order' + * on the process. The single threader must be allowed + * to continue however as this is a bad place to stop. + */ + if ((p->p_numthreads != 1) && (!P_SHOULDSTOP(p))) { + mtx_lock_spin(&sched_lock); + while (( td = TAILQ_FIRST(&p->p_suspended))) { + TAILQ_REMOVE(&p->p_suspended, td, td_runq); + p->p_suspcount--; + setrunqueue(td); + } + mtx_unlock_spin(&sched_lock); + } } + diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index 664dde45405b..0214237a64a0 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -804,6 +804,21 @@ thread_single_end(void) PROC_LOCK_ASSERT(p, MA_OWNED); p->p_flag &= ~P_STOPPED_SNGL; p->p_singlethread = NULL; - thread_unsuspend(p); + /* + * If there are other threads they mey now run, + * unless of course there is a blanket 'stop order' + * on the process. The single threader must be allowed + * to continue however as this is a bad place to stop. + */ + if ((p->p_numthreads != 1) && (!P_SHOULDSTOP(p))) { + mtx_lock_spin(&sched_lock); + while (( td = TAILQ_FIRST(&p->p_suspended))) { + TAILQ_REMOVE(&p->p_suspended, td, td_runq); + p->p_suspcount--; + setrunqueue(td); + } + mtx_unlock_spin(&sched_lock); + } } +