22
33//! Types and Traits for working with asynchronous tasks.
44//!
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
78//! `#[cfg(target_has_atomic = "ptr")]`.
89
10+ use crate :: rc:: Rc ;
911use core:: mem:: ManuallyDrop ;
10- use core:: task:: { RawWaker , RawWakerVTable , Waker } ;
12+ use core:: task:: { LocalWaker , RawWaker , RawWakerVTable } ;
1113
14+ #[ cfg( target_has_atomic = "ptr" ) ]
1215use crate :: sync:: Arc ;
16+ #[ cfg( target_has_atomic = "ptr" ) ]
17+ use core:: task:: Waker ;
1318
1419/// The implementation of waking a task on an executor.
1520///
@@ -73,6 +78,7 @@ use crate::sync::Arc;
7378/// println!("Hi from inside a future!");
7479/// });
7580/// ```
81+ #[ cfg( target_has_atomic = "ptr" ) ]
7682#[ stable( feature = "wake_trait" , since = "1.51.0" ) ]
7783pub trait Wake {
7884 /// Wake this task.
@@ -91,7 +97,7 @@ pub trait Wake {
9197 self . clone ( ) . wake ( ) ;
9298 }
9399}
94-
100+ # [ cfg ( target_has_atomic = "ptr" ) ]
95101#[ stable( feature = "wake_trait" , since = "1.51.0" ) ]
96102impl < W : Wake + Send + Sync + ' static > From < Arc < W > > for Waker {
97103 /// Use a `Wake`-able type as a `Waker`.
@@ -103,7 +109,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
103109 unsafe { Waker :: from_raw ( raw_waker ( waker) ) }
104110 }
105111}
106-
112+ # [ cfg ( target_has_atomic = "ptr" ) ]
107113#[ stable( feature = "wake_trait" , since = "1.51.0" ) ]
108114impl < W : Wake + Send + Sync + ' static > From < Arc < W > > for RawWaker {
109115 /// Use a `Wake`-able type as a `RawWaker`.
@@ -119,6 +125,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
119125// the safety of `From<Arc<W>> for Waker` does not depend on the correct
120126// trait dispatch - instead both impls call this function directly and
121127// explicitly.
128+ #[ cfg( target_has_atomic = "ptr" ) ]
122129#[ inline( always) ]
123130fn raw_waker < W : Wake + Send + Sync + ' static > ( waker : Arc < W > ) -> RawWaker {
124131 // 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 {
152159 & RawWakerVTable :: new ( clone_waker :: < W > , wake :: < W > , wake_by_ref :: < W > , drop_waker :: < W > ) ,
153160 )
154161}
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