Currently, the debugger attached to the process executing vfork() does
not get syscall exit notification until the child performed exec of exit. Swap the order of doing ptracestop() and waiting for P_PPWAIT clearing, by postponing the wait into syscallret after ptracestop() notification is done. Reported, tested and reviewed by: Dmitry Mikulin <dmitrym juniper net> MFC after: 2 weeks
This commit is contained in:
parent
963a74f13c
commit
1d7ca9bb8e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=232240
@ -708,6 +708,10 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
|
||||
_PHOLD(p2);
|
||||
p2_held = 1;
|
||||
}
|
||||
if (flags & RFPPWAIT) {
|
||||
td->td_pflags |= TDP_RFPPWAIT;
|
||||
td->td_rfppwait_p = p2;
|
||||
}
|
||||
PROC_UNLOCK(p2);
|
||||
if ((flags & RFSTOPPED) == 0) {
|
||||
/*
|
||||
@ -740,14 +744,6 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2,
|
||||
cv_wait(&p2->p_dbgwait, &p2->p_mtx);
|
||||
if (p2_held)
|
||||
_PRELE(p2);
|
||||
|
||||
/*
|
||||
* Preserve synchronization semantics of vfork. If waiting for
|
||||
* child to exec or exit, set P_PPWAIT on child, and sleep on our
|
||||
* proc (in case of exit).
|
||||
*/
|
||||
while (p2->p_flag & P_PPWAIT)
|
||||
cv_wait(&p2->p_pwait, &p2->p_mtx);
|
||||
PROC_UNLOCK(p2);
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ syscallenter(struct thread *td, struct syscall_args *sa)
|
||||
static inline void
|
||||
syscallret(struct thread *td, int error, struct syscall_args *sa __unused)
|
||||
{
|
||||
struct proc *p;
|
||||
struct proc *p, *p2;
|
||||
int traced;
|
||||
|
||||
p = td->td_proc;
|
||||
@ -223,4 +223,23 @@ syscallret(struct thread *td, int error, struct syscall_args *sa __unused)
|
||||
td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK);
|
||||
PROC_UNLOCK(p);
|
||||
}
|
||||
|
||||
if (td->td_pflags & TDP_RFPPWAIT) {
|
||||
/*
|
||||
* Preserve synchronization semantics of vfork. If
|
||||
* waiting for child to exec or exit, fork set
|
||||
* P_PPWAIT on child, and there we sleep on our proc
|
||||
* (in case of exit).
|
||||
*
|
||||
* Do it after the ptracestop() above is finished, to
|
||||
* not block our debugger until child execs or exits
|
||||
* to finish vfork wait.
|
||||
*/
|
||||
td->td_pflags &= ~TDP_RFPPWAIT;
|
||||
p2 = td->td_rfppwait_p;
|
||||
PROC_LOCK(p2);
|
||||
while (p2->p_flag & P_PPWAIT)
|
||||
cv_wait(&p2->p_pwait, &p2->p_mtx);
|
||||
PROC_UNLOCK(p2);
|
||||
}
|
||||
}
|
||||
|
@ -311,6 +311,7 @@ struct thread {
|
||||
struct vnet *td_vnet; /* (k) Effective vnet. */
|
||||
const char *td_vnet_lpush; /* (k) Debugging vnet push / pop. */
|
||||
struct trapframe *td_intr_frame;/* (k) Frame of the current irq */
|
||||
struct proc *td_rfppwait_p; /* (k) The vforked child */
|
||||
};
|
||||
|
||||
struct mtx *thread_lock_block(struct thread *);
|
||||
@ -415,6 +416,7 @@ do { \
|
||||
#define TDP_CALLCHAIN 0x00400000 /* Capture thread's callchain */
|
||||
#define TDP_IGNSUSP 0x00800000 /* Permission to ignore the MNTK_SUSPEND* */
|
||||
#define TDP_AUDITREC 0x01000000 /* Audit record pending on thread */
|
||||
#define TDP_RFPPWAIT 0x02000000 /* Handle RFPPWAIT on syscall exit */
|
||||
|
||||
/*
|
||||
* Reasons that the current thread can not be run yet.
|
||||
|
Loading…
Reference in New Issue
Block a user