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