]> git.lizzy.rs Git - rust.git/blob - src/liballoc/task.rs
Rollup merge of #58346 - RalfJung:rpath-pop, r=Mark-Simulacrum
[rust.git] / src / liballoc / task.rs
1 //! Types and Traits for working with asynchronous tasks.
2
3 pub use core::task::*;
4
5 #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
6 pub use if_arc::*;
7
8 #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
9 mod if_arc {
10     use super::*;
11     use core::marker::PhantomData;
12     use core::mem;
13     use core::ptr::{self, NonNull};
14     use crate::sync::Arc;
15
16     /// A way of waking up a specific task.
17     ///
18     /// Any task executor must provide a way of signaling that a task it owns
19     /// is ready to be `poll`ed again. Executors do so by implementing this trait.
20     pub trait Wake: Send + Sync {
21         /// Indicates that the associated task is ready to make progress and should
22         /// be `poll`ed.
23         ///
24         /// Executors generally maintain a queue of "ready" tasks; `wake` should place
25         /// the associated task onto this queue.
26         fn wake(arc_self: &Arc<Self>);
27
28         /// Indicates that the associated task is ready to make progress and should
29         /// be `poll`ed. This function is like `wake`, but can only be called from the
30         /// thread on which this `Wake` was created.
31         ///
32         /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
33         /// the associated task onto this queue.
34         #[inline]
35         unsafe fn wake_local(arc_self: &Arc<Self>) {
36             Self::wake(arc_self);
37         }
38     }
39
40     #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
41     struct ArcWrapped<T>(PhantomData<T>);
42
43     unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
44         #[inline]
45         unsafe fn clone_raw(&self) -> Waker {
46             let me: *const ArcWrapped<T> = self;
47             let arc = (*(&me as *const *const ArcWrapped<T> as *const Arc<T>)).clone();
48             Waker::from(arc)
49         }
50
51         #[inline]
52         unsafe fn drop_raw(&self) {
53             let mut me: *const ArcWrapped<T> = self;
54             let me = &mut me as *mut *const ArcWrapped<T> as *mut Arc<T>;
55             ptr::drop_in_place(me);
56         }
57
58         #[inline]
59         unsafe fn wake(&self) {
60             let me: *const ArcWrapped<T> = self;
61             T::wake(&*(&me as *const *const ArcWrapped<T> as *const Arc<T>))
62         }
63
64         #[inline]
65         unsafe fn wake_local(&self) {
66             let me: *const ArcWrapped<T> = self;
67             T::wake_local(&*(&me as *const *const ArcWrapped<T> as *const Arc<T>))
68         }
69     }
70
71     impl<T> From<Arc<T>> for Waker
72         where T: Wake + 'static,
73     {
74         fn from(rc: Arc<T>) -> Self {
75             unsafe {
76                 let ptr = mem::transmute::<Arc<T>, NonNull<ArcWrapped<T>>>(rc);
77                 Waker::new(ptr)
78             }
79         }
80     }
81
82     /// Creates a `LocalWaker` from a local `wake`.
83     ///
84     /// This function requires that `wake` is "local" (created on the current thread).
85     /// The resulting `LocalWaker` will call `wake.wake_local()` when awoken, and
86     /// will call `wake.wake()` if awoken after being converted to a `Waker`.
87     #[inline]
88     pub unsafe fn local_waker<W: Wake + 'static>(wake: Arc<W>) -> LocalWaker {
89         let ptr = mem::transmute::<Arc<W>, NonNull<ArcWrapped<W>>>(wake);
90         LocalWaker::new(ptr)
91     }
92
93     struct NonLocalAsLocal<T>(ArcWrapped<T>);
94
95     unsafe impl<T: Wake + 'static> UnsafeWake for NonLocalAsLocal<T> {
96         #[inline]
97         unsafe fn clone_raw(&self) -> Waker {
98             self.0.clone_raw()
99         }
100
101         #[inline]
102         unsafe fn drop_raw(&self) {
103             self.0.drop_raw()
104         }
105
106         #[inline]
107         unsafe fn wake(&self) {
108             self.0.wake()
109         }
110
111         #[inline]
112         unsafe fn wake_local(&self) {
113             // Since we're nonlocal, we can't call wake_local
114             self.0.wake()
115         }
116     }
117
118     /// Creates a `LocalWaker` from a non-local `wake`.
119     ///
120     /// This function is similar to `local_waker`, but does not require that `wake`
121     /// is local to the current thread. The resulting `LocalWaker` will call
122     /// `wake.wake()` when awoken.
123     #[inline]
124     pub fn local_waker_from_nonlocal<W: Wake + 'static>(wake: Arc<W>) -> LocalWaker {
125         unsafe {
126             let ptr = mem::transmute::<Arc<W>, NonNull<NonLocalAsLocal<W>>>(wake);
127             LocalWaker::new(ptr)
128         }
129     }
130 }