benchy 0.1.1

Benchy is a crate for benchmarking long-running tasks
Documentation
#[cfg(unix)]
pub(crate) fn fork<T: serde::Serialize + serde::de::DeserializeOwned>(
    f: impl FnOnce() -> T,
) -> nix::Result<T> {
    let (read_fd, write_fd) = nix::unistd::pipe()?;

    match unsafe { nix::unistd::fork() }? {
        nix::unistd::ForkResult::Parent { child } => {
            let (received_bytes_sender, received_bytes_receiver) =
                std::sync::mpsc::channel::<bool>();
            let handle = std::thread::spawn(move || {
                nix::sys::wait::waitpid(child, None).unwrap();
                let received_bytes = received_bytes_receiver
                    .recv_timeout(std::time::Duration::from_secs(1))
                    .unwrap_or(false);

                if !received_bytes {
                    nix::unistd::write(write_fd, b"exited").unwrap();
                    return;
                }
            });

            let mut buff = [0u8; 8092];
            let len = nix::unistd::read(read_fd, &mut buff)?;

            let _ = received_bytes_sender.send(true);
            handle.join().unwrap();

            if &buff[..len] == b"panic" {
                panic!("Benchmark function panicked");
            } else if &buff[..len] == b"exited" {
                panic!("Benchmark function exited without sending benchmark data. The function may have ran out of memory and was killed by the OS.");
            }

            let t = serde_json::from_slice(&buff[..len]).unwrap();
            nix::unistd::close(read_fd)?;
            nix::unistd::close(write_fd)?;

            Ok(t)
        }
        nix::unistd::ForkResult::Child => {
            std::panic::set_hook({
                let default_hook = std::panic::take_hook();
                Box::new(move |panic_info| {
                    nix::unistd::write(write_fd, b"panic").unwrap();
                    default_hook(panic_info);
                })
            });

            let t = f();
            let t_json = serde_json::to_string(&t).unwrap();
            nix::unistd::write(write_fd, t_json.as_bytes())?;

            std::process::exit(0);
        }
    }
}

#[cfg(not(unix))]
pub(crate) fn fork<T: serde::Serialize + serde::de::DeserializeOwned>(
    f: impl FnOnce() -> T,
) -> nix::Result<T> {
    Ok(f())
}