aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/cyccnt.rs39
-rw-r--r--src/lib.rs12
2 files changed, 33 insertions, 18 deletions
diff --git a/src/cyccnt.rs b/src/cyccnt.rs
index c8a1b7ee..86969cb1 100644
--- a/src/cyccnt.rs
+++ b/src/cyccnt.rs
@@ -1,11 +1,9 @@
-//! Data Watchpoint Trace (DWT) unit's CYCle CouNTer
+//! Data Watchpoint Trace (DWT) unit's CYCle CouNTer (CYCCNT)
use core::{
cmp::Ordering,
convert::{Infallible, TryInto},
- fmt,
- marker::PhantomData,
- ops,
+ fmt, ops,
};
use cortex_m::peripheral::DWT;
@@ -16,25 +14,25 @@ use crate::Fraction;
///
/// This data type is only available on ARMv7-M
///
-/// Note that this value is tied to the CYCCNT of one core and that sending it a different core
-/// makes it lose its meaning -- each Cortex-M core has its own CYCCNT counter and these are usually
-/// unsynchronized and they may even be running at different frequencies.
+/// # Correctness
+///
+/// Adding or subtracting a `Duration` of more than `(1 << 31)` cycles to an `Instant` effectively
+/// makes it "wrap around" and creates an incorrect value. This is also true if the operation is
+/// done in steps, e.g. `(instant + dur) + dur` where `dur` is `(1 << 30)` ticks.
+///
+/// In multi-core contexts: this value is tied to the CYCCNT of *one* core so sending it a different
+/// core makes it lose its meaning -- each Cortex-M core has its own CYCCNT counter and these are
+/// usually unsynchronized and may even be running at different frequencies.
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Instant {
inner: i32,
- _not_send_or_sync: PhantomData<*mut ()>,
}
-unsafe impl Sync for Instant {}
-
-unsafe impl Send for Instant {}
-
impl Instant {
/// Returns an instant corresponding to "now"
pub fn now() -> Self {
Instant {
inner: DWT::get_cycle_count() as i32,
- _not_send_or_sync: PhantomData,
}
}
@@ -61,6 +59,8 @@ impl fmt::Debug for Instant {
impl ops::AddAssign<Duration> for Instant {
fn add_assign(&mut self, dur: Duration) {
+ // NOTE this is a debug assertion because there's no foolproof way to detect a wrap around;
+ // the user may write `(instant + dur) + dur` where `dur` is `(1<<31)-1` ticks.
debug_assert!(dur.inner < (1 << 31));
self.inner = self.inner.wrapping_add(dur.inner as i32);
}
@@ -77,7 +77,7 @@ impl ops::Add<Duration> for Instant {
impl ops::SubAssign<Duration> for Instant {
fn sub_assign(&mut self, dur: Duration) {
- // XXX should this be a non-debug assertion?
+ // NOTE see the NOTE in `<Instant as AddAssign<Duration>>::add_assign`
debug_assert!(dur.inner < (1 << 31));
self.inner = self.inner.wrapping_sub(dur.inner as i32);
}
@@ -115,6 +115,12 @@ impl PartialOrd for Instant {
/// A `Duration` type to represent a span of time.
///
/// This data type is only available on ARMv7-M
+///
+/// # Correctness
+///
+/// This type is *not* appropriate for representing time spans in the order of, or larger than,
+/// seconds because it can hold a maximum of `(1 << 31)` "ticks" where each tick is the inverse of
+/// the CPU frequency, which usually is dozens of MHz.
#[derive(Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct Duration {
inner: u32,
@@ -208,9 +214,6 @@ impl crate::Monotonic for CYCCNT {
}
fn zero() -> Instant {
- Instant {
- inner: 0,
- _not_send_or_sync: PhantomData,
- }
+ Instant { inner: 0 }
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 959c9b7b..d661c54f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -138,9 +138,21 @@ pub trait Monotonic {
fn ratio() -> Fraction;
/// Returns the current time
+ ///
+ /// # Correctness
+ ///
+ /// This function is *allowed* to return nonsensical values if called before `reset` is invoked
+ /// by the runtime. Therefore application authors should *not* call this function during the
+ /// `#[init]` phase.
fn now() -> Self::Instant;
/// Resets the counter to *zero*
+ ///
+ /// # Safety
+ ///
+ /// This function will be called *exactly once* by the RTFM runtime after `#[init]` returns and
+ /// before tasks can start; this is also the case in multi-core applications. User code must
+ /// *never* call this function.
unsafe fn reset();
/// A `Self::Instant` that represents a count of *zero*