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:
parent
aba1ca528e
commit
8638fe7bea
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=275616
@ -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"));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user