Date: Mon, 8 Dec 2014 16:18:05 +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: r275616 - in head/sys: kern sys Message-ID: <201412081618.sB8GI5l3093010@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201412081618.sB8GI5l3093010>