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);
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to