]>
Commit | Line | Data |
---|---|---|
48663c56 | 1 | #![stable(feature = "futures_api", since = "1.36.0")] |
8faf50e0 | 2 | |
48663c56 XL |
3 | use crate::fmt; |
4 | use crate::marker::{PhantomData, Unpin}; | |
9fa01778 XL |
5 | |
6 | /// A `RawWaker` allows the implementor of a task executor to create a [`Waker`] | |
7 | /// which provides customized wakeup behavior. | |
8 | /// | |
9 | /// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table | |
10 | /// | |
11 | /// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that | |
12 | /// customizes the behavior of the `RawWaker`. | |
48663c56 XL |
13 | /// |
14 | /// [`Waker`]: struct.Waker.html | |
9fa01778 | 15 | #[derive(PartialEq, Debug)] |
48663c56 | 16 | #[stable(feature = "futures_api", since = "1.36.0")] |
9fa01778 XL |
17 | pub struct RawWaker { |
18 | /// A data pointer, which can be used to store arbitrary data as required | |
19 | /// by the executor. This could be e.g. a type-erased pointer to an `Arc` | |
20 | /// that is associated with the task. | |
21 | /// The value of this field gets passed to all functions that are part of | |
22 | /// the vtable as the first parameter. | |
23 | data: *const (), | |
24 | /// Virtual function pointer table that customizes the behavior of this waker. | |
25 | vtable: &'static RawWakerVTable, | |
26 | } | |
27 | ||
28 | impl RawWaker { | |
29 | /// Creates a new `RawWaker` from the provided `data` pointer and `vtable`. | |
30 | /// | |
31 | /// The `data` pointer can be used to store arbitrary data as required | |
32 | /// by the executor. This could be e.g. a type-erased pointer to an `Arc` | |
33 | /// that is associated with the task. | |
416331ca | 34 | /// The value of this pointer will get passed to all functions that are part |
9fa01778 XL |
35 | /// of the `vtable` as the first parameter. |
36 | /// | |
37 | /// The `vtable` customizes the behavior of a `Waker` which gets created | |
38 | /// from a `RawWaker`. For each operation on the `Waker`, the associated | |
39 | /// function in the `vtable` of the underlying `RawWaker` will be called. | |
3dfed10e | 40 | #[inline] |
532ac7d7 | 41 | #[rustc_promotable] |
48663c56 | 42 | #[stable(feature = "futures_api", since = "1.36.0")] |
dfeec247 | 43 | #[rustc_const_stable(feature = "futures_api", since = "1.36.0")] |
9fa01778 | 44 | pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { |
60c5eb7d | 45 | RawWaker { data, vtable } |
9fa01778 XL |
46 | } |
47 | } | |
48 | ||
49 | /// A virtual function pointer table (vtable) that specifies the behavior | |
50 | /// of a [`RawWaker`]. | |
51 | /// | |
52 | /// The pointer passed to all functions inside the vtable is the `data` pointer | |
53 | /// from the enclosing [`RawWaker`] object. | |
54 | /// | |
55 | /// The functions inside this struct are only intended be called on the `data` | |
56 | /// pointer of a properly constructed [`RawWaker`] object from inside the | |
57 | /// [`RawWaker`] implementation. Calling one of the contained functions using | |
58 | /// any other `data` pointer will cause undefined behavior. | |
48663c56 XL |
59 | /// |
60 | /// [`RawWaker`]: struct.RawWaker.html | |
61 | #[stable(feature = "futures_api", since = "1.36.0")] | |
9fa01778 XL |
62 | #[derive(PartialEq, Copy, Clone, Debug)] |
63 | pub struct RawWakerVTable { | |
64 | /// This function will be called when the [`RawWaker`] gets cloned, e.g. when | |
65 | /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned. | |
66 | /// | |
67 | /// The implementation of this function must retain all resources that are | |
68 | /// required for this additional instance of a [`RawWaker`] and associated | |
69 | /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup | |
70 | /// of the same task that would have been awoken by the original [`RawWaker`]. | |
48663c56 XL |
71 | /// |
72 | /// [`Waker`]: struct.Waker.html | |
73 | /// [`RawWaker`]: struct.RawWaker.html | |
532ac7d7 | 74 | clone: unsafe fn(*const ()) -> RawWaker, |
9fa01778 XL |
75 | |
76 | /// This function will be called when `wake` is called on the [`Waker`]. | |
77 | /// It must wake up the task associated with this [`RawWaker`]. | |
78 | /// | |
48663c56 XL |
79 | /// The implementation of this function must make sure to release any |
80 | /// resources that are associated with this instance of a [`RawWaker`] and | |
81 | /// associated task. | |
82 | /// | |
83 | /// [`Waker`]: struct.Waker.html | |
84 | /// [`RawWaker`]: struct.RawWaker.html | |
532ac7d7 XL |
85 | wake: unsafe fn(*const ()), |
86 | ||
48663c56 XL |
87 | /// This function will be called when `wake_by_ref` is called on the [`Waker`]. |
88 | /// It must wake up the task associated with this [`RawWaker`]. | |
89 | /// | |
90 | /// This function is similar to `wake`, but must not consume the provided data | |
91 | /// pointer. | |
92 | /// | |
93 | /// [`Waker`]: struct.Waker.html | |
94 | /// [`RawWaker`]: struct.RawWaker.html | |
95 | wake_by_ref: unsafe fn(*const ()), | |
96 | ||
532ac7d7 XL |
97 | /// This function gets called when a [`RawWaker`] gets dropped. |
98 | /// | |
99 | /// The implementation of this function must make sure to release any | |
100 | /// resources that are associated with this instance of a [`RawWaker`] and | |
101 | /// associated task. | |
48663c56 XL |
102 | /// |
103 | /// [`RawWaker`]: struct.RawWaker.html | |
532ac7d7 XL |
104 | drop: unsafe fn(*const ()), |
105 | } | |
9fa01778 | 106 | |
532ac7d7 | 107 | impl RawWakerVTable { |
48663c56 XL |
108 | /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`, |
109 | /// `wake_by_ref`, and `drop` functions. | |
532ac7d7 XL |
110 | /// |
111 | /// # `clone` | |
112 | /// | |
113 | /// This function will be called when the [`RawWaker`] gets cloned, e.g. when | |
114 | /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned. | |
115 | /// | |
116 | /// The implementation of this function must retain all resources that are | |
117 | /// required for this additional instance of a [`RawWaker`] and associated | |
118 | /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup | |
119 | /// of the same task that would have been awoken by the original [`RawWaker`]. | |
120 | /// | |
121 | /// # `wake` | |
122 | /// | |
123 | /// This function will be called when `wake` is called on the [`Waker`]. | |
124 | /// It must wake up the task associated with this [`RawWaker`]. | |
125 | /// | |
48663c56 XL |
126 | /// The implementation of this function must make sure to release any |
127 | /// resources that are associated with this instance of a [`RawWaker`] and | |
128 | /// associated task. | |
129 | /// | |
130 | /// # `wake_by_ref` | |
131 | /// | |
132 | /// This function will be called when `wake_by_ref` is called on the [`Waker`]. | |
133 | /// It must wake up the task associated with this [`RawWaker`]. | |
134 | /// | |
135 | /// This function is similar to `wake`, but must not consume the provided data | |
532ac7d7 XL |
136 | /// pointer. |
137 | /// | |
138 | /// # `drop` | |
139 | /// | |
9fa01778 XL |
140 | /// This function gets called when a [`RawWaker`] gets dropped. |
141 | /// | |
142 | /// The implementation of this function must make sure to release any | |
143 | /// resources that are associated with this instance of a [`RawWaker`] and | |
144 | /// associated task. | |
48663c56 XL |
145 | /// |
146 | /// [`Waker`]: struct.Waker.html | |
147 | /// [`RawWaker`]: struct.RawWaker.html | |
532ac7d7 | 148 | #[rustc_promotable] |
dc9dc135 | 149 | #[stable(feature = "futures_api", since = "1.36.0")] |
48663c56 XL |
150 | // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else |
151 | // without first consulting with T-Lang. | |
152 | // | |
153 | // FIXME: remove whenever we have a stable way to accept fn pointers from const fn | |
154 | // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062) | |
dc9dc135 | 155 | #[rustc_allow_const_fn_ptr] |
dfeec247 | 156 | #[rustc_const_stable(feature = "futures_api", since = "1.36.0")] |
532ac7d7 XL |
157 | pub const fn new( |
158 | clone: unsafe fn(*const ()) -> RawWaker, | |
159 | wake: unsafe fn(*const ()), | |
48663c56 | 160 | wake_by_ref: unsafe fn(*const ()), |
532ac7d7 XL |
161 | drop: unsafe fn(*const ()), |
162 | ) -> Self { | |
60c5eb7d | 163 | Self { clone, wake, wake_by_ref, drop } |
532ac7d7 XL |
164 | } |
165 | } | |
166 | ||
167 | /// The `Context` of an asynchronous task. | |
168 | /// | |
169 | /// Currently, `Context` only serves to provide access to a `&Waker` | |
170 | /// which can be used to wake the current task. | |
48663c56 | 171 | #[stable(feature = "futures_api", since = "1.36.0")] |
532ac7d7 XL |
172 | pub struct Context<'a> { |
173 | waker: &'a Waker, | |
174 | // Ensure we future-proof against variance changes by forcing | |
175 | // the lifetime to be invariant (argument-position lifetimes | |
176 | // are contravariant while return-position lifetimes are | |
177 | // covariant). | |
178 | _marker: PhantomData<fn(&'a ()) -> &'a ()>, | |
179 | } | |
180 | ||
181 | impl<'a> Context<'a> { | |
182 | /// Create a new `Context` from a `&Waker`. | |
48663c56 | 183 | #[stable(feature = "futures_api", since = "1.36.0")] |
532ac7d7 XL |
184 | #[inline] |
185 | pub fn from_waker(waker: &'a Waker) -> Self { | |
60c5eb7d | 186 | Context { waker, _marker: PhantomData } |
532ac7d7 XL |
187 | } |
188 | ||
189 | /// Returns a reference to the `Waker` for the current task. | |
48663c56 | 190 | #[stable(feature = "futures_api", since = "1.36.0")] |
532ac7d7 XL |
191 | #[inline] |
192 | pub fn waker(&self) -> &'a Waker { | |
193 | &self.waker | |
194 | } | |
195 | } | |
196 | ||
48663c56 | 197 | #[stable(feature = "futures_api", since = "1.36.0")] |
532ac7d7 | 198 | impl fmt::Debug for Context<'_> { |
48663c56 | 199 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
60c5eb7d | 200 | f.debug_struct("Context").field("waker", &self.waker).finish() |
532ac7d7 | 201 | } |
9fa01778 | 202 | } |
8faf50e0 XL |
203 | |
204 | /// A `Waker` is a handle for waking up a task by notifying its executor that it | |
205 | /// is ready to be run. | |
206 | /// | |
9fa01778 XL |
207 | /// This handle encapsulates a [`RawWaker`] instance, which defines the |
208 | /// executor-specific wakeup behavior. | |
209 | /// | |
e74abb32 | 210 | /// Implements [`Clone`], [`Send`], and [`Sync`]. |
48663c56 XL |
211 | /// |
212 | /// [`RawWaker`]: struct.RawWaker.html | |
8faf50e0 | 213 | #[repr(transparent)] |
48663c56 | 214 | #[stable(feature = "futures_api", since = "1.36.0")] |
8faf50e0 | 215 | pub struct Waker { |
9fa01778 | 216 | waker: RawWaker, |
8faf50e0 XL |
217 | } |
218 | ||
48663c56 | 219 | #[stable(feature = "futures_api", since = "1.36.0")] |
8faf50e0 | 220 | impl Unpin for Waker {} |
48663c56 | 221 | #[stable(feature = "futures_api", since = "1.36.0")] |
8faf50e0 | 222 | unsafe impl Send for Waker {} |
48663c56 | 223 | #[stable(feature = "futures_api", since = "1.36.0")] |
8faf50e0 XL |
224 | unsafe impl Sync for Waker {} |
225 | ||
226 | impl Waker { | |
8faf50e0 | 227 | /// Wake up the task associated with this `Waker`. |
532ac7d7 | 228 | #[inline] |
48663c56 XL |
229 | #[stable(feature = "futures_api", since = "1.36.0")] |
230 | pub fn wake(self) { | |
9fa01778 XL |
231 | // The actual wakeup call is delegated through a virtual function call |
232 | // to the implementation which is defined by the executor. | |
48663c56 XL |
233 | let wake = self.waker.vtable.wake; |
234 | let data = self.waker.data; | |
235 | ||
236 | // Don't call `drop` -- the waker will be consumed by `wake`. | |
237 | crate::mem::forget(self); | |
9fa01778 | 238 | |
48663c56 | 239 | // SAFETY: This is safe because `Waker::from_raw` is the only way |
9fa01778 XL |
240 | // to initialize `wake` and `data` requiring the user to acknowledge |
241 | // that the contract of `RawWaker` is upheld. | |
48663c56 XL |
242 | unsafe { (wake)(data) }; |
243 | } | |
244 | ||
245 | /// Wake up the task associated with this `Waker` without consuming the `Waker`. | |
246 | /// | |
247 | /// This is similar to `wake`, but may be slightly less efficient in the case | |
248 | /// where an owned `Waker` is available. This method should be preferred to | |
249 | /// calling `waker.clone().wake()`. | |
250 | #[inline] | |
251 | #[stable(feature = "futures_api", since = "1.36.0")] | |
252 | pub fn wake_by_ref(&self) { | |
253 | // The actual wakeup call is delegated through a virtual function call | |
254 | // to the implementation which is defined by the executor. | |
255 | ||
256 | // SAFETY: see `wake` | |
257 | unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) } | |
8faf50e0 XL |
258 | } |
259 | ||
532ac7d7 | 260 | /// Returns `true` if this `Waker` and another `Waker` have awoken the same task. |
8faf50e0 XL |
261 | /// |
262 | /// This function works on a best-effort basis, and may return false even | |
263 | /// when the `Waker`s would awaken the same task. However, if this function | |
9fa01778 | 264 | /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task. |
8faf50e0 XL |
265 | /// |
266 | /// This function is primarily used for optimization purposes. | |
532ac7d7 | 267 | #[inline] |
48663c56 | 268 | #[stable(feature = "futures_api", since = "1.36.0")] |
8faf50e0 | 269 | pub fn will_wake(&self, other: &Waker) -> bool { |
9fa01778 | 270 | self.waker == other.waker |
8faf50e0 | 271 | } |
0bf4aa26 | 272 | |
9fa01778 | 273 | /// Creates a new `Waker` from [`RawWaker`]. |
0bf4aa26 | 274 | /// |
9fa01778 XL |
275 | /// The behavior of the returned `Waker` is undefined if the contract defined |
276 | /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. | |
277 | /// Therefore this method is unsafe. | |
48663c56 XL |
278 | /// |
279 | /// [`RawWaker`]: struct.RawWaker.html | |
280 | /// [`RawWakerVTable`]: struct.RawWakerVTable.html | |
532ac7d7 | 281 | #[inline] |
48663c56 XL |
282 | #[stable(feature = "futures_api", since = "1.36.0")] |
283 | pub unsafe fn from_raw(waker: RawWaker) -> Waker { | |
60c5eb7d | 284 | Waker { waker } |
0bf4aa26 | 285 | } |
8faf50e0 XL |
286 | } |
287 | ||
48663c56 | 288 | #[stable(feature = "futures_api", since = "1.36.0")] |
8faf50e0 | 289 | impl Clone for Waker { |
532ac7d7 | 290 | #[inline] |
8faf50e0 | 291 | fn clone(&self) -> Self { |
9fa01778 | 292 | Waker { |
48663c56 | 293 | // SAFETY: This is safe because `Waker::from_raw` is the only way |
9fa01778 XL |
294 | // to initialize `clone` and `data` requiring the user to acknowledge |
295 | // that the contract of [`RawWaker`] is upheld. | |
296 | waker: unsafe { (self.waker.vtable.clone)(self.waker.data) }, | |
8faf50e0 XL |
297 | } |
298 | } | |
299 | } | |
300 | ||
48663c56 | 301 | #[stable(feature = "futures_api", since = "1.36.0")] |
8faf50e0 | 302 | impl Drop for Waker { |
532ac7d7 | 303 | #[inline] |
8faf50e0 | 304 | fn drop(&mut self) { |
48663c56 | 305 | // SAFETY: This is safe because `Waker::from_raw` is the only way |
9fa01778 XL |
306 | // to initialize `drop` and `data` requiring the user to acknowledge |
307 | // that the contract of `RawWaker` is upheld. | |
308 | unsafe { (self.waker.vtable.drop)(self.waker.data) } | |
8faf50e0 XL |
309 | } |
310 | } | |
311 | ||
48663c56 | 312 | #[stable(feature = "futures_api", since = "1.36.0")] |
9fa01778 | 313 | impl fmt::Debug for Waker { |
48663c56 | 314 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
9fa01778 XL |
315 | let vtable_ptr = self.waker.vtable as *const RawWakerVTable; |
316 | f.debug_struct("Waker") | |
317 | .field("data", &self.waker.data) | |
318 | .field("vtable", &vtable_ptr) | |
8faf50e0 XL |
319 | .finish() |
320 | } | |
321 | } |