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
//! As the name implies, d3-core is the core foundation for the server. It is responsible for creating //! a d3 machine from a raw implementation, scheduling that machine to run and running it. Creating a //! machine is trivial, as the exmples illustate. //! //! # examples //! ``` //! # use std::sync::Arc; //! # use parking_lot::Mutex; //! # #[allow(unused_imports)] //! # use d3_core::executor; //! # use d3_core::machine_impl::*; //! # use d3_core::send_cmd; //! # use d3_derive::*; //! # #[derive(Debug, MachineImpl)] //! # pub enum TestMessage {Test,} //! # //! // A simple Alice machine //! struct Alice {} //! // Alice implements the TestMessage instruction set //! impl Machine<TestMessage> for Alice { //! fn receive(&self, _message: TestMessage) {} //! } //! # executor::set_selector_maintenance_duration(std::time::Duration::from_millis(20)); //! # executor::start_server(); //! // Construct Alice, and connect her //! let (alice, sender) = executor::connect(Alice{}); //! // the returned alice is an Arc<Mutex<Alice>> //! // the returned sender is a Sender<TestMessage> //! // At this point, Alice is in the scheduler, but idle. //! // sending a command will wake her and call her receive method. //! send_cmd(&sender, TestMessage::Test); //! # executor::stop_server(); //! ``` //! Occasionally, a machine may implement multiple instruction sets. This //! is an example of Alice implementing TestMessage and StateTable. //! ``` //! # use std::sync::Arc; //! # use parking_lot::Mutex; //! # #[allow(unused_imports)] //! # use d3_core::executor; //! # use d3_core::machine_impl::*; //! # use d3_core::send_cmd; //! # use d3_derive::*; //! # #[derive(Debug, MachineImpl)] //! # pub enum TestMessage {Test,} //! # #[derive(Debug, MachineImpl)] //! # pub enum StateTable {Start,} //! # //! // A simple Alice machine //! struct Alice {} //! // Alice implements the TestMessage instruction set //! impl Machine<TestMessage> for Alice { //! fn receive(&self, _message: TestMessage) {} //! } //! // Alice also implements the StateTable instruction set //! impl Machine<StateTable> for Alice { //! fn receive(&self, _message: StateTable) {} //! } //! # executor::set_selector_maintenance_duration(std::time::Duration::from_millis(20)); //! # executor::start_server(); //! // Construct Alice, and connect her, this is for the TextMessage set //! let (alice, sender) = executor::connect::<_,TestMessage>(Alice{}); //! // the returned alice is an Arc<Mutex<Alice>> //! // the returned sender is a Sender<TestMessage> //! // At this point, Alice is in the scheduler, but idle. //! // Now add the StateTable instruction set //! let state_sender = executor::and_connect::<_,StateTable>(&alice); //! // the returned sender is a Sender<StateTable> //! // At this point, there are two Alice machines is in the scheduler, both idle. //! // Both machines share the Alice implementation, each with their own //! // sender and receiver. //! // sending a command will wake her and call her receive method. //! send_cmd(&sender, TestMessage::Test); //! send_cmd(&state_sender, StateTable::Start); //! # executor::stop_server(); //! ``` //! //! Instruction are varients in an enum, the enum is considered an insruction set. A MachineImpl //! derive macro is used to convert an enum into an instruction set. //! //! # examples //! //! ``` //! use std::sync::Arc; //! use parking_lot::Mutex; //! use d3_core::machine_impl::*; //! use d3_derive::*; //! #[derive(Debug, MachineImpl)] //! pub enum StateTable { //! Init, //! Start, //! Stop //! } //! // The MachineImpl provides all of the code necessary to support //! // a machine sending and receiving StateTable instructions. //! ``` // pull in commonly used elements use parking_lot::{Mutex, RwLock}; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; use std::iter; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Weak}; use std::thread; use std::time::{Duration, Instant}; // bring in addition utilities use atomic_refcell::AtomicRefCell; use crossbeam::atomic::AtomicCell; use uuid::Uuid; #[allow(unused_imports)] #[macro_use] extern crate smart_default; #[allow(unused_imports)] #[macro_use] extern crate log; // pull in all of the modules mod foundation { use super::*; pub mod linear_backoff; pub mod machine; pub mod simple_event_timer; pub mod thread_safe; } mod tls { #![allow(dead_code)] use super::*; use crate::foundation::{linear_backoff::LinearBackoff, thread_safe::*}; pub mod collective; pub mod tls_executor; } mod channel { #![allow(dead_code)] use super::*; use crate::foundation::machine::*; use crate::tls::collective::{MachineState, WeakShareableMachine}; use crate::tls::tls_executor::ExecutorData; mod connection; pub mod machine_channel; pub mod receiver; pub mod sender; } mod collective { #![allow(dead_code)] use super::*; use crate::channel::{receiver::*, sender::*}; use crate::foundation::machine::*; use crate::tls::collective::*; pub mod machine; } mod scheduler { #![allow(dead_code)] use super::*; use crate::collective::machine::*; use crate::foundation::{linear_backoff::*, machine::*, simple_event_timer::*}; use crate::tls::{collective::*, tls_executor::*}; pub mod executor; pub mod machine; mod overwatch; pub mod sched; mod sched_factory; pub mod setup_teardown; pub mod traits; } // publish the parts needed outside of the core // package up things needed for #[derive(MachineImpl)] pub mod machine_impl { pub use crate::channel::{ machine_channel::{channel, channel_with_capacity}, receiver::Receiver, sender::Sender, }; pub use crate::collective::machine::MachineBuilder; pub use crate::foundation::{machine::Machine, machine::MachineImpl}; pub use crate::tls::{ collective::{MachineAdapter, MachineDependentAdapter, MachineState, ShareableMachine, SharedMachineState}, tls_executor::{ tls_executor_data, ExecutorDataField, ExecutorStats, MachineDependentSenderAdapter, MachineSenderAdapter, Task, TrySendError, }, }; } // package up the send_cmd utility function pub use crate::collective::machine::send_cmd; // package up thing needed to tune and start the schduler and inject // machines into the collective. For backward compatability, export deprecated // symbols until they've been dprecrated for a while. #[allow(deprecated)] pub mod executor { pub use crate::scheduler::{ executor::{get_executors_snoozing, get_run_queue_len, get_time_slice, set_time_slice}, machine::{ and_connect, and_connect_unbounded, and_connect_with_capacity, connect, connect_unbounded, connect_with_capacity, get_default_channel_capacity, set_default_channel_capacity, }, sched::{ get_machine_count, get_machine_count_estimate, get_selector_maintenance_duration, set_machine_count_estimate, set_selector_maintenance_duration, }, setup_teardown::{get_executor_count, set_executor_count, start_server, stop_server}, }; pub mod stats { pub use crate::scheduler::{ sched::SchedStats, setup_teardown::{add_core_stats_sender, remove_core_stats_sender, request_machine_info, request_stats_now}, traits::{CoreStatsMessage, CoreStatsSender}, }; pub use crate::tls::tls_executor::ExecutorStats; } }