hey fyi tokio::time::sleep is only good down to ms resolutions, for more granularity we typically need something nanosleep or a hot loop, so this implementation won't be accurate for anything less than a couple of ms.
having had to solve this a couple of times i suspect a more accurate way to do this would involve using epoll_wait with a timeout for > 1us delays (more accurate kernel timing than sleep is, particularly under the tokio runtime) and a hot loop over Instant::elapsed() for > 1ns delays (check elapsed and hit the waker every round).
possibly combining both into something like:
let now = Instant::now()
loop {
// Grab elapsed at the start of the loop
let elapsed = now.elapsed();
// Break once we exceed the delay duration
if elapsed > duration {
break;
}
// Calculate the remaining sleep time
let remainder = duration - elapsed;
// epoll or spin depending on remainder
if remainder > Duration::from_millis(1) {
epoll_sleep().await;
} else {
spin_sleep().await;
}
}
>
> some folks do [more complex things](https://crates.io/crates/spin_sleep) to balance accuracy and cpu use, but, this is fairly straightforward and would be closer to operating as intended.
(it's also good to keep track of elapsed times because there are _reasons_ a sleep might end early, which has caused problems for me in the past)
_Originally posted by @ryankurte in https://github.com/rust-embedded/linux-embedded-hal/issues/109#issuecomment-1913732707_
// Break once we exceed the delay duration if elapsed > duration { break; }
// Calculate the remaining sleep time let remainder = duration - elapsed;
// epoll or spin depending on remainder if remainder > Duration::from_millis(1) { epoll_sleep().await; } else { spin_sleep().await; } }