From 5a5495aac43d75610735f2ca80fb6c8e8f31ed71 Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Tue, 26 Nov 2024 23:54:21 +0100 Subject: Refactor integrated-timers --- embassy-time-driver/src/lib.rs | 135 +---------------------------------------- 1 file changed, 3 insertions(+), 132 deletions(-) (limited to 'embassy-time-driver') diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs index 12f40b9b9..ffb363cd7 100644 --- a/embassy-time-driver/src/lib.rs +++ b/embassy-time-driver/src/lib.rs @@ -21,8 +21,8 @@ //! //! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions. //! -//! `embassy` internally defines the driver functions as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls them. -//! The driver crate defines the functions as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the +//! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it. +//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the //! calls from the `embassy` crate to call into the driver crate. //! //! If there is none or multiple drivers in the crate tree, linking will fail. @@ -38,7 +38,7 @@ //! # Example //! //! ``` -//! use embassy_time_driver::{Driver, AlarmHandle}; +//! use embassy_time_driver::Driver; //! //! struct MyDriver{} // not public! //! @@ -46,15 +46,6 @@ //! fn now(&self) -> u64 { //! todo!() //! } -//! unsafe fn allocate_alarm(&self) -> Option { -//! todo!() -//! } -//! fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { -//! todo!() -//! } -//! fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { -//! todo!() -//! } //! } //! //! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); @@ -70,28 +61,6 @@ mod tick; /// This value is specified by the [`tick-*` Cargo features](crate#tick-rate) pub const TICK_HZ: u64 = tick::TICK_HZ; -/// Alarm handle, assigned by the driver. -#[derive(Clone, Copy)] -pub struct AlarmHandle { - id: u8, -} - -impl AlarmHandle { - /// Create an AlarmHandle - /// - /// Safety: May only be called by the current global Driver impl. - /// The impl is allowed to rely on the fact that all `AlarmHandle` instances - /// are created by itself in unsafe code (e.g. indexing operations) - pub unsafe fn new(id: u8) -> Self { - Self { id } - } - - /// Get the ID of the AlarmHandle. - pub fn id(&self) -> u8 { - self.id - } -} - /// Time driver pub trait Driver: Send + Sync + 'static { /// Return the current timestamp in ticks. @@ -105,76 +74,10 @@ pub trait Driver: Send + Sync + 'static { /// you MUST extend them to 64-bit, for example by counting overflows in software, /// or chaining multiple timers together. fn now(&self) -> u64; - - /// Try allocating an alarm handle. Returns None if no alarms left. - /// Initially the alarm has no callback set, and a null `ctx` pointer. - /// - /// The allocated alarm is a reusable resource and can be used multiple times. - /// Once the alarm has fired, it remains allocated and can be set again without needing - /// to be reallocated. - /// - /// # Safety - /// It is UB to make the alarm fire before setting a callback. - unsafe fn allocate_alarm(&self) -> Option; - - /// Set the callback function to be called when the alarm triggers. - /// The callback may be called from any context (interrupt or thread mode). - /// - /// The callback is maintained after the alarm has fired. Callers do not need - /// to set a callback again before setting another alarm, unless they want to - /// change the callback function or context. - fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); - - /// Set an alarm at the given timestamp. - /// - /// ## Behavior - /// - /// If `timestamp` is in the future, `set_alarm` schedules calling the callback function - /// at that time, and returns `true`. - /// - /// If `timestamp` is in the past, `set_alarm` has two allowed behaviors. Implementations can pick whether to: - /// - /// - Schedule calling the callback function "immediately", as if the requested timestamp was "now+epsilon" and return `true`, or - /// - Not schedule the callback, and return `false`. - /// - /// Callers must ensure to behave correctly with either behavior. - /// - /// When callback is called, it is guaranteed that `now()` will return a value greater than or equal to `timestamp`. - /// - /// ## Reentrancy - /// - /// Calling the callback from `set_alarm` synchronously is not allowed. If the implementation chooses the first option above, - /// it must still call the callback from another context (i.e. an interrupt handler or background thread), it's not allowed - /// to call it synchronously in the context `set_alarm` is running. - /// - /// The reason for the above is callers are explicitly permitted to do both of: - /// - Lock a mutex in the alarm callback. - /// - Call `set_alarm` while having that mutex locked. - /// - /// If `set_alarm` called the callback synchronously, it'd cause a deadlock or panic because it'd cause the - /// mutex to be locked twice reentrantly in the same context. - /// - /// ## Overwriting alarms - /// - /// Only one alarm can be active at a time for each `AlarmHandle`. This overwrites any previously-set alarm if any. - /// - /// ## Unsetting the alarm - /// - /// There is no `unset_alarm` API. Instead, callers can call `set_alarm` with `timestamp` set to `u64::MAX`. - /// - /// This allows for more efficient implementations, since they don't need to distinguish between the "alarm set" and - /// "alarm not set" cases, thanks to the fact "Alarm set for u64::MAX" is effectively equivalent for "alarm not set". - /// - /// This means implementations need to be careful to avoid timestamp overflows. The recommendation is to make `timestamp` - /// be in the same units as hardware ticks to avoid any conversions, which makes avoiding overflow easier. - fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool; } extern "Rust" { fn _embassy_time_now() -> u64; - fn _embassy_time_allocate_alarm() -> Option; - fn _embassy_time_set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()); - fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool; } /// See [`Driver::now`] @@ -182,23 +85,6 @@ pub fn now() -> u64 { unsafe { _embassy_time_now() } } -/// See [`Driver::allocate_alarm`] -/// -/// Safety: it is UB to make the alarm fire before setting a callback. -pub unsafe fn allocate_alarm() -> Option { - _embassy_time_allocate_alarm() -} - -/// See [`Driver::set_alarm_callback`] -pub fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - unsafe { _embassy_time_set_alarm_callback(alarm, callback, ctx) } -} - -/// See [`Driver::set_alarm`] -pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool { - unsafe { _embassy_time_set_alarm(alarm, timestamp) } -} - /// Set the time Driver implementation. /// /// See the module documentation for an example. @@ -211,20 +97,5 @@ macro_rules! time_driver_impl { fn _embassy_time_now() -> u64 { <$t as $crate::Driver>::now(&$name) } - - #[no_mangle] - unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::AlarmHandle> { - <$t as $crate::Driver>::allocate_alarm(&$name) - } - - #[no_mangle] - fn _embassy_time_set_alarm_callback(alarm: $crate::AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - <$t as $crate::Driver>::set_alarm_callback(&$name, alarm, callback, ctx) - } - - #[no_mangle] - fn _embassy_time_set_alarm(alarm: $crate::AlarmHandle, timestamp: u64) -> bool { - <$t as $crate::Driver>::set_alarm(&$name, alarm, timestamp) - } }; } -- cgit