in reverie-ptrace/src/trace/mod.rs [977:1028]
fn trace<F>(f: F, options: Options) -> Result<(Pid, Stopped), Error>
where
F: FnOnce() -> i32,
{
match unsafe { fork() }.map_err(|err| err)? {
ForkResult::Parent { child, .. } => {
let mut running = Running::seize(child.into(), options)?;
// Keep consuming events until we reach a SIGSTOP or group stop.
let stopped = loop {
match running.wait()? {
Wait::Stopped(stopped, event) => {
if event == Event::Signal(Signal::SIGSTOP) || event == Event::Stop {
break stopped;
} else if let Event::Signal(sig) = event {
running = stopped.resume(Some(sig))?;
} else {
running = stopped.resume(None)?;
}
}
task => panic!("Got unexpected exit: {:?}", task),
}
};
Ok((stopped.pid(), stopped))
}
ForkResult::Child => {
// Create a new process group so we can wait on this process and
// every child more efficiently.
let _ = unsafe { libc::setpgid(0, 0) };
// Suppress core dumps for testing purposes.
let limit = libc::rlimit {
rlim_cur: 0,
rlim_max: 0,
};
let _ = unsafe { libc::setrlimit(libc::RLIMIT_CORE, &limit) };
// PTRACE_SEIZE is inherently racey, so we stop the child
// process here.
signal::raise(Signal::SIGSTOP).unwrap();
// Run the child when the process is resumed.
let exit_code = f();
// Note: We can't use the normal exit function here because we
// don't want to call atexit handlers since `execve` was never
// called.
let _ = unsafe { ::libc::_exit(exit_code) };
}
}
}