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
//! Core abstractions of the Real-Time Interrupt-driven Concurrency (RTIC) framework //! //! You can write generic *libraries* using the `Mutex` trait in this crate. If you want to write //! application code then you'll need an *implementation* of the RTIC framework for a particular //! architecture. Currently, there are implementations for these architectures and OSes: //! //! - [ARM Cortex-M](https://crates.io/crates/cortex-m-rtic) // - [Linux] // - [MSP430] // - [RISC-V] #![deny(missing_docs)] #![deny(rust_2018_compatibility)] #![deny(rust_2018_idioms)] #![deny(warnings)] #![no_std] use core::ops; /// Memory safe access to shared resources /// /// In RTIC, locks are implemented as critical sections that prevent other tasks from *starting*. /// These critical sections are implemented by temporarily increasing the dynamic priority of the /// current context. Entering and leaving these critical sections is always done in bounded constant /// time (a few instructions in bare metal contexts). pub trait Mutex { /// Data protected by the mutex type T; /// Creates a critical section and grants temporary access to the protected data fn lock<R>(&mut self, f: impl FnOnce(&mut Self::T) -> R) -> R; } impl<'a, M> Mutex for &'a mut M where M: Mutex, { type T = M::T; fn lock<R>(&mut self, f: impl FnOnce(&mut M::T) -> R) -> R { M::lock(self, f) } } /// Newtype over `&'a mut T` that implements the `Mutex` trait /// /// The `Mutex` implementation for this type is a no-op: no critical section is created pub struct Exclusive<'a, T>(pub &'a mut T); impl<'a, T> Mutex for Exclusive<'a, T> { type T = T; fn lock<R>(&mut self, f: impl FnOnce(&mut T) -> R) -> R { f(self.0) } } impl<'a, T> ops::Deref for Exclusive<'a, T> { type Target = T; fn deref(&self) -> &T { self.0 } } impl<'a, T> ops::DerefMut for Exclusive<'a, T> { fn deref_mut(&mut self) -> &mut T { self.0 } } /// Makes locks work on N-tuples, locks the mutexes from left-to-right in the tuple. These are /// used to reduce rightward drift in code and to help make intentions clearer. /// /// # Example /// /// ``` /// use mutex_trait::prelude::*; /// /// fn normal_lock( /// a: &mut impl Mutex<T = i32>, /// b: &mut impl Mutex<T = i32>, /// c: &mut impl Mutex<T = i32> /// ) { /// // A lot of rightward drift... /// a.lock(|a| { /// b.lock(|b| { /// c.lock(|c| { /// *a += 1; /// *b += 1; /// *c += 1; /// }); /// }); /// }); /// } /// ``` /// /// Has a shorthand as: /// /// ``` /// use mutex_trait::prelude::*; /// /// fn tuple_lock( /// a: &mut impl Mutex<T = i32>, /// b: &mut impl Mutex<T = i32>, /// c: &mut impl Mutex<T = i32> /// ) { /// // Look! Single indent and less to write /// (a, b, c).lock(|a, b, c| { /// *a += 1; /// *b += 1; /// *c += 1; /// }); /// } /// ``` pub mod prelude { pub use crate::Mutex; macro_rules! lock { ($e:ident, $fun:block) => { $e.lock(|$e| $fun ) }; ($e:ident, $($es:ident),+, $fun:block) => { $e.lock(|$e| lock!($($es),*, $fun)) }; } macro_rules! make_tuple_impl { ($name:ident, $($es:ident),+) => { /// Auto-generated tuple implementation, see [`Mutex`](../trait.Mutex.html) for details. pub trait $name { $( /// Data protected by the mutex. type $es; )* /// Creates a critical section and grants temporary access to the protected data. fn lock<R>(&mut self, f: impl FnOnce($(&mut Self::$es),*) -> R) -> R; } impl<$($es),+> $name for ($($es,)+) where $($es: crate::Mutex),* { $( type $es = $es::T; )* #[allow(non_snake_case)] fn lock<R>(&mut self, f: impl FnOnce($(&mut Self::$es),*) -> R) -> R { let ($( $es, )*) = self; lock!($($es),*, { f($($es),*) }) } } }; } // Generate tuple lock impls make_tuple_impl!(TupleExt01, T1); make_tuple_impl!(TupleExt02, T1, T2); make_tuple_impl!(TupleExt03, T1, T2, T3); make_tuple_impl!(TupleExt04, T1, T2, T3, T4); make_tuple_impl!(TupleExt05, T1, T2, T3, T4, T5); make_tuple_impl!(TupleExt06, T1, T2, T3, T4, T5, T6); make_tuple_impl!(TupleExt07, T1, T2, T3, T4, T5, T6, T7); make_tuple_impl!(TupleExt08, T1, T2, T3, T4, T5, T6, T7, T8); make_tuple_impl!(TupleExt09, T1, T2, T3, T4, T5, T6, T7, T8, T9); make_tuple_impl!(TupleExt10, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); make_tuple_impl!(TupleExt11, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); make_tuple_impl!(TupleExt12, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); }