in reverie-ptrace/src/perf.rs [665:721]
fn deliver_signal() {
ret_without_perf!();
use std::mem::MaybeUninit;
use std::sync::mpsc::sync_channel;
let (tx1, rx1) = sync_channel(0); // send TID
let (tx2, rx2) = sync_channel(0); // start guest spinn
// SIGSTKFLT defaults to TERM, so if any thread but the traced one
// receives the signal, the test will fail due to process exit.
const MARKER_SIGNAL: Signal = Signal::SIGSTKFLT;
const SPIN_BRANCHES: u64 = 50000; // big enough to "absorb" noise from debug/release
const SPINS_PER_EVENT: u64 = 10;
const SAMPLE_PERIOD: u64 = SPINS_PER_EVENT * SPIN_BRANCHES + (SPINS_PER_EVENT / 4);
fn signal_is_pending() -> bool {
unsafe {
let mut mask = MaybeUninit::<libc::sigset_t>::zeroed();
libc::sigemptyset(mask.as_mut_ptr());
libc::sigpending(mask.as_mut_ptr());
libc::sigismember(mask.as_ptr(), MARKER_SIGNAL as _) == 1
}
}
let handle = std::thread::spawn(move || {
unsafe {
let mut mask = MaybeUninit::<libc::sigset_t>::zeroed();
libc::sigemptyset(mask.as_mut_ptr());
libc::sigaddset(mask.as_mut_ptr(), MARKER_SIGNAL as _);
libc::sigprocmask(libc::SIG_BLOCK, mask.as_ptr(), std::ptr::null_mut());
}
tx1.send(gettid()).unwrap();
rx2.recv().unwrap();
let mut count = 0;
loop {
count += 1;
do_branches(SPIN_BRANCHES);
if signal_is_pending() {
break;
}
}
assert_eq!(count, SPINS_PER_EVENT);
});
let tid = rx1.recv().unwrap();
let pc = Builder::new(tid.as_raw(), -1)
.sample_period(SAMPLE_PERIOD)
.event(Event::Hardware(HardwareEvent::BranchInstructions))
.create()
.unwrap();
pc.set_signal_delivery(tid.into(), MARKER_SIGNAL).unwrap();
pc.enable().unwrap();
tx2.send(()).unwrap(); // tell thread to start
handle.join().unwrap(); // propagate panics
}