fix: Patch coarsetime for MIPS AtomicU64 support

- Vendor coarsetime crate with portable-atomic fallback
- Use portable-atomic on targets without 64-bit atomics
- Patch crates.io to use local coarsetime
- Fixes MIPS build failure (AtomicU64 missing)
This commit is contained in:
spinline
2026-02-06 00:20:51 +03:00
parent 25e2b6bec9
commit e8af1a1812
19 changed files with 1225 additions and 2 deletions

93
third_party/coarsetime/src/clock.rs vendored Normal file
View File

@@ -0,0 +1,93 @@
#[cfg(not(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown"
)))]
use std::time;
#[cfg(target_has_atomic = "64")]
use std::sync::atomic::{AtomicU64, Ordering};
#[cfg(not(target_has_atomic = "64"))]
use portable_atomic::{AtomicU64, Ordering};
use super::Duration;
static RECENT: AtomicU64 = AtomicU64::new(0);
#[cfg(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown"
))]
mod js_imports {
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
pub type Date;
#[wasm_bindgen(static_method_of = Date)]
pub fn now() -> f64;
}
}
/// System time
#[derive(Debug)]
pub struct Clock;
/// Alias for `Duration`.
pub type UnixTimeStamp = Duration;
impl Clock {
/// Returns the elapsed time since the UNIX epoch
#[inline]
pub fn now_since_epoch() -> UnixTimeStamp {
Duration::from_u64(unix_ts())
}
/// Returns the elapsed time since the UNIX epoch, based on the latest
/// explicit time update
#[inline]
pub fn recent_since_epoch() -> UnixTimeStamp {
Duration::from_u64(RECENT.load(Ordering::Relaxed))
}
/// Updates the cached system time.
///
/// This function should be called frequently, for example in an event loop
/// or using an `Updater` task.
#[inline]
pub fn update() {
let now = unix_ts();
RECENT.store(now, Ordering::Relaxed)
}
/// Sets the cached system time to the specified timestamp.
/// This function is intended for testing purposes only.
/// It should not be used in production code.
pub fn set_recent_since_epoch(recent: UnixTimeStamp) {
RECENT.store(recent.as_u64(), Ordering::Relaxed)
}
}
#[cfg(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown"
))]
#[inline]
fn unix_ts() -> u64 {
let unix_ts_now_sys = (js_imports::Date::now() / 1000.0).round() as u64;
let unix_ts_now = Duration::from_secs(unix_ts_now_sys);
unix_ts_now.as_u64()
}
#[cfg(not(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown"
)))]
#[inline]
fn unix_ts() -> u64 {
let unix_ts_now_sys = time::SystemTime::now()
.duration_since(time::UNIX_EPOCH)
.expect("The system clock is not properly set");
let unix_ts_now = Duration::from(unix_ts_now_sys);
unix_ts_now.as_u64()
}

270
third_party/coarsetime/src/duration.rs vendored Normal file
View File

@@ -0,0 +1,270 @@
use std::convert::From;
use std::ops::*;
use std::time;
use super::helpers::*;
/// A duration type to represent an approximate span of time
#[derive(Copy, Clone, Debug, Hash, Ord, Eq, PartialOrd, PartialEq, Default)]
pub struct Duration(u64);
impl Duration {
/// Creates a new `Duration` from the specified number of seconds and
/// additional nanosecond precision
#[inline]
pub const fn new(sec: u64, nanos: u32) -> Duration {
Duration(_timespec_to_u64(sec, nanos))
}
/// Creates a new Duration from the specified number of days
#[inline]
pub const fn from_days(days: u64) -> Duration {
Duration(_sec_to_u64(days * 86400))
}
/// Creates a new Duration from the specified number of hours
#[inline]
pub const fn from_hours(hours: u64) -> Duration {
Duration(_sec_to_u64(hours * 3600))
}
/// Creates a new Duration from the specified number of minutes
#[inline]
pub const fn from_mins(mins: u64) -> Duration {
Duration(_sec_to_u64(mins * 60))
}
/// Creates a new Duration from the specified number of seconds
#[inline]
pub const fn from_secs(secs: u64) -> Duration {
Duration(_sec_to_u64(secs))
}
/// Creates a new Duration from the specified number of milliseconds
#[inline]
pub const fn from_millis(millis: u64) -> Duration {
Duration(_millis_to_u64(millis))
}
/// Returns the number of days represented by this duration
#[inline]
pub const fn as_days(&self) -> u64 {
self.as_secs() / 86400
}
/// Returns the number of hours represented by this duration
#[inline]
pub const fn as_hours(&self) -> u64 {
self.as_secs() / 3600
}
/// Returns the number of minutes represented by this duration
#[inline]
pub const fn as_mins(&self) -> u64 {
self.as_secs() / 60
}
/// Returns the number of whole seconds represented by this duration
#[inline]
pub const fn as_secs(&self) -> u64 {
self.0 >> 32
}
/// Returns the number of whole milliseconds represented by this duration
#[inline]
pub const fn as_millis(&self) -> u64 {
((self.0 as u128 * 125) >> 29) as u64
}
/// Returns the number of whole microseconds represented by this duration
#[inline]
pub const fn as_micros(&self) -> u64 {
((self.0 as u128 * 125_000) >> 29) as u64
}
/// Returns the number of whole nanoseconds represented by this duration
#[inline]
pub const fn as_nanos(&self) -> u64 {
((self.0 as u128 * 125_000_000) >> 29) as u64
}
/// Returns the nanosecond precision represented by this duration
#[inline]
pub const fn subsec_nanos(&self) -> u32 {
((self.0 as u32 as u64 * 125_000_000) >> 29) as u32
}
/// Return this duration as a number of "ticks".
///
/// Note that length of a 'tick' is not guaranteed to represent
/// the same amount of time across different platforms, or from
/// one version of `coarsetime` to another.
#[inline]
pub const fn as_ticks(&self) -> u64 {
self.as_u64()
}
/// Creates a new Duration from the specified number of "ticks".
///
/// Note that length of a 'tick' is not guaranteed to represent
/// the same amount of time across different platforms, or from
/// one version of `coarsetime` to another.
#[inline]
pub const fn from_ticks(ticks: u64) -> Duration {
Self::from_u64(ticks)
}
#[doc(hidden)]
#[inline]
pub const fn as_u64(&self) -> u64 {
self.0
}
#[doc(hidden)]
#[inline]
pub const fn from_u64(ts: u64) -> Duration {
Duration(ts)
}
/// Returns the duration as a floating point number, representing the number
/// of seconds
#[inline]
pub fn as_f64(&self) -> f64 {
(self.0 as f64) / ((1u64 << 32) as f64)
}
/// Returns the absolute difference between two `Duration`s
#[inline]
pub const fn abs_diff(&self, other: Duration) -> Duration {
Duration(self.0.abs_diff(other.0))
}
/// Add two durations, saturating on overflow
#[inline]
pub const fn saturating_add(self, rhs: Duration) -> Duration {
Duration(self.0.saturating_add(rhs.0))
}
/// Add two durations, returning `None` on overflow
#[inline]
pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
self.0.checked_add(rhs.0).map(Duration)
}
/// Subtract two durations, saturating on underflow/overflow
#[inline]
pub const fn saturating_sub(self, rhs: Duration) -> Duration {
Duration(self.0.saturating_sub(rhs.0))
}
/// Subtract two durations, returning `None` on underflow/overflow
#[inline]
pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
self.0.checked_sub(rhs.0).map(Duration)
}
/// Multiply a duration by a scalar, saturating on overflow
#[inline]
pub const fn saturating_mul(self, rhs: u32) -> Duration {
Duration(self.0.saturating_mul(rhs as u64))
}
/// Multiply a duration by a scalar, returning `None` on overflow
#[inline]
pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
self.0.checked_mul(rhs as u64).map(Duration)
}
/// Divide a duration by a scalar, returning `None` for division by zero
#[inline]
pub fn checked_div(self, rhs: u32) -> Option<Duration> {
self.0.checked_div(rhs as u64).map(Duration)
}
}
#[doc(hidden)]
impl From<u64> for Duration {
#[doc(hidden)]
#[inline]
fn from(ts: u64) -> Duration {
Duration::from_u64(ts)
}
}
impl Add for Duration {
type Output = Duration;
#[inline]
fn add(self, rhs: Duration) -> Duration {
Duration(self.0 + rhs.0)
}
}
impl AddAssign for Duration {
#[inline]
fn add_assign(&mut self, rhs: Duration) {
*self = *self + rhs;
}
}
impl Sub for Duration {
type Output = Duration;
#[inline]
fn sub(self, rhs: Duration) -> Duration {
Duration(self.0 - rhs.0)
}
}
impl SubAssign for Duration {
#[inline]
fn sub_assign(&mut self, rhs: Duration) {
*self = *self - rhs;
}
}
impl Mul<u32> for Duration {
type Output = Duration;
#[inline]
fn mul(self, rhs: u32) -> Duration {
Duration(self.0 * rhs as u64)
}
}
impl MulAssign<u32> for Duration {
#[inline]
fn mul_assign(&mut self, rhs: u32) {
*self = *self * rhs;
}
}
impl Div<u32> for Duration {
type Output = Duration;
#[inline]
fn div(self, rhs: u32) -> Duration {
Duration(self.0 / rhs as u64)
}
}
impl DivAssign<u32> for Duration {
#[inline]
fn div_assign(&mut self, rhs: u32) {
*self = *self / rhs;
}
}
impl From<Duration> for time::Duration {
#[inline]
fn from(duration: Duration) -> time::Duration {
time::Duration::new(duration.as_secs(), duration.subsec_nanos())
}
}
impl From<time::Duration> for Duration {
#[inline]
fn from(duration_sys: time::Duration) -> Duration {
Duration::new(duration_sys.as_secs(), duration_sys.subsec_nanos())
}
}

26
third_party/coarsetime/src/helpers.rs vendored Normal file
View File

@@ -0,0 +1,26 @@
#[inline]
pub const fn _sec_to_u64(sec: u64) -> u64 {
sec.saturating_mul(1 << 32)
}
#[inline]
pub const fn _millis_to_u64(millis: u64) -> u64 {
let secs = millis / 1_000;
secs.saturating_mul(1 << 32) | ((millis - secs * 1_000) << 22)
}
#[inline]
pub const fn _nsecs_to_u64(nsecs: u64) -> u64 {
let secs = nsecs / 1_000_000_000;
_timespec_to_u64(secs, (nsecs - secs * 1_000_000_000) as u32)
}
#[inline]
pub const fn _timespec_to_u64(tp_sec: u64, tp_nsec: u32) -> u64 {
tp_sec.saturating_mul(1 << 32) | ((tp_nsec as u64 * 9_223_372_037) >> 31)
}
#[inline]
pub const fn _timeval_to_u64(tv_sec: u64, tv_usec: u32) -> u64 {
tv_sec.saturating_mul(1 << 32) | ((tv_usec as u64 * 9_223_372_036_855) >> 31)
}

335
third_party/coarsetime/src/instant.rs vendored Normal file
View File

@@ -0,0 +1,335 @@
#[allow(unused_imports)]
use std::mem::MaybeUninit;
use std::ops::*;
#[allow(unused_imports)]
use std::ptr::*;
#[cfg(target_has_atomic = "64")]
use std::sync::atomic::{AtomicU64, Ordering};
#[cfg(not(target_has_atomic = "64"))]
use portable_atomic::{AtomicU64, Ordering};
use super::duration::*;
#[allow(unused_imports)]
use super::helpers::*;
/// A measurement of a *monotonically* increasing clock.
/// Opaque and useful only with `Duration`.
///
/// Resulting durations are actual durations; they do not get affected by
/// clock adjustments, leap seconds, or similar.
/// In order to get a measurement of the *wall clock*, use `Date` instead.
#[derive(Copy, Clone, Debug, Hash, Ord, Eq, PartialOrd, PartialEq)]
pub struct Instant(u64);
static RECENT: AtomicU64 = AtomicU64::new(0);
#[cfg(windows)]
extern "system" {
pub fn GetTickCount64() -> libc::c_ulonglong;
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
#[allow(non_camel_case_types)]
type clockid_t = libc::c_int;
#[cfg(target_os = "macos")]
const CLOCK_MONOTONIC_RAW_APPROX: clockid_t = 5;
#[cfg(target_os = "macos")]
extern "system" {
fn clock_gettime_nsec_np(clk_id: clockid_t) -> u64;
}
#[cfg(target_os = "freebsd")]
const CLOCK_MONOTONIC_FAST: clockid_t = 12;
#[cfg(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown"
))]
mod js_imports {
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[allow(non_camel_case_types)]
pub type performance;
#[wasm_bindgen(static_method_of = performance)]
pub fn now() -> f64;
}
}
impl Instant {
/// Returns an instant corresponding to "now"
///
/// This function also updates the stored instant.
pub fn now() -> Instant {
let now = Self::_now();
Self::_update(now);
Instant(now)
}
/// Returns an instant corresponding to "now" without updating the cached value.
/// After this, `recent()` will still return the old instant.
///
/// `now()` is generally preferred over this function.
pub fn now_without_cache_update() -> Instant {
let now = Self::_now();
Instant(now)
}
/// Returns an instant corresponding to the latest update
pub fn recent() -> Instant {
match Self::_recent() {
0 => Instant::now(),
recent => Instant(recent),
}
}
/// Update the stored instant
///
/// This function should be called frequently, for example in an event loop
/// or using an `Updater` task.
pub fn update() {
let now = Self::_now();
Self::_update(now);
}
/// Returns the amount of time elapsed from another instant to this one
#[inline]
pub fn duration_since(&self, earlier: Instant) -> Duration {
*self - earlier
}
/// Returns the amount of time elapsed between the this instant was created
/// and the latest update
#[inline]
pub fn elapsed_since_recent(&self) -> Duration {
Self::recent() - *self
}
/// Returns the amount of time elapsed since this instant was created
///
/// This function also updates the stored instant.
#[inline]
pub fn elapsed(&self) -> Duration {
Self::now() - *self
}
/// Return a representation of this instant as a number of "ticks".
///
/// Note that length of a 'tick' is not guaranteed to represent
/// the same amount of time across different platforms, or from
/// one version of `coarsetime` to another.
///
/// Note also that the instant represented by "0" ticks is
/// unspecified. It is not guaranteed to be the same time across
/// different platforms, or from one version of `coarsetime` to
/// another.
///
/// This API is mainly intended for applications that need to
/// store the value of an `Instant` in an
/// [`AtomicU64`](std::sync::atomic::AtomicU64).
#[inline]
pub const fn as_ticks(&self) -> u64 {
self.as_u64()
}
/// Create an `Instant` from a number of "ticks".
///
/// Note that length of a 'tick' is not guaranteed to represent
/// the same amount of time across different platforms, or from
/// one version of `coarsetime` to another.
///
/// Note also that the instant represented by "0" ticks is
/// unspecified. It is not guaranteed to be the same time across
/// different platforms, or from one version of `coarsetime` to
/// another.
#[inline]
pub const fn from_ticks(ticks: u64) -> Instant {
Self::from_u64(ticks)
}
#[doc(hidden)]
#[inline]
pub const fn as_u64(&self) -> u64 {
self.0
}
#[doc(hidden)]
#[inline]
pub const fn from_u64(ts: u64) -> Instant {
Instant(ts)
}
/// Calculate an `Instant` that is a `Duration` later, saturating on overflow
#[inline]
pub const fn saturating_add(self, rhs: Duration) -> Instant {
Instant(self.0.saturating_add(rhs.as_u64()))
}
/// Calculate an `Instant` that is a `Duration` later, returning `None` on overflow
#[inline]
pub fn checked_add(self, rhs: Duration) -> Option<Instant> {
self.0.checked_add(rhs.as_u64()).map(Instant)
}
/// Calculate an `Instant` that is a `Duration` earlier, saturating on underflow
#[inline]
pub const fn saturating_sub(self, rhs: Duration) -> Instant {
Instant(self.0.saturating_sub(rhs.as_u64()))
}
/// Calculate an `Instant` that is a `Duration` earlier, returning `None` on underflow
#[inline]
pub fn checked_sub(self, rhs: Duration) -> Option<Instant> {
self.0.checked_sub(rhs.as_u64()).map(Instant)
}
#[cfg(any(target_os = "linux", target_os = "android"))]
fn _now() -> u64 {
let mut tp = MaybeUninit::<libc::timespec>::uninit();
let tp = unsafe {
libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr());
tp.assume_init()
};
_timespec_to_u64(tp.tv_sec as u64, tp.tv_nsec as u32)
}
#[cfg(target_os = "macos")]
fn _now() -> u64 {
let nsec = unsafe { clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW_APPROX) };
_nsecs_to_u64(nsec)
}
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
fn _now() -> u64 {
let mut tp = MaybeUninit::<libc::timespec>::uninit();
let tp = unsafe {
libc::clock_gettime(libc::CLOCK_MONOTONIC_FAST, tp.as_mut_ptr());
tp.assume_init()
};
_timespec_to_u64(tp.tv_sec as u64, tp.tv_nsec as u32)
}
#[cfg(all(
unix,
not(any(
target_os = "macos",
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "dragonfly"
))
))]
fn _now() -> u64 {
let mut tv = MaybeUninit::<libc::timeval>::uninit();
let tv = unsafe {
libc::gettimeofday(tv.as_mut_ptr(), null_mut());
tv.assume_init()
};
_timeval_to_u64(tv.tv_sec as u64, tv.tv_usec as u32)
}
#[cfg(windows)]
fn _now() -> u64 {
let tc = unsafe { GetTickCount64() } as u64;
_millis_to_u64(tc)
}
#[cfg(all(target_os = "wasi", not(feature = "wasi-abi2")))]
fn _now() -> u64 {
use wasix::{clock_time_get, CLOCKID_MONOTONIC, CLOCKID_REALTIME};
let nsec = unsafe { clock_time_get(CLOCKID_MONOTONIC, 1_000_000) }
.or_else(|_| unsafe { clock_time_get(CLOCKID_REALTIME, 1_000_000) })
.expect("Clock not available");
_nsecs_to_u64(nsec)
}
#[cfg(all(target_os = "wasi", feature = "wasi-abi2"))]
fn _now() -> u64 {
let nsec = wasi_abi2::clocks::monotonic_clock::now();
_nsecs_to_u64(nsec)
}
#[cfg(all(
any(target_arch = "wasm32", target_arch = "wasm64"),
target_os = "unknown"
))]
fn _now() -> u64 {
_millis_to_u64(js_imports::performance::now() as u64)
}
#[cfg(all(target_arch = "x86_64", target_env = "sgx", target_vendor = "fortanix"))]
fn _now() -> u64 {
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap();
timestamp.as_secs() * 1_000_000_000 + (timestamp.subsec_nanos() as u64)
}
#[inline]
fn _update(now: u64) {
RECENT.store(now, Ordering::Relaxed)
}
#[inline]
fn _recent() -> u64 {
let recent = RECENT.load(Ordering::Relaxed);
if recent != 0 {
recent
} else {
let now = Self::_now();
Self::_update(now);
Self::_recent()
}
}
}
impl Default for Instant {
fn default() -> Instant {
Self::now()
}
}
impl Sub<Instant> for Instant {
type Output = Duration;
#[inline]
fn sub(self, other: Instant) -> Duration {
Duration::from_u64(self.0.saturating_sub(other.0))
}
}
impl Sub<Duration> for Instant {
type Output = Instant;
#[inline]
fn sub(self, rhs: Duration) -> Instant {
Instant(self.0 - rhs.as_u64())
}
}
impl SubAssign<Duration> for Instant {
#[inline]
fn sub_assign(&mut self, rhs: Duration) {
*self = *self - rhs;
}
}
impl Add<Duration> for Instant {
type Output = Instant;
#[inline]
fn add(self, rhs: Duration) -> Instant {
Instant(self.0 + rhs.as_u64())
}
}
impl AddAssign<Duration> for Instant {
#[inline]
fn add_assign(&mut self, rhs: Duration) {
*self = *self + rhs;
}
}

37
third_party/coarsetime/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,37 @@
//! A crate to make time measurements that focuses on speed.
//!
//! This crate is a partial replacement for the `Time` and `Duration` structures
//! from the standard library, with the following differences:
//!
//! * Speed is privileged over accuracy. In particular, `CLOCK_MONOTONIC_COARSE`
//! is used to retrieve the clock value on Linux systems, and transformations avoid
//! operations that can be slow on non-Intel systems.
//! * The number of system calls can be kept to a minimum. The "most recent
//! timestamp" is always kept in memory.
//! It can be read with just a load operation, and can be
//! updated only as frequently as necessary.
//!
//! # Installation
//!
//! `coarsetime` is available on [crates.io](https://crates.io/crates/coarsetime) and works on
//! Rust stable, beta, and nightly.
//!
//! Windows and Unix-like systems are supported.
#![allow(clippy::trivially_copy_pass_by_ref)]
mod clock;
mod duration;
mod helpers;
mod instant;
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
mod updater;
#[cfg(test)]
mod tests;
pub use self::clock::*;
pub use self::duration::*;
pub use self::instant::*;
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
pub use self::updater::*;

55
third_party/coarsetime/src/tests.rs vendored Normal file
View File

@@ -0,0 +1,55 @@
use std::thread::sleep;
use std::time;
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
use super::Updater;
use super::{Clock, Duration, Instant};
#[test]
fn tests() {
let ts = Instant::now();
let d = Duration::from_secs(2);
sleep(time::Duration::new(3, 0));
let elapsed = ts.elapsed().as_secs();
println!("Elapsed: {elapsed} secs");
assert!(elapsed >= 2);
assert!(elapsed < 100);
assert!(ts.elapsed_since_recent() > d);
let ts = Instant::now();
sleep(time::Duration::new(1, 0));
assert_eq!(Instant::recent(), ts);
Instant::update();
assert!(Instant::recent() > ts);
let clock_now = Clock::recent_since_epoch();
sleep(time::Duration::new(1, 0));
assert_eq!(Clock::recent_since_epoch(), clock_now);
assert!(Clock::now_since_epoch() > clock_now);
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
tests_updater();
}
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
#[test]
fn tests_updater() {
let updater = Updater::new(250)
.start()
.expect("Unable to start a background updater");
let ts = Instant::recent();
let clock_recent = Clock::recent_since_epoch();
sleep(time::Duration::new(2, 0));
assert!(Clock::recent_since_epoch() > clock_recent);
assert!(Instant::recent() != ts);
updater.stop().unwrap();
let clock_recent = Clock::recent_since_epoch();
sleep(time::Duration::new(1, 0));
assert_eq!(Clock::recent_since_epoch(), clock_recent);
}
#[test]
fn tests_duration() {
let duration = Duration::from_days(1000);
assert_eq!(duration.as_days(), 1000);
}

58
third_party/coarsetime/src/updater.rs vendored Normal file
View File

@@ -0,0 +1,58 @@
use std::io;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time;
use super::clock::*;
use super::instant::*;
/// A service to periodically call `Instant::update()`
#[derive(Debug)]
pub struct Updater {
period: time::Duration,
running: Arc<AtomicBool>,
th: Option<thread::JoinHandle<()>>,
}
impl Updater {
/// Spawns a background task to call `Instant::update()` periodically
pub fn start(mut self) -> Result<Self, io::Error> {
let period = self.period;
let running = self.running.clone();
running.store(true, Ordering::Relaxed);
let th: thread::JoinHandle<()> = thread::Builder::new()
.name("coarsetime".to_string())
.spawn(move || {
while running.load(Ordering::Relaxed) {
thread::sleep(period);
Instant::update();
Clock::update();
}
})?;
self.th = Some(th);
Instant::update();
Clock::update();
Ok(self)
}
/// Stops the periodic updates
pub fn stop(mut self) -> Result<(), io::Error> {
self.running.store(false, Ordering::Relaxed);
self.th
.take()
.expect("updater is not running")
.join()
.map_err(|_| io::Error::other("failed to properly stop the updater"))
}
/// Creates a new `Updater` with the specified update period, in
/// milliseconds.
pub fn new(period_millis: u64) -> Updater {
Updater {
period: time::Duration::from_millis(period_millis),
running: Arc::new(AtomicBool::new(false)),
th: None,
}
}
}