1#![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 pub(crate) io: IoHandle,
24
25 #[cfg_attr(any(not(unix), loom), allow(dead_code))]
27 pub(crate) signal: SignalHandle,
28
29 pub(crate) time: TimeHandle,
31
32 #[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 #[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
146cfg_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 pub(crate) fn is_enabled(&self) -> bool {
250 false
251 }
252 }
253}
254
255cfg_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
280cfg_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
300cfg_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}