Files
@ 1aef293674a6
Branch filter:
Location: CSY/reowolf/src/runtime2/global_store.rs
1aef293674a6
3.8 KiB
application/rls-services+xml
experimenting with multithreaded scheduler sync primitives
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 | use crate::collections::{MpmcQueue, RawVec};
use super::connector::Connector;
use std::ptr;
use std::sync::RwLock;
/// A kind of token that, once obtained, allows access to a container.
struct ConnectorKey {
index: u32, // of connector
}
struct ConnectorStore {
connectors: RawVec<*mut Connector>,
free: Vec<usize>,
}
impl ConnectorStore {
fn with_capacity(capacity: usize) -> Self {
Self{
connectors: RawVec::with_capacity(capacity),
free: Vec::with_capacity(capacity),
}
}
fn get_mut(&self, key: &ConnectorKey) -> &'static mut Connector {
unsafe {
let connector = self.connectors.get_mut(key.index as usize);
debug_assert!(!connector.is_null());
return *connector as &mut _;
}
}
fn create(&mut self, connector: Connector) -> ConnectorKey {
let index;
if self.free.is_empty() {
let connector = Box::into_raw(Box::new(connector));
unsafe {
// Cheating a bit here. Anyway, move to heap, store in list
index = self.connectors.len();
self.connectors.push(connector);
}
} else {
index = self.free.pop().unwrap();
unsafe {
let target = self.connectors.get_mut(index);
debug_assert!(!target.is_null());
ptr::write(*target, connector);
}
}
return ConnectorKey{ index: index as u32 };
}
fn destroy(&mut self, key: ConnectorKey) {
unsafe {
let connector = self.connectors.get_mut(key.index as usize);
ptr::drop_in_place(*connector);
// Note: but not deallocating!
}
self.free.push(key.index as usize);
}
}
impl Drop for ConnectorStore {
fn drop(&mut self) {
for idx in 0..self.connectors.len() {
unsafe {
let memory = *self.connectors.get_mut(idx);
let boxed = Box::from_raw(memory); // takes care of deallocation
}
}
}
}
/// Global store of connectors, ports and queues that are used by the sceduler
/// threads. The global store has the appearance of a thread-safe datatype, but
/// one needs to be careful using it.
///
/// The intention of this data structure is to enforce the rules:
/// TODO: @docs
pub struct GlobalStore {
connector_queue: MpmcQueue<ConnectorKey>,
connectors: RwLock<ConnectorStore>,
}
impl GlobalStore {
pub fn new() -> Self {
Self{
connector_queue: MpmcQueue::with_capacity(256),
connectors: RwLock::new(ConnectorStore::with_capacity(256)),
}
}
// Taking connectors out of global queue
pub fn pop_key(&self) -> Option<ConnectorKey> {
return self.connector_queue.pop_front();
}
pub fn push_key(&self, key: ConnectorKey) {
self.connector_queue.push_back(key);
}
// Creating, retrieving and destroying connectors
/// Retrieves a connector using the provided key. Note that the returned
/// reference is not truly static, the `GlobalStore` needs to stay alive.
pub fn get_connector(&self, key: &ConnectorKey) -> &'static mut Connector {
let connectors = self.connectors.read().unwrap();
return connectors.get_mut(key);
}
/// Adds a connector to the global system. Will also queue it to run
pub fn add_connector(&self, connector: Connector) {
let key = {
let mut connectors = self.connectors.write().unwrap();
connectors.create(connector)
};
self.connector_queue.push_back(key);
}
/// Destroys a connector
pub fn destroy_connector(&self, key: ConnectorKey) {
let mut connectors = self.connectors.write().unwrap();
connectors.destroy(key);
}
}
|