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
/*********************************************************************************************************************** * Copyright (c) 2019 by the authors * * Author: André Borrmann * License: Apache License 2.0 **********************************************************************************************************************/ //! # Spinlock //! Providing simple atomic Spinlock. This can be used to ensure cross core atomic access to data that is typically //! shared between them. For example MMIO mapped registers that allow access to peripherals. Please note that usage //! of Spinlocks on Raspberry Pi is only safe if the MMU has ben configured properly. Otherwise the cores trying to aquire //! a lock will just hang, even if the lock would be available to them. //! //! # Example //! ``` //! use ruspiro_lock::Spinlock; //! //! static LOCK: Spinlock = Spinlock::new(); //! //! fn main () { //! LOCK.aquire(); // will only return if the lock could be set //! // do something //! //! LOCK.release(); // releasing the lock //! } //! ``` use core::sync::atomic::{AtomicBool, Ordering}; /// A blocking cross core lock to guarantee mutual exclusive access. While this lock might block other cores /// to continue processing this lock should be held as short as possible. Also care shall be taken /// while using this lock within interrupt handlers, as this might lead to deadlock situations if the /// lock holding core is interrupted and the interrupt is also trying to aquire the same lock. #[derive(Debug)] #[repr(C, align(16))] pub struct Spinlock { flag: AtomicBool, } impl Spinlock { /// Create a new Spinlock. To ensure it is shared between cores, it's typically assigned to a static variable /// # Example /// ``` /// # use ruspiro_lock::Spinlock; /// static LOCK: Spinlock = Spinlock::new(); /// ``` pub const fn new() -> Spinlock { Spinlock { flag: AtomicBool::new(false), } } /// Aquire a spinlock. This will block the current core until the lock could be aquired. /// # Example /// ```no_run /// # use ruspiro_lock::Spinlock; /// static LOCK: Spinlock = Spinlock::new(); /// # fn main() { /// LOCK.aquire(); /// // execution continues only if the lock could be aquired /// # } /// ``` pub fn aquire(&self) { // set the atomic value to true if it has been false before (set the lock) while self.flag.compare_and_swap(false, true, Ordering::SeqCst) {} } /// Release an aquired spinlock. /// # Example /// ```no_run /// # use ruspiro_lock::Spinlock; /// static LOCK: Spinlock = Spinlock::new(); /// # fn main() { /// LOCK.release(); /// # } /// ``` pub fn release(&self) { self.flag.store(false, Ordering::SeqCst); } }