1use std::any::{Any, TypeId};
2use std::collections::VecDeque;
3use std::sync::{Arc, atomic::AtomicBool, atomic::AtomicUsize, atomic::Ordering};
4use std::time::{Duration, Instant};
5use std::{cell::RefCell, fmt, future::Future, pin::Pin};
6
7use async_channel::{Receiver, Sender, unbounded};
8use futures_timer::Delay;
9use parking_lot::{Mutex, RwLock};
10
11use crate::arbiter::Arbiter;
12use crate::pool::{PoolMetrics, ThreadPool};
13use crate::{BlockingResult, Builder, Handle, HashMap, Runner, SystemRunner};
14
15static SYSTEM_COUNT: AtomicUsize = AtomicUsize::new(0);
16
17thread_local!(
18 static PINGS: RefCell<HashMap<Id, VecDeque<PingRecord>>> = RefCell::new(HashMap::default());
19);
20
21#[derive(Default)]
22struct Arbiters {
23 all: HashMap<Id, Arbiter>,
24 list: Vec<Arbiter>,
25}
26
27#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
31pub struct Id(pub(crate) usize);
32
33pub struct System(pub(crate) Arc<SystemInner>);
41
42pub(crate) struct SystemInner {
43 id: usize,
44 arbiter: Arbiter,
45 pub(crate) config: SystemConfig,
46 sender: Sender<SystemCommand>,
47 receiver: Receiver<SystemCommand>,
48 storage: RwLock<HashMap<TypeId, Box<dyn Any + Sync + Send>>>,
49 arbiters: Mutex<Arbiters>,
50 signals: AtomicBool,
51 pool: ThreadPool,
52}
53
54#[derive(Clone)]
60pub struct SystemConfig {
61 pub(super) name: String,
62 pub(super) stack_size: usize,
63 pub(super) ping_interval: usize,
64 pub(super) ping_threshold: usize,
65 pub(super) latency_interval: usize,
66 pub(super) pool_limit: usize,
67 pub(super) pool_recv_timeout: Duration,
68 pub(super) testing: bool,
69 pub(super) runner: Arc<dyn Runner>,
70}
71
72thread_local!(
73 static CURRENT: RefCell<Option<System>> = const { RefCell::new(None) };
74);
75
76impl Clone for System {
77 fn clone(&self) -> Self {
78 Self(self.0.clone())
79 }
80}
81
82impl SystemInner {
83 pub(crate) fn arbiters(&self) -> Vec<Arbiter> {
85 self.arbiters.lock().list.clone()
86 }
87}
88
89impl System {
90 pub(super) fn start(config: SystemConfig) -> (Self, oneshot::Receiver<i32>) {
92 let id = SYSTEM_COUNT.fetch_add(1, Ordering::SeqCst);
93 let (sender, receiver) = unbounded();
94
95 let pool = ThreadPool::new(&config.name, config.pool_limit, config.pool_recv_timeout);
96 let (arbiter, controller) = Arbiter::new_system(id, config.name.clone());
97
98 let mut arbiters = Arbiters::default();
99 arbiters.all.insert(arbiter.id(), arbiter.clone());
100 arbiters.list.push(arbiter.clone());
101
102 let sys = System(Arc::new(SystemInner {
103 id,
104 config,
105 arbiter,
106 sender,
107 receiver,
108 pool,
109 arbiters: Mutex::new(arbiters),
110 storage: RwLock::new(HashMap::default()),
111 signals: AtomicBool::new(false),
112 }));
113 System::set_current(sys.clone());
114
115 let (stop_tx, stop) = oneshot::channel();
116
117 crate::spawn_detached(SystemSupport::new(&sys, stop_tx).run());
119 crate::spawn_detached(controller.run(sys.clone()));
120
121 (sys, stop)
122 }
123
124 pub fn build() -> Builder {
128 Builder::new()
129 }
130
131 #[allow(clippy::new_ret_no_self)]
132 pub fn new<R: Runner>(name: &str, runner: R) -> SystemRunner {
136 Self::build().name(name).build(runner)
137 }
138
139 #[allow(clippy::new_ret_no_self)]
140 pub fn with_config(name: &str, mut config: SystemConfig) -> SystemRunner {
145 name.clone_into(&mut config.name);
146 Self::build().name(name).build_with(config)
147 }
148
149 pub fn current() -> System {
155 CURRENT.with(|cell| match *cell.borrow() {
156 Some(ref sys) => sys.clone(),
157 None => panic!("System is not running"),
158 })
159 }
160
161 pub fn try_current() -> Option<System> {
163 CURRENT.with(|cell| cell.borrow().as_ref().map(Clone::clone))
164 }
165
166 #[doc(hidden)]
168 pub fn set_current(sys: System) {
169 CURRENT.with(|s| {
170 *s.borrow_mut() = Some(sys);
171 });
172 }
173
174 pub(crate) fn register_arbiter(&self, arb: Arbiter) {
175 CURRENT.with(|s| {
176 *s.borrow_mut() = Some(self.clone());
177 });
178 let mut arbiters = self.0.arbiters.lock();
179 arbiters.all.insert(arb.id(), arb.clone());
180 arbiters.list.push(arb);
181 }
182
183 pub(crate) fn unregister_arbiter(&self, id: Id) {
184 CURRENT.with(|s| {
185 *s.borrow_mut() = None;
186 });
187 let mut arbiters = self.0.arbiters.lock();
188 if let Some(hnd) = arbiters.all.remove(&id) {
189 for (idx, arb) in arbiters.list.iter().enumerate() {
190 if &hnd == arb {
191 arbiters.list.remove(idx);
192 break;
193 }
194 }
195 }
196 }
197
198 pub(super) fn remove_current() {
199 CURRENT.with(|cell| {
200 cell.borrow_mut().take();
201 });
202 }
203
204 pub(super) fn take_arbiters(&self) -> Vec<Arbiter> {
206 let mut arbiters = self.0.arbiters.lock();
207 arbiters.all.clear();
208 std::mem::take(&mut arbiters.list)
209 }
210
211 pub(super) fn stop_arbiters(&self) {
213 for arb in self.take_arbiters() {
214 arb.stop();
215 }
216 }
217
218 pub fn id(&self) -> Id {
220 Id(self.0.id)
221 }
222
223 pub fn name(&self) -> &str {
225 &self.0.config.name
226 }
227
228 pub fn stop(&self) {
232 self.stop_with_code(0);
233 }
234
235 pub fn stop_with_code(&self, code: i32) {
242 let _ = self.0.sender.try_send(SystemCommand::Exit(code));
243 }
244
245 pub fn signals(&self) -> bool {
247 self.0.signals.load(Ordering::Relaxed)
248 }
249
250 pub fn enable_signals(&self) {
256 if !self.signals() && crate::signals::start(self) {
257 self.0.signals.store(true, Ordering::Relaxed);
258 }
259 }
260
261 pub fn disable_signals(&self) {
263 if self.signals() {
264 crate::signals::stop(self);
265 self.0.signals.store(false, Ordering::Relaxed);
266 }
267 }
268
269 pub fn arbiter(&self) -> Arbiter {
271 self.0.arbiter.clone()
272 }
273
274 pub fn list_arbiters<F, R>(&self, f: F) -> R
281 where
282 F: FnOnce(&[Arbiter]) -> R,
283 {
284 f(&self.0.arbiters())
285 }
286
287 pub fn list_arbiter_pings<F>(mut f: F)
301 where
302 F: FnMut(&Arbiter, &mut VecDeque<PingRecord>),
303 {
304 PINGS.with(|pings| {
305 let mut p = pings.borrow_mut();
306 let sys = System::current();
307 let arbiters: Vec<_> = {
308 let arbiters = sys.0.arbiters.lock();
309 p.keys()
310 .filter_map(|id| arbiters.all.get(id).map(|arb| (*id, arb.clone())))
311 .collect()
312 };
313
314 for (id, arb) in &arbiters {
316 if let Some(recs) = p.get_mut(id) {
317 f(arb, recs);
318 }
319 }
320 });
321 }
322
323 #[doc(hidden)]
324 pub fn set_latency_callback<F>(f: F)
332 where
333 F: Fn(ntex_error::Backtrace, Option<&'static std::panic::Location<'static>>)
334 + Send
335 + Sync
336 + 'static,
337 {
338 crate::watchdog::set_latency_callback(Arc::new(f));
339 }
340
341 pub fn config(&self) -> SystemConfig {
343 self.0.config.clone()
344 }
345
346 #[inline]
347 pub fn handle(&self) -> Handle {
349 self.arbiter().handle().clone()
350 }
351
352 pub fn testing(&self) -> bool {
354 self.0.config.testing()
355 }
356
357 pub fn spawn_blocking<F, R>(&self, f: F) -> BlockingResult<R>
367 where
368 F: FnOnce() -> R + Send + 'static,
369 R: Send + 'static,
370 {
371 self.0.pool.execute(f)
372 }
373
374 pub fn pool_metrics(&self) -> PoolMetrics {
376 self.0.pool.metrics()
377 }
378
379 pub fn get_value<T>(&self, f: impl FnOnce() -> T) -> T
386 where
387 T: Clone + Send + Sync + 'static,
388 {
389 if let Some(boxed) = self.0.storage.read().get(&TypeId::of::<T>())
390 && let Some(val) = (&**boxed as &(dyn Any + 'static)).downcast_ref::<T>()
391 {
392 val.clone()
393 } else {
394 let val = f();
395 self.0
396 .storage
397 .write()
398 .insert(TypeId::of::<T>(), Box::new(val.clone()));
399 val
400 }
401 }
402}
403
404impl SystemConfig {
405 #[inline]
406 pub fn testing(&self) -> bool {
408 self.testing
409 }
410}
411
412impl fmt::Debug for System {
413 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
414 f.debug_struct("System")
415 .field("id", &self.0.id)
416 .field("config", &self.0.config)
417 .field("signals", &self.signals())
418 .field("pool", &self.0.pool)
419 .finish()
420 }
421}
422
423impl fmt::Debug for SystemConfig {
424 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425 f.debug_struct("SystemConfig")
426 .field("name", &self.name)
427 .field("testing", &self.testing)
428 .field("stack_size", &self.stack_size)
429 .finish()
430 }
431}
432
433#[derive(Debug)]
434pub(super) enum SystemCommand {
435 Exit(i32),
436}
437
438#[derive(Debug)]
439struct SystemSupport {
440 sys: System,
441 stop: Option<oneshot::Sender<i32>>,
442 commands: Receiver<SystemCommand>,
443 watchdog: Option<Arc<AtomicBool>>,
444}
445
446impl Drop for SystemSupport {
447 fn drop(&mut self) {
448 self.stop_watchdog();
449 }
450}
451
452impl SystemSupport {
453 fn new(sys: &System, stop: oneshot::Sender<i32>) -> Self {
454 Self {
455 sys: sys.clone(),
456 stop: Some(stop),
457 commands: sys.0.receiver.clone(),
458 watchdog: None,
459 }
460 }
461
462 fn stop_watchdog(&mut self) {
463 if let Some(stop) = self.watchdog.take() {
464 stop.store(true, Ordering::Relaxed);
465 }
466 }
467
468 async fn run(mut self) {
469 crate::metrics::start_latency_sampler(
470 &self.sys.0.arbiter.0.latency,
471 self.sys.0.config.latency_interval,
472 );
473 self.watchdog = crate::watchdog::start(&self.sys);
474 if self.sys.0.config.ping_interval != 0 {
475 crate::spawn_detached(ping_arbiters(self.sys.clone()));
476 }
477
478 loop {
479 match self.commands.recv().await {
480 Ok(SystemCommand::Exit(code)) => {
481 log::debug!("Stopping system with {code} code");
482 self.stop_watchdog();
483 self.sys.stop_arbiters();
484
485 crate::arbiter::run_shutdown_callbacks();
486
487 if let Some(stop) = self.stop.take() {
489 let _ = stop.send(code);
490 }
491 }
492 Err(_) => {
493 log::debug!("System stopped");
494 return;
495 }
496 }
497 }
498 }
499}
500
501#[derive(Copy, Clone, Debug)]
503pub struct PingRecord {
504 pub start: Instant,
506 pub rtt: Option<Duration>,
511}
512
513async fn ping_arbiters(sys: System) {
514 let interval = Duration::from_millis(sys.0.config.ping_interval as u64);
515
516 loop {
517 Delay::new(interval).await;
519
520 let start = Instant::now();
521 let arbiters = sys.0.arbiters.lock();
522
523 PINGS.with(|pings| {
525 pings
526 .borrow_mut()
527 .retain(|id, _| arbiters.all.contains_key(id));
528 });
529
530 for arb in &arbiters.list {
531 let id = arb.id();
532 let fut = arb.handle().spawn(async move {
533 yield_to().await;
534 });
535
536 PINGS.with(|pings| {
537 let mut p = pings.borrow_mut();
538 let recs = p.entry(id).or_default();
539 recs.push_front(PingRecord { start, rtt: None });
540 recs.truncate(10);
541 });
542
543 crate::spawn_detached(async move {
544 if fut.await.is_ok() {
545 PINGS.with(|pings| {
546 if let Some(recs) = pings.borrow_mut().get_mut(&id)
548 && let Some(rec) = recs.iter_mut().find(|r| r.start == start)
549 {
550 rec.rtt = Some(start.elapsed());
551 }
552 });
553 }
554 });
555 }
556 }
557}
558
559async fn yield_to() {
560 use std::task::{Context, Poll};
561
562 struct Yield {
563 completed: bool,
564 }
565
566 impl Future for Yield {
567 type Output = ();
568
569 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
570 if self.completed {
571 return Poll::Ready(());
572 }
573 self.completed = true;
574 cx.waker().wake_by_ref();
575 Poll::Pending
576 }
577 }
578
579 Yield { completed: false }.await;
580}
581
582#[cfg(test)]
583#[path = "../tests/unit/system.rs"]
584mod tests;