1 use crate::runtime::task::RawTask;
2 
3 use std::fmt;
4 use std::future::Future;
5 use std::marker::PhantomData;
6 use std::pin::Pin;
7 use std::task::{Context, Poll};
8 
9 doc_rt_core! {
10     /// An owned permission to join on a task (await its termination).
11     ///
12     /// This can be thought of as the equivalent of [`std::thread::JoinHandle`] for
13     /// a task rather than a thread.
14     ///
15     /// A `JoinHandle` *detaches* the associated task when it is dropped, which
16     /// means that there is no longer any handle to the task, and no way to `join`
17     /// on it.
18     ///
19     /// This `struct` is created by the [`task::spawn`] and [`task::spawn_blocking`]
20     /// functions.
21     ///
22     /// # Examples
23     ///
24     /// Creation from [`task::spawn`]:
25     ///
26     /// ```
27     /// use tokio::task;
28     ///
29     /// # async fn doc() {
30     /// let join_handle: task::JoinHandle<_> = task::spawn(async {
31     ///     // some work here
32     /// });
33     /// # }
34     /// ```
35     ///
36     /// Creation from [`task::spawn_blocking`]:
37     ///
38     /// ```
39     /// use tokio::task;
40     ///
41     /// # async fn doc() {
42     /// let join_handle: task::JoinHandle<_> = task::spawn_blocking(|| {
43     ///     // some blocking work here
44     /// });
45     /// # }
46     /// ```
47     ///
48     /// Child being detached and outliving its parent:
49     ///
50     /// ```no_run
51     /// use tokio::task;
52     /// use tokio::time;
53     /// use std::time::Duration;
54     ///
55     /// # #[tokio::main] async fn main() {
56     /// let original_task = task::spawn(async {
57     ///     let _detached_task = task::spawn(async {
58     ///         // Here we sleep to make sure that the first task returns before.
59     ///         time::delay_for(Duration::from_millis(10)).await;
60     ///         // This will be called, even though the JoinHandle is dropped.
61     ///         println!("♫ Still alive ♫");
62     ///     });
63     /// });
64     ///
65     /// original_task.await.expect("The task being joined has panicked");
66     /// println!("Original task is joined.");
67     ///
68     /// // We make sure that the new task has time to run, before the main
69     /// // task returns.
70     ///
71     /// time::delay_for(Duration::from_millis(1000)).await;
72     /// # }
73     /// ```
74     ///
75     /// [`task::spawn`]: crate::task::spawn()
76     /// [`task::spawn_blocking`]: crate::task::spawn_blocking
77     /// [`std::thread::JoinHandle`]: std::thread::JoinHandle
78     pub struct JoinHandle<T> {
79         raw: Option<RawTask>,
80         _p: PhantomData<T>,
81     }
82 }
83 
84 unsafe impl<T: Send> Send for JoinHandle<T> {}
85 unsafe impl<T: Send> Sync for JoinHandle<T> {}
86 
87 impl<T> JoinHandle<T> {
new(raw: RawTask) -> JoinHandle<T>88     pub(super) fn new(raw: RawTask) -> JoinHandle<T> {
89         JoinHandle {
90             raw: Some(raw),
91             _p: PhantomData,
92         }
93     }
94 }
95 
96 impl<T> Unpin for JoinHandle<T> {}
97 
98 impl<T> Future for JoinHandle<T> {
99     type Output = super::Result<T>;
100 
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>101     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
102         let mut ret = Poll::Pending;
103 
104         // Keep track of task budget
105         ready!(crate::coop::poll_proceed(cx));
106 
107         // Raw should always be set. If it is not, this is due to polling after
108         // completion
109         let raw = self
110             .raw
111             .as_ref()
112             .expect("polling after `JoinHandle` already completed");
113 
114         // Try to read the task output. If the task is not yet complete, the
115         // waker is stored and is notified once the task does complete.
116         //
117         // The function must go via the vtable, which requires erasing generic
118         // types. To do this, the function "return" is placed on the stack
119         // **before** calling the function and is passed into the function using
120         // `*mut ()`.
121         //
122         // Safety:
123         //
124         // The type of `T` must match the task's output type.
125         unsafe {
126             raw.try_read_output(&mut ret as *mut _ as *mut (), cx.waker());
127         }
128 
129         ret
130     }
131 }
132 
133 impl<T> Drop for JoinHandle<T> {
drop(&mut self)134     fn drop(&mut self) {
135         if let Some(raw) = self.raw.take() {
136             if raw.header().state.drop_join_handle_fast().is_ok() {
137                 return;
138             }
139 
140             raw.drop_join_handle_slow();
141         }
142     }
143 }
144 
145 impl<T> fmt::Debug for JoinHandle<T>
146 where
147     T: fmt::Debug,
148 {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result149     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
150         fmt.debug_struct("JoinHandle").finish()
151     }
152 }
153