2
2
3
3
//! Types and Traits for working with asynchronous tasks.
4
4
//!
5
- //! **Note**: This module is only available on platforms that support atomic
6
- //! loads and stores of pointers. This may be detected at compile time using
5
+ //! **Note**: Some of the types in this module are only available
6
+ //! on platforms that support atomic loads and stores of pointers.
7
+ //! This may be detected at compile time using
7
8
//! `#[cfg(target_has_atomic = "ptr")]`.
8
9
10
+ use crate :: rc:: Rc ;
9
11
use core:: mem:: ManuallyDrop ;
10
- use core:: task:: { RawWaker , RawWakerVTable , Waker } ;
12
+ use core:: task:: { LocalWaker , RawWaker , RawWakerVTable } ;
11
13
14
+ #[ cfg( target_has_atomic = "ptr" ) ]
12
15
use crate :: sync:: Arc ;
16
+ #[ cfg( target_has_atomic = "ptr" ) ]
17
+ use core:: task:: Waker ;
13
18
14
19
/// The implementation of waking a task on an executor.
15
20
///
@@ -73,6 +78,7 @@ use crate::sync::Arc;
73
78
/// println!("Hi from inside a future!");
74
79
/// });
75
80
/// ```
81
+ #[ cfg( target_has_atomic = "ptr" ) ]
76
82
#[ stable( feature = "wake_trait" , since = "1.51.0" ) ]
77
83
pub trait Wake {
78
84
/// Wake this task.
@@ -91,7 +97,7 @@ pub trait Wake {
91
97
self . clone ( ) . wake ( ) ;
92
98
}
93
99
}
94
-
100
+ # [ cfg ( target_has_atomic = "ptr" ) ]
95
101
#[ stable( feature = "wake_trait" , since = "1.51.0" ) ]
96
102
impl < W : Wake + Send + Sync + ' static > From < Arc < W > > for Waker {
97
103
/// Use a `Wake`-able type as a `Waker`.
@@ -103,7 +109,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
103
109
unsafe { Waker :: from_raw ( raw_waker ( waker) ) }
104
110
}
105
111
}
106
-
112
+ # [ cfg ( target_has_atomic = "ptr" ) ]
107
113
#[ stable( feature = "wake_trait" , since = "1.51.0" ) ]
108
114
impl < W : Wake + Send + Sync + ' static > From < Arc < W > > for RawWaker {
109
115
/// Use a `Wake`-able type as a `RawWaker`.
@@ -119,6 +125,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
119
125
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
120
126
// trait dispatch - instead both impls call this function directly and
121
127
// explicitly.
128
+ #[ cfg( target_has_atomic = "ptr" ) ]
122
129
#[ inline( always) ]
123
130
fn raw_waker < W : Wake + Send + Sync + ' static > ( waker : Arc < W > ) -> RawWaker {
124
131
// Increment the reference count of the arc to clone it.
@@ -152,3 +159,171 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
152
159
& RawWakerVTable :: new ( clone_waker :: < W > , wake :: < W > , wake_by_ref :: < W > , drop_waker :: < W > ) ,
153
160
)
154
161
}
162
+
163
+ /// An analogous trait to `Wake` but used to construct a `LocalWaker`. This API
164
+ /// works in exactly the same way as `Wake`, except that it uses an `Rc` instead
165
+ /// of an `Arc`, and the result is a `LocalWaker` instead of a `Waker`.
166
+ ///
167
+ /// The benefits of using `LocalWaker` over `Waker` are that it allows the local waker
168
+ /// to hold data that does not implement `Send` and `Sync`. Additionally, it saves calls
169
+ /// to `Arc::clone`, which requires atomic synchronization.
170
+ ///
171
+ ///
172
+ /// # Examples
173
+ ///
174
+ /// This is a simplified example of a `spawn` and a `block_on` function. The `spawn` function
175
+ /// is used to push new tasks onto the run queue, while the block on function will remove them
176
+ /// and poll them. When a task is woken, it will put itself back on the run queue to be polled
177
+ /// by the executor.
178
+ ///
179
+ /// **Note:** This example trades correctness for simplicity. A real world example would interleave
180
+ /// poll calls with calls to an io reactor to wait for events instead of spinning on a loop.
181
+ ///
182
+ /// ```rust
183
+ /// #![feature(local_waker)]
184
+ /// #![feature(noop_waker)]
185
+ /// use std::task::{LocalWake, ContextBuilder, LocalWaker, Waker};
186
+ /// use std::future::Future;
187
+ /// use std::pin::Pin;
188
+ /// use std::rc::Rc;
189
+ /// use std::cell::RefCell;
190
+ /// use std::collections::VecDeque;
191
+ ///
192
+ ///
193
+ /// thread_local! {
194
+ /// // A queue containing all tasks ready to do progress
195
+ /// static RUN_QUEUE: RefCell<VecDeque<Rc<Task>>> = RefCell::default();
196
+ /// }
197
+ ///
198
+ /// type BoxedFuture = Pin<Box<dyn Future<Output = ()>>>;
199
+ ///
200
+ /// struct Task(RefCell<BoxedFuture>);
201
+ ///
202
+ /// impl LocalWake for Task {
203
+ /// fn wake(self: Rc<Self>) {
204
+ /// RUN_QUEUE.with_borrow_mut(|queue| {
205
+ /// queue.push_back(self)
206
+ /// })
207
+ /// }
208
+ /// }
209
+ ///
210
+ /// fn spawn<F>(future: F)
211
+ /// where
212
+ /// F: Future<Output=()> + 'static + Send + Sync
213
+ /// {
214
+ /// let task = RefCell::new(Box::pin(future));
215
+ /// RUN_QUEUE.with_borrow_mut(|queue| {
216
+ /// queue.push_back(Rc::new(Task(task)));
217
+ /// });
218
+ /// }
219
+ ///
220
+ /// fn block_on<F>(future: F)
221
+ /// where
222
+ /// F: Future<Output=()> + 'static + Sync + Send
223
+ /// {
224
+ /// spawn(future);
225
+ /// loop {
226
+ /// let Some(task) = RUN_QUEUE.with_borrow_mut(|queue| queue.pop_front()) else {
227
+ /// // we exit, since there are no more tasks remaining on the queue
228
+ /// return;
229
+ /// };
230
+ ///
231
+ /// // cast the Rc<Task> into a `LocalWaker`
232
+ /// let local_waker: LocalWaker = task.clone().into();
233
+ /// // Build the context using `ContextBuilder`
234
+ /// let mut cx = ContextBuilder::from_waker(Waker::noop())
235
+ /// .local_waker(&local_waker)
236
+ /// .build();
237
+ ///
238
+ /// // Poll the task
239
+ /// let _ = task.0
240
+ /// .borrow_mut()
241
+ /// .as_mut()
242
+ /// .poll(&mut cx);
243
+ /// }
244
+ /// }
245
+ ///
246
+ /// block_on(async {
247
+ /// println!("hello world");
248
+ /// });
249
+ /// ```
250
+ ///
251
+ #[ unstable( feature = "local_waker" , issue = "118959" ) ]
252
+ pub trait LocalWake {
253
+ /// Wake this task.
254
+ #[ unstable( feature = "local_waker" , issue = "118959" ) ]
255
+ fn wake ( self : Rc < Self > ) ;
256
+
257
+ /// Wake this task without consuming the local waker.
258
+ ///
259
+ /// If an executor supports a cheaper way to wake without consuming the
260
+ /// waker, it should override this method. By default, it clones the
261
+ /// [`Rc`] and calls [`wake`] on the clone.
262
+ ///
263
+ /// [`wake`]: LocalWaker::wake
264
+ #[ unstable( feature = "local_waker" , issue = "118959" ) ]
265
+ fn wake_by_ref ( self : & Rc < Self > ) {
266
+ self . clone ( ) . wake ( ) ;
267
+ }
268
+ }
269
+
270
+ #[ unstable( feature = "local_waker" , issue = "118959" ) ]
271
+ impl < W : LocalWake + ' static > From < Rc < W > > for LocalWaker {
272
+ /// Use a `Wake`-able type as a `LocalWaker`.
273
+ ///
274
+ /// No heap allocations or atomic operations are used for this conversion.
275
+ fn from ( waker : Rc < W > ) -> LocalWaker {
276
+ // SAFETY: This is safe because raw_waker safely constructs
277
+ // a RawWaker from Rc<W>.
278
+ unsafe { LocalWaker :: from_raw ( local_raw_waker ( waker) ) }
279
+ }
280
+ }
281
+ #[ allow( ineffective_unstable_trait_impl) ]
282
+ #[ unstable( feature = "local_waker" , issue = "118959" ) ]
283
+ impl < W : LocalWake + ' static > From < Rc < W > > for RawWaker {
284
+ /// Use a `Wake`-able type as a `RawWaker`.
285
+ ///
286
+ /// No heap allocations or atomic operations are used for this conversion.
287
+ fn from ( waker : Rc < W > ) -> RawWaker {
288
+ local_raw_waker ( waker)
289
+ }
290
+ }
291
+
292
+ // NB: This private function for constructing a RawWaker is used, rather than
293
+ // inlining this into the `From<Rc<W>> for RawWaker` impl, to ensure that
294
+ // the safety of `From<Rc<W>> for Waker` does not depend on the correct
295
+ // trait dispatch - instead both impls call this function directly and
296
+ // explicitly.
297
+ #[ inline( always) ]
298
+ fn local_raw_waker < W : LocalWake + ' static > ( waker : Rc < W > ) -> RawWaker {
299
+ // Increment the reference count of the Rc to clone it.
300
+ unsafe fn clone_waker < W : LocalWake + ' static > ( waker : * const ( ) ) -> RawWaker {
301
+ unsafe { Rc :: increment_strong_count ( waker as * const W ) } ;
302
+ RawWaker :: new (
303
+ waker as * const ( ) ,
304
+ & RawWakerVTable :: new ( clone_waker :: < W > , wake :: < W > , wake_by_ref :: < W > , drop_waker :: < W > ) ,
305
+ )
306
+ }
307
+
308
+ // Wake by value, moving the Rc into the LocalWake::wake function
309
+ unsafe fn wake < W : LocalWake + ' static > ( waker : * const ( ) ) {
310
+ let waker = unsafe { Rc :: from_raw ( waker as * const W ) } ;
311
+ <W as LocalWake >:: wake ( waker) ;
312
+ }
313
+
314
+ // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
315
+ unsafe fn wake_by_ref < W : LocalWake + ' static > ( waker : * const ( ) ) {
316
+ let waker = unsafe { ManuallyDrop :: new ( Rc :: from_raw ( waker as * const W ) ) } ;
317
+ <W as LocalWake >:: wake_by_ref ( & waker) ;
318
+ }
319
+
320
+ // Decrement the reference count of the Rc on drop
321
+ unsafe fn drop_waker < W : LocalWake + ' static > ( waker : * const ( ) ) {
322
+ unsafe { Rc :: decrement_strong_count ( waker as * const W ) } ;
323
+ }
324
+
325
+ RawWaker :: new (
326
+ Rc :: into_raw ( waker) as * const ( ) ,
327
+ & RawWakerVTable :: new ( clone_waker :: < W > , wake :: < W > , wake_by_ref :: < W > , drop_waker :: < W > ) ,
328
+ )
329
+ }
0 commit comments