Skip to main content

tokio/runtime/
driver.rs

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
10use crate::runtime::park::{ParkThread, UnparkThread};
11
12use std::io;
13use std::time::Duration;
14
15#[derive(Debug)]
16pub(crate) struct Driver {
17    inner: TimeDriver,
18}
19
20#[derive(Debug)]
21pub(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
37pub(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    pub(crate) nevents_busy: Option<usize>,
44    pub(crate) timer_flavor: crate::runtime::TimerFlavor,
45}
46
47impl Driver {
48    pub(crate) fn new(cfg: Cfg) -> io::Result<(Self, Handle)> {
49        let (io_stack, io_handle, signal_handle) =
50            create_io_stack(cfg.enable_io, cfg.nevents, cfg.nevents_busy)?;
51
52        let clock = create_clock(cfg.enable_pause_time, cfg.start_paused);
53
54        let (time_driver, time_handle) =
55            create_time_driver(cfg.enable_time, cfg.timer_flavor, io_stack, &clock);
56
57        Ok((
58            Self { inner: time_driver },
59            Handle {
60                io: io_handle,
61                signal: signal_handle,
62                time: time_handle,
63                clock,
64            },
65        ))
66    }
67
68    pub(crate) fn park(&mut self, handle: &Handle) {
69        self.inner.park(handle);
70    }
71
72    pub(crate) fn park_timeout(&mut self, handle: &Handle, duration: Duration) {
73        self.inner.park_timeout(handle, duration);
74    }
75
76    pub(crate) fn shutdown(&mut self, handle: &Handle) {
77        self.inner.shutdown(handle);
78    }
79}
80
81impl Handle {
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    pub(crate) fn unpark_self(&self) {
92        #[cfg(feature = "time")]
93        if let Some(handle) = &self.time {
94            handle.unpark();
95        }
96    }
97
98    cfg_io_driver! {
99        #[track_caller]
100        pub(crate) fn io(&self) -> &crate::runtime::io::Handle {
101            self.io
102                .as_ref()
103                .expect("A Tokio 1.x context was found, but IO is disabled. Call `enable_io` on the runtime builder to enable IO.")
104        }
105    }
106
107    cfg_signal_internal_and_unix! {
108        #[track_caller]
109        pub(crate) fn signal(&self) -> &crate::runtime::signal::Handle {
110            self.signal
111                .as_ref()
112                .expect("A Tokio 1.x context was found, but IO is disabled. Call `enable_io` on the runtime builder to enable IO.")
113        }
114    }
115
116    cfg_time! {
117        /// Returns a reference to the time driver handle.
118        ///
119        /// Panics if no time driver is present.
120        #[track_caller]
121        pub(crate) fn time(&self) -> &crate::runtime::time::Handle {
122            self.time
123                .as_ref()
124                .expect("A Tokio 1.x context was found, but timers are disabled. Call `enable_time` on the runtime builder to enable timers.")
125        }
126
127        #[cfg(tokio_unstable)]
128        pub(crate) fn with_time<F, R>(&self, f: F) -> R
129        where
130            F: FnOnce(Option<&crate::runtime::time::Handle>) -> R,
131        {
132            f(self.time.as_ref())
133        }
134
135        pub(crate) fn clock(&self) -> &Clock {
136            &self.clock
137        }
138
139        #[cfg(test)]
140        pub(crate) fn now(&self) -> u64 {
141           self.time().time_source().deadline_to_tick(self.clock.now())
142        }
143    }
144}
145
146// ===== io driver =====
147
148cfg_io_driver! {
149    pub(crate) type IoDriver = crate::runtime::io::Driver;
150
151    #[derive(Debug)]
152    pub(crate) enum IoStack {
153        Enabled(ProcessDriver),
154        Disabled(ParkThread),
155    }
156
157    #[derive(Debug)]
158    pub(crate) enum IoHandle {
159        Enabled(crate::runtime::io::Handle),
160        Disabled(UnparkThread),
161    }
162
163    fn create_io_stack(enabled: bool, nevents: usize, nevents_busy: Option<usize>) -> io::Result<(IoStack, IoHandle, SignalHandle)> {
164        #[cfg(loom)]
165        assert!(!enabled);
166
167        let ret = if enabled {
168            let (io_driver, io_handle) = crate::runtime::io::Driver::new(nevents, nevents_busy)?;
169
170            let (signal_driver, signal_handle) = create_signal_driver(io_driver, &io_handle)?;
171            let process_driver = create_process_driver(signal_driver);
172
173            (IoStack::Enabled(process_driver), IoHandle::Enabled(io_handle), signal_handle)
174        } else {
175            let park_thread = ParkThread::new();
176            let unpark_thread = park_thread.unpark();
177            (IoStack::Disabled(park_thread), IoHandle::Disabled(unpark_thread), Default::default())
178        };
179
180        Ok(ret)
181    }
182
183    impl IoStack {
184        pub(crate) fn park(&mut self, handle: &Handle) {
185            match self {
186                IoStack::Enabled(v) => v.park(handle),
187                IoStack::Disabled(v) => v.park(),
188            }
189        }
190
191        pub(crate) fn park_timeout(&mut self, handle: &Handle, duration: Duration) {
192            match self {
193                IoStack::Enabled(v) => v.park_timeout(handle, duration),
194                IoStack::Disabled(v) => v.park_timeout(duration),
195            }
196        }
197
198        pub(crate) fn shutdown(&mut self, handle: &Handle) {
199            match self {
200                IoStack::Enabled(v) => v.shutdown(handle),
201                IoStack::Disabled(v) => v.shutdown(),
202            }
203        }
204    }
205
206    impl IoHandle {
207        pub(crate) fn unpark(&self) {
208            match self {
209                IoHandle::Enabled(handle) => handle.unpark(),
210                IoHandle::Disabled(handle) => handle.unpark(),
211            }
212        }
213
214        pub(crate) fn as_ref(&self) -> Option<&crate::runtime::io::Handle> {
215            match self {
216                IoHandle::Enabled(v) => Some(v),
217                IoHandle::Disabled(..) => None,
218            }
219        }
220    }
221}
222
223cfg_not_io_driver! {
224    pub(crate) type IoHandle = UnparkThread;
225
226    #[derive(Debug)]
227    pub(crate) struct IoStack(ParkThread);
228
229    fn create_io_stack(_enabled: bool, _nevents: usize, _nevents_busy: Option<usize>) -> io::Result<(IoStack, IoHandle, SignalHandle)> {
230        let park_thread = ParkThread::new();
231        let unpark_thread = park_thread.unpark();
232        Ok((IoStack(park_thread), unpark_thread, Default::default()))
233    }
234
235    impl IoStack {
236        pub(crate) fn park(&mut self, _handle: &Handle) {
237            self.0.park();
238        }
239
240        pub(crate) fn park_timeout(&mut self, _handle: &Handle, duration: Duration) {
241            self.0.park_timeout(duration);
242        }
243
244        pub(crate) fn shutdown(&mut self, _handle: &Handle) {
245            self.0.shutdown();
246        }
247
248        /// This is not a "real" driver, so it is not considered enabled.
249        pub(crate) fn is_enabled(&self) -> bool {
250            false
251        }
252    }
253}
254
255// ===== signal driver =====
256
257cfg_signal_internal_and_unix! {
258    type SignalDriver = crate::runtime::signal::Driver;
259    pub(crate) type SignalHandle = Option<crate::runtime::signal::Handle>;
260
261    fn create_signal_driver(io_driver: IoDriver, io_handle: &crate::runtime::io::Handle) -> io::Result<(SignalDriver, SignalHandle)> {
262        let driver = crate::runtime::signal::Driver::new(io_driver, io_handle)?;
263        let handle = driver.handle();
264        Ok((driver, Some(handle)))
265    }
266}
267
268cfg_not_signal_internal_and_unix! {
269    pub(crate) type SignalHandle = ();
270
271    cfg_io_driver! {
272        type SignalDriver = IoDriver;
273
274        fn create_signal_driver(io_driver: IoDriver, _io_handle: &crate::runtime::io::Handle) -> io::Result<(SignalDriver, SignalHandle)> {
275            Ok((io_driver, ()))
276        }
277    }
278}
279
280// ===== process driver =====
281
282cfg_process_driver! {
283    type ProcessDriver = crate::runtime::process::Driver;
284
285    fn create_process_driver(signal_driver: SignalDriver) -> ProcessDriver {
286        ProcessDriver::new(signal_driver)
287    }
288}
289
290cfg_not_process_driver! {
291    cfg_io_driver! {
292        type ProcessDriver = SignalDriver;
293
294        fn create_process_driver(signal_driver: SignalDriver) -> ProcessDriver {
295            signal_driver
296        }
297    }
298}
299
300// ===== time driver =====
301
302cfg_time! {
303    #[derive(Debug)]
304    pub(crate) enum TimeDriver {
305        Enabled {
306            driver: crate::runtime::time::Driver,
307        },
308        EnabledAlt(IoStack),
309        Disabled(IoStack),
310    }
311
312    pub(crate) type Clock = crate::time::Clock;
313    pub(crate) type TimeHandle = Option<crate::runtime::time::Handle>;
314
315    fn create_clock(enable_pausing: bool, start_paused: bool) -> Clock {
316        crate::time::Clock::new(enable_pausing, start_paused)
317    }
318
319    fn create_time_driver(
320        enable: bool,
321        timer_flavor: crate::runtime::TimerFlavor,
322        io_stack: IoStack,
323        clock: &Clock,
324    ) -> (TimeDriver, TimeHandle) {
325        if enable {
326            match timer_flavor {
327                crate::runtime::TimerFlavor::Traditional => {
328                    let (driver, handle) = crate::runtime::time::Driver::new(io_stack, clock);
329                    (TimeDriver::Enabled { driver }, Some(handle))
330                }
331                #[cfg(all(tokio_unstable, feature = "rt-multi-thread"))]
332                crate::runtime::TimerFlavor::Alternative => {
333                    (TimeDriver::EnabledAlt(io_stack), Some(crate::runtime::time::Driver::new_alt(clock)))
334                }
335            }
336        } else {
337            (TimeDriver::Disabled(io_stack), None)
338        }
339    }
340
341    impl TimeDriver {
342        pub(crate) fn park(&mut self, handle: &Handle) {
343            match self {
344                TimeDriver::Enabled { driver, .. } => driver.park(handle),
345                TimeDriver::EnabledAlt(v) => v.park(handle),
346                TimeDriver::Disabled(v) => v.park(handle),
347            }
348        }
349
350        pub(crate) fn park_timeout(&mut self, handle: &Handle, duration: Duration) {
351            match self {
352                TimeDriver::Enabled { driver } => driver.park_timeout(handle, duration),
353                TimeDriver::EnabledAlt(v) => v.park_timeout(handle, duration),
354                TimeDriver::Disabled(v) => v.park_timeout(handle, duration),
355            }
356        }
357
358        pub(crate) fn shutdown(&mut self, handle: &Handle) {
359            match self {
360                TimeDriver::Enabled { driver } => driver.shutdown(handle),
361                TimeDriver::EnabledAlt(v) => v.shutdown(handle),
362                TimeDriver::Disabled(v) => v.shutdown(handle),
363            }
364        }
365    }
366}
367
368cfg_not_time! {
369    type TimeDriver = IoStack;
370
371    pub(crate) type Clock = ();
372    pub(crate) type TimeHandle = ();
373
374    fn create_clock(_enable_pausing: bool, _start_paused: bool) -> Clock {
375        ()
376    }
377
378    fn create_time_driver(
379        _enable: bool,
380        _timer_flavor: crate::runtime::TimerFlavor,
381        io_stack: IoStack,
382        _clock: &Clock,
383    ) -> (TimeDriver, TimeHandle) {
384        (io_stack, ())
385    }
386}
387
388cfg_io_uring! {
389    pub(crate) mod op;
390}