Open dvdsk opened 1 year ago
Each of the three options has its downsides:
Sleep is not consistent between platforms. For example on Linux time suspended is not counted while on other Unixes it is. Not counting time suspended is a bad default, kernel devs tried to fix, which caused enough issues it was reverted soon after. That just underlines the need to get this right before stabilizing.
Using a different clock could get confusing, for example when the time slept
by sleep_until was different from what a sleep call would yield. Finally, if
the argument is of type Instant
then the time slept should match what
Instant::elapsed
reports. It currently uses the Monotonic clock on all
platforms.
Making the clock a choice, means designing a new clock API (proposed in the
APC by @the8472). It would make 'sleep_until' more complex to use and breaks
the similarity between it and sleep
.
I think the clock question is not constrained to sleep_until
. There are more
APIs that could support configurable clocks. I propose we separate that question
from sleep_until
and address it in its own APC.
There we can figure out:
I would love to write a Pre-Rfc for such an API if we decide to go that route.
I am in favor of using Instant
, that implies monotonic behavior which is
needed for most use cases (cache invalidation etc.). We could offer a version
that can take a SystemTime
as argument. I am not aware of any use cases for
that though I would love to hear them.
If we decide to support both we need to figure out if we want two functions or
a generic argument. The latter would involve introducing a trait, maybe
Deadline
?
Are there OS APIs that support sleeping to a deadline? The current implementation will have large tail latencies:
let now = Instant::now();
if let Some(delay) = deadline.checked_duration_since(now) {
// Context switch here. Oops, now we'll end up arbitrarily blowing past the deadline
sleep(delay);
}
There's clock_nanosleep
that supports deadlines, it has been part of POSIX for a while so I assume a lot of unices have it.
We could offer a version that can take a SystemTime as argument. I am not aware of any use cases for that though I would love to hear them.
Wall-time based synchronization/execution of events. E.g. if something is supposed to run in a cronjob-like fashion. Or a distributed protocol that says "nodes try to rendezvous every 5 minutes, at the start of a minute divisible by 5, UTC".
There's
clock_nanosleep
that supports deadlines, it has been part of POSIX for a while so I assume a lot of unices have it.
Thanks for bringing this up! We can freely use that on Linux, the minimum kernel version current Rust supports includes it. I would have to check it for POSIX. Even if that does not pan out we should 'specialize' this method on Linux.
Before we go down that road I would like to nail down the API. To answer that we must know whether we want a Clock API in Rust. That however is better addressed in a separate proposal. I am more then willing to write that up however I would like to estimate interest first.
I am not sure how to proceed there, an option would be to create a crate that adds a clock API to std-lib functions/types where appropriate (using traits). Then look at how popular that gets over time. (taking care to prevent an itertools situation). Another easier path would be a users forum post or github code search.
You could also look at prior art in other languages and frequently used libraries. E.g. C++ has it std::chrono.
There's
clock_nanosleep
that supports deadlines, it has been part of POSIX for a while so I assume a lot of unices have it.
macOS and the other Apple platforms don't have it, even on the newest versions.
There seems to be a function called mach_wait_until
but I can't find any docs for it.
Replying to @neachdainn who commented on the RFC
I just want to point out that the proposed solution isn't a full.
It's temporary, the idea was to see if we could take the clock choice further and introduce a clock API. That would allow use of clocks that are not supported on each platform (such as clock BOOTTIME
). Unfortunately I haven't done that yet.
I am gonna paraphrase your use case here, I think it is an important one:
use case: running a robotic control. Using an OS. Need to make sure that the thread is going to wake up at exactly the specified time:
fn run() { let deadline = Instant::now() + INTERVAL; loop { do_quick_calculation_and_set_pins(); thread::sleep_until(deadline); deadline += INTERVAL; } }
As it is critical to the above use case I will open a PR to switch over the placeholder implementation for Linux to use clock_nanosleep
with TIMER_ABSTIME
. We should also document the behavior when using real time schedulers.
Then I will see if we can get the same behavior on the other operation systems.
This is a tracking comment tracking the effort to specialize/optimizing the sleep_until
implementation for major target_os's.
SubscriptionClock
and flag ABSTIME
@dvdsk Clock Nano sleep is available in libc for VxWorks.
Feature gate:
#![feature(sleep_until)]
This is a tracking issue for the
thread::sleep_until
method. It pauses the current thread until a given deadline.Public API
Steps / History
Unresolved Questions
thread::sleep
, something different or passed in by the user?Instant
, aSystemTime
or do we support both?