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-all
mailing list