svn commit: r275616 - in head/sys: kern sys

Konstantin Belousov kib at FreeBSD.org
Mon Dec 8 16:18:06 UTC 2014


Author: kib
Date: Mon Dec  8 16:18:05 2014
New Revision: 275616
URL: https://svnweb.freebsd.org/changeset/base/275616

Log:
  Thread waiting for the vfork(2)-ed child to exec or exit, must allow
  for the suspension.
  
  Currently, the loop performs uninterruptible cv_wait(9) call, which
  prevents suspension until child allows further execution of parent.
  If child is stopped, suspension or single-threading is delayed
  indefinitely.
  
  Create a helper thread_suspend_check_needed() to identify the need for
  a call to thread_suspend_check().  It is required since call to the
  thread_suspend_check() cannot be safely done while owning the child
  (p2) process lock.  Only when suspension is needed, drop p2 lock and
  call thread_suspend_check().  Perform wait for cv with timeout, in
  case suspend is requested after wait started; I do not see a better
  way to interrupt the wait.
  
  Reported and tested by:	pho
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week

Modified:
  head/sys/kern/kern_thread.c
  head/sys/kern/subr_syscall.c
  head/sys/sys/proc.h

Modified: head/sys/kern/kern_thread.c
==============================================================================
--- head/sys/kern/kern_thread.c	Mon Dec  8 16:02:02 2014	(r275615)
+++ head/sys/kern/kern_thread.c	Mon Dec  8 16:18:05 2014	(r275616)
@@ -725,6 +725,19 @@ stopme:
 	return (0);
 }
 
+bool
+thread_suspend_check_needed(void)
+{
+	struct proc *p;
+	struct thread *td;
+
+	td = curthread;
+	p = td->td_proc;
+	PROC_LOCK_ASSERT(p, MA_OWNED);
+	return (P_SHOULDSTOP(p) || ((p->p_flag & P_TRACED) != 0 &&
+	    (td->td_dbgflags & TDB_SUSPEND) != 0));
+}
+
 /*
  * Called in from locations that can safely check to see
  * whether we have to suspend or at least throttle for a
@@ -769,8 +782,7 @@ thread_suspend_check(int return_instead)
 	p = td->td_proc;
 	mtx_assert(&Giant, MA_NOTOWNED);
 	PROC_LOCK_ASSERT(p, MA_OWNED);
-	while (P_SHOULDSTOP(p) ||
-	      ((p->p_flag & P_TRACED) && (td->td_dbgflags & TDB_SUSPEND))) {
+	while (thread_suspend_check_needed()) {
 		if (P_SHOULDSTOP(p) == P_STOPPED_SINGLE) {
 			KASSERT(p->p_singlethread != NULL,
 			    ("singlethread not set"));

Modified: head/sys/kern/subr_syscall.c
==============================================================================
--- head/sys/kern/subr_syscall.c	Mon Dec  8 16:02:02 2014	(r275615)
+++ head/sys/kern/subr_syscall.c	Mon Dec  8 16:18:05 2014	(r275616)
@@ -226,9 +226,20 @@ syscallret(struct thread *td, int error,
 		 */
 		td->td_pflags &= ~TDP_RFPPWAIT;
 		p2 = td->td_rfppwait_p;
+again:
 		PROC_LOCK(p2);
-		while (p2->p_flag & P_PPWAIT)
-			cv_wait(&p2->p_pwait, &p2->p_mtx);
+		while (p2->p_flag & P_PPWAIT) {
+			PROC_LOCK(p);
+			if (thread_suspend_check_needed()) {
+				PROC_UNLOCK(p2);
+				thread_suspend_check(0);
+				PROC_UNLOCK(p);
+				goto again;
+			} else {
+				PROC_UNLOCK(p);
+			}
+			cv_timedwait(&p2->p_pwait, &p2->p_mtx, hz);
+		}
 		PROC_UNLOCK(p2);
 	}
 }

Modified: head/sys/sys/proc.h
==============================================================================
--- head/sys/sys/proc.h	Mon Dec  8 16:02:02 2014	(r275615)
+++ head/sys/sys/proc.h	Mon Dec  8 16:18:05 2014	(r275616)
@@ -970,6 +970,7 @@ void	childproc_stopped(struct proc *chil
 void	childproc_continued(struct proc *child);
 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_one(struct thread *td);
 void	thread_unlink(struct thread *td);


More information about the svn-src-head mailing list