summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_thread.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2014-12-27 00:55:14 +0000
committerkib <kib@FreeBSD.org>2014-12-27 00:55:14 +0000
commit38f7dd4bb8ccb6cb4ed506840f0c8d52fa87d499 (patch)
tree43d08c4b52a8e715790b7e3ff2f90ae29aa645b9 /sys/kern/kern_thread.c
parente8e2e634b5ab8e91afb9b7f93c7f0ff096369abe (diff)
downloadFreeBSD-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.c120
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);
}
OpenPOWER on IntegriCloud