diff options
author | kib <kib@FreeBSD.org> | 2014-12-27 00:55:14 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2014-12-27 00:55:14 +0000 |
commit | 38f7dd4bb8ccb6cb4ed506840f0c8d52fa87d499 (patch) | |
tree | 43d08c4b52a8e715790b7e3ff2f90ae29aa645b9 /sys/kern/kern_thread.c | |
parent | e8e2e634b5ab8e91afb9b7f93c7f0ff096369abe (diff) | |
download | FreeBSD-src-38f7dd4bb8ccb6cb4ed506840f0c8d52fa87d499.zip FreeBSD-src-38f7dd4bb8ccb6cb4ed506840f0c8d52fa87d499.tar.gz |
MFC r275745:
Add facility to stop all userspace processes.
MFC r275753:
Fix gcc build.
MFC r275820:
Add missed break.
Diffstat (limited to 'sys/kern/kern_thread.c')
-rw-r--r-- | sys/kern/kern_thread.c | 120 |
1 files changed, 82 insertions, 38 deletions
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index 280cb04..62d92b0 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -446,7 +446,7 @@ thread_exit(void) if (p->p_numthreads == p->p_suspcount) { thread_lock(p->p_singlethread); wakeup_swapper = thread_unsuspend_one( - p->p_singlethread); + p->p_singlethread, p); thread_unlock(p->p_singlethread); if (wakeup_swapper) kick_proc0(); @@ -575,7 +575,7 @@ calc_remaining(struct proc *p, int mode) remaining = p->p_numthreads; else if (mode == SINGLE_BOUNDARY) remaining = p->p_numthreads - p->p_boundary_count; - else if (mode == SINGLE_NO_EXIT) + else if (mode == SINGLE_NO_EXIT || mode == SINGLE_ALLPROC) remaining = p->p_numthreads - p->p_suspcount; else panic("calc_remaining: wrong mode %d", mode); @@ -586,7 +586,7 @@ static int remain_for_mode(int mode) { - return (1); + return (mode == SINGLE_ALLPROC ? 0 : 1); } static int @@ -602,22 +602,43 @@ weed_inhib(int mode, struct thread *td2, struct proc *p) switch (mode) { case SINGLE_EXIT: if (TD_IS_SUSPENDED(td2)) - wakeup_swapper |= thread_unsuspend_one(td2); + wakeup_swapper |= thread_unsuspend_one(td2, p); if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) wakeup_swapper |= sleepq_abort(td2, EINTR); break; case SINGLE_BOUNDARY: if (TD_IS_SUSPENDED(td2) && (td2->td_flags & TDF_BOUNDARY) == 0) - wakeup_swapper |= thread_unsuspend_one(td2); + wakeup_swapper |= thread_unsuspend_one(td2, p); if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) wakeup_swapper |= sleepq_abort(td2, ERESTART); break; case SINGLE_NO_EXIT: if (TD_IS_SUSPENDED(td2) && (td2->td_flags & TDF_BOUNDARY) == 0) - wakeup_swapper |= thread_unsuspend_one(td2); + wakeup_swapper |= thread_unsuspend_one(td2, p); if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) wakeup_swapper |= sleepq_abort(td2, ERESTART); break; + case SINGLE_ALLPROC: + /* + * ALLPROC suspend tries to avoid spurious EINTR for + * threads sleeping interruptable, by suspending the + * thread directly, similarly to sig_suspend_threads(). + * Since such sleep is not performed at the user + * boundary, TDF_BOUNDARY flag is not set, and TDF_ALLPROCSUSP + * is used to avoid immediate un-suspend. + */ + if (TD_IS_SUSPENDED(td2) && (td2->td_flags & (TDF_BOUNDARY | + TDF_ALLPROCSUSP)) == 0) + wakeup_swapper |= thread_unsuspend_one(td2, p); + if (TD_ON_SLEEPQ(td2) && (td2->td_flags & TDF_SINTR) != 0) { + if ((td2->td_flags & TDF_SBDRY) == 0) { + thread_suspend_one(td2); + td2->td_flags |= TDF_ALLPROCSUSP; + } else { + wakeup_swapper |= sleepq_abort(td2, ERESTART); + } + } + break; } return (wakeup_swapper); } @@ -636,19 +657,29 @@ weed_inhib(int mode, struct thread *td2, struct proc *p) * any sleeping threads that are interruptable. (PCATCH). */ int -thread_single(int mode) +thread_single(struct proc *p, int mode) { struct thread *td; struct thread *td2; - struct proc *p; int remaining, wakeup_swapper; td = curthread; - p = td->td_proc; + KASSERT(mode == SINGLE_EXIT || mode == SINGLE_BOUNDARY || + mode == SINGLE_ALLPROC || mode == SINGLE_NO_EXIT, + ("invalid mode %d", mode)); + /* + * If allowing non-ALLPROC singlethreading for non-curproc + * callers, calc_remaining() and remain_for_mode() should be + * adjusted to also account for td->td_proc != p. For now + * this is not implemented because it is not used. + */ + KASSERT((mode == SINGLE_ALLPROC && td->td_proc != p) || + (mode != SINGLE_ALLPROC && td->td_proc == p), + ("mode %d proc %p curproc %p", mode, p, td->td_proc)); mtx_assert(&Giant, MA_NOTOWNED); PROC_LOCK_ASSERT(p, MA_OWNED); - if ((p->p_flag & P_HADTHREADS) == 0) + if ((p->p_flag & P_HADTHREADS) == 0 && mode != SINGLE_ALLPROC) return (0); /* Is someone already single threading? */ @@ -665,6 +696,8 @@ thread_single(int mode) else p->p_flag &= ~P_SINGLE_BOUNDARY; } + if (mode == SINGLE_ALLPROC) + p->p_flag |= P_TOTAL_STOP; p->p_flag |= P_STOPPED_SINGLE; PROC_SLOCK(p); p->p_singlethread = td; @@ -678,13 +711,13 @@ thread_single(int mode) continue; thread_lock(td2); td2->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK; - if (TD_IS_INHIBITED(td2)) + if (TD_IS_INHIBITED(td2)) { wakeup_swapper |= weed_inhib(mode, td2, p); #ifdef SMP - else if (TD_IS_RUNNING(td2) && td != td2) { + } else if (TD_IS_RUNNING(td2) && td != td2) { forward_signal(td2); - } #endif + } thread_unlock(td2); } if (wakeup_swapper) @@ -702,7 +735,7 @@ stopme: * Wake us up when everyone else has suspended. * In the mean time we suspend as well. */ - thread_suspend_switch(td); + thread_suspend_switch(td, p); remaining = calc_remaining(p, mode); } if (mode == SINGLE_EXIT) { @@ -812,8 +845,9 @@ thread_suspend_check(int return_instead) * Ignore suspend requests for stop signals if they * are deferred. */ - if (P_SHOULDSTOP(p) == P_STOPPED_SIG && - td->td_flags & TDF_SBDRY) { + if ((P_SHOULDSTOP(p) == P_STOPPED_SIG || + (p->p_flag & P_TOTAL_STOP) != 0) && + (td->td_flags & TDF_SBDRY) != 0) { KASSERT(return_instead, ("TDF_SBDRY set for unsafe thread_suspend_check")); return (0); @@ -840,7 +874,7 @@ thread_suspend_check(int return_instead) if (p->p_numthreads == p->p_suspcount + 1) { thread_lock(p->p_singlethread); wakeup_swapper = - thread_unsuspend_one(p->p_singlethread); + thread_unsuspend_one(p->p_singlethread, p); thread_unlock(p->p_singlethread); if (wakeup_swapper) kick_proc0(); @@ -873,11 +907,9 @@ thread_suspend_check(int return_instead) } void -thread_suspend_switch(struct thread *td) +thread_suspend_switch(struct thread *td, struct proc *p) { - struct proc *p; - p = td->td_proc; KASSERT(!TD_IS_SUSPENDED(td), ("already suspended")); PROC_LOCK_ASSERT(p, MA_OWNED); PROC_SLOCK_ASSERT(p, MA_OWNED); @@ -885,8 +917,10 @@ thread_suspend_switch(struct thread *td) * We implement thread_suspend_one in stages here to avoid * dropping the proc lock while the thread lock is owned. */ - thread_stopped(p); - p->p_suspcount++; + if (p == td->td_proc) { + thread_stopped(p); + p->p_suspcount++; + } PROC_UNLOCK(p); thread_lock(td); td->td_flags &= ~TDF_NEEDSUSPCHK; @@ -904,8 +938,9 @@ thread_suspend_switch(struct thread *td) void thread_suspend_one(struct thread *td) { - struct proc *p = td->td_proc; + struct proc *p; + p = td->td_proc; PROC_SLOCK_ASSERT(p, MA_OWNED); THREAD_LOCK_ASSERT(td, MA_OWNED); KASSERT(!TD_IS_SUSPENDED(td), ("already suspended")); @@ -916,15 +951,17 @@ thread_suspend_one(struct thread *td) } int -thread_unsuspend_one(struct thread *td) +thread_unsuspend_one(struct thread *td, struct proc *p) { - struct proc *p = td->td_proc; - PROC_SLOCK_ASSERT(p, MA_OWNED); THREAD_LOCK_ASSERT(td, MA_OWNED); KASSERT(TD_IS_SUSPENDED(td), ("Thread not suspended")); TD_CLR_SUSPENDED(td); - p->p_suspcount--; + td->td_flags &= ~TDF_ALLPROCSUSP; + if (td->td_proc == p) { + PROC_SLOCK_ASSERT(p, MA_OWNED); + p->p_suspcount--; + } return (setrunnable(td)); } @@ -944,7 +981,7 @@ thread_unsuspend(struct proc *p) FOREACH_THREAD_IN_PROC(p, td) { thread_lock(td); if (TD_IS_SUSPENDED(td)) { - wakeup_swapper |= thread_unsuspend_one(td); + wakeup_swapper |= thread_unsuspend_one(td, p); } thread_unlock(td); } @@ -955,9 +992,12 @@ thread_unsuspend(struct proc *p) * threading request. Now we've downgraded to single-threaded, * let it continue. */ - thread_lock(p->p_singlethread); - wakeup_swapper = thread_unsuspend_one(p->p_singlethread); - thread_unlock(p->p_singlethread); + if (p->p_singlethread->td_proc == p) { + thread_lock(p->p_singlethread); + wakeup_swapper = thread_unsuspend_one( + p->p_singlethread, p); + thread_unlock(p->p_singlethread); + } } if (wakeup_swapper) kick_proc0(); @@ -967,15 +1007,20 @@ thread_unsuspend(struct proc *p) * End the single threading mode.. */ void -thread_single_end(void) +thread_single_end(struct proc *p, int mode) { struct thread *td; - struct proc *p; int wakeup_swapper; - p = curproc; + KASSERT(mode == SINGLE_EXIT || mode == SINGLE_BOUNDARY || + mode == SINGLE_ALLPROC || mode == SINGLE_NO_EXIT, + ("invalid mode %d", mode)); PROC_LOCK_ASSERT(p, MA_OWNED); - p->p_flag &= ~(P_STOPPED_SINGLE | P_SINGLE_EXIT | P_SINGLE_BOUNDARY); + KASSERT((mode == SINGLE_ALLPROC && (p->p_flag & P_TOTAL_STOP) != 0) || + (mode != SINGLE_ALLPROC && (p->p_flag & P_TOTAL_STOP) == 0), + ("mode %d does not match P_TOTAL_STOP", mode)); + p->p_flag &= ~(P_STOPPED_SINGLE | P_SINGLE_EXIT | P_SINGLE_BOUNDARY | + P_TOTAL_STOP); PROC_SLOCK(p); p->p_singlethread = NULL; wakeup_swapper = 0; @@ -985,12 +1030,11 @@ thread_single_end(void) * on the process. The single threader must be allowed * to continue however as this is a bad place to stop. */ - if (p->p_numthreads != remain_for_mode(SINGLE_EXIT) && - !P_SHOULDSTOP(p)) { + if (p->p_numthreads != remain_for_mode(mode) && !P_SHOULDSTOP(p)) { FOREACH_THREAD_IN_PROC(p, td) { thread_lock(td); if (TD_IS_SUSPENDED(td)) { - wakeup_swapper |= thread_unsuspend_one(td); + wakeup_swapper |= thread_unsuspend_one(td, p); } thread_unlock(td); } |