Deinline vfork handling out of the syscall return path.

vfork is rarely called (comparatively to other syscalls) and it avoidably
pollutes the fast path.

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
mjg 2018-12-19 20:27:26 +00:00
parent 53ce85a9e3
commit 94437ac557
3 changed files with 49 additions and 38 deletions

View File

@ -757,6 +757,51 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread *
}
}
void
fork_rfppwait(struct thread *td)
{
struct proc *p, *p2;
MPASS(td->td_pflags & TDP_RFPPWAIT);
p = td->td_proc;
/*
* 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;
again:
PROC_LOCK(p2);
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);
if (td->td_dbgflags & TDB_VFORK) {
PROC_LOCK(p);
if (p->p_ptevents & PTRACE_VFORK)
ptracestop(td, SIGTRAP, NULL);
td->td_dbgflags &= ~TDB_VFORK;
PROC_UNLOCK(p);
}
}
int
fork1(struct thread *td, struct fork_req *fr)
{

View File

@ -165,7 +165,7 @@ syscallenter(struct thread *td)
static inline void
syscallret(struct thread *td, int error)
{
struct proc *p, *p2;
struct proc *p;
struct syscall_args *sa;
ksiginfo_t ksi;
int traced, error1;
@ -230,41 +230,6 @@ syscallret(struct thread *td, int error)
PROC_UNLOCK(p);
}
if (__predict_false(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;
again:
PROC_LOCK(p2);
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);
if (td->td_dbgflags & TDB_VFORK) {
PROC_LOCK(p);
if (p->p_ptevents & PTRACE_VFORK)
ptracestop(td, SIGTRAP, NULL);
td->td_dbgflags &= ~TDB_VFORK;
PROC_UNLOCK(p);
}
}
if (__predict_false(td->td_pflags & TDP_RFPPWAIT))
fork_rfppwait(td);
}

View File

@ -1026,6 +1026,7 @@ int enterthispgrp(struct proc *p, struct pgrp *pgrp);
void faultin(struct proc *p);
void fixjobc(struct proc *p, struct pgrp *pgrp, int entering);
int fork1(struct thread *, struct fork_req *);
void fork_rfppwait(struct thread *);
void fork_exit(void (*)(void *, struct trapframe *), void *,
struct trapframe *);
void fork_return(struct thread *, struct trapframe *);