Skip to main content

tokio/
blocking.rs

1cfg_rt! {
2    #[cfg(not(target_os = "emscripten"))]
3    pub(crate) use crate::runtime::spawn_blocking;
4
5    cfg_io_blocking! {
6        #[cfg(not(target_os = "emscripten"))]
7        #[allow(unused_imports)]
8        pub(crate) use crate::runtime::spawn_mandatory_blocking;
9    }
10
11    #[cfg(not(target_os = "emscripten"))]
12    pub(crate) use crate::task::JoinHandle;
13
14    // Emscripten's filesystem is synchronous, so `fs` and `io-std` run inline
15    // here, pthread builds included. Public `task::spawn_blocking` is unaffected.
16    //
17    // The completed future is wrapped in `Coop` so that polling it consumes
18    // task budget exactly like the native `task::JoinHandle::poll` does. The
19    // `fs` and `io-std` consumers rely on that budget for their yield points:
20    // without it a loop of always-ready file reads never returns `Pending`
21    // and starves every other task on the single-threaded runtime.
22    #[cfg(target_os = "emscripten")]
23    pub(crate) type JoinHandle<T> =
24        crate::task::coop::Coop<std::future::Ready<Result<T, crate::task::JoinError>>>;
25
26    #[cfg(target_os = "emscripten")]
27    #[track_caller]
28    pub(crate) fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>
29    where
30        F: FnOnce() -> R + Send + 'static,
31        R: Send + 'static,
32    {
33        let _rt = crate::runtime::Handle::current();
34        crate::task::coop::cooperative(std::future::ready(Ok(f())))
35    }
36
37    #[cfg(all(target_os = "emscripten", any(feature = "fs", feature = "io-std")))]
38    // `fs` unit tests use the `fs::mocks` version instead, so this is unused
39    // when `io-std` is disabled.
40    #[allow(dead_code)]
41    #[track_caller]
42    pub(crate) fn spawn_mandatory_blocking<F, R>(f: F) -> Option<JoinHandle<R>>
43    where
44        F: FnOnce() -> R + Send + 'static,
45        R: Send + 'static,
46    {
47        Some(spawn_blocking(f))
48    }
49}
50
51cfg_not_rt! {
52    use std::fmt;
53    use std::future::Future;
54    use std::pin::Pin;
55    use std::task::{Context, Poll};
56
57    pub(crate) fn spawn_blocking<F, R>(_f: F) -> JoinHandle<R>
58    where
59        F: FnOnce() -> R + Send + 'static,
60        R: Send + 'static,
61    {
62        assert_send_sync::<JoinHandle<std::cell::Cell<()>>>();
63        panic!("requires the `rt` Tokio feature flag")
64    }
65
66    cfg_io_blocking! {
67        pub(crate) fn spawn_mandatory_blocking<F, R>(_f: F) -> Option<JoinHandle<R>>
68        where
69            F: FnOnce() -> R + Send + 'static,
70            R: Send + 'static,
71        {
72            panic!("requires the `rt` Tokio feature flag")
73        }
74    }
75
76    pub(crate) struct JoinHandle<R> {
77        _p: std::marker::PhantomData<R>,
78    }
79
80    unsafe impl<T: Send> Send for JoinHandle<T> {}
81    unsafe impl<T: Send> Sync for JoinHandle<T> {}
82
83    impl<R> Future for JoinHandle<R> {
84        type Output = Result<R, std::io::Error>;
85
86        fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
87            unreachable!()
88        }
89    }
90
91    impl<T> fmt::Debug for JoinHandle<T>
92    where
93        T: fmt::Debug,
94    {
95        fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
96            fmt.debug_struct("JoinHandle").finish()
97        }
98    }
99
100    fn assert_send_sync<T: Send + Sync>() {
101    }
102}