1 use super::{Context, CONTEXT};
2 
3 use crate::runtime::{scheduler, TryCurrentError};
4 use crate::util::markers::SyncNotSend;
5 
6 use std::cell::{Cell, RefCell};
7 use std::marker::PhantomData;
8 
9 #[derive(Debug)]
10 #[must_use]
11 pub(crate) struct SetCurrentGuard {
12     // The previous handle
13     prev: Option<scheduler::Handle>,
14 
15     // The depth for this guard
16     depth: usize,
17 
18     // Don't let the type move across threads.
19     _p: PhantomData<SyncNotSend>,
20 }
21 
22 pub(super) struct HandleCell {
23     /// Current handle
24     handle: RefCell<Option<scheduler::Handle>>,
25 
26     /// Tracks the number of nested calls to `try_set_current`.
27     depth: Cell<usize>,
28 }
29 
30 /// Sets this [`Handle`] as the current active [`Handle`].
31 ///
32 /// [`Handle`]: crate::runtime::scheduler::Handle
try_set_current(handle: &scheduler::Handle) -> Option<SetCurrentGuard>33 pub(crate) fn try_set_current(handle: &scheduler::Handle) -> Option<SetCurrentGuard> {
34     CONTEXT.try_with(|ctx| ctx.set_current(handle)).ok()
35 }
36 
with_current<F, R>(f: F) -> Result<R, TryCurrentError> where F: FnOnce(&scheduler::Handle) -> R,37 pub(crate) fn with_current<F, R>(f: F) -> Result<R, TryCurrentError>
38 where
39     F: FnOnce(&scheduler::Handle) -> R,
40 {
41     match CONTEXT.try_with(|ctx| ctx.current.handle.borrow().as_ref().map(f)) {
42         Ok(Some(ret)) => Ok(ret),
43         Ok(None) => Err(TryCurrentError::new_no_context()),
44         Err(_access_error) => Err(TryCurrentError::new_thread_local_destroyed()),
45     }
46 }
47 
48 impl Context {
set_current(&self, handle: &scheduler::Handle) -> SetCurrentGuard49     pub(super) fn set_current(&self, handle: &scheduler::Handle) -> SetCurrentGuard {
50         let old_handle = self.current.handle.borrow_mut().replace(handle.clone());
51         let depth = self.current.depth.get();
52 
53         assert!(depth != usize::MAX, "reached max `enter` depth");
54 
55         let depth = depth + 1;
56         self.current.depth.set(depth);
57 
58         SetCurrentGuard {
59             prev: old_handle,
60             depth,
61             _p: PhantomData,
62         }
63     }
64 }
65 
66 impl HandleCell {
new() -> HandleCell67     pub(super) const fn new() -> HandleCell {
68         HandleCell {
69             handle: RefCell::new(None),
70             depth: Cell::new(0),
71         }
72     }
73 }
74 
75 impl Drop for SetCurrentGuard {
drop(&mut self)76     fn drop(&mut self) {
77         CONTEXT.with(|ctx| {
78             let depth = ctx.current.depth.get();
79 
80             if depth != self.depth {
81                 if !std::thread::panicking() {
82                     panic!(
83                         "`EnterGuard` values dropped out of order. Guards returned by \
84                          `tokio::runtime::Handle::enter()` must be dropped in the reverse \
85                          order as they were acquired."
86                     );
87                 } else {
88                     // Just return... this will leave handles in a wonky state though...
89                     return;
90                 }
91             }
92 
93             *ctx.current.handle.borrow_mut() = self.prev.take();
94             ctx.current.depth.set(depth - 1);
95         });
96     }
97 }
98