diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-06-16 07:18:43 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-16 07:18:43 +0000 |
commit | 23177ba7eb800d32a48f70fe568ae9bf6b2cde98 (patch) | |
tree | f259b15d26428b8a448e5c14f055a975138470c0 | |
parent | a8920bced5e72ca130e92c7680c2d839794d31f6 (diff) | |
parent | 25ddb26be815ec3029ea9d28ba812bd541a0face (diff) | |
download | embassy-23177ba7eb800d32a48f70fe568ae9bf6b2cde98.zip |
Merge #813
813: Document remaining public APIs in embassy crate r=lulf a=lulf
This also includes the README.md in the toplevel crate documentation, fixing a few formatting issues with it as well.
Please review the mutex in detail in case I've misunderstood/missed a few things there.
Co-authored-by: Ulf Lilleengen <lulf@redhat.com>
-rw-r--r-- | README.md | 17 | ||||
-rw-r--r-- | embassy/src/blocking_mutex/mod.rs | 34 | ||||
-rw-r--r-- | embassy/src/blocking_mutex/raw.rs | 23 | ||||
-rw-r--r-- | embassy/src/channel/mpmc.rs | 2 | ||||
-rw-r--r-- | embassy/src/channel/signal.rs | 1 | ||||
-rw-r--r-- | embassy/src/executor/raw/mod.rs | 8 | ||||
-rw-r--r-- | embassy/src/lib.rs | 1 | ||||
-rw-r--r-- | embassy/src/mutex.rs | 24 | ||||
-rw-r--r-- | embassy/src/util/steal.rs | 10 | ||||
-rw-r--r-- | embassy/src/waitqueue/waker.rs | 9 |
10 files changed, 105 insertions, 24 deletions
@@ -2,7 +2,7 @@ Embassy is the next-generation framework for embedded applications. Write safe, correct and energy-efficient embedded code faster, using the Rust programming language, its async facilities, and the Embassy libraries. -## [Documentation](https://embassy.dev/embassy/dev/index.html) - [API reference](https://docs.embassy.dev/) - [Website](https://embassy.dev/) - [Chat](https://matrix.to/#/#embassy-rs:matrix.org) +## <a href="https://embassy.dev/embassy/dev/index.html">Documentation</a> - <a href="https://docs.embassy.dev/">API reference</a> - <a href="https://embassy.dev/">Website</a> - <a href="https://matrix.to/#/#embassy-rs:matrix.org">Chat</a> ## Rust + async ❤️ embedded The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. @@ -42,7 +42,7 @@ The <a href="https://github.com/embassy-rs/nrf-softdevice">nrf-softdevice</a> cr ## Sneak peek -```rust +```rust,ignore use defmt::info; use embassy::executor::Spawner; use embassy::time::{Duration, Timer}; @@ -93,20 +93,21 @@ Examples are found in the `examples/` folder seperated by the chip manufacturer ### Running examples - Setup git submodules (needed for STM32 examples) -``` + +```bash git submodule init git submodule update ``` - Install `probe-run` with defmt support. -``` +```bash cargo install probe-run ``` - Change directory to the sample's base directory. For example: -``` +```bash cd examples/nrf ``` @@ -114,7 +115,7 @@ cd examples/nrf For example: -``` +```bash cargo run --bin blinky ``` @@ -145,8 +146,8 @@ EMBedded ASYnc! :) This work is licensed under either of - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + <http://www.apache.org/licenses/LICENSE-2.0>) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>) at your option. diff --git a/embassy/src/blocking_mutex/mod.rs b/embassy/src/blocking_mutex/mod.rs index eb3cd939..602ec8a0 100644 --- a/embassy/src/blocking_mutex/mod.rs +++ b/embassy/src/blocking_mutex/mod.rs @@ -1,14 +1,27 @@ -//! Blocking mutex (not async) - +//! Blocking mutex. +//! +//! This module provides a blocking mutex that can be used to synchronize data. pub mod raw; use core::cell::UnsafeCell; use self::raw::RawMutex; -/// Any object implementing this trait guarantees exclusive access to the data contained -/// within the mutex for the duration of the lock. -/// Adapted from <https://github.com/rust-embedded/mutex-trait>. +/// Blocking mutex (not async) +/// +/// Provides a blocking mutual exclusion primitive backed by an implementation of [`raw::RawMutex`]. +/// +/// Which implementation you select depends on the context in which you're using the mutex, and you can choose which kind +/// of interior mutability fits your use case. +/// +/// Use [`CriticalSectionMutex`] when data can be shared between threads and interrupts. +/// +/// Use [`NoopMutex`] when data is only shared between tasks running on the same executor. +/// +/// Use [`ThreadModeMutex`] when data is shared between tasks running on the same executor but you want a global singleton. +/// +/// In all cases, the blocking mutex is intended to be short lived and not held across await points. +/// Use the async [`Mutex`](crate::mutex::Mutex) if you need a lock that is held across await points. pub struct Mutex<R, T: ?Sized> { // NOTE: `raw` must be FIRST, so when using ThreadModeMutex the "can't drop in non-thread-mode" gets // to run BEFORE dropping `data`. @@ -78,7 +91,18 @@ impl<R, T> Mutex<R, T> { } } +/// A mutex that allows borrowing data across executors and interrupts. +/// +/// # Safety +/// +/// This mutex is safe to share between different executors and interrupts. pub type CriticalSectionMutex<T> = Mutex<raw::CriticalSectionRawMutex, T>; + +/// A mutex that allows borrowing data in the context of a single executor. +/// +/// # Safety +/// +/// **This Mutex is only safe within a single executor.** pub type NoopMutex<T> = Mutex<raw::NoopRawMutex, T>; impl<T> Mutex<raw::CriticalSectionRawMutex, T> { diff --git a/embassy/src/blocking_mutex/raw.rs b/embassy/src/blocking_mutex/raw.rs index f9d249b0..bdb443e4 100644 --- a/embassy/src/blocking_mutex/raw.rs +++ b/embassy/src/blocking_mutex/raw.rs @@ -1,11 +1,22 @@ +//! Mutex primitives. +//! +//! This module provides a trait for mutexes that can be used in different contexts. use core::marker::PhantomData; +/// Any object implementing this trait guarantees exclusive access to the data contained +/// within the mutex for the duration of the lock. +/// Adapted from <https://github.com/rust-embedded/mutex-trait>. pub trait RawMutex { const INIT: Self; fn lock<R>(&self, f: impl FnOnce() -> R) -> R; } +/// A mutex that allows borrowing data across executors and interrupts. +/// +/// # Safety +/// +/// This mutex is safe to share between different executors and interrupts. pub struct CriticalSectionRawMutex { _phantom: PhantomData<()>, } @@ -28,6 +39,11 @@ impl RawMutex for CriticalSectionRawMutex { // ================ +/// A mutex that allows borrowing data in the context of a single executor. +/// +/// # Safety +/// +/// **This Mutex is only safe within a single executor.** pub struct NoopRawMutex { _phantom: PhantomData<*mut ()>, } @@ -53,6 +69,13 @@ impl RawMutex for NoopRawMutex { mod thread_mode { use super::*; + /// A "mutex" that only allows borrowing from thread mode. + /// + /// # Safety + /// + /// **This Mutex is only safe on single-core systems.** + /// + /// On multi-core systems, a `ThreadModeRawMutex` **is not sufficient** to ensure exclusive access. pub struct ThreadModeRawMutex { _phantom: PhantomData<()>, } diff --git a/embassy/src/channel/mpmc.rs b/embassy/src/channel/mpmc.rs index 48056cd8..1d03eef1 100644 --- a/embassy/src/channel/mpmc.rs +++ b/embassy/src/channel/mpmc.rs @@ -433,7 +433,7 @@ where /// Attempt to immediately send a message. /// - /// This method differs from [`send`] by returning immediately if the channel's + /// This method differs from [`send`](Channel::send) by returning immediately if the channel's /// buffer is full, instead of waiting. /// /// # Errors diff --git a/embassy/src/channel/signal.rs b/embassy/src/channel/signal.rs index 5a2c9d47..cf78dad8 100644 --- a/embassy/src/channel/signal.rs +++ b/embassy/src/channel/signal.rs @@ -1,3 +1,4 @@ +//! A synchronization primitive for passing the latest value to a task. use core::cell::UnsafeCell; use core::future::Future; use core::mem; diff --git a/embassy/src/executor/raw/mod.rs b/embassy/src/executor/raw/mod.rs index 09429c19..b8455442 100644 --- a/embassy/src/executor/raw/mod.rs +++ b/embassy/src/executor/raw/mod.rs @@ -5,7 +5,7 @@ //! ## WARNING: here be dragons! //! //! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe -//! executor wrappers in [`crate::executor`] and the [`crate::task`] macro, which are fully safe. +//! executor wrappers in [`executor`](crate::executor) and the [`embassy::task`](embassy_macros::task) macro, which are fully safe. mod run_queue; #[cfg(feature = "time")] @@ -115,7 +115,7 @@ impl TaskHeader { /// A `TaskStorage` must live forever, it may not be deallocated even after the task has finished /// running. Hence the relevant methods require `&'static self`. It may be reused, however. /// -/// Internally, the [embassy::task](crate::task) macro allocates an array of `TaskStorage`s +/// Internally, the [embassy::task](embassy_macros::task) macro allocates an array of `TaskStorage`s /// in a `static`. The most common reason to use the raw `Task` is to have control of where /// the memory for the task is allocated: on the stack, or on the heap with e.g. `Box::leak`, etc. @@ -158,7 +158,7 @@ impl<F: Future + 'static> TaskStorage<F> { /// /// This function will fail if the task is already spawned and has not finished running. /// In this case, the error is delayed: a "poisoned" SpawnToken is returned, which will - /// cause [`Spawner::spawn()`] to return the error. + /// cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error. /// /// Once the task has finished running, you may spawn it again. It is allowed to spawn it /// on a different executor. @@ -230,7 +230,7 @@ impl<F: Future + 'static, const N: usize> TaskPool<F, N> { /// /// This will loop over the pool and spawn the task in the first storage that /// is currently free. If none is free, a "poisoned" SpawnToken is returned, - /// which will cause [`Spawner::spawn()`] to return the error. + /// which will cause [`Spawner::spawn()`](super::Spawner::spawn) to return the error. pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> { for task in &self.pool { if task.spawn_mark_used() { diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs index 1b6ff2d4..c3b2726a 100644 --- a/embassy/src/lib.rs +++ b/embassy/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] #![cfg_attr(feature = "nightly", feature(generic_associated_types, type_alias_impl_trait))] #![allow(clippy::new_without_default)] +#![doc = include_str!("../../README.md")] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; diff --git a/embassy/src/mutex.rs b/embassy/src/mutex.rs index 7b6bcb14..9cfaaa84 100644 --- a/embassy/src/mutex.rs +++ b/embassy/src/mutex.rs @@ -1,9 +1,6 @@ -/// Async mutex. -/// -/// The mutex is generic over a blocking [`RawMutex`](crate::blocking_mutex::raw::RawMutex). -/// The raw mutex is used to guard access to the internal "is locked" flag. It -/// is held for very short periods only, while locking and unlocking. It is *not* held -/// for the entire time the async Mutex is locked. +//! Async mutex. +//! +//! This module provides a mutex that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; use core::ops::{Deref, DerefMut}; use core::task::Poll; @@ -24,6 +21,21 @@ struct State { waker: WakerRegistration, } +/// Async mutex. +/// +/// The mutex is generic over a blocking [`RawMutex`](crate::blocking_mutex::raw::RawMutex). +/// The raw mutex is used to guard access to the internal "is locked" flag. It +/// is held for very short periods only, while locking and unlocking. It is *not* held +/// for the entire time the async Mutex is locked. +/// +/// Which implementation you select depends on the context in which you're using the mutex. +/// +/// Use [`CriticalSectionRawMutex`](crate::blocking_mutex::raw::CriticalSectionRawMutex) when data can be shared between threads and interrupts. +/// +/// Use [`NoopRawMutex`](crate::blocking_mutex::raw::NoopRawMutex) when data is only shared between tasks running on the same executor. +/// +/// Use [`ThreadModeRawMutex`](crate::blocking_mutex::raw::ThreadModeRawMutex) when data is shared between tasks running on the same executor but you want a singleton. +/// pub struct Mutex<M, T> where M: RawMutex, diff --git a/embassy/src/util/steal.rs b/embassy/src/util/steal.rs index a0d5f135..07eb5fff 100644 --- a/embassy/src/util/steal.rs +++ b/embassy/src/util/steal.rs @@ -1,3 +1,13 @@ +/// A type that can retrieved unsafely from anywhere. pub trait Steal { + /// Retrieve and instance of this type. + /// + /// # Safety + /// + /// It is the responsibility of the application to ensure that the + /// usage of the returned instance is not in conflict with other uses + /// of this instance. + /// + /// The implementation may panic if the instance is already in use. unsafe fn steal() -> Self; } diff --git a/embassy/src/waitqueue/waker.rs b/embassy/src/waitqueue/waker.rs index 1ac6054f..da907300 100644 --- a/embassy/src/waitqueue/waker.rs +++ b/embassy/src/waitqueue/waker.rs @@ -6,6 +6,10 @@ use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering}; use crate::executor::raw::{task_from_waker, wake_task, TaskHeader}; /// Utility struct to register and wake a waker. +/// +/// # Safety +/// +/// This type is optimized for (and only works with) embassy tasks. #[derive(Debug)] pub struct WakerRegistration { waker: Option<NonNull<TaskHeader>>, @@ -53,6 +57,11 @@ impl WakerRegistration { unsafe impl Send for WakerRegistration {} unsafe impl Sync for WakerRegistration {} +/// Utility struct to atomically register and wake a waker. +/// +/// # Safety +/// +/// This type is optimized for (and only works with) embassy tasks. pub struct AtomicWaker { waker: AtomicPtr<TaskHeader>, } |