diff options
author | kib <kib@FreeBSD.org> | 2012-02-27 21:10:10 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2012-02-27 21:10:10 +0000 |
commit | 0c3998cc9e3ca0b91b97214b281c4549287bcca7 (patch) | |
tree | 288af65037796dba1ccb410821163bb5b70f55f7 /sys/kern/subr_syscall.c | |
parent | 57e2f851ed8c3cd5f35ee1d8ab0edc357c7137f1 (diff) | |
download | FreeBSD-src-0c3998cc9e3ca0b91b97214b281c4549287bcca7.zip FreeBSD-src-0c3998cc9e3ca0b91b97214b281c4549287bcca7.tar.gz |
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
Diffstat (limited to 'sys/kern/subr_syscall.c')
-rw-r--r-- | sys/kern/subr_syscall.c | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c index 9c4dd48..367ea67 100644 --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -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); + } } |