1 //! Thread local runtime context
2 use crate::runtime::{Handle, TryCurrentError};
3 
4 use std::cell::RefCell;
5 
6 thread_local! {
7     static CONTEXT: RefCell<Option<Handle>> = RefCell::new(None)
8 }
9 
try_current() -> Result<Handle, crate::runtime::TryCurrentError>10 pub(crate) fn try_current() -> Result<Handle, crate::runtime::TryCurrentError> {
11     match CONTEXT.try_with(|ctx| ctx.borrow().clone()) {
12         Ok(Some(handle)) => Ok(handle),
13         Ok(None) => Err(TryCurrentError::new_no_context()),
14         Err(_access_error) => Err(TryCurrentError::new_thread_local_destroyed()),
15     }
16 }
17 
current() -> Handle18 pub(crate) fn current() -> Handle {
19     match try_current() {
20         Ok(handle) => handle,
21         Err(e) => panic!("{}", e),
22     }
23 }
24 
25 cfg_io_driver! {
26     pub(crate) fn io_handle() -> crate::runtime::driver::IoHandle {
27         match CONTEXT.try_with(|ctx| {
28             let ctx = ctx.borrow();
29             ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).io_handle.clone()
30         }) {
31             Ok(io_handle) => io_handle,
32             Err(_) => panic!("{}", crate::util::error::THREAD_LOCAL_DESTROYED_ERROR),
33         }
34     }
35 }
36 
37 cfg_signal_internal! {
38     #[cfg(unix)]
39     pub(crate) fn signal_handle() -> crate::runtime::driver::SignalHandle {
40         match CONTEXT.try_with(|ctx| {
41             let ctx = ctx.borrow();
42             ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).signal_handle.clone()
43         }) {
44             Ok(signal_handle) => signal_handle,
45             Err(_) => panic!("{}", crate::util::error::THREAD_LOCAL_DESTROYED_ERROR),
46         }
47     }
48 }
49 
50 cfg_time! {
51     pub(crate) fn time_handle() -> crate::runtime::driver::TimeHandle {
52         match CONTEXT.try_with(|ctx| {
53             let ctx = ctx.borrow();
54             ctx.as_ref().expect(crate::util::error::CONTEXT_MISSING_ERROR).time_handle.clone()
55         }) {
56             Ok(time_handle) => time_handle,
57             Err(_) => panic!("{}", crate::util::error::THREAD_LOCAL_DESTROYED_ERROR),
58         }
59     }
60 
61     cfg_test_util! {
62         pub(crate) fn clock() -> Option<crate::runtime::driver::Clock> {
63             match CONTEXT.try_with(|ctx| (*ctx.borrow()).as_ref().map(|ctx| ctx.clock.clone())) {
64                 Ok(clock) => clock,
65                 Err(_) => panic!("{}", crate::util::error::THREAD_LOCAL_DESTROYED_ERROR),
66             }
67         }
68     }
69 }
70 
71 cfg_rt! {
72     pub(crate) fn spawn_handle() -> Option<crate::runtime::Spawner> {
73         match CONTEXT.try_with(|ctx| (*ctx.borrow()).as_ref().map(|ctx| ctx.spawner.clone())) {
74             Ok(spawner) => spawner,
75             Err(_) => panic!("{}", crate::util::error::THREAD_LOCAL_DESTROYED_ERROR),
76         }
77     }
78 }
79 
80 /// Sets this [`Handle`] as the current active [`Handle`].
81 ///
82 /// [`Handle`]: Handle
enter(new: Handle) -> EnterGuard83 pub(crate) fn enter(new: Handle) -> EnterGuard {
84     match try_enter(new) {
85         Some(guard) => guard,
86         None => panic!("{}", crate::util::error::THREAD_LOCAL_DESTROYED_ERROR),
87     }
88 }
89 
90 /// Sets this [`Handle`] as the current active [`Handle`].
91 ///
92 /// [`Handle`]: Handle
try_enter(new: Handle) -> Option<EnterGuard>93 pub(crate) fn try_enter(new: Handle) -> Option<EnterGuard> {
94     CONTEXT
95         .try_with(|ctx| {
96             let old = ctx.borrow_mut().replace(new);
97             EnterGuard(old)
98         })
99         .ok()
100 }
101 
102 #[derive(Debug)]
103 pub(crate) struct EnterGuard(Option<Handle>);
104 
105 impl Drop for EnterGuard {
drop(&mut self)106     fn drop(&mut self) {
107         CONTEXT.with(|ctx| {
108             *ctx.borrow_mut() = self.0.take();
109         });
110     }
111 }
112