aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/kern_fork.c
diff options
context:
space:
mode:
authorMateusz Guzik <mjg@FreeBSD.org>2018-12-19 20:27:26 +0000
committerMateusz Guzik <mjg@FreeBSD.org>2018-12-19 20:27:26 +0000
commit7d065d876e1e220bcd4f0f9a833b07b7a61bcd4e (patch)
treee77b79806bc3ea325538972f2c8a3656b88ab15d /sys/kern/kern_fork.c
parent1ea91370aee7a939446e29391ee4e706c83356be (diff)
downloadsrc-7d065d876e1e220bcd4f0f9a833b07b7a61bcd4e.tar.gz
src-7d065d876e1e220bcd4f0f9a833b07b7a61bcd4e.zip
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
Notes
Notes: svn path=/head/; revision=342236
Diffstat (limited to 'sys/kern/kern_fork.c')
-rw-r--r--sys/kern/kern_fork.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index acba58b89c8f..f897f78b48ca 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -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)
{