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:
Konstantin Belousov 2012-02-27 21:10:10 +00:00
parent 963a74f13c
commit 1d7ca9bb8e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=232240
3 changed files with 26 additions and 9 deletions

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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.