• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Abstracts out the entire chain of runtime sub-drivers into common types.
2 
3 // Eventually, this file will see significant refactoring / cleanup. For now, we
4 // don't need to worry much about dead code with certain feature permutations.
5 #![cfg_attr(
6     any(not(all(tokio_unstable, feature = "full")), target_family = "wasm"),
7     allow(dead_code)
8 )]
9 
10 use crate::runtime::park::{ParkThread, UnparkThread};
11 
12 use std::io;
13 use std::time::Duration;
14 
15 #[derive(Debug)]
16 pub(crate) struct Driver {
17     inner: TimeDriver,
18 }
19 
20 #[derive(Debug)]
21 pub(crate) struct Handle {
22     /// IO driver handle
23     pub(crate) io: IoHandle,
24 
25     /// Signal driver handle
26     #[cfg_attr(any(not(unix), loom), allow(dead_code))]
27     pub(crate) signal: SignalHandle,
28 
29     /// Time driver handle
30     pub(crate) time: TimeHandle,
31 
32     /// Source of `Instant::now()`
33     #[cfg_attr(not(all(feature = "time", feature = "test-util")), allow(dead_code))]
34     pub(crate) clock: Clock,
35 }
36 
37 pub(crate) struct Cfg {
38     pub(crate) enable_io: bool,
39     pub(crate) enable_time: bool,
40     pub(crate) enable_pause_time: bool,
41     pub(crate) start_paused: bool,
42     pub(crate) nevents: usize,
43 }
44 
45 impl Driver {
new(cfg: Cfg) -> io::Result<(Self, Handle)>46     pub(crate) fn new(cfg: Cfg) -> io::Result<(Self, Handle)> {
47         let (io_stack, io_handle, signal_handle) = create_io_stack(cfg.enable_io, cfg.nevents)?;
48 
49         let clock = create_clock(cfg.enable_pause_time, cfg.start_paused);
50 
51         let (time_driver, time_handle) = create_time_driver(cfg.enable_time, io_stack, &clock);
52 
53         Ok((
54             Self { inner: time_driver },
55             Handle {
56                 io: io_handle,
57                 signal: signal_handle,
58                 time: time_handle,
59                 clock,
60             },
61         ))
62     }
63 
is_enabled(&self) -> bool64     pub(crate) fn is_enabled(&self) -> bool {
65         self.inner.is_enabled()
66     }
67 
park(&mut self, handle: &Handle)68     pub(crate) fn park(&mut self, handle: &Handle) {
69         self.inner.park(handle)
70     }
71 
park_timeout(&mut self, handle: &Handle, duration: Duration)72     pub(crate) fn park_timeout(&mut self, handle: &Handle, duration: Duration) {
73         self.inner.park_timeout(handle, duration)
74     }
75 
shutdown(&mut self, handle: &Handle)76     pub(crate) fn shutdown(&mut self, handle: &Handle) {
77         self.inner.shutdown(handle)
78     }
79 }
80 
81 impl Handle {
unpark(&self)82     pub(crate) fn unpark(&self) {
83         #[cfg(feature = "time")]
84         if let Some(handle) = &self.time {
85             handle.unpark();
86         }
87 
88         self.io.unpark();
89     }
90 
91     cfg_io_driver! {
92         #[track_caller]
93         pub(crate) fn io(&self) -> &crate::runtime::io::Handle {
94             self.io
95                 .as_ref()
96                 .expect("A Tokio 1.x context was found, but IO is disabled. Call `enable_io` on the runtime builder to enable IO.")
97         }
98     }
99 
100     cfg_signal_internal_and_unix! {
101         #[track_caller]
102         pub(crate) fn signal(&self) -> &crate::runtime::signal::Handle {
103             self.signal
104                 .as_ref()
105                 .expect("there is no signal driver running, must be called from the context of Tokio runtime")
106         }
107     }
108 
109     cfg_time! {
110         /// Returns a reference to the time driver handle.
111         ///
112         /// Panics if no time driver is present.
113         #[track_caller]
114         pub(crate) fn time(&self) -> &crate::runtime::time::Handle {
115             self.time
116                 .as_ref()
117                 .expect("A Tokio 1.x context was found, but timers are disabled. Call `enable_time` on the runtime builder to enable timers.")
118         }
119 
120         pub(crate) fn clock(&self) -> &Clock {
121             &self.clock
122         }
123     }
124 }
125 
126 // ===== io driver =====
127 
128 cfg_io_driver! {
129     pub(crate) type IoDriver = crate::runtime::io::Driver;
130 
131     #[derive(Debug)]
132     pub(crate) enum IoStack {
133         Enabled(ProcessDriver),
134         Disabled(ParkThread),
135     }
136 
137     #[derive(Debug)]
138     pub(crate) enum IoHandle {
139         Enabled(crate::runtime::io::Handle),
140         Disabled(UnparkThread),
141     }
142 
143     fn create_io_stack(enabled: bool, nevents: usize) -> io::Result<(IoStack, IoHandle, SignalHandle)> {
144         #[cfg(loom)]
145         assert!(!enabled);
146 
147         let ret = if enabled {
148             let (io_driver, io_handle) = crate::runtime::io::Driver::new(nevents)?;
149 
150             let (signal_driver, signal_handle) = create_signal_driver(io_driver, &io_handle)?;
151             let process_driver = create_process_driver(signal_driver);
152 
153             (IoStack::Enabled(process_driver), IoHandle::Enabled(io_handle), signal_handle)
154         } else {
155             let park_thread = ParkThread::new();
156             let unpark_thread = park_thread.unpark();
157             (IoStack::Disabled(park_thread), IoHandle::Disabled(unpark_thread), Default::default())
158         };
159 
160         Ok(ret)
161     }
162 
163     impl IoStack {
164         pub(crate) fn is_enabled(&self) -> bool {
165             match self {
166                 IoStack::Enabled(..) => true,
167                 IoStack::Disabled(..) => false,
168             }
169         }
170 
171         pub(crate) fn park(&mut self, handle: &Handle) {
172             match self {
173                 IoStack::Enabled(v) => v.park(handle),
174                 IoStack::Disabled(v) => v.park(),
175             }
176         }
177 
178         pub(crate) fn park_timeout(&mut self, handle: &Handle, duration: Duration) {
179             match self {
180                 IoStack::Enabled(v) => v.park_timeout(handle, duration),
181                 IoStack::Disabled(v) => v.park_timeout(duration),
182             }
183         }
184 
185         pub(crate) fn shutdown(&mut self, handle: &Handle) {
186             match self {
187                 IoStack::Enabled(v) => v.shutdown(handle),
188                 IoStack::Disabled(v) => v.shutdown(),
189             }
190         }
191     }
192 
193     impl IoHandle {
194         pub(crate) fn unpark(&self) {
195             match self {
196                 IoHandle::Enabled(handle) => handle.unpark(),
197                 IoHandle::Disabled(handle) => handle.unpark(),
198             }
199         }
200 
201         pub(crate) fn as_ref(&self) -> Option<&crate::runtime::io::Handle> {
202             match self {
203                 IoHandle::Enabled(v) => Some(v),
204                 IoHandle::Disabled(..) => None,
205             }
206         }
207     }
208 }
209 
210 cfg_not_io_driver! {
211     pub(crate) type IoHandle = UnparkThread;
212 
213     #[derive(Debug)]
214     pub(crate) struct IoStack(ParkThread);
215 
216     fn create_io_stack(_enabled: bool, _nevents: usize) -> io::Result<(IoStack, IoHandle, SignalHandle)> {
217         let park_thread = ParkThread::new();
218         let unpark_thread = park_thread.unpark();
219         Ok((IoStack(park_thread), unpark_thread, Default::default()))
220     }
221 
222     impl IoStack {
223         pub(crate) fn park(&mut self, _handle: &Handle) {
224             self.0.park();
225         }
226 
227         pub(crate) fn park_timeout(&mut self, _handle: &Handle, duration: Duration) {
228             self.0.park_timeout(duration);
229         }
230 
231         pub(crate) fn shutdown(&mut self, _handle: &Handle) {
232             self.0.shutdown();
233         }
234 
235         /// This is not a "real" driver, so it is not considered enabled.
236         pub(crate) fn is_enabled(&self) -> bool {
237             false
238         }
239     }
240 }
241 
242 // ===== signal driver =====
243 
244 cfg_signal_internal_and_unix! {
245     type SignalDriver = crate::runtime::signal::Driver;
246     pub(crate) type SignalHandle = Option<crate::runtime::signal::Handle>;
247 
248     fn create_signal_driver(io_driver: IoDriver, io_handle: &crate::runtime::io::Handle) -> io::Result<(SignalDriver, SignalHandle)> {
249         let driver = crate::runtime::signal::Driver::new(io_driver, io_handle)?;
250         let handle = driver.handle();
251         Ok((driver, Some(handle)))
252     }
253 }
254 
255 cfg_not_signal_internal! {
256     pub(crate) type SignalHandle = ();
257 
258     cfg_io_driver! {
259         type SignalDriver = IoDriver;
260 
261         fn create_signal_driver(io_driver: IoDriver, _io_handle: &crate::runtime::io::Handle) -> io::Result<(SignalDriver, SignalHandle)> {
262             Ok((io_driver, ()))
263         }
264     }
265 }
266 
267 // ===== process driver =====
268 
269 cfg_process_driver! {
270     type ProcessDriver = crate::runtime::process::Driver;
271 
272     fn create_process_driver(signal_driver: SignalDriver) -> ProcessDriver {
273         ProcessDriver::new(signal_driver)
274     }
275 }
276 
277 cfg_not_process_driver! {
278     cfg_io_driver! {
279         type ProcessDriver = SignalDriver;
280 
281         fn create_process_driver(signal_driver: SignalDriver) -> ProcessDriver {
282             signal_driver
283         }
284     }
285 }
286 
287 // ===== time driver =====
288 
289 cfg_time! {
290     #[derive(Debug)]
291     pub(crate) enum TimeDriver {
292         Enabled {
293             driver: crate::runtime::time::Driver,
294         },
295         Disabled(IoStack),
296     }
297 
298     pub(crate) type Clock = crate::time::Clock;
299     pub(crate) type TimeHandle = Option<crate::runtime::time::Handle>;
300 
301     fn create_clock(enable_pausing: bool, start_paused: bool) -> Clock {
302         crate::time::Clock::new(enable_pausing, start_paused)
303     }
304 
305     fn create_time_driver(
306         enable: bool,
307         io_stack: IoStack,
308         clock: &Clock,
309     ) -> (TimeDriver, TimeHandle) {
310         if enable {
311             let (driver, handle) = crate::runtime::time::Driver::new(io_stack, clock);
312 
313             (TimeDriver::Enabled { driver }, Some(handle))
314         } else {
315             (TimeDriver::Disabled(io_stack), None)
316         }
317     }
318 
319     impl TimeDriver {
320         pub(crate) fn is_enabled(&self) -> bool {
321             match self {
322                 TimeDriver::Enabled { .. } => true,
323                 TimeDriver::Disabled(inner) => inner.is_enabled(),
324             }
325         }
326 
327         pub(crate) fn park(&mut self, handle: &Handle) {
328             match self {
329                 TimeDriver::Enabled { driver, .. } => driver.park(handle),
330                 TimeDriver::Disabled(v) => v.park(handle),
331             }
332         }
333 
334         pub(crate) fn park_timeout(&mut self, handle: &Handle, duration: Duration) {
335             match self {
336                 TimeDriver::Enabled { driver } => driver.park_timeout(handle, duration),
337                 TimeDriver::Disabled(v) => v.park_timeout(handle, duration),
338             }
339         }
340 
341         pub(crate) fn shutdown(&mut self, handle: &Handle) {
342             match self {
343                 TimeDriver::Enabled { driver } => driver.shutdown(handle),
344                 TimeDriver::Disabled(v) => v.shutdown(handle),
345             }
346         }
347     }
348 }
349 
350 cfg_not_time! {
351     type TimeDriver = IoStack;
352 
353     pub(crate) type Clock = ();
354     pub(crate) type TimeHandle = ();
355 
356     fn create_clock(_enable_pausing: bool, _start_paused: bool) -> Clock {
357         ()
358     }
359 
360     fn create_time_driver(
361         _enable: bool,
362         io_stack: IoStack,
363         _clock: &Clock,
364     ) -> (TimeDriver, TimeHandle) {
365         (io_stack, ())
366     }
367 }
368