Files @ 1aef293674a6
Branch filter:

Location: CSY/reowolf/src/runtime2/global_store.rs

1aef293674a6 3.8 KiB application/rls-services+xml Show Annotation Show as Raw Download as Raw
mh
experimenting with multithreaded scheduler sync primitives
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);
    }
}