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) timer_resolution: u8,
69 pub(super) testing: bool,
70 pub(super) runner: Arc<dyn Runner>,
71}
72
73thread_local!(
74 static CURRENT: RefCell<Option<System>> = const { RefCell::new(None) };
75);
76
77impl Clone for System {
78 fn clone(&self) -> Self {
79 Self(self.0.clone())
80 }
81}
82
83impl SystemInner {
84 pub(crate) fn arbiters(&self) -> Vec<Arbiter> {
86 self.arbiters.lock().list.clone()
87 }
88}
89
90impl System {
91 pub(super) fn start(config: SystemConfig) -> (Self, oneshot::Receiver<i32>) {
93 let id = SYSTEM_COUNT.fetch_add(1, Ordering::SeqCst);
94 let (sender, receiver) = unbounded();
95
96 let pool = ThreadPool::new(&config.name, config.pool_limit, config.pool_recv_timeout);
97 let (arbiter, controller) = Arbiter::new_system(id, config.name.clone());
98
99 let mut arbiters = Arbiters::default();
100 arbiters.all.insert(arbiter.id(), arbiter.clone());
101 arbiters.list.push(arbiter.clone());
102
103 let sys = System(Arc::new(SystemInner {
104 id,
105 config,
106 arbiter,
107 sender,
108 receiver,
109 pool,
110 arbiters: Mutex::new(arbiters),
111 storage: RwLock::new(HashMap::default()),
112 signals: AtomicBool::new(false),
113 }));
114 System::set_current(sys.clone());
115
116 let (stop_tx, stop) = oneshot::channel();
117
118 crate::spawn_detached(SystemSupport::new(&sys, stop_tx).run());
120 crate::spawn_detached(controller.run(sys.clone()));
121
122 (sys, stop)
123 }
124
125 pub fn build() -> Builder {
129 Builder::new()
130 }
131
132 #[allow(clippy::new_ret_no_self)]
133 pub fn new<R: Runner>(name: &str, runner: R) -> SystemRunner {
137 Self::build().name(name).build(runner)
138 }
139
140 #[allow(clippy::new_ret_no_self)]
141 pub fn with_config(name: &str, mut config: SystemConfig) -> SystemRunner {
146 name.clone_into(&mut config.name);
147 Self::build().name(name).build_with(config)
148 }
149
150 pub fn current() -> System {
156 CURRENT.with(|cell| match *cell.borrow() {
157 Some(ref sys) => sys.clone(),
158 None => panic!("System is not running"),
159 })
160 }
161
162 pub fn try_current() -> Option<System> {
164 CURRENT.with(|cell| cell.borrow().as_ref().map(Clone::clone))
165 }
166
167 #[doc(hidden)]
169 pub fn set_current(sys: System) {
170 CURRENT.with(|s| {
171 *s.borrow_mut() = Some(sys);
172 });
173 }
174
175 pub(crate) fn register_arbiter(&self, arb: Arbiter) {
176 CURRENT.with(|s| {
177 *s.borrow_mut() = Some(self.clone());
178 });
179 let mut arbiters = self.0.arbiters.lock();
180 arbiters.all.insert(arb.id(), arb.clone());
181 arbiters.list.push(arb);
182 }
183
184 pub(crate) fn unregister_arbiter(&self, id: Id) {
185 CURRENT.with(|s| {
186 *s.borrow_mut() = None;
187 });
188 let mut arbiters = self.0.arbiters.lock();
189 if let Some(hnd) = arbiters.all.remove(&id) {
190 for (idx, arb) in arbiters.list.iter().enumerate() {
191 if &hnd == arb {
192 arbiters.list.remove(idx);
193 break;
194 }
195 }
196 }
197 }
198
199 pub(super) fn remove_current() {
200 CURRENT.with(|cell| {
201 cell.borrow_mut().take();
202 });
203 }
204
205 pub(super) fn take_arbiters(&self) -> Vec<Arbiter> {
207 let mut arbiters = self.0.arbiters.lock();
208 arbiters.all.clear();
209 std::mem::take(&mut arbiters.list)
210 }
211
212 pub(super) fn stop_arbiters(&self) {
214 for arb in self.take_arbiters() {
215 arb.stop();
216 }
217 }
218
219 pub fn id(&self) -> Id {
221 Id(self.0.id)
222 }
223
224 pub fn name(&self) -> &str {
226 &self.0.config.name
227 }
228
229 pub fn stop(&self) {
233 self.stop_with_code(0);
234 }
235
236 pub fn stop_with_code(&self, code: i32) {
243 let _ = self.0.sender.try_send(SystemCommand::Exit(code));
244 }
245
246 pub fn signals(&self) -> bool {
248 self.0.signals.load(Ordering::Relaxed)
249 }
250
251 pub fn enable_signals(&self) {
257 if !self.signals() && crate::signals::start(self) {
258 self.0.signals.store(true, Ordering::Relaxed);
259 }
260 }
261
262 pub fn disable_signals(&self) {
264 if self.signals() {
265 crate::signals::stop(self);
266 self.0.signals.store(false, Ordering::Relaxed);
267 }
268 }
269
270 pub fn arbiter(&self) -> Arbiter {
272 self.0.arbiter.clone()
273 }
274
275 pub fn list_arbiters<F, R>(&self, f: F) -> R
282 where
283 F: FnOnce(&[Arbiter]) -> R,
284 {
285 f(&self.0.arbiters())
286 }
287
288 pub fn list_arbiter_pings<F>(mut f: F)
302 where
303 F: FnMut(&Arbiter, &mut VecDeque<PingRecord>),
304 {
305 PINGS.with(|pings| {
306 let mut p = pings.borrow_mut();
307 let sys = System::current();
308 let arbiters: Vec<_> = {
309 let arbiters = sys.0.arbiters.lock();
310 p.keys()
311 .filter_map(|id| arbiters.all.get(id).map(|arb| (*id, arb.clone())))
312 .collect()
313 };
314
315 for (id, arb) in &arbiters {
317 if let Some(recs) = p.get_mut(id) {
318 f(arb, recs);
319 }
320 }
321 });
322 }
323
324 #[doc(hidden)]
325 pub fn set_latency_callback<F>(f: F)
333 where
334 F: Fn(ntex_error::Backtrace, Option<&'static std::panic::Location<'static>>)
335 + Send
336 + Sync
337 + 'static,
338 {
339 crate::watchdog::set_latency_callback(Arc::new(f));
340 }
341
342 pub fn config(&self) -> SystemConfig {
344 self.0.config.clone()
345 }
346
347 #[inline]
348 pub fn handle(&self) -> Handle {
350 self.arbiter().handle().clone()
351 }
352
353 pub fn testing(&self) -> bool {
355 self.0.config.testing()
356 }
357
358 #[inline]
359 pub fn timer_resolution(&self) -> u8 {
363 self.0.config.timer_resolution()
364 }
365
366 pub fn spawn_blocking<F, R>(&self, f: F) -> BlockingResult<R>
376 where
377 F: FnOnce() -> R + Send + 'static,
378 R: Send + 'static,
379 {
380 self.0.pool.execute(f)
381 }
382
383 pub fn pool_metrics(&self) -> PoolMetrics {
385 self.0.pool.metrics()
386 }
387
388 pub fn get_value<T>(&self, f: impl FnOnce() -> T) -> T
395 where
396 T: Clone + Send + Sync + 'static,
397 {
398 if let Some(boxed) = self.0.storage.read().get(&TypeId::of::<T>())
399 && let Some(val) = (&**boxed as &(dyn Any + 'static)).downcast_ref::<T>()
400 {
401 val.clone()
402 } else {
403 let val = f();
404 self.0
405 .storage
406 .write()
407 .insert(TypeId::of::<T>(), Box::new(val.clone()));
408 val
409 }
410 }
411}
412
413impl SystemConfig {
414 #[inline]
415 pub fn testing(&self) -> bool {
417 self.testing
418 }
419
420 #[inline]
421 pub fn timer_resolution(&self) -> u8 {
425 self.timer_resolution
426 }
427}
428
429impl fmt::Debug for System {
430 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431 f.debug_struct("System")
432 .field("id", &self.0.id)
433 .field("config", &self.0.config)
434 .field("signals", &self.signals())
435 .field("pool", &self.0.pool)
436 .finish()
437 }
438}
439
440impl fmt::Debug for SystemConfig {
441 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442 f.debug_struct("SystemConfig")
443 .field("name", &self.name)
444 .field("testing", &self.testing)
445 .field("stack_size", &self.stack_size)
446 .field("timer_resolution", &self.timer_resolution)
447 .finish()
448 }
449}
450
451#[derive(Debug)]
452pub(super) enum SystemCommand {
453 Exit(i32),
454}
455
456#[derive(Debug)]
457struct SystemSupport {
458 sys: System,
459 stop: Option<oneshot::Sender<i32>>,
460 commands: Receiver<SystemCommand>,
461 watchdog: Option<Arc<AtomicBool>>,
462}
463
464impl Drop for SystemSupport {
465 fn drop(&mut self) {
466 self.stop_watchdog();
467 }
468}
469
470impl SystemSupport {
471 fn new(sys: &System, stop: oneshot::Sender<i32>) -> Self {
472 Self {
473 sys: sys.clone(),
474 stop: Some(stop),
475 commands: sys.0.receiver.clone(),
476 watchdog: None,
477 }
478 }
479
480 fn stop_watchdog(&mut self) {
481 if let Some(stop) = self.watchdog.take() {
482 stop.store(true, Ordering::Relaxed);
483 }
484 }
485
486 async fn run(mut self) {
487 crate::metrics::start_latency_sampler(
488 &self.sys.0.arbiter.0.latency,
489 self.sys.0.config.latency_interval,
490 );
491 self.watchdog = crate::watchdog::start(&self.sys);
492 if self.sys.0.config.ping_interval != 0 {
493 crate::spawn_detached(ping_arbiters(self.sys.clone()));
494 }
495
496 loop {
497 match self.commands.recv().await {
498 Ok(SystemCommand::Exit(code)) => {
499 log::debug!("Stopping system with {code} code");
500 self.stop_watchdog();
501 self.sys.stop_arbiters();
502
503 crate::arbiter::run_shutdown_callbacks();
504
505 if let Some(stop) = self.stop.take() {
507 let _ = stop.send(code);
508 }
509 }
510 Err(_) => {
511 log::debug!("System stopped");
512 return;
513 }
514 }
515 }
516 }
517}
518
519#[derive(Copy, Clone, Debug)]
521pub struct PingRecord {
522 pub start: Instant,
524 pub rtt: Option<Duration>,
529}
530
531async fn ping_arbiters(sys: System) {
532 let interval = Duration::from_millis(sys.0.config.ping_interval as u64);
533
534 loop {
535 Delay::new(interval).await;
537
538 let start = Instant::now();
539 let arbiters = sys.0.arbiters.lock();
540
541 PINGS.with(|pings| {
543 pings
544 .borrow_mut()
545 .retain(|id, _| arbiters.all.contains_key(id));
546 });
547
548 for arb in &arbiters.list {
549 let id = arb.id();
550 let fut = arb.handle().spawn(async move {
551 yield_to().await;
552 });
553
554 PINGS.with(|pings| {
555 let mut p = pings.borrow_mut();
556 let recs = p.entry(id).or_default();
557 recs.push_front(PingRecord { start, rtt: None });
558 recs.truncate(10);
559 });
560
561 crate::spawn_detached(async move {
562 if fut.await.is_ok() {
563 PINGS.with(|pings| {
564 if let Some(recs) = pings.borrow_mut().get_mut(&id)
566 && let Some(rec) = recs.iter_mut().find(|r| r.start == start)
567 {
568 rec.rtt = Some(start.elapsed());
569 }
570 });
571 }
572 });
573 }
574 }
575}
576
577async fn yield_to() {
578 use std::task::{Context, Poll};
579
580 struct Yield {
581 completed: bool,
582 }
583
584 impl Future for Yield {
585 type Output = ();
586
587 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
588 if self.completed {
589 return Poll::Ready(());
590 }
591 self.completed = true;
592 cx.waker().wake_by_ref();
593 Poll::Pending
594 }
595 }
596
597 Yield { completed: false }.await;
598}
599
600#[cfg(test)]
601#[path = "../tests/unit/system.rs"]
602mod tests;