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