1use std::{
2 cell::RefCell,
3 fmt,
4 future::Future,
5 pin::Pin,
6 sync::atomic::{AtomicUsize, Ordering},
7 task::{Context, Poll},
8 thread,
9};
10
11use futures_core::ready;
12use tokio::sync::mpsc;
13
14use crate::system::{System, SystemCommand};
15
16pub(crate) static COUNT: AtomicUsize = AtomicUsize::new(0);
17
18thread_local!(
19 static HANDLE: RefCell<Option<ArbiterHandle>> = const { RefCell::new(None) };
20);
21
22pub(crate) enum ArbiterCommand {
23 Stop,
24 Execute(Pin<Box<dyn Future<Output = ()> + Send>>),
25}
26
27impl fmt::Debug for ArbiterCommand {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 ArbiterCommand::Stop => write!(f, "ArbiterCommand::Stop"),
31 ArbiterCommand::Execute(_) => write!(f, "ArbiterCommand::Execute"),
32 }
33 }
34}
35
36#[derive(Debug, Clone)]
38pub struct ArbiterHandle {
39 tx: mpsc::UnboundedSender<ArbiterCommand>,
40}
41
42impl ArbiterHandle {
43 pub(crate) fn new(tx: mpsc::UnboundedSender<ArbiterCommand>) -> Self {
44 Self { tx }
45 }
46
47 pub fn spawn<Fut>(&self, future: Fut) -> bool
53 where
54 Fut: Future<Output = ()> + Send + 'static,
55 {
56 self.tx
57 .send(ArbiterCommand::Execute(Box::pin(future)))
58 .is_ok()
59 }
60
61 pub fn spawn_fn<F>(&self, f: F) -> bool
68 where
69 F: FnOnce() + Send + 'static,
70 {
71 self.spawn(async { f() })
72 }
73
74 pub fn stop(&self) -> bool {
79 self.tx.send(ArbiterCommand::Stop).is_ok()
80 }
81}
82
83#[derive(Debug)]
88pub struct Arbiter {
89 tx: mpsc::UnboundedSender<ArbiterCommand>,
90 thread_handle: thread::JoinHandle<()>,
91}
92
93impl Arbiter {
94 #[allow(clippy::new_without_default)]
99 pub fn new() -> Arbiter {
100 Self::with_tokio_rt(|| {
101 crate::runtime::default_tokio_runtime().expect("Cannot create new Arbiter's Runtime.")
102 })
103 }
104
105 pub fn with_tokio_rt<F, R>(runtime_factory: F) -> Arbiter
114 where
115 F: FnOnce() -> R + Send + 'static,
116 R: Into<crate::runtime::Runtime> + Send + 'static,
117 {
118 let sys = System::current();
119 let system_id = sys.id();
120 let arb_id = COUNT.fetch_add(1, Ordering::Relaxed);
121
122 let name = format!("actix-rt|system:{system_id}|arbiter:{arb_id}");
123 let (tx, rx) = mpsc::unbounded_channel();
124
125 let (ready_tx, ready_rx) = std::sync::mpsc::channel::<()>();
126
127 let thread_handle = thread::Builder::new()
128 .name(name.clone())
129 .spawn({
130 let tx = tx.clone();
131 move || {
132 let rt = runtime_factory().into();
133 let hnd = ArbiterHandle::new(tx);
134
135 System::set_current(sys);
136
137 HANDLE.with(|cell| *cell.borrow_mut() = Some(hnd.clone()));
138
139 let _ = System::current()
141 .tx()
142 .send(SystemCommand::RegisterArbiter(arb_id, hnd));
143
144 ready_tx.send(()).unwrap();
145
146 rt.block_on(ArbiterRunner { rx });
148
149 let _ = System::current()
151 .tx()
152 .send(SystemCommand::DeregisterArbiter(arb_id));
153 }
154 })
155 .unwrap_or_else(|err| panic!("Cannot spawn Arbiter's thread: {name:?}: {err:?}"));
156
157 ready_rx.recv().unwrap();
158
159 Arbiter { tx, thread_handle }
160 }
161
162 pub(crate) fn in_new_system() -> ArbiterHandle {
164 let (tx, rx) = mpsc::unbounded_channel();
165
166 let hnd = ArbiterHandle::new(tx);
167
168 HANDLE.with(|cell| *cell.borrow_mut() = Some(hnd.clone()));
169
170 crate::spawn(ArbiterRunner { rx });
171
172 hnd
173 }
174
175 pub fn handle(&self) -> ArbiterHandle {
177 ArbiterHandle::new(self.tx.clone())
178 }
179
180 pub fn current() -> ArbiterHandle {
185 HANDLE.with(|cell| match *cell.borrow() {
186 Some(ref hnd) => hnd.clone(),
187 None => panic!("Arbiter is not running."),
188 })
189 }
190
191 pub fn try_current() -> Option<ArbiterHandle> {
197 HANDLE.with(|cell| cell.borrow().clone())
198 }
199
200 pub fn stop(&self) -> bool {
204 self.tx.send(ArbiterCommand::Stop).is_ok()
205 }
206
207 #[track_caller]
213 pub fn spawn<Fut>(&self, future: Fut) -> bool
214 where
215 Fut: Future<Output = ()> + Send + 'static,
216 {
217 self.tx
218 .send(ArbiterCommand::Execute(Box::pin(future)))
219 .is_ok()
220 }
221
222 #[track_caller]
229 pub fn spawn_fn<F>(&self, f: F) -> bool
230 where
231 F: FnOnce() + Send + 'static,
232 {
233 self.spawn(async { f() })
234 }
235
236 pub fn join(self) -> thread::Result<()> {
240 self.thread_handle.join()
241 }
242}
243
244struct ArbiterRunner {
246 rx: mpsc::UnboundedReceiver<ArbiterCommand>,
247}
248
249impl Future for ArbiterRunner {
250 type Output = ();
251
252 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
253 loop {
255 match ready!(self.rx.poll_recv(cx)) {
256 None => return Poll::Ready(()),
258
259 Some(item) => match item {
261 ArbiterCommand::Stop => {
262 return Poll::Ready(());
263 }
264 ArbiterCommand::Execute(task_fut) => {
265 tokio::task::spawn_local(task_fut);
266 }
267 },
268 }
269 }
270 }
271}