Coverage Report

Created: 2025-07-23 07:04

/rust/registry/src/index.crates.io-6f17d22bba15001f/tokio-1.44.2/src/task/spawn.rs
Line
Count
Source (jump to first uncovered line)
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
0
    pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
167
0
    where
168
0
        F: Future + Send + 'static,
169
0
        F::Output: Send + 'static,
170
0
    {
171
0
        let fut_size = std::mem::size_of::<F>();
172
0
        if fut_size > BOX_FUTURE_THRESHOLD {
173
0
            spawn_inner(Box::pin(future), SpawnMeta::new_unnamed(fut_size))
174
        } else {
175
0
            spawn_inner(future, SpawnMeta::new_unnamed(fut_size))
176
        }
177
0
    }
178
179
    #[track_caller]
180
0
    pub(super) fn spawn_inner<T>(future: T, meta: SpawnMeta<'_>) -> JoinHandle<T::Output>
181
0
    where
182
0
        T: Future + Send + 'static,
183
0
        T::Output: Send + 'static,
184
0
    {
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
0
        let id = task::Id::next();
200
0
        let task = crate::util::trace::task(future, "task", meta, id.as_u64());
201
0
202
0
        match context::with_current(|handle| handle.spawn(task, id)) {
203
0
            Ok(join_handle) => join_handle,
204
0
            Err(e) => panic!("{}", e),
205
        }
206
0
    }
207
}