d3_core/
lib.rs

1//! As the name implies, d3-core is the core foundation for the server. It is responsible for creating
2//! a d3 machine from a raw implementation, scheduling that machine to run and running it. Creating a
3//! machine is trivial, as the exmples illustate.
4//!
5//! # examples
6//! ```
7//! # use std::sync::Arc;
8//! # use parking_lot::Mutex;
9//! # #[allow(unused_imports)]
10//! # use d3_core::executor;
11//! # use d3_core::machine_impl::*;
12//! # use d3_core::send_cmd;
13//! # use d3_derive::*;
14//! # #[derive(Debug, MachineImpl)]
15//! # pub enum TestMessage {Test,}
16//! #
17//! // A simple Alice machine
18//! struct Alice {}
19//! // Alice implements the TestMessage instruction set
20//! impl Machine<TestMessage> for Alice {
21//!   fn receive(&self, _message: TestMessage) {}
22//! }
23//! # executor::set_selector_maintenance_duration(std::time::Duration::from_millis(20));
24//! # executor::start_server();
25//! // Construct Alice, and connect her
26//! let (alice, sender) = executor::connect(Alice{});
27//! // the returned alice is an Arc<Mutex<Alice>>
28//! // the returned sender is a Sender<TestMessage>
29//! // At this point, Alice is in the scheduler, but idle.
30//! // sending a command will wake her and call her receive method.
31//! send_cmd(&sender, TestMessage::Test);
32//! # executor::stop_server();
33//! ```
34//! Occasionally, a machine may implement multiple instruction sets. This
35//! is an example of Alice implementing TestMessage and StateTable.
36//! ```
37//! # use std::sync::Arc;
38//! # use parking_lot::Mutex;
39//! # #[allow(unused_imports)]
40//! # use d3_core::executor;
41//! # use d3_core::machine_impl::*;
42//! # use d3_core::send_cmd;
43//! # use d3_derive::*;
44//! # #[derive(Debug, MachineImpl)]
45//! # pub enum TestMessage {Test,}
46//! # #[derive(Debug, MachineImpl)]
47//! # pub enum StateTable {Start,}
48//! #
49//! // A simple Alice machine
50//! struct Alice {}
51//! // Alice implements the TestMessage instruction set
52//! impl Machine<TestMessage> for Alice {
53//!   fn receive(&self, _message: TestMessage) {}
54//! }
55//! // Alice also implements the StateTable instruction set
56//! impl Machine<StateTable> for Alice {
57//!   fn receive(&self, _message: StateTable) {}
58//! }
59//! # executor::set_selector_maintenance_duration(std::time::Duration::from_millis(20));
60//! # executor::start_server();
61//! // Construct Alice, and connect her, this is for the TextMessage set
62//! let (alice, sender) = executor::connect::<_,TestMessage>(Alice{});
63//! // the returned alice is an Arc<Mutex<Alice>>
64//! // the returned sender is a Sender<TestMessage>
65//! // At this point, Alice is in the scheduler, but idle.
66//! // Now add the StateTable instruction set
67//! let state_sender = executor::and_connect::<_,StateTable>(&alice);
68//! // the returned sender is a Sender<StateTable>
69//! // At this point, there are two Alice machines is in the scheduler, both idle.
70//! // Both machines share the Alice implementation, each with their own
71//! // sender and receiver.
72//! // sending a command will wake her and call her receive method.
73//! send_cmd(&sender, TestMessage::Test);
74//! send_cmd(&state_sender, StateTable::Start);
75//! # executor::stop_server();
76//! ```
77//!
78//! Instruction are varients in an enum, the enum is considered an insruction set. A MachineImpl
79//! derive macro is used to convert an enum into an instruction set.
80//!
81//! # examples
82//!
83//! ```
84//! use std::sync::Arc;
85//! use parking_lot::Mutex;
86//! use d3_core::machine_impl::*;
87//! use d3_derive::*;
88//! #[derive(Debug, MachineImpl)]
89//! pub enum StateTable {
90//!     Init,
91//!     Start,
92//!     Stop
93//! }
94//! // The MachineImpl provides all of the code necessary to support
95//! // a machine sending and receiving StateTable instructions.
96//! ```
97// pull in commonly used elements
98use parking_lot::{Mutex, RwLock};
99use std::cell::RefCell;
100use std::collections::HashMap;
101use std::fmt;
102use std::iter;
103use std::sync::atomic::{AtomicUsize, Ordering};
104use std::sync::{Arc, Weak};
105use std::thread;
106use std::time::{Duration, Instant};
107
108// bring in addition utilities
109use atomic_refcell::AtomicRefCell;
110use crossbeam::atomic::AtomicCell;
111
112use uuid::Uuid;
113
114#[allow(unused_imports)]
115#[macro_use]
116extern crate smart_default;
117
118#[allow(unused_imports)]
119#[macro_use]
120extern crate log;
121
122// pull in all of the modules
123mod foundation {
124    use super::*;
125    pub mod linear_backoff;
126    pub mod machine;
127    pub mod simple_event_timer;
128    pub mod thread_safe;
129}
130mod tls {
131    #![allow(dead_code)]
132    use super::*;
133    use crate::foundation::{linear_backoff::LinearBackoff, thread_safe::*};
134    pub mod collective;
135    pub mod tls_executor;
136}
137mod channel {
138    #![allow(dead_code)]
139    use super::*;
140    use crate::foundation::machine::*;
141    use crate::tls::collective::{MachineState, WeakShareableMachine};
142    use crate::tls::tls_executor::ExecutorData;
143    mod connection;
144    pub mod machine_channel;
145    pub mod receiver;
146    pub mod sender;
147}
148mod collective {
149    #![allow(dead_code)]
150    use super::*;
151    use crate::channel::{receiver::*, sender::*};
152    use crate::foundation::machine::*;
153    use crate::tls::collective::*;
154    pub mod machine;
155}
156mod scheduler {
157    #![allow(dead_code)]
158    use super::*;
159    use crate::collective::machine::*;
160    use crate::foundation::{linear_backoff::*, machine::*, simple_event_timer::*};
161    use crate::tls::{collective::*, tls_executor::*};
162    pub mod executor;
163    pub mod machine;
164    mod overwatch;
165    pub mod sched;
166    mod sched_factory;
167    pub mod setup_teardown;
168    pub mod traits;
169}
170
171// publish the parts needed outside of the core
172
173// package up things needed for #[derive(MachineImpl)]
174pub mod machine_impl {
175    pub use crate::channel::{
176        machine_channel::{channel, channel_with_capacity},
177        receiver::Receiver,
178        sender::Sender,
179    };
180    pub use crate::collective::machine::MachineBuilder;
181    pub use crate::foundation::{machine::Machine, machine::MachineImpl};
182    pub use crate::tls::{
183        collective::{MachineAdapter, MachineDependentAdapter, MachineState, ShareableMachine, SharedMachineState},
184        tls_executor::{
185            tls_executor_data, ExecutorDataField, ExecutorStats, MachineDependentSenderAdapter, MachineSenderAdapter, Task, TrySendError,
186        },
187    };
188}
189
190// package up the send_cmd utility function
191pub use crate::collective::machine::send_cmd;
192
193// package up thing needed to tune and start the schduler and inject
194// machines into the collective. For backward compatability, export deprecated
195// symbols until they've been dprecrated for a while.
196#[allow(deprecated)]
197pub mod executor {
198    pub use crate::scheduler::{
199        executor::{get_executors_snoozing, get_run_queue_len, get_time_slice, set_time_slice},
200        machine::{
201            and_connect, and_connect_unbounded, and_connect_with_capacity, connect, connect_unbounded, connect_with_capacity,
202            get_default_channel_capacity, set_default_channel_capacity,
203        },
204        sched::{
205            get_machine_count, get_machine_count_estimate, get_selector_maintenance_duration, set_machine_count_estimate,
206            set_selector_maintenance_duration,
207        },
208        setup_teardown::{get_executor_count, set_executor_count, start_server, stop_server},
209    };
210    pub mod stats {
211        pub use crate::scheduler::{
212            sched::SchedStats,
213            setup_teardown::{add_core_stats_sender, remove_core_stats_sender, request_machine_info, request_stats_now},
214            traits::{CoreStatsMessage, CoreStatsSender},
215        };
216        pub use crate::tls::tls_executor::ExecutorStats;
217    }
218}