summaryrefslogtreecommitdiffstats
path: root/library/std/src/sys/itron/time.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys/itron/time.rs')
-rw-r--r--library/std/src/sys/itron/time.rs114
1 files changed, 114 insertions, 0 deletions
diff --git a/library/std/src/sys/itron/time.rs b/library/std/src/sys/itron/time.rs
new file mode 100644
index 000000000..427ea0d80
--- /dev/null
+++ b/library/std/src/sys/itron/time.rs
@@ -0,0 +1,114 @@
+use super::{abi, error::expect_success};
+use crate::{mem::MaybeUninit, time::Duration};
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(abi::SYSTIM);
+
+impl Instant {
+ pub fn now() -> Instant {
+ // Safety: The provided pointer is valid
+ unsafe {
+ let mut out = MaybeUninit::uninit();
+ expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim");
+ Instant(out.assume_init())
+ }
+ }
+
+ pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+ self.0.checked_sub(other.0).map(|ticks| {
+ // `SYSTIM` is measured in microseconds
+ Duration::from_micros(ticks)
+ })
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+ // `SYSTIM` is measured in microseconds
+ let ticks = other.as_micros();
+
+ Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?))
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ // `SYSTIM` is measured in microseconds
+ let ticks = other.as_micros();
+
+ Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?))
+ }
+}
+
+/// Split `Duration` into zero or more `RELTIM`s.
+#[inline]
+pub fn dur2reltims(dur: Duration) -> impl Iterator<Item = abi::RELTIM> {
+ // `RELTIM` is microseconds
+ let mut ticks = dur.as_micros();
+
+ crate::iter::from_fn(move || {
+ if ticks == 0 {
+ None
+ } else if ticks <= abi::TMAX_RELTIM as u128 {
+ Some(crate::mem::replace(&mut ticks, 0) as abi::RELTIM)
+ } else {
+ ticks -= abi::TMAX_RELTIM as u128;
+ Some(abi::TMAX_RELTIM)
+ }
+ })
+}
+
+/// Split `Duration` into one or more `TMO`s.
+#[inline]
+fn dur2tmos(dur: Duration) -> impl Iterator<Item = abi::TMO> {
+ // `TMO` is microseconds
+ let mut ticks = dur.as_micros();
+ let mut end = false;
+
+ crate::iter::from_fn(move || {
+ if end {
+ None
+ } else if ticks <= abi::TMAX_RELTIM as u128 {
+ end = true;
+ Some(crate::mem::replace(&mut ticks, 0) as abi::TMO)
+ } else {
+ ticks -= abi::TMAX_RELTIM as u128;
+ Some(abi::TMAX_RELTIM)
+ }
+ })
+}
+
+/// Split `Duration` into one or more API calls with timeout.
+#[inline]
+pub fn with_tmos(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER {
+ let mut er = abi::E_TMOUT;
+ for tmo in dur2tmos(dur) {
+ er = f(tmo);
+ if er != abi::E_TMOUT {
+ break;
+ }
+ }
+ er
+}
+
+/// Split `Duration` into one or more API calls with timeout. This function can
+/// handle spurious wakeups.
+#[inline]
+pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER {
+ // `TMO` and `SYSTIM` are microseconds.
+ // Clamp at `SYSTIM::MAX` for performance reasons. This shouldn't cause
+ // a problem in practice. (`u64::MAX` μs ≈ 584942 years)
+ let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM;
+
+ let start = Instant::now().0;
+ let mut elapsed = 0;
+ let mut er = abi::E_TMOUT;
+ while elapsed <= ticks {
+ er = f(elapsed.min(abi::TMAX_RELTIM as abi::SYSTIM) as abi::TMO);
+ if er != abi::E_TMOUT {
+ break;
+ }
+ elapsed = Instant::now().0.wrapping_sub(start);
+ }
+
+ er
+}
+
+#[cfg(test)]
+mod tests;