// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Types and Traits for working with asynchronous tasks. pub use core::task::*; #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))] pub use self::if_arc::*; #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))] mod if_arc { use super::*; use core::marker::PhantomData; use core::mem; use core::ptr::{self, NonNull}; use sync::Arc; /// A way of waking up a specific task. /// /// Any task executor must provide a way of signaling that a task it owns /// is ready to be `poll`ed again. Executors do so by implementing this trait. pub trait Wake: Send + Sync { /// Indicates that the associated task is ready to make progress and should /// be `poll`ed. /// /// Executors generally maintain a queue of "ready" tasks; `wake` should place /// the associated task onto this queue. fn wake(arc_self: &Arc); /// Indicates that the associated task is ready to make progress and should /// be `poll`ed. This function is like `wake`, but can only be called from the /// thread on which this `Wake` was created. /// /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place /// the associated task onto this queue. #[inline] unsafe fn wake_local(arc_self: &Arc) { Self::wake(arc_self); } } #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))] struct ArcWrapped(PhantomData); unsafe impl UnsafeWake for ArcWrapped { #[inline] unsafe fn clone_raw(&self) -> Waker { let me: *const ArcWrapped = self; let arc = (*(&me as *const *const ArcWrapped as *const Arc)).clone(); Waker::from(arc) } #[inline] unsafe fn drop_raw(&self) { let mut me: *const ArcWrapped = self; let me = &mut me as *mut *const ArcWrapped as *mut Arc; ptr::drop_in_place(me); } #[inline] unsafe fn wake(&self) { let me: *const ArcWrapped = self; T::wake(&*(&me as *const *const ArcWrapped as *const Arc)) } #[inline] unsafe fn wake_local(&self) { let me: *const ArcWrapped = self; T::wake_local(&*(&me as *const *const ArcWrapped as *const Arc)) } } impl From> for Waker where T: Wake + 'static, { fn from(rc: Arc) -> Self { unsafe { let ptr = mem::transmute::, NonNull>>(rc); Waker::new(ptr) } } } /// Creates a `LocalWaker` from a local `wake`. /// /// This function requires that `wake` is "local" (created on the current thread). /// The resulting `LocalWaker` will call `wake.wake_local()` when awoken, and /// will call `wake.wake()` if awoken after being converted to a `Waker`. #[inline] pub unsafe fn local_waker(wake: Arc) -> LocalWaker { let ptr = mem::transmute::, NonNull>>(wake); LocalWaker::new(ptr) } struct NonLocalAsLocal(ArcWrapped); unsafe impl UnsafeWake for NonLocalAsLocal { #[inline] unsafe fn clone_raw(&self) -> Waker { self.0.clone_raw() } #[inline] unsafe fn drop_raw(&self) { self.0.drop_raw() } #[inline] unsafe fn wake(&self) { self.0.wake() } #[inline] unsafe fn wake_local(&self) { // Since we're nonlocal, we can't call wake_local self.0.wake() } } /// Creates a `LocalWaker` from a non-local `wake`. /// /// This function is similar to `local_waker`, but does not require that `wake` /// is local to the current thread. The resulting `LocalWaker` will call /// `wake.wake()` when awoken. #[inline] pub fn local_waker_from_nonlocal(wake: Arc) -> LocalWaker { unsafe { let ptr = mem::transmute::, NonNull>>(wake); LocalWaker::new(ptr) } } }