//! # Synchronization module //! //! Provides synchronization objects for thread-safe memory sharing. use core::cell::UnsafeCell; use core::marker::{Send, Sized, Sync}; use core::ops::FnOnce; /// # Synchronization interfaces /// /// Provides Synchronization traits. pub mod interface { use core::ops::FnOnce; /// # Mutex Trait /// /// Basic Locking primitive to allow single-process access to data pub trait Mutex { /// # The data /// /// Each mutex protects some internal data from modification across /// processes when it is in use. This is important if the process /// is preempted while the function is using it. type Data; /// # Locking mechanism /// /// Locks the mutex to access the data in a closure. /// The data can be read and modified in this closure without worry /// of poisoning the data across processes. fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut Self::Data) -> R) -> R; } /// # Initializable /// /// Initializable type pub trait Initializable { fn init(&mut self); } } /// # Basic Lock Structure pub struct NullLock where T: ?Sized, { /// The internal data to safely share data: UnsafeCell, } /// # Allow thread sharing unsafe impl Send for NullLock where T: ?Sized + Send {} /// # Allow thread sharing unsafe impl Sync for NullLock where T: ?Sized + Send {} impl NullLock { /// # Create a new instance of the lock pub const fn new(data: T) -> Self { Self { data: UnsafeCell::new(data), } } } impl NullLock { pub fn init(&self) { use interface::Mutex; self.lock(|initializable| { initializable.init(); }); } } impl interface::Mutex for NullLock { /// # Underlying data of the lock type Data = T; /// # Locking mechanism /// /// Locks the Mutex, and passes a mutable reference /// to the encapsulated data to a closure. fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut T) -> R) -> R { let data = unsafe { &mut *self.data.get() }; f(data) } } use core::sync::atomic::{AtomicBool, Ordering}; pub struct SpinLock where T: Sized, { data: UnsafeCell, lock: AtomicBool, } unsafe impl Send for SpinLock where T: Sized + Send {} unsafe impl Sync for SpinLock where T: Sized + Send {} impl SpinLock { /// # New lock pub const fn new(data: T) -> Self { Self { data: UnsafeCell::new(data), lock: AtomicBool::new(false), } } } impl SpinLock { /// # Init pub fn init(&self) { use interface::Mutex; self.lock(|init| { init.init(); }); } } impl interface::Mutex for SpinLock { /// # Data type type Data = T; /// # Lock fn lock<'a, R>(&'a self, f: impl FnOnce(&'a mut T) -> R) -> R { loop { // Loop until acquired the lock match self.lock .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) { Ok(_) => { break; } _ => {} } } let data = unsafe { &mut *self.data.get() }; let res = f(data); // Release the lock after finished with the underlying data self.lock.store(false, Ordering::Release); res } }