cputimeout 0.1.0

a very unsafe way of time-outing a cpu-bounded task.
Documentation
use nix::libc::{
    clockid_t, gettid, sigaction, sigevent, siginfo_t, timer_create, timer_delete, timer_settime,
    timer_t, CLOCK_THREAD_CPUTIME_ID, SA_SIGINFO, SIGALRM, SIGEV_THREAD_ID,
};
use std::{ffi::c_void, time::Duration};

pub struct Watchdog {
    timer_id: timer_t,
    callback: *mut Box<dyn Fn()>,
}

type CallBack = Box<dyn Fn()>;

extern "C" fn handler(_: i32, info: &mut siginfo_t, _: *mut c_void) {
    let callback = unsafe { &mut *((info.si_value().sival_ptr) as *mut CallBack) };
    callback();
}

impl Watchdog {
    pub fn new(callback: CallBack) -> Self {
        let mut action: sigaction = unsafe { std::mem::zeroed() };
        action.sa_flags = SA_SIGINFO;
        action.sa_sigaction = handler as usize;
        unsafe { sigaction(SIGALRM, &action, std::ptr::null_mut()) };
        let tid = unsafe { gettid() };

        let clockid: clockid_t = CLOCK_THREAD_CPUTIME_ID;

        let mut timer_id: timer_t = unsafe { std::mem::zeroed() };

        let mut sev: sigevent = unsafe { std::mem::zeroed() };
        sev.sigev_notify = SIGEV_THREAD_ID;
        sev.sigev_signo = SIGALRM;
        sev.sigev_notify_thread_id = tid;
        let callback = Box::into_raw(Box::new(callback));
        sev.sigev_value.sival_ptr = callback as *mut c_void;
        unsafe { timer_create(clockid, &mut sev, &mut timer_id) };
        Watchdog { timer_id, callback }
    }

    pub fn arm(&self, timeout: Duration) -> bool {
        if timeout.is_zero() {
            return false;
        }
        let time = &mut unsafe { std::mem::zeroed::<nix::libc::itimerspec>() };
        time.it_value.tv_sec = timeout.as_secs() as _;
        time.it_value.tv_nsec = timeout.subsec_nanos() as _;
        unsafe {
            timer_settime(self.timer_id, 0, time, std::ptr::null_mut());
        }

        true
    }

    pub fn disarm(&self) {
        let time = &mut unsafe { std::mem::zeroed::<nix::libc::itimerspec>() };
        unsafe {
            timer_settime(self.timer_id, 0, time, std::ptr::null_mut());
        }
    }
}

impl Drop for Watchdog {
    fn drop(&mut self) {
        unsafe {
            timer_delete(self.timer_id);
            drop(Box::from_raw(self.callback));
        }
    }
}