1#![allow(clippy::missing_panics_doc)]
2use std::sync::{Arc, atomic::AtomicBool, atomic::AtomicUsize, atomic::Ordering};
3use std::{any::Any, any::TypeId, cell::RefCell, fmt, mem, panic, pin::Pin, thread};
4
5use async_channel::{Receiver, Sender, unbounded};
6use parking_lot::Mutex;
7
8use crate::{Handle, HashMap, Id, System};
9
10thread_local!(
11 static ADDR: RefCell<Option<Arbiter>> = const { RefCell::new(None) };
12 static STORAGE: RefCell<HashMap<TypeId, Box<dyn Any>>> = RefCell::new(HashMap::default());
13);
14
15pub(super) static COUNT: AtomicUsize = AtomicUsize::new(99);
16
17pub(super) enum ArbiterCommand {
18 Stop,
19 #[allow(dead_code)]
20 Execute(Pin<Box<dyn Future<Output = ()> + Send>>),
21}
22
23pub struct Arbiter(pub(crate) Arc<ArbiterInner>);
29
30type OnCloseStorage = Arc<Mutex<Vec<Box<dyn Fn() + Send + Sync>>>>;
31
32pub(crate) struct ArbiterInner {
33 id: usize,
34 name: Arc<String>,
35 sys_id: usize,
36 hnd: Option<Handle>,
37 pub(crate) sender: Sender<ArbiterCommand>,
38 thread_handle: Mutex<Option<thread::JoinHandle<()>>>,
39 on_stop: OnCloseStorage,
40 running: AtomicBool,
41 #[cfg(target_os = "linux")]
42 tid: i32,
43}
44
45impl fmt::Debug for Arbiter {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(f, "Arbiter({:?})", self.0.name.as_ref())
48 }
49}
50
51impl Clone for Arbiter {
52 fn clone(&self) -> Self {
53 Self(self.0.clone())
54 }
55}
56
57impl Default for Arbiter {
58 fn default() -> Self {
59 Self::new()
60 }
61}
62
63impl Arbiter {
64 #[allow(clippy::borrowed_box)]
65 pub(super) fn new_system(id: usize, name: String) -> (Self, ArbiterController) {
66 let (tx, rx) = unbounded();
67
68 let aid = COUNT.fetch_add(1, Ordering::Relaxed);
69 let arb = Arbiter::with_sender(id, aid, Arc::new(name), tx, Arc::default());
70 ADDR.with(|cell| *cell.borrow_mut() = Some(arb.clone()));
71 STORAGE.with(|cell| cell.borrow_mut().clear());
72
73 (
74 arb,
75 ArbiterController {
76 rx,
77 sys: None,
78 stop: None,
79 },
80 )
81 }
82
83 pub fn current() -> Arbiter {
89 ADDR.with(|cell| match *cell.borrow() {
90 Some(ref addr) => addr.clone(),
91 None => panic!("Arbiter is not running"),
92 })
93 }
94
95 pub fn stop(&self) {
97 let _ = self.0.sender.try_send(ArbiterCommand::Stop);
98 }
99
100 pub fn new() -> Arbiter {
103 let id = COUNT.load(Ordering::Relaxed) + 1;
104 Arbiter::with_name(format!("{}:arb:{}", System::current().name(), id))
105 }
106
107 pub fn with_name(name: String) -> Arbiter {
111 let id = COUNT.fetch_add(1, Ordering::Relaxed);
112 let sys = System::current();
113 let name2 = Arc::new(name.clone());
114 let config = sys.config();
115 let (arb_tx, arb_rx) = unbounded();
116
117 let builder = if sys.config().stack_size > 0 {
118 thread::Builder::new()
119 .name(name)
120 .stack_size(sys.config().stack_size)
121 } else {
122 thread::Builder::new().name(name)
123 };
124
125 let name = name2.clone();
126 let sys_id = sys.id();
127 let (arb_hnd_tx, arb_hnd_rx) = oneshot::channel();
128
129 let handle = builder
130 .spawn(move || {
131 let name3 = name2.clone();
132 log::info!("Starting {name3:?} arbiter");
133
134 let sys2 = sys.clone();
135 let (stop, stop_rx) = oneshot::channel();
136 STORAGE.with(|cell| cell.borrow_mut().clear());
137
138 let on_stop = Arc::new(Mutex::new(Vec::new()));
139 let on_stop2 = on_stop.clone();
140
141 let result = crate::driver::block_on(config.runner.as_ref(), async move {
142 let arb = Arbiter::with_sender(sys_id.0, id, name2, arb_tx, on_stop);
143 sys.register_arbiter(arb.clone());
144 arb_hnd_tx
145 .send(arb.clone())
146 .expect("Controller thread has gone");
147
148 crate::spawn(
150 ArbiterController {
151 sys: None,
152 stop: Some(stop),
153 rx: arb_rx,
154 }
155 .run(sys),
156 );
157 ADDR.with(|cell| *cell.borrow_mut() = Some(arb.clone()));
158
159 let _ = stop_rx.await;
161
162 arb.0.running.store(false, Ordering::Relaxed);
164 });
165
166 let on_stop = mem::take(&mut *on_stop2.lock());
167 for f in on_stop {
168 f();
169 }
170
171 sys2.unregister_arbiter(Id(id));
173 unsafe {
174 remove_all_items();
175 }
176
177 if let Err(e) = result {
178 log::error!("Arbiter {name3:?} has panicked.");
179 panic::resume_unwind(e);
180 }
181 log::info!("Arbiter {name3:?} has stopped");
182 })
183 .unwrap_or_else(|err| panic!("Cannot spawn an arbiter's thread {name:?}: {err:?}"));
184
185 let arb = arb_hnd_rx.recv().expect("Could not start new arbiter");
186 *arb.0.thread_handle.lock() = Some(handle);
187 arb
188 }
189
190 fn with_sender(
191 sys_id: usize,
192 id: usize,
193 name: Arc<String>,
194 sender: Sender<ArbiterCommand>,
195 on_stop: OnCloseStorage,
196 ) -> Self {
197 #[cfg(feature = "tokio")]
198 let hnd = { Handle::new(sender.clone()) };
199
200 #[cfg(feature = "compio")]
201 let hnd = { Handle::new(sender.clone()) };
202
203 #[cfg(all(not(feature = "compio"), not(feature = "tokio")))]
204 let hnd = { Handle::current() };
205
206 Self(Arc::new(ArbiterInner {
207 id,
208 sys_id,
209 name,
210 sender,
211 on_stop,
212 hnd: Some(hnd),
213 thread_handle: Mutex::new(None),
214 running: AtomicBool::new(true),
215 #[cfg(target_os = "linux")]
216 #[allow(clippy::cast_possible_truncation)]
217 tid: unsafe { libc::syscall(libc::SYS_gettid) } as i32,
218 }))
219 }
220
221 pub fn id(&self) -> Id {
223 Id(self.0.id)
224 }
225
226 #[cfg(target_os = "linux")]
227 pub(crate) fn tid(&self) -> i32 {
229 self.0.tid
230 }
231
232 pub fn name(&self) -> &str {
234 self.0.name.as_ref()
235 }
236
237 #[inline]
238 pub fn handle(&self) -> &Handle {
240 self.0.hnd.as_ref().unwrap()
241 }
242
243 #[inline]
244 pub fn is_running(&self) -> bool {
246 self.0.running.load(Ordering::Relaxed)
247 }
248
249 pub fn get_value<T, F>(f: F) -> T
251 where
252 T: Clone + 'static,
253 F: FnOnce() -> T,
254 {
255 STORAGE.with(move |cell| {
256 let mut st = cell.borrow_mut();
257 if let Some(boxed) = st.get(&TypeId::of::<T>())
258 && let Some(val) = (&**boxed as &(dyn Any + 'static)).downcast_ref::<T>()
259 {
260 return val.clone();
261 }
262 let val = f();
263 st.insert(TypeId::of::<T>(), Box::new(val.clone()));
264 val
265 })
266 }
267
268 #[must_use]
269 pub fn on_stop<F>(self, f: F) -> Self
271 where
272 F: Fn() + Send + Sync + 'static,
273 {
274 self.0.on_stop.lock().push(Box::new(f));
275 self
276 }
277
278 pub fn join(&mut self) -> thread::Result<()> {
280 if let Some(thread_handle) = self.0.thread_handle.lock().take() {
281 thread_handle.join()
282 } else {
283 Ok(())
284 }
285 }
286}
287
288impl Eq for Arbiter {}
289
290impl PartialEq for Arbiter {
291 fn eq(&self, other: &Self) -> bool {
292 self.0.id == other.0.id && self.0.sys_id == other.0.sys_id
293 }
294}
295
296pub(crate) struct ArbiterController {
297 sys: Option<System>,
298 rx: Receiver<ArbiterCommand>,
299 stop: Option<oneshot::Sender<i32>>,
300}
301
302impl ArbiterController {
303 pub(super) async fn run(mut self, sys: System) {
304 self.sys = Some(sys);
305 loop {
306 match self.rx.recv().await {
307 Ok(ArbiterCommand::Stop) => {
308 if let Some(stop) = self.stop.take() {
309 let _ = stop.send(0);
310 }
311 }
312 Ok(ArbiterCommand::Execute(fut)) => {
313 crate::spawn(fut);
314 }
315 Err(_) => break,
316 }
317 }
318 }
319}
320
321pub fn set_item<T: 'static>(item: T) {
323 STORAGE.with(move |cell| cell.borrow_mut().insert(TypeId::of::<T>(), Box::new(item)));
324}
325
326pub fn get_item<T: Clone + 'static>() -> Option<T> {
328 STORAGE.with(move |cell| {
329 cell.borrow()
330 .get(&TypeId::of::<T>())
331 .and_then(|boxed| boxed.downcast_ref())
332 .cloned()
333 })
334}
335
336pub fn with_item<T: Default + 'static, F, R>(f: F) -> R
338where
339 F: FnOnce(&T) -> R,
340{
341 STORAGE.with(move |cell| {
342 let val: &T = unsafe {
345 let mut st = cell.borrow_mut();
346 if let Some(boxed) = st.get(&TypeId::of::<T>()) {
347 std::mem::transmute::<&T, &T>(boxed.downcast_ref::<T>().unwrap())
348 } else {
349 st.insert(TypeId::of::<T>(), Box::new(T::default()));
350 let boxed = st.get(&TypeId::of::<T>()).unwrap();
351 std::mem::transmute::<&T, &T>(boxed.downcast_ref::<T>().unwrap())
352 }
353 };
354 f(val)
355 })
356}
357
358#[doc(hidden)]
359pub unsafe fn remove_all_items() {
365 STORAGE.with(move |cell| {
366 loop {
367 let mut items = cell.borrow_mut();
368 let Some(key) = items.keys().next().copied() else {
369 break;
370 };
371 items.remove(&key);
372 drop(items);
373 }
374 });
375 System::remove_current();
376}