1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
mod timeheap;
use futures_lite::future::FutureExt;
use once_cell::sync::Lazy;
use std::{
thread::JoinHandle,
time::{Duration, Instant},
};
use timeheap::TimeHeap;
static START: Lazy<Instant> = Lazy::new(Instant::now);
fn instant_to_epoch(i: Instant) -> u64 {
i.saturating_duration_since(*START).as_millis() as u64
}
fn epoch_to_instant(e: u64) -> Instant {
*START + Duration::from_millis(e)
}
static EVENT_QUEUE: Lazy<TimeHeap> = Lazy::new(Default::default);
static WAKER: Lazy<JoinHandle<()>> = Lazy::new(|| {
std::thread::Builder::new()
.name("microsleep".into())
.spawn(|| {
loop {
let now = instant_to_epoch(Instant::now());
EVENT_QUEUE.fire_before(now);
let earliest = EVENT_QUEUE.earliest_tick().unwrap_or(u64::MAX);
if earliest.saturating_sub(now) > 50 {
let wait = EVENT_QUEUE.wait_until_change();
let earliest = EVENT_QUEUE.earliest_tick().unwrap_or(u64::MAX);
let timer = async move {
async_io::Timer::at(epoch_to_instant(earliest)).await;
};
futures_lite::future::block_on(timer.race(wait));
} else {
spin_sleep::native_sleep(Duration::from_millis(1));
}
}
})
.unwrap()
});
pub async fn sleep(dur: Duration) {
until(Instant::now() + dur).await
}
pub async fn until(i: Instant) {
Lazy::force(&WAKER);
futures_lite::future::yield_now().await;
let epoch = instant_to_epoch(i);
if instant_to_epoch(Instant::now()) >= epoch {
return;
}
EVENT_QUEUE.subscribe(epoch).wait().await;
}