Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 13 Dec 2014 16:18:30 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r275745 - in head: bin/ps sys/kern sys/rpc sys/sys
Message-ID:  <201412131618.sBDGIUYK050710@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Sat Dec 13 16:18:29 2014
New Revision: 275745
URL: https://svnweb.freebsd.org/changeset/base/275745

Log:
  Add facility to stop all userspace processes.  The supposed use of the
  feature is to quisce the system before suspend.
  
  Stop is implemented by reusing the thread_single(9) with the special
  mode SINGLE_ALLPROC.  SINGLE_ALLPROC differs from the existing
  single-threading modes by allowing (requiring) caller to operate on
  other process.  Interruptible sleeps for !TDF_SBDRY threads are
  suspended like SIGSTOP does it, instead of aborting the sleep, like
  SINGLE_NO_EXIT, to avoid spurious EINTRs on resume.
  
  Provide debugging sysctl debug.stop_all_proc, which causes total stop
  and suspends syncer, while waiting for variable reset for resume.  It
  is used for debugging; should be removed after the real use of the
  interface is added.
  
  In collaboration with:	pho
  Discussed with:	avg
  Sponsored by:	The FreeBSD Foundation
  MFC after:	2 weeks

Modified:
  head/bin/ps/ps.1
  head/sys/kern/kern_exec.c
  head/sys/kern/kern_exit.c
  head/sys/kern/kern_fork.c
  head/sys/kern/kern_proc.c
  head/sys/kern/kern_sig.c
  head/sys/kern/kern_thread.c
  head/sys/rpc/svc.c
  head/sys/sys/proc.h

Modified: head/bin/ps/ps.1
==============================================================================
--- head/bin/ps/ps.1	Sat Dec 13 16:07:01 2014	(r275744)
+++ head/bin/ps/ps.1	Sat Dec 13 16:18:29 2014	(r275745)
@@ -29,7 +29,7 @@
 .\"     @(#)ps.1	8.3 (Berkeley) 4/18/94
 .\" $FreeBSD$
 .\"
-.Dd August 27, 2014
+.Dd December 9, 2014
 .Dt PS 1
 .Os
 .Sh NAME
@@ -332,6 +332,7 @@ the include file
 .It Dv "P_SINGLE_BOUNDARY" Ta No "0x400000" Ta "Threads should suspend at user boundary"
 .It Dv "P_HWPMC" Ta No "0x800000" Ta "Process is using HWPMCs"
 .It Dv "P_JAILED" Ta No "0x1000000" Ta "Process is in jail"
+.It Dv "P_TOTAL_STOP" Ta No "0x2000000" Ta "Stopped for system suspend"
 .It Dv "P_INEXEC" Ta No "0x4000000" Ta "Process is in execve()"
 .It Dv "P_STATCHILD" Ta No "0x8000000" Ta "Child process stopped or exited"
 .It Dv "P_INMEM" Ta No "0x10000000" Ta "Loaded into memory"

Modified: head/sys/kern/kern_exec.c
==============================================================================
--- head/sys/kern/kern_exec.c	Sat Dec 13 16:07:01 2014	(r275744)
+++ head/sys/kern/kern_exec.c	Sat Dec 13 16:18:29 2014	(r275745)
@@ -289,7 +289,7 @@ kern_execve(td, args, mac_p)
 	    args->endp - args->begin_envv);
 	if (p->p_flag & P_HADTHREADS) {
 		PROC_LOCK(p);
-		if (thread_single(SINGLE_BOUNDARY)) {
+		if (thread_single(p, SINGLE_BOUNDARY)) {
 			PROC_UNLOCK(p);
 	       		exec_free_args(args);
 			return (ERESTART);	/* Try again later. */
@@ -308,9 +308,9 @@ kern_execve(td, args, mac_p)
 		 * force other threads to suicide.
 		 */
 		if (error == 0)
-			thread_single(SINGLE_EXIT);
+			thread_single(p, SINGLE_EXIT);
 		else
-			thread_single_end();
+			thread_single_end(p, SINGLE_BOUNDARY);
 		PROC_UNLOCK(p);
 	}
 	if ((td->td_pflags & TDP_EXECVMSPC) != 0) {

Modified: head/sys/kern/kern_exit.c
==============================================================================
--- head/sys/kern/kern_exit.c	Sat Dec 13 16:07:01 2014	(r275744)
+++ head/sys/kern/kern_exit.c	Sat Dec 13 16:18:29 2014	(r275745)
@@ -207,7 +207,7 @@ exit1(struct thread *td, int rv)
 		 * re-check all suspension request, the thread should
 		 * either be suspended there or exit.
 		 */
-		if (!thread_single(SINGLE_EXIT))
+		if (!thread_single(p, SINGLE_EXIT))
 			/*
 			 * All other activity in this process is now
 			 * stopped.  Threading support has been turned

Modified: head/sys/kern/kern_fork.c
==============================================================================
--- head/sys/kern/kern_fork.c	Sat Dec 13 16:07:01 2014	(r275744)
+++ head/sys/kern/kern_fork.c	Sat Dec 13 16:18:29 2014	(r275745)
@@ -317,7 +317,7 @@ fork_norfproc(struct thread *td, int fla
 	if (((p1->p_flag & (P_HADTHREADS|P_SYSTEM)) == P_HADTHREADS) &&
 	    (flags & (RFCFDG | RFFDG))) {
 		PROC_LOCK(p1);
-		if (thread_single(SINGLE_BOUNDARY)) {
+		if (thread_single(p1, SINGLE_BOUNDARY)) {
 			PROC_UNLOCK(p1);
 			return (ERESTART);
 		}
@@ -348,7 +348,7 @@ fail:
 	if (((p1->p_flag & (P_HADTHREADS|P_SYSTEM)) == P_HADTHREADS) &&
 	    (flags & (RFCFDG | RFFDG))) {
 		PROC_LOCK(p1);
-		thread_single_end();
+		thread_single_end(p1, SINGLE_BOUNDARY);
 		PROC_UNLOCK(p1);
 	}
 	return (error);
@@ -384,6 +384,7 @@ do_fork(struct thread *td, int flags, st
 	p2->p_pid = trypid;
 	AUDIT_ARG_PID(p2->p_pid);
 	LIST_INSERT_HEAD(&allproc, p2, p_list);
+	allproc_gen++;
 	LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
 	tidhash_add(td2);
 	PROC_LOCK(p2);

Modified: head/sys/kern/kern_proc.c
==============================================================================
--- head/sys/kern/kern_proc.c	Sat Dec 13 16:07:01 2014	(r275744)
+++ head/sys/kern/kern_proc.c	Sat Dec 13 16:18:29 2014	(r275745)
@@ -2896,3 +2896,141 @@ static SYSCTL_NODE(_kern_proc, KERN_PROC
 static SYSCTL_NODE(_kern_proc, KERN_PROC_SIGTRAMP, sigtramp, CTLFLAG_RD |
 	CTLFLAG_MPSAFE, sysctl_kern_proc_sigtramp,
 	"Process signal trampoline location");
+
+int allproc_gen;
+
+void
+stop_all_proc(void)
+{
+	struct proc *cp, *p;
+	int r, gen;
+	bool restart, seen_stopped, seen_exiting, stopped_some;
+
+	cp = curproc;
+	/*
+	 * stop_all_proc() assumes that all process which have
+	 * usermode must be stopped, except current process, for
+	 * obvious reasons.  Since other threads in the process
+	 * establishing global stop could unstop something, disable
+	 * calls from multithreaded processes as precaution.  The
+	 * service must not be user-callable anyway.
+	 */
+	KASSERT((cp->p_flag & P_HADTHREADS) == 0 ||
+	    (cp->p_flag & P_KTHREAD) != 0, ("mt stop_all_proc"));
+
+allproc_loop:
+	sx_xlock(&allproc_lock);
+	gen = allproc_gen;
+	seen_exiting = seen_stopped = stopped_some = restart = false;
+	LIST_REMOVE(cp, p_list);
+	LIST_INSERT_HEAD(&allproc, cp, p_list);
+	for (;;) {
+		p = LIST_NEXT(cp, p_list);
+		if (p == NULL)
+			break;
+		LIST_REMOVE(cp, p_list);
+		LIST_INSERT_AFTER(p, cp, p_list);
+		PROC_LOCK(p);
+		if ((p->p_flag & (P_KTHREAD | P_SYSTEM |
+		    P_TOTAL_STOP)) != 0) {
+			PROC_UNLOCK(p);
+			continue;
+		}
+		if ((p->p_flag & P_WEXIT) != 0) {
+			seen_exiting = true;
+			PROC_UNLOCK(p);
+			continue;
+		}
+		if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) {
+			/*
+			 * Stopped processes are tolerated when there
+			 * are no other processes which might continue
+			 * them.  P_STOPPED_SINGLE but not
+			 * P_TOTAL_STOP process still has at least one
+			 * thread running.
+			 */
+			seen_stopped = true;
+			PROC_UNLOCK(p);
+			continue;
+		}
+		_PHOLD(p);
+		sx_xunlock(&allproc_lock);
+		r = thread_single(p, SINGLE_ALLPROC);
+		if (r != 0)
+			restart = true;
+		else
+			stopped_some = true;
+		_PRELE(p);
+		PROC_UNLOCK(p);
+		sx_xlock(&allproc_lock);
+	}
+	/* Catch forked children we did not see in iteration. */
+	if (gen != allproc_gen)
+		restart = true;
+	sx_xunlock(&allproc_lock);
+	if (restart || stopped_some || seen_exiting || seen_stopped) {
+		kern_yield(PRI_USER);
+		goto allproc_loop;
+	}
+}
+
+void
+resume_all_proc(void)
+{
+	struct proc *cp, *p;
+
+	cp = curproc;
+	sx_xlock(&allproc_lock);
+	LIST_REMOVE(cp, p_list);
+	LIST_INSERT_HEAD(&allproc, cp, p_list);
+	for (;;) {
+		p = LIST_NEXT(cp, p_list);
+		if (p == NULL)
+			break;
+		LIST_REMOVE(cp, p_list);
+		LIST_INSERT_AFTER(p, cp, p_list);
+		PROC_LOCK(p);
+		if ((p->p_flag & P_TOTAL_STOP) != 0) {
+			sx_xunlock(&allproc_lock);
+			_PHOLD(p);
+			thread_single_end(p, SINGLE_ALLPROC);
+			_PRELE(p);
+			PROC_UNLOCK(p);
+			sx_xlock(&allproc_lock);
+		} else {
+			PROC_UNLOCK(p);
+		}
+	}
+	sx_xunlock(&allproc_lock);
+}
+
+#define	TOTAL_STOP_DEBUG	1
+#ifdef TOTAL_STOP_DEBUG
+volatile static int ap_resume;
+#include <sys/mount.h>
+
+static int
+sysctl_debug_stop_all_proc(SYSCTL_HANDLER_ARGS)
+{
+	int error, val;
+
+	val = 0;
+	ap_resume = 0;
+	error = sysctl_handle_int(oidp, &val, 0, req);
+	if (error != 0 || req->newptr == NULL)
+		return (error);
+	if (val != 0) {
+		stop_all_proc();
+		syncer_suspend();
+		while (ap_resume == 0)
+			;
+		syncer_resume();
+		resume_all_proc();
+	}
+	return (0);
+}
+
+SYSCTL_PROC(_debug, OID_AUTO, stop_all_proc, CTLTYPE_INT | CTLFLAG_RW |
+    CTLFLAG_MPSAFE, (void *)&ap_resume, 0, sysctl_debug_stop_all_proc, "I",
+    "");
+#endif

Modified: head/sys/kern/kern_sig.c
==============================================================================
--- head/sys/kern/kern_sig.c	Sat Dec 13 16:07:01 2014	(r275744)
+++ head/sys/kern/kern_sig.c	Sat Dec 13 16:18:29 2014	(r275745)
@@ -2491,7 +2491,7 @@ ptracestop(struct thread *td, int sig)
 			cv_broadcast(&p->p_dbgwait);
 		}
 stopme:
-		thread_suspend_switch(td);
+		thread_suspend_switch(td, p);
 		if (p->p_xthread == td)
 			p->p_xthread = NULL;
 		if (!(p->p_flag & P_TRACED))
@@ -2752,7 +2752,7 @@ issignal(struct thread *td)
 				p->p_xstat = sig;
 				PROC_SLOCK(p);
 				sig_suspend_threads(td, p, 0);
-				thread_suspend_switch(td);
+				thread_suspend_switch(td, p);
 				PROC_SUNLOCK(p);
 				mtx_lock(&ps->ps_mtx);
 				break;
@@ -2933,7 +2933,7 @@ sigexit(td, sig)
 	 * XXX If another thread attempts to single-thread before us
 	 *     (e.g. via fork()), we won't get a dump at all.
 	 */
-	if ((sigprop(sig) & SA_CORE) && (thread_single(SINGLE_NO_EXIT) == 0)) {
+	if ((sigprop(sig) & SA_CORE) && thread_single(p, SINGLE_NO_EXIT) == 0) {
 		p->p_sig = sig;
 		/*
 		 * Log signals which would cause core dumps

Modified: head/sys/kern/kern_thread.c
==============================================================================
--- head/sys/kern/kern_thread.c	Sat Dec 13 16:07:01 2014	(r275744)
+++ head/sys/kern/kern_thread.c	Sat Dec 13 16:18:29 2014	(r275745)
@@ -445,7 +445,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();
@@ -576,7 +576,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);
@@ -587,7 +587,7 @@ static int
 remain_for_mode(int mode)
 {
 
-	return (1);
+	return (mode == SINGLE_ALLPROC ? 0 : 1);
 }
 
 static int
@@ -603,21 +603,41 @@ weed_inhib(int mode, struct thread *td2,
 	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);
+	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);
@@ -637,19 +657,29 @@ weed_inhib(int mode, struct thread *td2,
  * 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? */
@@ -666,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;
@@ -679,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)
@@ -703,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) {
@@ -813,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);
@@ -841,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();
@@ -874,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);
@@ -886,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;
@@ -905,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"));
@@ -917,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));
 }
 
@@ -945,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);
 		}
@@ -956,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();
@@ -968,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;
@@ -986,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);
 		}

Modified: head/sys/rpc/svc.c
==============================================================================
--- head/sys/rpc/svc.c	Sat Dec 13 16:07:01 2014	(r275744)
+++ head/sys/rpc/svc.c	Sat Dec 13 16:18:29 2014	(r275745)
@@ -1190,7 +1190,8 @@ svc_run_internal(SVCGROUP *grp, bool_t i
 				mtx_unlock(&grp->sg_lock);
 				p = curproc;
 				PROC_LOCK(p);
-				if (P_SHOULDSTOP(p)) {
+				if (P_SHOULDSTOP(p) ||
+				    (p->p_flag & P_TOTAL_STOP) != 0) {
 					thread_suspend_check(0);
 					PROC_UNLOCK(p);
 					mtx_lock(&grp->sg_lock);

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h	Sat Dec 13 16:07:01 2014	(r275744)
+++ head/sys/sys/proc.h	Sat Dec 13 16:18:29 2014	(r275745)
@@ -361,7 +361,7 @@ do {									\
 #define	TDF_CANSWAP	0x00000040 /* Thread can be swapped. */
 #define	TDF_SLEEPABORT	0x00000080 /* sleepq_abort was called. */
 #define	TDF_KTH_SUSP	0x00000100 /* kthread is suspended */
-#define	TDF_UNUSED09	0x00000200 /* --available-- */
+#define	TDF_ALLPROCSUSP	0x00000200 /* suspended by SINGLE_ALLPROC */
 #define	TDF_BOUNDARY	0x00000400 /* Thread suspended at user boundary */
 #define	TDF_ASTPENDING	0x00000800 /* Thread has some asynchronous events. */
 #define	TDF_TIMOFAIL	0x00001000 /* Timeout from sleep after we were awake. */
@@ -652,7 +652,7 @@ struct proc {
 #define	P_SINGLE_BOUNDARY 0x400000 /* Threads should suspend at user boundary. */
 #define	P_HWPMC		0x800000 /* Process is using HWPMCs */
 #define	P_JAILED	0x1000000 /* Process is in jail. */
-#define	P_UNUSED1	0x2000000
+#define	P_TOTAL_STOP	0x2000000 /* Stopped in proc_stop_total. */
 #define	P_INEXEC	0x4000000 /* Process is in execve(). */
 #define	P_STATCHILD	0x8000000 /* Child process stopped or exited. */
 #define	P_INMEM		0x10000000 /* Loaded into memory. */
@@ -713,6 +713,7 @@ struct proc {
 #define	SINGLE_NO_EXIT	0
 #define	SINGLE_EXIT	1
 #define	SINGLE_BOUNDARY	2
+#define	SINGLE_ALLPROC	3
 
 #ifdef MALLOC_DECLARE
 MALLOC_DECLARE(M_PARGS);
@@ -839,6 +840,7 @@ extern LIST_HEAD(pgrphashhead, pgrp) *pg
 extern u_long pgrphash;
 
 extern struct sx allproc_lock;
+extern int allproc_gen;
 extern struct sx proctree_lock;
 extern struct mtx ppeers_lock;
 extern struct proc proc0;		/* Process slot for swapper. */
@@ -962,8 +964,8 @@ void	thread_exit(void) __dead2;
 void	thread_free(struct thread *td);
 void	thread_link(struct thread *td, struct proc *p);
 void	thread_reap(void);
-int	thread_single(int how);
-void	thread_single_end(void);
+int	thread_single(struct proc *p, int how);
+void	thread_single_end(struct proc *p, int how);
 void	thread_stash(struct thread *td);
 void	thread_stopped(struct proc *p);
 void	childproc_stopped(struct proc *child, int reason);
@@ -971,14 +973,17 @@ void	childproc_continued(struct proc *ch
 void	childproc_exited(struct proc *child);
 int	thread_suspend_check(int how);
 bool	thread_suspend_check_needed(void);
-void	thread_suspend_switch(struct thread *);
+void	thread_suspend_switch(struct thread *, struct proc *p);
 void	thread_suspend_one(struct thread *td);
 void	thread_unlink(struct thread *td);
 void	thread_unsuspend(struct proc *p);
-int	thread_unsuspend_one(struct thread *td);
+int	thread_unsuspend_one(struct thread *td, struct proc *p);
 void	thread_wait(struct proc *p);
 struct thread	*thread_find(struct proc *p, lwpid_t tid);
 
+void	stop_all_proc(void);
+void	resume_all_proc(void);
+
 static __inline int
 curthread_pflags_set(int flags)
 {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201412131618.sBDGIUYK050710>