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
This commit is contained in:
Konstantin Belousov 2014-12-08 16:18:05 +00:00
parent aba1ca528e
commit 8638fe7bea
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=275616
3 changed files with 28 additions and 4 deletions

View File

@ -725,6 +725,19 @@ thread_single(int mode)
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"));

View File

@ -226,9 +226,20 @@ syscallret(struct thread *td, int error, struct syscall_args *sa __unused)
*/
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);
}
}

View File

@ -970,6 +970,7 @@ void childproc_stopped(struct proc *child, int reason);
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);