• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{task::JoinHandle, util::error::CONTEXT_MISSING_ERROR};
2 
3 use std::future::Future;
4 
5 cfg_rt! {
6     /// Spawns a new asynchronous task, returning a
7     /// [`JoinHandle`](super::JoinHandle) for it.
8     ///
9     /// Spawning a task enables the task to execute concurrently to other tasks. The
10     /// spawned task may execute on the current thread, or it may be sent to a
11     /// different thread to be executed. The specifics depend on the current
12     /// [`Runtime`](crate::runtime::Runtime) configuration.
13     ///
14     /// There is no guarantee that a spawned task will execute to completion.
15     /// When a runtime is shutdown, all outstanding tasks are dropped,
16     /// regardless of the lifecycle of that task.
17     ///
18     /// This function must be called from the context of a Tokio runtime. Tasks running on
19     /// the Tokio runtime are always inside its context, but you can also enter the context
20     /// using the [`Runtime::enter`](crate::runtime::Runtime::enter()) method.
21     ///
22     /// # Examples
23     ///
24     /// In this example, a server is started and `spawn` is used to start a new task
25     /// that processes each received connection.
26     ///
27     /// ```no_run
28     /// use tokio::net::{TcpListener, TcpStream};
29     ///
30     /// use std::io;
31     ///
32     /// async fn process(socket: TcpStream) {
33     ///     // ...
34     /// # drop(socket);
35     /// }
36     ///
37     /// #[tokio::main]
38     /// async fn main() -> io::Result<()> {
39     ///     let listener = TcpListener::bind("127.0.0.1:8080").await?;
40     ///
41     ///     loop {
42     ///         let (socket, _) = listener.accept().await?;
43     ///
44     ///         tokio::spawn(async move {
45     ///             // Process each socket concurrently.
46     ///             process(socket).await
47     ///         });
48     ///     }
49     /// }
50     /// ```
51     ///
52     /// # Panics
53     ///
54     /// Panics if called from **outside** of the Tokio runtime.
55     ///
56     /// # Using `!Send` values from a task
57     ///
58     /// The task supplied to `spawn` must implement `Send`. However, it is
59     /// possible to **use** `!Send` values from the task as long as they only
60     /// exist between calls to `.await`.
61     ///
62     /// For example, this will work:
63     ///
64     /// ```
65     /// use tokio::task;
66     ///
67     /// use std::rc::Rc;
68     ///
69     /// fn use_rc(rc: Rc<()>) {
70     ///     // Do stuff w/ rc
71     /// # drop(rc);
72     /// }
73     ///
74     /// #[tokio::main]
75     /// async fn main() {
76     ///     tokio::spawn(async {
77     ///         // Force the `Rc` to stay in a scope with no `.await`
78     ///         {
79     ///             let rc = Rc::new(());
80     ///             use_rc(rc.clone());
81     ///         }
82     ///
83     ///         task::yield_now().await;
84     ///     }).await.unwrap();
85     /// }
86     /// ```
87     ///
88     /// This will **not** work:
89     ///
90     /// ```compile_fail
91     /// use tokio::task;
92     ///
93     /// use std::rc::Rc;
94     ///
95     /// fn use_rc(rc: Rc<()>) {
96     ///     // Do stuff w/ rc
97     /// # drop(rc);
98     /// }
99     ///
100     /// #[tokio::main]
101     /// async fn main() {
102     ///     tokio::spawn(async {
103     ///         let rc = Rc::new(());
104     ///
105     ///         task::yield_now().await;
106     ///
107     ///         use_rc(rc.clone());
108     ///     }).await.unwrap();
109     /// }
110     /// ```
111     ///
112     /// Holding on to a `!Send` value across calls to `.await` will result in
113     /// an unfriendly compile error message similar to:
114     ///
115     /// ```text
116     /// `[... some type ...]` cannot be sent between threads safely
117     /// ```
118     ///
119     /// or:
120     ///
121     /// ```text
122     /// error[E0391]: cycle detected when processing `main`
123     /// ```
124     #[cfg_attr(tokio_track_caller, track_caller)]
125     pub fn spawn<T>(future: T) -> JoinHandle<T::Output>
126     where
127         T: Future + Send + 'static,
128         T::Output: Send + 'static,
129     {
130         // preventing stack overflows on debug mode, by quickly sending the
131         // task to the heap.
132         if cfg!(debug_assertions) && std::mem::size_of::<T>() > 2048 {
133             spawn_inner(Box::pin(future), None)
134         } else {
135             spawn_inner(future, None)
136         }
137     }
138 
139     #[cfg_attr(tokio_track_caller, track_caller)]
140     pub(super) fn spawn_inner<T>(future: T, name: Option<&str>) -> JoinHandle<T::Output>
141     where
142         T: Future + Send + 'static,
143         T::Output: Send + 'static,
144     {
145         let spawn_handle = crate::runtime::context::spawn_handle().expect(CONTEXT_MISSING_ERROR);
146         let task = crate::util::trace::task(future, "task", name);
147         spawn_handle.spawn(task)
148     }
149 }
150