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