diff --git a/src/runtime2/global_store.rs b/src/runtime2/global_store.rs index 4e7b9f621ed03fe587d80c4186d72249417ca598..ded4be362c43d4da660cd1117837216957f33af9 100644 --- a/src/runtime2/global_store.rs +++ b/src/runtime2/global_store.rs @@ -3,88 +3,13 @@ use std::sync::{Arc, RwLock}; use std::sync::atomic::{AtomicBool, AtomicU32}; use crate::collections::{MpmcQueue, RawVec}; - -use super::connector::{ConnectorPDL, ConnectorPublic}; -use super::scheduler::Router; - use crate::ProtocolDescription; -use crate::runtime2::connector::{ConnectorScheduling, RunDeltaState}; -use crate::runtime2::inbox::MessageContents; -use crate::runtime2::native::{Connector, ConnectorApplication}; -use crate::runtime2::scheduler::ConnectorCtx; - -/// A kind of token that, once obtained, allows mutable access to a connector. -/// We're trying to use move semantics as much as possible: the owner of this -/// key is the only one that may execute the connector's code. -pub(crate) struct ConnectorKey { - pub index: u32, // of connector -} - -impl ConnectorKey { - /// Downcasts the `ConnectorKey` type, which can be used to obtain mutable - /// access, to a "regular ID" which can be used to obtain immutable access. - #[inline] - pub fn downcast(&self) -> ConnectorId { - return ConnectorId(self.index); - } - - /// Turns the `ConnectorId` into a `ConnectorKey`, marked as unsafe as it - /// bypasses the type-enforced `ConnectorKey`/`ConnectorId` system - #[inline] - pub unsafe fn from_id(id: ConnectorId) -> ConnectorKey { - return ConnectorKey{ index: id.0 }; - } -} -/// A kind of token that allows shared access to a connector. Multiple threads -/// may hold this -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub(crate) struct ConnectorId(pub u32); +use super::scheduler::{Router, ConnectorCtx}; +use super::connector::{ConnectorPDL, ConnectorPublic, ConnectorScheduling, RunDeltaState}; +use super::inbox::Message; +use super::native::{Connector, ConnectorApplication}; -impl ConnectorId { - // TODO: Like the other `new_invalid`, maybe remove - #[inline] - pub fn new_invalid() -> ConnectorId { - return ConnectorId(u32::MAX); - } - - #[inline] - pub(crate) fn is_valid(&self) -> bool { - return self.0 != u32::MAX; - } -} - -// TODO: Change this, I hate this. But I also don't want to put `public` and -// `router` of `ScheduledConnector` back into `Connector`. The reason I don't -// want `Box` everywhere is because of the v-table overhead. But -// to truly design this properly I need some benchmarks. -pub enum ConnectorVariant { - UserDefined(ConnectorPDL), - Native(Box), -} - -impl Connector for ConnectorVariant { - fn handle_message(&mut self, message: MessageContents, ctx: &ConnectorCtx, delta_state: &mut RunDeltaState) { - match self { - ConnectorVariant::UserDefined(c) => c.handle_message(message, ctx, delta_state), - ConnectorVariant::Native(c) => c.handle_message(message, ctx, delta_state), - } - } - - fn run(&mut self, protocol_description: &ProtocolDescription, ctx: &ConnectorCtx, delta_state: &mut RunDeltaState) -> ConnectorScheduling { - match self { - ConnectorVariant::UserDefined(c) => c.run(protocol_description, ctx, delta_state), - ConnectorVariant::Native(c) => c.run(protocol_description, ctx, delta_state), - } - } -} - -pub struct ScheduledConnector { - pub connector: ConnectorVariant, // access by connector - pub context: ConnectorCtx, // mutable access by scheduler, immutable by connector - pub public: ConnectorPublic, // accessible by all schedulers and connectors - pub router: Router, -} /// The registry containing all connectors. The idea here is that when someone /// owns a `ConnectorKey`, then one has unique access to that connector. @@ -138,16 +63,17 @@ impl ConnectorStore { pub(crate) fn create_interface(&self, connector: ConnectorApplication) -> ConnectorKey { // Connector interface does not own any initial ports, and cannot be // created by another connector - let key = self.create_connector_raw(ConnectorVariant::Native(Box::new(connector))); + let key = self.create_connector_raw(ConnectorVariant::Native(Box::new(connector)), true); return key; } /// Create a new connector, returning the key that can be used to retrieve /// and/or queue it. The caller must make sure that the constructed /// connector's code is initialized with the same ports as the ports in the - /// `initial_ports` array. + /// `initial_ports` array. Furthermore the connector is initialized as not + /// sleeping, so MUST be put on the connector queue by the caller. pub(crate) fn create_pdl(&self, created_by: &mut ScheduledConnector, connector: ConnectorPDL) -> ConnectorKey { - let key = self.create_connector_raw(ConnectorVariant::UserDefined(connector)); + let key = self.create_connector_raw(ConnectorVariant::UserDefined(connector), false); let new_connector = self.get_mut(&key); // Transferring ownership of ports (and crashing if there is a @@ -166,7 +92,7 @@ impl ConnectorStore { } pub(crate) fn destroy(&self, key: ConnectorKey) { - let lock = self.inner.write().unwrap(); + let mut lock = self.inner.write().unwrap(); unsafe { let connector = lock.connectors.get_mut(key.index as usize); @@ -178,26 +104,23 @@ impl ConnectorStore { } /// Creates a connector but does not set its initial ports - fn create_connector_raw(&self, connector: ConnectorVariant) -> ConnectorKey { + fn create_connector_raw(&self, connector: ConnectorVariant, initialize_as_sleeping: bool) -> ConnectorKey { // Creation of the connector in the global store, requires a lock let index; { - let lock = self.inner.write().unwrap(); + let mut lock = self.inner.write().unwrap(); let connector = ScheduledConnector { connector, context: ConnectorCtx::new(self.port_counter.clone()), - public: ConnectorPublic::new(), + public: ConnectorPublic::new(initialize_as_sleeping), router: Router::new(), }; if lock.free.is_empty() { let connector = Box::into_raw(Box::new(connector)); - unsafe { - // Cheating a bit here. Anyway, move to heap, store in list - index = lock.connectors.len(); - lock.connectors.push(connector); - } + index = lock.connectors.len(); + lock.connectors.push(connector); } else { index = lock.free.pop().unwrap(); @@ -239,14 +162,14 @@ impl Drop for ConnectorStore { /// TODO: @docs /// TODO: @Optimize, very lazy implementation of concurrent datastructures. /// This includes the `should_exit` and `did_exit` pair! -pub struct GlobalStore { +pub(crate) struct GlobalStore { pub connector_queue: MpmcQueue, pub connectors: ConnectorStore, pub should_exit: AtomicBool, // signal threads to exit } impl GlobalStore { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self{ connector_queue: MpmcQueue::with_capacity(256), connectors: ConnectorStore::with_capacity(256),