1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-12-19 15:32:38 +01:00
actix-net/actix-rt/src/system.rs

198 lines
5.2 KiB
Rust
Raw Normal View History

2021-01-26 10:46:14 +01:00
use std::{
cell::RefCell,
2021-01-29 05:08:14 +01:00
collections::HashMap,
future::Future,
2021-01-26 10:46:14 +01:00
io,
2021-01-29 05:08:14 +01:00
pin::Pin,
2021-01-26 10:46:14 +01:00
sync::atomic::{AtomicUsize, Ordering},
2021-01-29 05:08:14 +01:00
task::{Context, Poll},
2021-01-26 10:46:14 +01:00
};
2018-12-10 04:55:40 +01:00
2021-01-29 05:08:14 +01:00
use futures_core::ready;
use tokio::sync::{mpsc, oneshot};
2018-12-10 04:55:40 +01:00
2021-01-26 10:46:14 +01:00
use crate::{
builder::{Builder, SystemRunner},
2021-01-29 05:08:14 +01:00
worker::Worker,
2021-01-26 10:46:14 +01:00
};
2018-12-10 04:55:40 +01:00
static SYSTEM_COUNT: AtomicUsize = AtomicUsize::new(0);
2018-12-10 04:55:40 +01:00
/// System is a runtime manager.
#[derive(Clone, Debug)]
pub struct System {
id: usize,
2021-01-29 05:08:14 +01:00
tx: mpsc::UnboundedSender<SystemCommand>,
worker: Worker,
2018-12-10 04:55:40 +01:00
stop_on_panic: bool,
}
thread_local!(
static CURRENT: RefCell<Option<System>> = RefCell::new(None);
);
impl System {
/// Constructs new system and sets it as current
pub(crate) fn construct(
2021-01-29 05:08:14 +01:00
sys: mpsc::UnboundedSender<SystemCommand>,
worker: Worker,
2018-12-10 04:55:40 +01:00
stop_on_panic: bool,
) -> Self {
let sys = System {
2021-01-29 03:21:06 +01:00
tx: sys,
2021-01-29 05:08:14 +01:00
worker,
2018-12-10 04:55:40 +01:00
stop_on_panic,
id: SYSTEM_COUNT.fetch_add(1, Ordering::SeqCst),
2018-12-10 04:55:40 +01:00
};
System::set_current(sys.clone());
sys
}
2021-01-29 05:08:14 +01:00
/// Build a new system with a customized Tokio runtime.
2018-12-10 04:55:40 +01:00
///
2021-01-26 10:46:14 +01:00
/// This allows to customize the runtime. See [`Builder`] for more information.
2018-12-10 04:55:40 +01:00
pub fn builder() -> Builder {
Builder::new()
}
/// Create new system.
///
2021-01-29 05:08:14 +01:00
/// This method panics if it can not create Tokio runtime
2021-01-26 10:46:14 +01:00
#[allow(clippy::new_ret_no_self)]
2021-01-29 03:21:06 +01:00
pub fn new(name: impl Into<String>) -> SystemRunner {
2018-12-10 04:55:40 +01:00
Self::builder().name(name).build()
}
/// Get current running system.
pub fn current() -> System {
CURRENT.with(|cell| match *cell.borrow() {
Some(ref sys) => sys.clone(),
None => panic!("System is not running"),
})
}
2021-01-26 10:46:14 +01:00
/// Check if current system has started.
pub fn is_set() -> bool {
2018-12-10 04:55:40 +01:00
CURRENT.with(|cell| cell.borrow().is_some())
}
/// Set current running system.
#[doc(hidden)]
pub fn set_current(sys: System) {
CURRENT.with(|s| {
*s.borrow_mut() = Some(sys);
})
}
/// Execute function with system reference.
pub fn with_current<F, R>(f: F) -> R
where
F: FnOnce(&System) -> R,
{
CURRENT.with(|cell| match *cell.borrow() {
Some(ref sys) => f(sys),
None => panic!("System is not running"),
})
}
2021-01-26 10:46:14 +01:00
/// Numeric system ID.
pub fn id(&self) -> usize {
self.id
}
2021-01-26 10:46:14 +01:00
/// Stop the system (with code 0).
2018-12-10 04:55:40 +01:00
pub fn stop(&self) {
self.stop_with_code(0)
}
/// Stop the system with a particular exit code.
pub fn stop_with_code(&self, code: i32) {
2021-01-29 03:21:06 +01:00
let _ = self.tx.send(SystemCommand::Exit(code));
2018-12-10 04:55:40 +01:00
}
2021-01-29 05:08:14 +01:00
pub(crate) fn tx(&self) -> &mpsc::UnboundedSender<SystemCommand> {
2021-01-29 03:21:06 +01:00
&self.tx
2018-12-10 04:55:40 +01:00
}
/// Return status of 'stop_on_panic' option which controls whether the System is stopped when an
/// uncaught panic is thrown from a worker thread.
2021-01-26 10:46:14 +01:00
pub(crate) fn stop_on_panic(&self) -> bool {
2018-12-10 04:55:40 +01:00
self.stop_on_panic
}
2021-01-26 10:46:14 +01:00
/// Get shared reference to system arbiter.
2021-01-29 05:08:14 +01:00
pub fn arbiter(&self) -> &Worker {
&self.worker
2018-12-10 04:55:40 +01:00
}
2021-01-29 05:08:14 +01:00
/// This function will start Tokio runtime and will finish once the `System::stop()` message
/// is called. Function `f` is called within Tokio runtime context.
pub fn run<F>(f: F) -> io::Result<()>
2018-12-10 04:55:40 +01:00
where
F: FnOnce(),
2018-12-10 04:55:40 +01:00
{
Self::builder().run(f)
}
}
2021-01-29 05:08:14 +01:00
#[derive(Debug)]
pub(crate) enum SystemCommand {
Exit(i32),
RegisterArbiter(usize, Worker),
DeregisterArbiter(usize),
}
#[derive(Debug)]
pub(crate) struct SystemWorker {
stop: Option<oneshot::Sender<i32>>,
commands: mpsc::UnboundedReceiver<SystemCommand>,
workers: HashMap<usize, Worker>,
}
impl SystemWorker {
pub(crate) fn new(
commands: mpsc::UnboundedReceiver<SystemCommand>,
stop: oneshot::Sender<i32>,
) -> Self {
SystemWorker {
commands,
stop: Some(stop),
workers: HashMap::new(),
}
}
}
impl Future for SystemWorker {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// process all items currently buffered in channel
loop {
match ready!(Pin::new(&mut self.commands).poll_recv(cx)) {
// channel closed; no more messages can be received
None => return Poll::Ready(()),
// process system command
Some(cmd) => match cmd {
SystemCommand::Exit(code) => {
// stop arbiters
for arb in self.workers.values() {
arb.stop();
}
// stop event loop
if let Some(stop) = self.stop.take() {
let _ = stop.send(code);
}
}
SystemCommand::RegisterArbiter(name, hnd) => {
self.workers.insert(name, hnd);
}
SystemCommand::DeregisterArbiter(name) => {
self.workers.remove(&name);
}
},
}
}
}
}