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
#![no_std]
#[cfg(test)]
#[macro_use] extern crate std;
extern crate alloc;
// #[macro_use] extern crate lazy_static; // for lazy static initialization
extern crate spin;
extern crate atomic_linked_list;
// #[macro_use] extern crate mopa;
// #[macro_use] mod downcast_rs_no_std;
// use downcast_rs_no_std::Downcast;
// Any trait allows dynamic type checks
use core::any::{Any, TypeId};
use core::sync::atomic::{AtomicPtr, Ordering};
use alloc::boxed::Box;
use spin::{Once};
use alloc::sync::{Arc, Weak};
use atomic_linked_list::atomic_map::AtomicMap;
/// Thanks to Rust's lack of a base type like Java's Object,
/// we have to use this dumbass List structure of Box<Any>,
/// in which what we actually add to the List is not the type T itself,
/// but rather an Arc<T> that itself is wrapped in the Box.
/// In summary, Any = Arc<T>, and Box<Any> = Box<Arc<T>>
/// in order for us to obtain weak references to that specific type T.
struct SystemStateList( pub AtomicMap<TypeId, Box<dyn Any>> );
impl SystemStateList {
fn new() -> SystemStateList {
SystemStateList( AtomicMap::new() )
}
}
// /// A convenience method that converts Weak<SystemState> to Arc<S>.
// /// This function takes a Weak pointer to a generic object that implements the `SystemState` Trait
// /// and returns a strong Arc reference to the given specific subtype `S`.
// /// Returns None if the
// pub fn upgrade_downcast<'a, S: SystemState>(weak_ptr: &'a Weak<SSData>) -> Option<&'a S> {
// /*
// let strong = weak_ptr.upgrade();
// match strong {
// Some(d) => d.downcast_ref::<S>(),
// _ => None,
// }
// */
// None
// // weak_ptr.upgrade().map( |p| { p.downcast_ref::<S>().unwrap() } )
// // let strong = weak_ptr.upgrade().unwrap();
// // strong.downcast_ref::<S>()
// }
/// A key-value store containing all of the system-wide states,
/// of which there is only one instance of each (underlying storage is an AtomicMap, backed by an AtomicLinkedList).
/// Instead of wrapping the entire SYSTEM_STATE map in a coarse-grained global lock (RwLock or Mutex),
/// the caller can use fine-grained locking to protect each element individually.
///
/// This design permits individual modules to retain Weak Arc references to their individual data elements
/// without having to constantly ask the data store module to get and re-insert a module's state.
static SYSTEM_STATE: Once<SystemStateList> = Once::new();
pub fn init() {
SYSTEM_STATE.call_once( || {
SystemStateList::new()
});
}
/// Inserts a new SystemState-implementing type into the map.
// /// If the map did not previously have a SystemState of this type, `None` is returned.
// /// If the map did previously have one, the value is updated, and the old value is returned.
pub fn insert_state<S: Any>(state: S) -> Option<S> {
let old_val: Option<Box<dyn Any>> = SYSTEM_STATE.get().expect("SYSTEM_STATE uninited").0.insert(
TypeId::of::<S>(),
Box::new( Arc::new(state) ) // Arc<S> is the type that is represented by Any
);
// now we have the old value, we need to downcast it from Any to S,
// and then obtain a single-count Arc<S> from that &Arc<S>,
// while we achieve by cloning the &Arc<S> and then letting it drop out of scope.
let solo_arc = match old_val {
Some(g) => g.downcast_ref::<Arc<S>>().map(Arc::clone),
_ => None,
};
// now that this Arc is a single reference, unwrap it to take ownership of its inner S
solo_arc.and_then( |s_arc| Arc::try_unwrap(s_arc).ok())
}
/// A thread-safe cached reference to a system-wide state.
/// Internally, this contains a Weak pointer to `S`,
/// which is upgraded / updated whenenver the caller invokes `get()`.
pub struct SSCached<S: Any> ( AtomicPtr<Option<Weak<S>>> );
impl<S: Any> SSCached<S> {
/// Tries to upgrade the internal Weak pointer to a Strong (Arc) pointer.
/// If successful, the weak pointer is still valid, so we return the `Arc<S>`.
/// If not, the current internal Weak reference is None, so we try to reaquire it.
/// If it cannot be reacquired, there is currently not a system-wide state of type `S`,
/// so we return None.
#[allow(unreachable_code)]
pub fn get(&self) -> Option<Arc<S>> {
// this is the VERY common case, simply loading the cached weak pointer and upgrading it
// SAFE: because we're the only ones able to access this AtomicPtr
let val: &Option<Weak<S>> = unsafe{ &*self.0.load(Ordering::Acquire) };
if let Some(ref v) = val {
if let Some(arc) = v.upgrade() {
// weird structure, because we only want to return if upgrade works!
return Some(arc);
}
}
// remove this when we support real fault tolerance
panic!("In state_store SSCached::get(): reached a fault tolerance condition; cached SystemState was None!");
// here: cached value was none, so try to get it again
let new_state = get_state_internal::<S>();
let (new_cached_val, return_val) = match new_state {
Some(ns_weak) => ( Some(Weak::clone(&ns_weak)), ns_weak.upgrade() ), // NOTE: I haven't been able to fully test this yet
_ => (None, None)
};
// update the cached pointer to the new value
let old_ptr = self.0.swap(Box::into_raw(Box::new(new_cached_val)), Ordering::Release);
// clean up the old cached value to allow it to be dropped
// SAFE: we are the only ones touching this AtomicPtr
unsafe {
let _ = Box::from_raw(old_ptr);
}
return_val
}
}
/// Returns a Weak reference to the SystemState of the requested type `S`,
/// which the caller can downcast into the specific type `S`
/// by invoking downcast_ref() on the data inside the Weak<> wrapper.
/// It's safe for the caller to save/cache the returned value.
pub fn get_state<S: Any>() -> SSCached<S> {
SSCached( AtomicPtr::new(Box::into_raw(Box::new(get_state_internal::<S>()))) )
}
fn get_state_internal<S: Any>() -> Option<Weak<S>> {
SYSTEM_STATE.get().expect("SYSTEM_STATE uninited").0
.get(&TypeId::of::<S>()) // get the Option<Arc<Any>> value
.and_then( |g| g.downcast_ref::<Arc<S>>()) // if it's Some(g), then downcast g to S
.map( |dcast_arc| Arc::downgrade(dcast_arc)) // transform result of downcast to weak ptr
}
// --------------- TESTING BELOW ----------------------
#[cfg(test)]
#[derive(Debug)]
struct TestStruct {
data: u32,
extra: u64,
}
#[cfg(test)]
#[derive(Debug)]
struct Red (u64);
#[cfg(test)]
#[derive(Debug)]
struct Green (u64);
// To run this: cargo test statetest -- --nocapture
#[test]
fn statetest() {
// add some things to SYSTEM_STATE
println!("here1 ");
let res = insert_state(Red(32));
println!("here2, res = {:?} ", res);
let res = insert_state(Green(42));
println!("here3, res = {:?} ", res);
let oldred = insert_state(Red(55));
println!("oldred = {:?}", oldred);
let res = insert_state(TestStruct{
data: 45,
extra: 239874,
});
println!("here4, res = {:?} ", res);
// try to retrieve those things from the SYSTEM_STATE
{
let red = get_state::<Red>().get();
println!("here5 ");
let green = get_state::<Green>().get();
println!("here6 ");
let test = get_state::<TestStruct>().get();
println!("here7 ");
let rr: Option<Arc<Red>> = get_state().get();
println!("r: {:?} g: {:?} t: {:?}, rr: {:?}", red, green, test, rr);
// let redred: &Red = red.downcast_ref().expect();
// let greengreen: &Green = green.downcast_ref().expect();
// let testtest: &TestStruct = test.downcast_ref::<TestStruct>().expect();
}
println!("DONE!");
}