madsim_real_tokio/task/
spawn.rs

1use crate::task::JoinHandle;
2
3use std::future::Future;
4
5cfg_rt! {
6    /// Spawns a new asynchronous task, returning a
7    /// [`JoinHandle`](super::JoinHandle) for it.
8    ///
9    /// The provided future will start running in the background immediately
10    /// when `spawn` is called, even if you don't await the returned
11    /// `JoinHandle`.
12    ///
13    /// Spawning a task enables the task to execute concurrently to other tasks. The
14    /// spawned task may execute on the current thread, or it may be sent to a
15    /// different thread to be executed. The specifics depend on the current
16    /// [`Runtime`](crate::runtime::Runtime) configuration.
17    ///
18    /// It is guaranteed that spawn will not synchronously poll the task being spawned.
19    /// This means that calling spawn while holding a lock does not pose a risk of
20    /// deadlocking with the spawned task.
21    ///
22    /// There is no guarantee that a spawned task will execute to completion.
23    /// When a runtime is shutdown, all outstanding tasks are dropped,
24    /// regardless of the lifecycle of that task.
25    ///
26    /// This function must be called from the context of a Tokio runtime. Tasks running on
27    /// the Tokio runtime are always inside its context, but you can also enter the context
28    /// using the [`Runtime::enter`](crate::runtime::Runtime::enter()) method.
29    ///
30    /// # Examples
31    ///
32    /// In this example, a server is started and `spawn` is used to start a new task
33    /// that processes each received connection.
34    ///
35    /// ```no_run
36    /// use tokio::net::{TcpListener, TcpStream};
37    ///
38    /// use std::io;
39    ///
40    /// async fn process(socket: TcpStream) {
41    ///     // ...
42    /// # drop(socket);
43    /// }
44    ///
45    /// #[tokio::main]
46    /// async fn main() -> io::Result<()> {
47    ///     let listener = TcpListener::bind("127.0.0.1:8080").await?;
48    ///
49    ///     loop {
50    ///         let (socket, _) = listener.accept().await?;
51    ///
52    ///         tokio::spawn(async move {
53    ///             // Process each socket concurrently.
54    ///             process(socket).await
55    ///         });
56    ///     }
57    /// }
58    /// ```
59    ///
60    /// To run multiple tasks in parallel and receive their results, join
61    /// handles can be stored in a vector.
62    /// ```
63    /// # #[tokio::main(flavor = "current_thread")] async fn main() {
64    /// async fn my_background_op(id: i32) -> String {
65    ///     let s = format!("Starting background task {}.", id);
66    ///     println!("{}", s);
67    ///     s
68    /// }
69    ///
70    /// let ops = vec![1, 2, 3];
71    /// let mut tasks = Vec::with_capacity(ops.len());
72    /// for op in ops {
73    ///     // This call will make them start running in the background
74    ///     // immediately.
75    ///     tasks.push(tokio::spawn(my_background_op(op)));
76    /// }
77    ///
78    /// let mut outputs = Vec::with_capacity(tasks.len());
79    /// for task in tasks {
80    ///     outputs.push(task.await.unwrap());
81    /// }
82    /// println!("{:?}", outputs);
83    /// # }
84    /// ```
85    /// This example pushes the tasks to `outputs` in the order they were
86    /// started in. If you do not care about the ordering of the outputs, then
87    /// you can also use a [`JoinSet`].
88    ///
89    /// [`JoinSet`]: struct@crate::task::JoinSet
90    ///
91    /// # Panics
92    ///
93    /// Panics if called from **outside** of the Tokio runtime.
94    ///
95    /// # Using `!Send` values from a task
96    ///
97    /// The task supplied to `spawn` must implement `Send`. However, it is
98    /// possible to **use** `!Send` values from the task as long as they only
99    /// exist between calls to `.await`.
100    ///
101    /// For example, this will work:
102    ///
103    /// ```
104    /// use tokio::task;
105    ///
106    /// use std::rc::Rc;
107    ///
108    /// fn use_rc(rc: Rc<()>) {
109    ///     // Do stuff w/ rc
110    /// # drop(rc);
111    /// }
112    ///
113    /// #[tokio::main]
114    /// async fn main() {
115    ///     tokio::spawn(async {
116    ///         // Force the `Rc` to stay in a scope with no `.await`
117    ///         {
118    ///             let rc = Rc::new(());
119    ///             use_rc(rc.clone());
120    ///         }
121    ///
122    ///         task::yield_now().await;
123    ///     }).await.unwrap();
124    /// }
125    /// ```
126    ///
127    /// This will **not** work:
128    ///
129    /// ```compile_fail
130    /// use tokio::task;
131    ///
132    /// use std::rc::Rc;
133    ///
134    /// fn use_rc(rc: Rc<()>) {
135    ///     // Do stuff w/ rc
136    /// # drop(rc);
137    /// }
138    ///
139    /// #[tokio::main]
140    /// async fn main() {
141    ///     tokio::spawn(async {
142    ///         let rc = Rc::new(());
143    ///
144    ///         task::yield_now().await;
145    ///
146    ///         use_rc(rc.clone());
147    ///     }).await.unwrap();
148    /// }
149    /// ```
150    ///
151    /// Holding on to a `!Send` value across calls to `.await` will result in
152    /// an unfriendly compile error message similar to:
153    ///
154    /// ```text
155    /// `[... some type ...]` cannot be sent between threads safely
156    /// ```
157    ///
158    /// or:
159    ///
160    /// ```text
161    /// error[E0391]: cycle detected when processing `main`
162    /// ```
163    #[track_caller]
164    pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
165    where
166        F: Future + Send + 'static,
167        F::Output: Send + 'static,
168    {
169        // preventing stack overflows on debug mode, by quickly sending the
170        // task to the heap.
171        if cfg!(debug_assertions) && std::mem::size_of::<F>() > 2048 {
172            spawn_inner(Box::pin(future), None)
173        } else {
174            spawn_inner(future, None)
175        }
176    }
177
178    #[track_caller]
179    pub(super) fn spawn_inner<T>(future: T, name: Option<&str>) -> JoinHandle<T::Output>
180    where
181        T: Future + Send + 'static,
182        T::Output: Send + 'static,
183    {
184        use crate::runtime::{context, task};
185
186        #[cfg(all(
187            tokio_unstable,
188            tokio_taskdump,
189            feature = "rt",
190            target_os = "linux",
191            any(
192                target_arch = "aarch64",
193                target_arch = "x86",
194                target_arch = "x86_64"
195            )
196        ))]
197        let future = task::trace::Trace::root(future);
198        let id = task::Id::next();
199        let task = crate::util::trace::task(future, "task", name, id.as_u64());
200
201        match context::with_current(|handle| handle.spawn(task, id)) {
202            Ok(join_handle) => join_handle,
203            Err(e) => panic!("{}", e),
204        }
205    }
206}