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}