Crate smelling_salts[][src]

Expand description

Getting Started

Add the following to your Cargo.toml.

[dependencies]
smelling_salts = "0.2"
pasts = "0.7"

Example

use smelling_salts::{Device, Watcher};
use std::future::Future;
use std::mem::MaybeUninit;
use std::os::raw;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;

#[repr(C)]
struct TimeSpec {
    sec: isize,
    nsec: raw::c_long,
}

#[repr(C)]
struct ITimerSpec {
    interval: TimeSpec,
    value: TimeSpec,
}

extern "C" {
    fn timerfd_create(clockid: raw::c_int, flags: raw::c_int) -> raw::c_int;
    fn timerfd_settime(
        fd: raw::c_int,
        flags: raw::c_int,
        new_value: *const ITimerSpec,
        old_value: *mut ITimerSpec,
    ) -> raw::c_int;
    fn read(fd: raw::c_int, buf: *mut u64, count: usize) -> isize;
    fn close(fd: raw::c_int) -> raw::c_int;
    fn __errno_location() -> *mut raw::c_int;
}

struct Sleep(Device, u64);

impl Sleep {
    fn new(dur: Duration) -> Self {
        let sec = dur.as_secs() as _;
        let nsec = dur.subsec_nanos() as _;

        let timerfd = unsafe {
            timerfd_create(1 /*Monotonic*/, 2048 /*Nonblock*/)
        };
        let x = unsafe {
            timerfd_settime(
                timerfd,
                0,
                &ITimerSpec {
                    interval: TimeSpec { sec, nsec },
                    value: TimeSpec { sec, nsec },
                },
                std::ptr::null_mut(),
            )
        };
        assert_eq!(0, x);

        Sleep(Device::new(timerfd, Watcher::new().input()), 0)
    }
}

impl Future for Sleep {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
        // Queue
        if self.1 != 0 {
            self.1 -= 1;
            return Poll::Ready(());
        }
        // Early return if a different device woke the executor.
        if self.0.pending() {
            return self.0.sleep(cx);
        }
        //
        let mut x = MaybeUninit::<u64>::uninit();
        let v = unsafe {
            read(self.0.raw(), x.as_mut_ptr(), std::mem::size_of::<u64>())
        };
        if v > 0 {
            self.1 += unsafe { x.assume_init() };
            self.poll(cx)
        } else {
            self.0.sleep(cx)
        }
    }
}

impl Drop for Sleep {
    fn drop(&mut self) {
        assert_eq!(0, unsafe { close(self.0.stop()) });
    }
}

fn main() {
    pasts::block_on(async {
        for _ in 0..5 {
            println!("Sleeping for 1 second…");
            Sleep::new(Duration::new(1, 0)).await;
        }
    });
}

Structs

Represents some device.

Which events to watch for to trigger a wake-up.

Type Definitions

On Linux, RawDevice corresponds to RawFd