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
/*********************************************************************************************************************** * Copyright (c) 2019 by the authors * * Author: André Borrmann * License: Apache License 2.0 **********************************************************************************************************************/ #![doc(html_root_url = "https://docs.rs/ruspiro-singleton/0.2.0")] #![no_std] #![feature(asm)] //! # Singleton pattern implementation //! //! Provide a cross core synchronisation safe singleton implementation pattern //! //! # Example //! ``` //! static MY_SINGLETON: Singleton<MySingleton> = Singleton::new(MySingleton::new(0)); //! //! struct MySingleton { //! count: u32, //! } //! //! impl MySingleton { //! pub fn new(initial_count: u32) -> Self { //! MySingleton { //! count: initial_count, //! } //! } //! //! pub fn count(&self) -> u32 { //! self.count //! } //! //! pub fn add_count(&mut self, value: u32) -> u32 { //! self.count += value; //! self.count //! } //! } //! //! fn some_function () { //! let counter = MY_SINGLETON.take_for( |singleton| { //! println!("secure access to the singleton"); //! // do something with the singleton, it is mutable inside 'take_for' //! let c = singleton.add_count(1); //! // and return any value, the return value of take_for is inferred from the return //! // value of the closure given to this function. //! c //! }); //! //! println!("successfull {}", counter); //! } //! ``` //! //! In case only immutable access to the contents of the singleton is required the ``use_for`` function //! can be used. //! ``` //! fn some_other_function() { //! let counter = MY_SINGLETON.use_for( |s| { //! s.count() //! }); //! //! println!("current counter: {}", counter); //! } //! ``` //! use core::cell::RefCell; use ruspiro_lock::Spinlock; use ruspiro_interrupt_core::{disable_interrupts, re_enable_interrupts}; /// The Singleton wrapper stores any type pub struct Singleton<T: 'static> { inner: RefCell<T>, lock: Spinlock, } // The Singleton need to implement Sync to ensure cross core sync compile check mechanisms #[doc(hidden)] unsafe impl<T> Sync for Singleton<T> { } impl<T: 'static> Singleton<T> { /// Create a new singleton instance to be used in a static variable. Only ``const fn`` constructors are allowed here. /// If this is not sufficient the ``Singleton`` may be further wrapped by a ``lazy_static!`` available as /// external crate from [crates.io](https://crates.io/crates/lazy_static) pub const fn new(data: T) -> Singleton<T> { Singleton { inner: RefCell::new(data), lock: Spinlock::new(), } } /// Take the stored singleton for whatever operation and prevent usage by other cores /// Safe access to the singleton mutable instance is guarantied inside the given closure. /// /// # Example /// ``` /// # fn doc() { /// MY_SINGLETON.take_for(|my| { /// // do something with [my] /// my.any_mutable_function(); /// # } /// ``` pub fn take_for<F, R>(&self, f: F) -> R where F: FnOnce(&mut T) -> R { // to ensure atomic access to the singleton wrapped resource we aquire a lock before allowing to access // the same // deactivate interrupts while locking this instance for access // this ensures thee are now deadlocks possible when a lock is interrupted and the handler // tries to aquire the same lock self.lock.aquire(); disable_interrupts(); let r = f( &mut *self.inner.borrow_mut() ); // after processing we can release the lock so other cores can access the singleton as well self.lock.release(); re_enable_interrupts(); r } /// Immutable access to a singleton for a specific operation. /// This access does not enforce any lock nor guarantees safe atomic access to the instance. However, it is usefull /// in read-only access scenarios like inside interrupt handlers. /// /// # Example /// ``` /// # fn doc() { /// MY_SINGLETON.use_for(|my| { /// // do something with [my] /// let _ = my.any_immutable_function(); /// }); /// # } /// ``` pub fn use_for<F, R>(&self, f: F) -> R where F: FnOnce(&T) -> R { f( & *self.inner.borrow() ) } }