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, panic, pin::Pin, rc::Rc};
6
7use async_channel::{Receiver, Sender, unbounded};
8use futures_timer::Delay;
9use parking_lot::{Mutex, RwLock};
10
11use crate::arbiter::Arbiter;
12use crate::pool::ThreadPool;
13use crate::{BlockingResult, Builder, Handle, HashMap, HashSet, Runner, SystemRunner};
14
15static SYSTEM_COUNT: AtomicUsize = AtomicUsize::new(0);
16
17thread_local!(
18 static PINGS: RefCell<HashMap<Id, VecDeque<PingRecord>>> =
19 RefCell::new(HashMap::default());
20);
21
22#[derive(Default)]
23struct Arbiters {
24 all: HashMap<Id, Arbiter>,
25 list: Vec<Arbiter>,
26}
27
28#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
30pub struct Id(pub(crate) usize);
31
32pub struct System(Arc<SystemInner>);
34
35struct SystemInner {
36 id: usize,
37 arbiter: Arbiter,
38 config: SystemConfig,
39 sender: Sender<SystemCommand>,
40 receiver: Receiver<SystemCommand>,
41 storage: RwLock<HashMap<TypeId, Box<dyn Any + Sync + Send>>>,
42 arbiters: Mutex<Arbiters>,
43 signals: AtomicBool,
44 pool: ThreadPool,
45}
46
47#[derive(Clone)]
48pub struct SystemConfig {
49 pub(super) name: String,
50 pub(super) stack_size: usize,
51 pub(super) ping_interval: usize,
52 #[allow(dead_code)]
53 pub(super) ping_threshold: usize,
54 pub(super) pool_limit: usize,
55 pub(super) pool_recv_timeout: Duration,
56 pub(super) testing: bool,
57 pub(super) runner: Arc<dyn Runner>,
58}
59
60thread_local!(
61 static CURRENT: RefCell<Option<System>> = const { RefCell::new(None) };
62);
63
64impl Clone for System {
65 fn clone(&self) -> Self {
66 Self(self.0.clone())
67 }
68}
69
70impl System {
71 pub(super) fn start(config: SystemConfig) -> (Self, oneshot::Receiver<i32>) {
73 let id = SYSTEM_COUNT.fetch_add(1, Ordering::SeqCst);
74 let (sender, receiver) = unbounded();
75
76 let pool =
77 ThreadPool::new(&config.name, config.pool_limit, config.pool_recv_timeout);
78 let (arbiter, controller) = Arbiter::new_system(id, config.name.clone());
79
80 let mut arbiters = Arbiters::default();
81 arbiters.all.insert(arbiter.id(), arbiter.clone());
82 arbiters.list.push(arbiter.clone());
83
84 let sys = System(Arc::new(SystemInner {
85 id,
86 config,
87 arbiter,
88 sender,
89 receiver,
90 pool,
91 arbiters: Mutex::new(arbiters),
92 storage: RwLock::new(HashMap::default()),
93 signals: AtomicBool::new(false),
94 }));
95 System::set_current(sys.clone());
96
97 let (stop_tx, stop) = oneshot::channel();
98
99 crate::spawn(SystemSupport::new(&sys, stop_tx).run());
101 crate::spawn(controller.run(sys.clone()));
102
103 (sys, stop)
104 }
105
106 pub fn build() -> Builder {
111 Builder::new()
112 }
113
114 #[allow(clippy::new_ret_no_self)]
115 pub fn new<R: Runner>(name: &str, runner: R) -> SystemRunner {
119 Self::build().name(name).build(runner)
120 }
121
122 #[allow(clippy::new_ret_no_self)]
123 pub fn with_config(name: &str, config: SystemConfig) -> SystemRunner {
127 Self::build().name(name).build_with(config)
128 }
129
130 pub fn current() -> System {
136 CURRENT.with(|cell| match *cell.borrow() {
137 Some(ref sys) => sys.clone(),
138 None => panic!("System is not running"),
139 })
140 }
141
142 pub fn try_current() -> Option<System> {
144 CURRENT.with(|cell| cell.borrow().as_ref().map(Clone::clone))
145 }
146
147 #[doc(hidden)]
149 pub fn set_current(sys: System) {
150 CURRENT.with(|s| {
151 *s.borrow_mut() = Some(sys);
152 });
153 }
154
155 pub(crate) fn register_arbiter(&self, arb: Arbiter) {
156 CURRENT.with(|s| {
157 *s.borrow_mut() = Some(self.clone());
158 });
159 let mut arbiters = self.0.arbiters.lock();
160 arbiters.all.insert(arb.id(), arb.clone());
161 arbiters.list.push(arb);
162 }
163
164 pub(crate) fn unregister_arbiter(&self, id: Id) {
165 CURRENT.with(|s| {
166 *s.borrow_mut() = None;
167 });
168 let mut arbiters = self.0.arbiters.lock();
169 if let Some(hnd) = arbiters.all.remove(&id) {
170 for (idx, arb) in arbiters.list.iter().enumerate() {
171 if &hnd == arb {
172 arbiters.list.remove(idx);
173 break;
174 }
175 }
176 }
177 }
178
179 pub(super) fn remove_current() {
180 CURRENT.with(|cell| {
181 cell.borrow_mut().take();
182 });
183 }
184
185 pub fn id(&self) -> Id {
187 Id(self.0.id)
188 }
189
190 pub fn name(&self) -> &str {
192 &self.0.config.name
193 }
194
195 pub fn stop(&self) {
197 self.stop_with_code(0);
198 }
199
200 pub fn stop_with_code(&self, code: i32) {
202 let _ = self.0.sender.try_send(SystemCommand::Exit(code));
203 }
204
205 #[doc(hidden)]
206 #[deprecated(since = "3.17.0")]
207 pub fn stop_on_panic(&self) -> bool {
212 false
213 }
214
215 pub fn signals(&self) -> bool {
217 self.0.signals.load(Ordering::Relaxed)
218 }
219
220 pub fn enable_signals(&self) {
222 if !self.signals() {
223 crate::signals::start(self);
224 self.0.signals.store(true, Ordering::Relaxed);
225 }
226 }
227
228 pub fn disable_signals(&self) {
230 if self.signals() {
231 crate::signals::stop(self);
232 self.0.signals.store(false, Ordering::Relaxed);
233 }
234 }
235
236 pub fn arbiter(&self) -> Arbiter {
242 self.0.arbiter.clone()
243 }
244
245 pub fn list_arbiters<F, R>(&self, f: F) -> R
250 where
251 F: FnOnce(&[Arbiter]) -> R,
252 {
253 f(&self.0.arbiters.lock().list)
254 }
255
256 pub fn list_arbiter_pings<F>(mut f: F)
261 where
262 F: FnMut(&Arbiter, &mut VecDeque<PingRecord>),
263 {
264 PINGS.with(|pings| {
265 let mut p = pings.borrow_mut();
266 let sys = System::current();
267 let arbiters = sys.0.arbiters.lock();
268
269 for (id, recs) in &mut *p {
270 if let Some(arb) = arbiters.all.get(id) {
271 f(arb, recs);
272 }
273 }
274 });
275 }
276
277 #[cfg(target_os = "linux")]
278 #[doc(hidden)]
279 pub fn set_latency_callback<F: Fn(ntex_error::Backtrace) + 'static>(f: F) {
286 unsafe {
287 ARB_CB = Some(Box::new(f));
288 }
289 }
290
291 pub fn config(&self) -> SystemConfig {
293 self.0.config.clone()
294 }
295
296 #[inline]
297 pub fn handle(&self) -> Handle {
299 self.arbiter().handle().clone()
300 }
301
302 pub fn testing(&self) -> bool {
304 self.0.config.testing()
305 }
306
307 pub fn spawn_blocking<F, R>(&self, f: F) -> BlockingResult<R>
312 where
313 F: FnOnce() -> R + Send + 'static,
314 R: Send + 'static,
315 {
316 self.0.pool.execute(f)
317 }
318
319 pub fn get_value<T>(&self, f: impl FnOnce() -> T) -> T
324 where
325 T: Clone + Send + Sync + 'static,
326 {
327 if let Some(boxed) = self.0.storage.read().get(&TypeId::of::<T>())
328 && let Some(val) = (&**boxed as &(dyn Any + 'static)).downcast_ref::<T>()
329 {
330 val.clone()
331 } else {
332 let val = f();
333 self.0
334 .storage
335 .write()
336 .insert(TypeId::of::<T>(), Box::new(val.clone()));
337 val
338 }
339 }
340}
341
342impl SystemConfig {
343 #[inline]
344 pub fn testing(&self) -> bool {
346 self.testing
347 }
348}
349
350impl fmt::Debug for System {
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 f.debug_struct("System")
353 .field("id", &self.0.id)
354 .field("config", &self.0.config)
355 .field("signals", &self.signals())
356 .field("pool", &self.0.pool)
357 .finish()
358 }
359}
360
361impl fmt::Debug for SystemConfig {
362 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
363 f.debug_struct("SystemConfig")
364 .field("name", &self.name)
365 .field("testing", &self.testing)
366 .field("stack_size", &self.stack_size)
367 .finish()
368 }
369}
370
371#[derive(Debug)]
372pub(super) enum SystemCommand {
373 Exit(i32),
374}
375
376#[derive(Debug)]
377struct SystemSupport {
378 sys: System,
379 stop: Option<oneshot::Sender<i32>>,
380 commands: Receiver<SystemCommand>,
381}
382
383impl SystemSupport {
384 fn new(sys: &System, stop: oneshot::Sender<i32>) -> Self {
385 Self {
386 sys: sys.clone(),
387 stop: Some(stop),
388 commands: sys.0.receiver.clone(),
389 }
390 }
391
392 async fn run(mut self) {
393 if self.sys.0.config.ping_interval != 0 {
394 crate::spawn(ping_arbiters(self.sys.clone()));
395 }
396
397 loop {
398 match self.commands.recv().await {
399 Ok(SystemCommand::Exit(code)) => {
400 log::debug!("Stopping system with {code} code");
401
402 let mut arbiters = self.sys.0.arbiters.lock();
404 for arb in arbiters.list.drain(..) {
405 arb.stop();
406 }
407 arbiters.all.clear();
408
409 if let Some(stop) = self.stop.take() {
411 let _ = stop.send(code);
412 }
413 }
414 Err(_) => {
415 log::debug!("System stopped");
416 return;
417 }
418 }
419 }
420 }
421}
422
423#[derive(Copy, Clone, Debug)]
424pub struct PingRecord {
425 pub start: Instant,
427 pub rtt: Option<Duration>,
429}
430
431async fn ping_arbiters(sys: System) {
432 let arbs = Rc::new(RefCell::new(HashSet::default()));
433 let interval = Duration::from_millis(sys.0.config.ping_interval as u64);
434 #[cfg(target_os = "linux")]
435 let threshold = Duration::from_millis(sys.0.config.ping_threshold as u64);
436
437 loop {
438 Delay::new(interval).await;
440
441 {
443 arbs.borrow_mut().clear();
444
445 let start = Instant::now();
446 let arbiters = sys.0.arbiters.lock();
447
448 for arb in &arbiters.list {
449 let id = arb.id();
450 let arbs = arbs.clone();
451 let fut = arb.handle().spawn(async move {
452 yield_to().await;
453 });
454
455 PINGS.with(|pings| {
457 let mut p = pings.borrow_mut();
458 let recs = p.entry(arb.id()).or_default();
459 recs.push_front(PingRecord { start, rtt: None });
460 recs.truncate(10);
461 });
462
463 crate::spawn(async move {
464 if fut.await.is_ok() {
465 arbs.borrow_mut().insert(id);
466
467 PINGS.with(|pings| {
468 if let Some(recs) = pings.borrow_mut().get_mut(&id)
469 && let Some(rec) = recs.front_mut()
470 {
471 rec.rtt = Some(start.elapsed());
472 }
473 });
474 }
475 });
476 }
477 }
478
479 #[cfg(target_os = "linux")]
481 {
482 const SPIN: Duration = Duration::from_micros(100);
483
484 Delay::new(threshold).await;
486
487 let mut no_pongs = Vec::new();
488 {
489 for arb in &sys.0.arbiters.lock().list {
490 let pong = arbs.borrow_mut().remove(&arb.id());
491 if !pong {
492 no_pongs.push(arb.clone());
493 }
494 }
495 }
496
497 if !crate::signals::is_enabled() {
498 continue;
499 }
500
501 for arb in no_pongs {
502 log::error!("Arbiter {}({:?}) did not return pong", arb.name(), arb.id());
504
505 *CAPTURED.lock() = None;
507 EXPECTED_TID.store(arb.tid(), Ordering::Release);
508 let result = unsafe {
509 libc::syscall(
510 libc::SYS_tgkill,
511 libc::getpid(),
512 arb.tid(),
513 libc::SIGUSR2,
514 )
515 };
516
517 if result == -1 {
518 log::error!(
519 "Unsable to send SIGUSR2 to arbiter {}({:?}): {}",
520 arb.name(),
521 arb.id(),
522 std::io::Error::last_os_error()
523 );
524 } else {
525 for _ in 0..1000 {
527 Delay::new(SPIN).await;
528 if let Some(bt) = CAPTURED.lock().take() {
529 let bt = ntex_error::Backtrace::from(bt);
530 #[allow(static_mut_refs)]
531 if let Some(f) = unsafe { ARB_CB.as_ref() } {
532 f(bt);
533 } else {
534 bt.resolver().resolve();
535 log::error!(
536 "Worker does not returned pong within {interval:?} time.\n{bt:?}"
537 );
538 }
539 break;
540 }
541 }
542 }
543 }
544 }
545 }
546}
547
548async fn yield_to() {
549 use std::task::{Context, Poll};
550
551 struct Yield {
552 completed: bool,
553 }
554
555 impl Future for Yield {
556 type Output = ();
557
558 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
559 if self.completed {
560 return Poll::Ready(());
561 }
562 self.completed = true;
563 cx.waker().wake_by_ref();
564 Poll::Pending
565 }
566 }
567
568 Yield { completed: false }.await;
569}
570
571#[cfg(target_os = "linux")]
572static mut ARB_CB: Option<Box<dyn Fn(ntex_error::Backtrace)>> = None;
573
574#[cfg(target_os = "linux")]
575static EXPECTED_TID: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
576#[cfg(target_os = "linux")]
577static CAPTURED: Mutex<Option<ntex_error::BacktraceRaw>> = Mutex::new(None);
578
579#[track_caller]
580#[cfg(target_family = "unix")]
581pub(crate) fn sig_usr2() {
582 #[cfg(target_os = "linux")]
583 #[allow(clippy::cast_possible_truncation)]
584 {
585 let tid = unsafe { libc::syscall(libc::SYS_gettid) } as i32;
586 if EXPECTED_TID.load(Ordering::Acquire) == tid {
587 let bt = ntex_error::BacktraceRaw::new(panic::Location::caller());
590 *CAPTURED.lock() = Some(bt);
591 }
592 }
593}