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