1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
//! Nonblocking synchronization structures //! //! This crate is designed for `no_std` applications where heap allocation is not possible. As //! such, there is no dependency on the standard library and all allocations are the responsibility //! of the caller. //! //! # The Mutex //! //! The [`Mutex`] provided here can be used to provide exclusive access to a value. Because of this //! library's non-blocking nature, care must be exercised to avoid resource starvation. The lock //! method requires a [`bare_metal::CriticalSection`]. //! //! # The Channel //! //! The [`fifo::Channel`] provides a single-producer single-consumer queue which is `Sync` and can //! be optionally split into a [`fifo::Sender`] and [`fifo::Receiver`] which are both `Send`. A key //! difference between using the `Channel` by itself vs the `Sender` and `Receiver` together is //! that the `Channel` requires a [`bare_metal::CriticalSection`] for several of its methods in //! order to provide safety. The `Sender` and `Receiver` can be used without this requirement. //! //! ## Channel Examples //! //! There are two ways a [`fifo::Channel`] can be used: //! //! ### Direct usage //! //! Direct usage requires passing an object that implements [`fifo::NonReentrant`]. //! //! //! ``` //! extern crate bare_metal; //! extern crate nb_sync; //! //! use nb_sync::fifo::Channel; //! //! //In an actual program this would be obtained safely //! let cs = unsafe { bare_metal::CriticalSection::new() }; //! //! let mut buffer: [Option<u8>; 4] = [None; 4]; //! let channel = Channel::new(&mut buffer); //! //! channel.send(10, &cs).unwrap(); //! channel.recv(&cs).unwrap(); //! ``` //! //! ### Split into a sender and receiver //! //! This uses similar `send` and `recv` methods to the previous example, but does not require //! a [`bare_metal::CriticalSection`]. //! //! #### Method 1: Basic "send" with a clonable //! //! For clonable types, the `fifo::Sender::send` method can be used inside an `await!` directly. //! //! ``` //! extern crate nb; //! extern crate nb_sync; //! //! use nb_sync::fifo::Channel; //! //! let mut buffer: [Option<u8>; 4] = [None; 4]; //! let mut channel = Channel::new(&mut buffer); //! //! let (mut receiver, mut sender) = channel.split(); //! //! let clonable = 5; //! // this loop is "await!(sender.send(clonable)).unwrap()" //! loop { //! match sender.send(clonable) { //! Ok(()) => break Ok(()), //! Err(nb::Error::WouldBlock) => {}, //! Err(nb::Error::Other(e)) => break Err(e), //! } //! }.unwrap(); //! //! // recv is also compatible with nb's await! macro //! receiver.recv().unwrap(); //! ``` //! //! #### Method 2: Sending with a completion //! //! Non-clonable types can be sent using the [`fifo::Sender::send_with_completion`] method. This is //! based on the [`fifo::Sender::send_lossless`] method. A [`fifo::SendCompletion`] is used to make //! this more directly usable with the `await!` macro. It takes ownership of the `Sender` and the //! passed value for the duration of the sending process. When [`fifo::SendCompletion::done`] is //! called the `Sender` will be returned along with an `Option` which contains the original value //! if it was not ultimately sent. //! //! ``` //! extern crate nb; //! extern crate nb_sync; //! //! use nb_sync::fifo::Channel; //! //! struct NonClone { //! _0: (), //! } //! impl NonClone { //! fn new() -> Self { NonClone { _0: () } } //! } //! //! let mut buffer: [Option<NonClone>; 4] = [None, None, None, None]; //! let mut channel = Channel::new(&mut buffer); //! //! let (mut receiver, mut sender) = channel.split(); //! //! let value = NonClone::new(); //! let completion = sender.send_with_completion(value); //! // Completions can be aborted. //! let (s, v) = completion.done(); //! sender = s; //! let value = v.unwrap(); //the original, unsent value is returned here //! //! let mut completion = sender.send_with_completion(value); //! // This loop is "await!(completion.poll()).unwrap()" //! loop { //! match completion.poll() { //! Ok(()) => break Ok(()), //! Err(nb::Error::WouldBlock) => {}, //! Err(nb::Error::Other(e)) => break Err(e), //! } //! }.unwrap(); //! //! let (s, v) = completion.done(); //! sender = s; //! assert!(v.is_none()); //the value has been sent. //! //! receiver.recv().unwrap(); //! ``` //! #![cfg_attr(not(test), no_std)] #![feature(const_fn)] #![feature(optin_builtin_traits)] #![feature(never_type)] extern crate nb; extern crate bare_metal; pub mod fifo; // In test mode, std is available since we are compiling for x86 #[cfg(test)] use std as core; use core::cell::UnsafeCell; use core::ops::{Deref, DerefMut}; use bare_metal::CriticalSection; /// Mutex with interior mutability /// /// This mutex assues that `panic!` is unrecoverable and crashes the program. This is a safe /// assumption for this embedded application since the `panic!` transforms into two `udf` /// instructions which result in a hard fault. If the user program incorporates any measures to /// recover from this sort of hard fault, this mutex is no longer safe since it does not implement /// the concept of "poisoning". /// /// Since this mutex is polled and does not block, it is easy to have resource starvation occur. /// Care should be taken as to where the `lock` function is called to allow other tasks to have an /// opportunity to also grab the mutex. pub struct Mutex<T> { data: UnsafeCell<T>, count: UnsafeCell<i32>, } impl<T> Mutex<T> { /// Creates a new mutex in the unlocked state pub const fn new(val: T) -> Self { Mutex { data: UnsafeCell::new(val), count: UnsafeCell::new(1) } } /// Attempts to lock the mutex /// /// Once this function returns a `MutexGuard`, all other ongoing calls to `try_lock` will fail /// until the `MutexGuard` is `Drop`d. pub fn lock(&self, _cs: &CriticalSection) -> nb::Result<MutexGuard<T>, !> { // This critical section ensures that the references to our interior are safe. unsafe { if *self.count.get() > 0 { *self.count.get() -= 1; Ok(MutexGuard::new(&self)) } else { Err(nb::Error::WouldBlock) } } } /// Consumes this mutex and returns the underlying data /// /// This is statically safe since we consume `self`. pub fn into_inner(self) -> T { self.data.into_inner() } /// Unlocks this mutex /// /// This is unsafe because it is not thread-safe. The caller must ensure that they are the /// exclusive owner of this mutex's inner value. A `MutexGuard` is an example of an object that /// can make such a guarantee. unsafe fn unlock(&self) { *self.count.get() += 1; } } impl<T> From<T> for Mutex<T> { /// Creates a new mutex from a value in an unlocked state fn from(v: T) -> Mutex<T> { Mutex::new(v) } } unsafe impl<T> Sync for Mutex<T> { } /// Scoped mutex access. This will unlock the mutex when dropped. pub struct MutexGuard<'a, T:'a> { mutex: &'a Mutex<T>, } impl<'a, T: 'a> MutexGuard<'a, T> { fn new(mutex: &'a Mutex<T>) -> Self { MutexGuard { mutex: mutex } } } impl<'a, T: 'a> Drop for MutexGuard<'a, T> { /// Releases this mutex guard fn drop(&mut self) { // Being the exclusive owner of the mutex, we can call the unlock method. Since this is // inside drop, we ensure that this is only called once by us. unsafe { self.mutex.unlock() } } } impl<'a, T: 'a> Deref for MutexGuard<'a, T> { type Target = T; fn deref(&self) -> &T { unsafe { &*self.mutex.data.get() } } } impl<'a, T: 'a> DerefMut for MutexGuard<'a, T> { fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.mutex.data.get() } } } #[cfg(test)] mod tests { }