141 lines
4.7 KiB
Rust
141 lines
4.7 KiB
Rust
// 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 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Self>);
|
|
|
|
/// 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>) {
|
|
Self::wake(arc_self);
|
|
}
|
|
}
|
|
|
|
#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
|
|
struct ArcWrapped<T>(PhantomData<T>);
|
|
|
|
unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
|
|
#[inline]
|
|
unsafe fn clone_raw(&self) -> Waker {
|
|
let me: *const ArcWrapped<T> = self;
|
|
let arc = (*(&me as *const *const ArcWrapped<T> as *const Arc<T>)).clone();
|
|
Waker::from(arc)
|
|
}
|
|
|
|
#[inline]
|
|
unsafe fn drop_raw(&self) {
|
|
let mut me: *const ArcWrapped<T> = self;
|
|
let me = &mut me as *mut *const ArcWrapped<T> as *mut Arc<T>;
|
|
ptr::drop_in_place(me);
|
|
}
|
|
|
|
#[inline]
|
|
unsafe fn wake(&self) {
|
|
let me: *const ArcWrapped<T> = self;
|
|
T::wake(&*(&me as *const *const ArcWrapped<T> as *const Arc<T>))
|
|
}
|
|
|
|
#[inline]
|
|
unsafe fn wake_local(&self) {
|
|
let me: *const ArcWrapped<T> = self;
|
|
T::wake_local(&*(&me as *const *const ArcWrapped<T> as *const Arc<T>))
|
|
}
|
|
}
|
|
|
|
impl<T> From<Arc<T>> for Waker
|
|
where T: Wake + 'static,
|
|
{
|
|
fn from(rc: Arc<T>) -> Self {
|
|
unsafe {
|
|
let ptr = mem::transmute::<Arc<T>, NonNull<ArcWrapped<T>>>(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<W: Wake + 'static>(wake: Arc<W>) -> LocalWaker {
|
|
let ptr = mem::transmute::<Arc<W>, NonNull<ArcWrapped<W>>>(wake);
|
|
LocalWaker::new(ptr)
|
|
}
|
|
|
|
struct NonLocalAsLocal<T>(ArcWrapped<T>);
|
|
|
|
unsafe impl<T: Wake + 'static> UnsafeWake for NonLocalAsLocal<T> {
|
|
#[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<W: Wake + 'static>(wake: Arc<W>) -> LocalWaker {
|
|
unsafe {
|
|
let ptr = mem::transmute::<Arc<W>, NonNull<NonLocalAsLocal<W>>>(wake);
|
|
LocalWaker::new(ptr)
|
|
}
|
|
}
|
|
}
|