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}
44
45impl Driver {
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
64 pub(crate) fn is_enabled(&self) -> bool {
65 self.inner.is_enabled()
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 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
128cfg_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
210cfg_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
244cfg_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
255cfg_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
269cfg_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
277cfg_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
289cfg_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
350cfg_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