diff options
| author | David Lönnhager <david.l@mullvad.net> | 2022-04-08 10:01:31 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2022-04-11 13:09:58 +0200 |
| commit | bdf327cfa3a482b4b8dd336f61fdc644f55d3f21 (patch) | |
| tree | ed7e1bd727d39bf12aa2460817dd5eebaaf427c3 /talpid-time | |
| parent | 744fb04aa9e7180f37c00d63cd8d068fb04882b1 (diff) | |
| download | mullvadvpn-bdf327cfa3a482b4b8dd336f61fdc644f55d3f21.tar.xz mullvadvpn-bdf327cfa3a482b4b8dd336f61fdc644f55d3f21.zip | |
Add talpid-time crate
Diffstat (limited to 'talpid-time')
| -rw-r--r-- | talpid-time/Cargo.toml | 12 | ||||
| -rw-r--r-- | talpid-time/src/lib.rs | 53 | ||||
| -rw-r--r-- | talpid-time/src/unix.rs | 58 |
3 files changed, 123 insertions, 0 deletions
diff --git a/talpid-time/Cargo.toml b/talpid-time/Cargo.toml new file mode 100644 index 0000000000..754007e84a --- /dev/null +++ b/talpid-time/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "talpid-time" +version = "0.1.0" +authors = ["Mullvad VPN"] +description = "Time functions" +license = "GPL-3.0" +edition = "2021" +publish = false + +[dependencies] +tokio = { version = "1.8", features = ["time"] } +libc = "0.2" diff --git a/talpid-time/src/lib.rs b/talpid-time/src/lib.rs new file mode 100644 index 0000000000..3b536eda54 --- /dev/null +++ b/talpid-time/src/lib.rs @@ -0,0 +1,53 @@ +use std::time::Duration; + +#[cfg(target_os = "windows")] +mod inner { + pub use std::time::Instant; +} + +#[cfg(unix)] +#[path = "unix.rs"] +mod inner; + +const MAX_SLEEP_INTERVAL: Duration = Duration::from_secs(60); + +/// Represents a measurement of a monotonic clock. +/// Unlike [std::time::Instant], the difference between two +/// instances is guaranteed to include time spent in system +/// sleep. +#[derive(Clone, Copy)] +pub struct Instant { + t: inner::Instant, +} + +impl Instant { + pub fn now() -> Self { + Self { + t: inner::Instant::now(), + } + } + + pub fn duration_since(&self, earlier: Instant) -> Duration { + self.t.duration_since(earlier.t) + } +} + +/// Waits for the specified interval while taking into account system sleep or suspension. +/// The accuracy is to within about one minute. +pub async fn sleep(duration: Duration) { + let started = Instant::now(); + + loop { + let elapsed = Instant::now().duration_since(started); + + if elapsed >= duration { + return; + } + + tokio::time::sleep(std::cmp::min( + MAX_SLEEP_INTERVAL, + duration.saturating_sub(elapsed), + )) + .await; + } +} diff --git a/talpid-time/src/unix.rs b/talpid-time/src/unix.rs new file mode 100644 index 0000000000..b9721dd27a --- /dev/null +++ b/talpid-time/src/unix.rs @@ -0,0 +1,58 @@ +use libc::{clock_gettime, clockid_t, timespec}; +use std::{mem::MaybeUninit, time::Duration}; + +const NSEC_PER_SEC: i64 = 1000000000; + +#[cfg(target_os = "macos")] +const CLOCK_ID: clockid_t = libc::CLOCK_MONOTONIC; + +#[cfg(any(target_os = "linux", target_os = "android"))] +const CLOCK_ID: clockid_t = libc::CLOCK_BOOTTIME; + +#[derive(Clone, Copy)] +pub struct Instant { + t: timespec, +} + +impl Instant { + pub fn now() -> Self { + Self { t: now() } + } + + fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> { + // Assumptions: + // * `tv_sec >= 0` + // * `tv_nsec < NSEC_PER_SEC` + + let (tv_sec, tv_nsec) = if self.t.tv_nsec < earlier.t.tv_nsec { + ( + self.t.tv_sec - earlier.t.tv_sec - 1, + NSEC_PER_SEC - earlier.t.tv_nsec + self.t.tv_nsec, + ) + } else { + ( + self.t.tv_sec - earlier.t.tv_sec, + self.t.tv_nsec - earlier.t.tv_nsec, + ) + }; + + if tv_sec < 0 { + return None; + } + + Some(Duration::new(tv_sec as _, tv_nsec as _)) + } + + pub fn duration_since(&self, earlier: Instant) -> Duration { + self.checked_duration_since(earlier) + .unwrap_or(Duration::ZERO) + } +} + +fn now() -> timespec { + let mut t = MaybeUninit::zeroed(); + unsafe { + clock_gettime(CLOCK_ID, t.as_mut_ptr()); + t.assume_init() + } +} |
