in reverie-ptrace/src/trace/mod.rs [1342:1406]
fn peeksiginfo_returns_pending_siginfo() -> Result<(), Box<dyn std::error::Error + 'static>> {
let (parent_pid, tracee) = trace(
move || {
let _ = unsafe {
block_signals(&[Signal::SIGALRM, Signal::SIGVTALRM, Signal::SIGPROF])
};
assert!(signal::raise(Signal::SIGALRM).is_ok());
assert!(signal::raise(Signal::SIGVTALRM).is_ok());
assert!(signal::raise(Signal::SIGPROF).is_ok());
// All threads should be alive at this point. SYS_exit_group
// should force all threads to exit.
let _ = unsafe { libc::syscall(libc::SYS_exit_group, 0) };
unreachable!()
},
Options::PTRACE_O_EXITKILL
| Options::PTRACE_O_TRACEEXIT
| ptrace::Options::PTRACE_O_TRACECLONE,
)?;
tracee.resume(None)?;
let mut exited = Vec::new();
// Keep consuming events until everything has exited.
while let Some(wait) = wait_group(parent_pid)? {
match wait {
Wait::Stopped(tracee, Event::Exit) => {
let pending: Vec<_> = tracee
.peeksiginfo(None)?
.iter()
.map(|&si| Signal::try_from(si.si_signo).unwrap())
.collect();
assert_eq!(
pending,
[Signal::SIGALRM, Signal::SIGVTALRM, Signal::SIGPROF]
);
// do a second peek here to demostrate peek doesn't
// *pop* pending signals.
let pending: Vec<_> = tracee
.peeksiginfo(None)?
.iter()
.map(|&si| Signal::try_from(si.si_signo).unwrap())
.collect();
assert_eq!(
pending,
[Signal::SIGALRM, Signal::SIGVTALRM, Signal::SIGPROF]
);
tracee.resume(None)?;
}
Wait::Stopped(tracee, _event) => {
tracee.resume(None)?;
}
Wait::Exited(pid, exit_status) => {
exited.push((pid, exit_status));
}
}
}
// The parent should have exited last
assert_eq!(exited.pop(), Some((parent_pid, ExitStatus::Exited(0))));
Ok(())
}