From 1f259536aa38da193d94acdba82b1d0f933fb2bd Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 9 Feb 2020 16:09:00 +0100 Subject: [PATCH 1/6] Remove `Peripheral` It appears to be unused by cortex-m and generated PACs --- src/lib.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index da9f6b0..6749f19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,36 +7,6 @@ use core::cell::UnsafeCell; use core::marker::PhantomData; -/// A peripheral -#[derive(Debug)] -pub struct Peripheral -where - T: 'static, -{ - address: *mut T, -} - -impl Peripheral { - /// Creates a new peripheral - /// - /// `address` is the base address of the register block - pub const unsafe fn new(address: usize) -> Self { - Peripheral { - address: address as *mut T, - } - } - - /// Borrows the peripheral for the duration of a critical section - pub fn borrow<'cs>(&self, _ctxt: CriticalSection<'cs>) -> &'cs T { - unsafe { &*self.get() } - } - - /// Returns a pointer to the register block - pub fn get(&self) -> *mut T { - self.address as *mut T - } -} - /// Critical section token /// /// Indicates that you are executing code within a critical section From 3e0114e9edce1d1fddfa5c29bb72fd30162fed72 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 9 Feb 2020 16:11:38 +0100 Subject: [PATCH 2/6] Move `Sync` impl to the rest of the mutex code --- src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6749f19..f87ffb1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,11 @@ impl Mutex { } } +// NOTE A `Mutex` can be used as a channel so the protected data must be `Send` +// to prevent sending non-Sendable stuff (e.g. access tokens) across different +// execution contexts (e.g. interrupts) +unsafe impl Sync for Mutex where T: Send {} + /// ``` compile_fail /// fn bad(cs: bare_metal::CriticalSection) -> &u32 { /// let x = bare_metal::Mutex::new(42u32); @@ -67,8 +72,3 @@ pub unsafe trait Nr { /// Returns the number associated with an interrupt fn nr(&self) -> u8; } - -// NOTE A `Mutex` can be used as a channel so the protected data must be `Send` -// to prevent sending non-Sendable stuff (e.g. access tokens) across different -// execution contexts (e.g. interrupts) -unsafe impl Sync for Mutex where T: Send {} From 4c27ef8dfdcbfc5d7b6235280e0c8afd8e7e1975 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 9 Feb 2020 16:16:55 +0100 Subject: [PATCH 3/6] End doc sentences --- src/lib.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f87ffb1..b58f630 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! Abstractions common to bare metal systems +//! Abstractions common to bare metal systems. #![deny(missing_docs)] #![deny(warnings)] @@ -7,16 +7,16 @@ use core::cell::UnsafeCell; use core::marker::PhantomData; -/// Critical section token +/// Critical section token. /// -/// Indicates that you are executing code within a critical section +/// Indicates that you are executing code within a critical section. #[derive(Clone, Copy)] pub struct CriticalSection<'cs> { _0: PhantomData<&'cs ()>, } impl<'cs> CriticalSection<'cs> { - /// Creates a critical section token + /// Creates a critical section token. /// /// This method is meant to be used to create safe abstractions rather than /// meant to be directly used in applications. @@ -26,7 +26,7 @@ impl<'cs> CriticalSection<'cs> { } } -/// A "mutex" based on critical sections +/// A "mutex" based on critical sections. /// /// # Safety /// @@ -38,7 +38,7 @@ pub struct Mutex { } impl Mutex { - /// Creates a new mutex + /// Creates a new mutex. pub const fn new(value: T) -> Self { Mutex { inner: UnsafeCell::new(value), @@ -47,7 +47,7 @@ impl Mutex { } impl Mutex { - /// Borrows the data for the duration of the critical section + /// Borrows the data for the duration of the critical section. pub fn borrow<'cs>(&'cs self, _cs: CriticalSection<'cs>) -> &'cs T { unsafe { &*self.inner.get() } } @@ -67,8 +67,8 @@ unsafe impl Sync for Mutex where T: Send {} #[allow(dead_code)] const GH_6: () = (); -/// Interrupt number +/// Interrupt number. pub unsafe trait Nr { - /// Returns the number associated with an interrupt + /// Returns the number associated with an interrupt. fn nr(&self) -> u8; } From 621fd69abc7172bcbbd6bd45fe7ea41255f932bc Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 9 Feb 2020 16:17:02 +0100 Subject: [PATCH 4/6] Update changelog --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a06a869..6c25874 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,18 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Breaking Changes + +- Use `CriticalSection<'cs>` everywhere instead of `&'cs CriticalSection` + (this makes it a zero-sized type). +- Removed the `const-fn` feature. +- Removed the `Peripheral` wrapper type. + ## [v0.2.5] - 2019-08-29 ### Changed -- The `const-fn` feature is now stable +- The `const-fn` feature is now stable. ## [v0.2.4] - 2018-10-30 From 7420011a72e98393c9f93fbbfe66131478254fbc Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 9 Feb 2020 16:31:07 +0100 Subject: [PATCH 5/6] Add a `StaticResource` trait --- CHANGELOG.md | 4 ++++ src/lib.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c25874..3cf98ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added + +- Added the `StaticResource` trait. + ### Breaking Changes - Use `CriticalSection<'cs>` everywhere instead of `&'cs CriticalSection` diff --git a/src/lib.rs b/src/lib.rs index b58f630..7428ab7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,3 +72,51 @@ pub unsafe trait Nr { /// Returns the number associated with an interrupt. fn nr(&self) -> u8; } + +/// Trait for static (singleton) resources with managed ownership. +/// +/// This trait allows application code and libraries to take ownership of resources that exist once +/// on every core, or once on the entire system. +/// +/// # Safety +/// +/// In order to safely implement this trait, the implementor must ensure that: +/// - A call to `take()` or `steal()` atomically ensures that no further call to `take()` will +/// succeed. This is commonly accomplished by using a static `AtomicBool` variable and a +/// compare-and-swap operation or a critical section. +/// - It is impossible to link multiple crates containing the synchronization state together. This +/// is usually accomplished by defining a well-known [`links = "..."`][links] key in the +/// `Cargo.toml`. +/// +/// [links]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#the-links-manifest-key +pub unsafe trait StaticResource: Sized { + /// Obtains ownership of this resource singleton and makes it unavailable to future callers of + /// `take()`. + /// + /// If `take()` or `steal()` have been called before, this returns `None`. + fn take() -> Option; + + /// Obtains an instance of this resource and makes all future calls to `take()` return `None`. + /// + /// This will not check if `take()` or `steal()` have already been called before. It is the + /// caller's responsibility to use the returned instance in a safe way that does not conflict + /// with other instances. + /// + /// This function is intended to be used when it is statically known that the resource is still + /// available (for example, in generated code that runs immediately after reset). It generally + /// has lower cost than `take().unwrap()`. + unsafe fn steal() -> Self; + + /// Unsafely obtains an instance of this resource. + /// + /// This will not check if `take()` or `steal()` have already been called before. It is the + /// caller's responsibility to use the returned instance in a safe way that does not conflict + /// with other instances. + /// + /// Contrary to `steal()`, `conjure()` will *not* make future calls to `take()` return `None`. + /// + /// This function can be used to perform operations on a resource, ignoring any current + /// ownership of the resource. The safety of this depends on the specific resource, and on the + /// operations performed. + unsafe fn conjure() -> Self; +} From 3002f9840e8a135d078d3e1e55b38c5e6bfe57f0 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 9 Feb 2020 17:17:41 +0100 Subject: [PATCH 6/6] Improve `CriticalSection` docs --- src/lib.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7428ab7..e23b1e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,9 @@ use core::marker::PhantomData; /// Critical section token. /// -/// Indicates that you are executing code within a critical section. +/// An instance of this type indicates that the current core is executing code within a critical +/// section. This means that no interrupts must be enabled that could preempt the currently running +/// code. #[derive(Clone, Copy)] pub struct CriticalSection<'cs> { _0: PhantomData<&'cs ()>, @@ -18,8 +20,17 @@ pub struct CriticalSection<'cs> { impl<'cs> CriticalSection<'cs> { /// Creates a critical section token. /// - /// This method is meant to be used to create safe abstractions rather than - /// meant to be directly used in applications. + /// This method is meant to be used to create safe abstractions rather than being directly used + /// in applications. + /// + /// # Safety + /// + /// This must only be called when the current core is in a critical section. The caller must + /// ensure that the returned instance will not live beyond the end of the critical section. + /// + /// Note that the lifetime `'cs` of the returned instance is unconstrained. User code must not + /// be able to influence the lifetime picked for this type, since that might cause it to be + /// inferred to `'static`. #[inline(always)] pub unsafe fn new() -> Self { CriticalSection { _0: PhantomData }