about summary refs log tree commit diff
path: root/src/libcore/task
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2018-08-19 18:34:46 +0200
committerGitHub <noreply@github.com>2018-08-19 18:34:46 +0200
commit08b1d83a46848dd7bd778aeae67a1e529e95d8cd (patch)
tree9153a34f91860b175afb24f904fd50ac09e77c4e /src/libcore/task
parentac64ef33756d05557153e00211cdf8fcf65d4be3 (diff)
parentb355906919927ab3c879becd14392f023af883a1 (diff)
downloadrust-08b1d83a46848dd7bd778aeae67a1e529e95d8cd.tar.gz
rust-08b1d83a46848dd7bd778aeae67a1e529e95d8cd.zip
Merge branch 'master' into feature/core_convert_id
Diffstat (limited to 'src/libcore/task')
-rw-r--r--src/libcore/task/context.rs98
-rw-r--r--src/libcore/task/mod.rs27
-rw-r--r--src/libcore/task/poll.rs137
-rw-r--r--src/libcore/task/spawn.rs93
-rw-r--r--src/libcore/task/wake.rs279
5 files changed, 634 insertions, 0 deletions
diff --git a/src/libcore/task/context.rs b/src/libcore/task/context.rs
new file mode 100644
index 00000000000..5a29c8528ef
--- /dev/null
+++ b/src/libcore/task/context.rs
@@ -0,0 +1,98 @@
+// 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.
+
+#![unstable(feature = "futures_api",
+            reason = "futures in libcore are unstable",
+            issue = "50547")]
+
+use fmt;
+use super::{Spawn, Waker, LocalWaker};
+
+/// Information about the currently-running task.
+///
+/// Contexts are always tied to the stack, since they are set up specifically
+/// when performing a single `poll` step on a task.
+pub struct Context<'a> {
+    local_waker: &'a LocalWaker,
+    spawner: &'a mut dyn Spawn,
+}
+
+impl<'a> fmt::Debug for Context<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Context")
+            .finish()
+    }
+}
+
+impl<'a> Context<'a> {
+    /// Create a new task `Context` with the provided `local_waker`, `waker`,
+    /// and `spawner`.
+    #[inline]
+    pub fn new(
+        local_waker: &'a LocalWaker,
+        spawner: &'a mut dyn Spawn,
+    ) -> Context<'a> {
+        Context { local_waker, spawner }
+    }
+
+    /// Get the `LocalWaker` associated with the current task.
+    #[inline]
+    pub fn local_waker(&self) -> &'a LocalWaker {
+        self.local_waker
+    }
+
+    /// Get the `Waker` associated with the current task.
+    #[inline]
+    pub fn waker(&self) -> &'a Waker {
+        unsafe { &*(self.local_waker as *const LocalWaker as *const Waker) }
+    }
+
+    /// Get the spawner associated with this task.
+    ///
+    /// This method is useful primarily if you want to explicitly handle
+    /// spawn failures.
+    #[inline]
+    pub fn spawner(&mut self) -> &mut dyn Spawn {
+        self.spawner
+    }
+
+    /// Produce a context like the current one, but using the given waker
+    /// instead.
+    ///
+    /// This advanced method is primarily used when building "internal
+    /// schedulers" within a task, where you want to provide some customized
+    /// wakeup logic.
+    #[inline]
+    pub fn with_waker<'b>(
+        &'b mut self,
+        local_waker: &'b LocalWaker,
+    ) -> Context<'b> {
+        Context {
+            local_waker,
+            spawner: self.spawner,
+        }
+    }
+
+    /// Produce a context like the current one, but using the given spawner
+    /// instead.
+    ///
+    /// This advanced method is primarily used when building "internal
+    /// schedulers" within a task.
+    #[inline]
+    pub fn with_spawner<'b, Sp: Spawn>(
+        &'b mut self,
+        spawner: &'b mut Sp,
+    ) -> Context<'b> {
+        Context {
+            local_waker: self.local_waker,
+            spawner,
+        }
+    }
+}
diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs
new file mode 100644
index 00000000000..f51e5f7ce0e
--- /dev/null
+++ b/src/libcore/task/mod.rs
@@ -0,0 +1,27 @@
+// 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.
+
+#![unstable(feature = "futures_api",
+            reason = "futures in libcore are unstable",
+            issue = "50547")]
+
+//! Types and Traits for working with asynchronous tasks.
+
+mod context;
+pub use self::context::Context;
+
+mod spawn;
+pub use self::spawn::{Spawn, SpawnErrorKind, SpawnObjError, SpawnLocalObjError};
+
+mod poll;
+pub use self::poll::Poll;
+
+mod wake;
+pub use self::wake::{Waker, LocalWaker, UnsafeWake};
diff --git a/src/libcore/task/poll.rs b/src/libcore/task/poll.rs
new file mode 100644
index 00000000000..fb027efc6dc
--- /dev/null
+++ b/src/libcore/task/poll.rs
@@ -0,0 +1,137 @@
+// 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.
+
+#![unstable(feature = "futures_api",
+            reason = "futures in libcore are unstable",
+            issue = "50547")]
+
+use ops::Try;
+use result::Result;
+
+/// Indicates whether a value is available or if the current task has been
+/// scheduled to receive a wakeup instead.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+pub enum Poll<T> {
+    /// Represents that a value is immediately ready.
+    Ready(T),
+
+    /// Represents that a value is not ready yet.
+    ///
+    /// When a function returns `Pending`, the function *must* also
+    /// ensure that the current task is scheduled to be awoken when
+    /// progress can be made.
+    Pending,
+}
+
+impl<T> Poll<T> {
+    /// Change the ready value of this `Poll` with the closure provided
+    pub fn map<U, F>(self, f: F) -> Poll<U>
+        where F: FnOnce(T) -> U
+    {
+        match self {
+            Poll::Ready(t) => Poll::Ready(f(t)),
+            Poll::Pending => Poll::Pending,
+        }
+    }
+
+    /// Returns whether this is `Poll::Ready`
+    #[inline]
+    pub fn is_ready(&self) -> bool {
+        match *self {
+            Poll::Ready(_) => true,
+            Poll::Pending => false,
+        }
+    }
+
+    /// Returns whether this is `Poll::Pending`
+    #[inline]
+    pub fn is_pending(&self) -> bool {
+        !self.is_ready()
+    }
+}
+
+impl<T, E> Poll<Result<T, E>> {
+    /// Change the success value of this `Poll` with the closure provided
+    pub fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
+        where F: FnOnce(T) -> U
+    {
+        match self {
+            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
+            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
+            Poll::Pending => Poll::Pending,
+        }
+    }
+
+    /// Change the error value of this `Poll` with the closure provided
+    pub fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
+        where F: FnOnce(E) -> U
+    {
+        match self {
+            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
+            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
+            Poll::Pending => Poll::Pending,
+        }
+    }
+}
+
+impl<T> From<T> for Poll<T> {
+    fn from(t: T) -> Poll<T> {
+        Poll::Ready(t)
+    }
+}
+
+impl<T, E> Try for Poll<Result<T, E>> {
+    type Ok = Poll<T>;
+    type Error = E;
+
+    #[inline]
+    fn into_result(self) -> Result<Self::Ok, Self::Error> {
+        match self {
+            Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
+            Poll::Ready(Err(e)) => Err(e),
+            Poll::Pending => Ok(Poll::Pending),
+        }
+    }
+
+    #[inline]
+    fn from_error(e: Self::Error) -> Self {
+        Poll::Ready(Err(e))
+    }
+
+    #[inline]
+    fn from_ok(x: Self::Ok) -> Self {
+        x.map(Ok)
+    }
+}
+
+impl<T, E> Try for Poll<Option<Result<T, E>>> {
+    type Ok = Poll<Option<T>>;
+    type Error = E;
+
+    #[inline]
+    fn into_result(self) -> Result<Self::Ok, Self::Error> {
+        match self {
+            Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
+            Poll::Ready(Some(Err(e))) => Err(e),
+            Poll::Ready(None) => Ok(Poll::Ready(None)),
+            Poll::Pending => Ok(Poll::Pending),
+        }
+    }
+
+    #[inline]
+    fn from_error(e: Self::Error) -> Self {
+        Poll::Ready(Some(Err(e)))
+    }
+
+    #[inline]
+    fn from_ok(x: Self::Ok) -> Self {
+        x.map(|x| x.map(Ok))
+    }
+}
diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs
new file mode 100644
index 00000000000..58ee85d232b
--- /dev/null
+++ b/src/libcore/task/spawn.rs
@@ -0,0 +1,93 @@
+// 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.
+
+#![unstable(feature = "futures_api",
+            reason = "futures in libcore are unstable",
+            issue = "50547")]
+
+use fmt;
+use future::{FutureObj, LocalFutureObj};
+
+/// Spawns tasks that poll futures to completion onto its associated task
+/// executor.
+///
+/// The term "task" refers to a kind of lightweight "thread". Task executors
+/// are responsible for scheduling the execution of tasks on operating system
+/// threads.
+pub trait Spawn {
+    /// Spawns a new task with the given future. The future will be polled until
+    /// completion.
+    ///
+    /// # Errors
+    ///
+    /// The executor may be unable to spawn tasks, either because it has
+    /// been shut down or is resource-constrained.
+    fn spawn_obj(
+        &mut self,
+        future: FutureObj<'static, ()>,
+    ) -> Result<(), SpawnObjError>;
+
+    /// Determines whether the executor is able to spawn new tasks.
+    ///
+    /// # Returns
+    ///
+    /// An `Ok` return means the executor is *likely* (but not guaranteed)
+    /// to accept a subsequent spawn attempt. Likewise, an `Err` return
+    /// means that `spawn` is likely, but not guaranteed, to yield an error.
+    #[inline]
+    fn status(&self) -> Result<(), SpawnErrorKind> {
+        Ok(())
+    }
+}
+
+/// Provides the reason that an executor was unable to spawn.
+pub struct SpawnErrorKind {
+    _hidden: (),
+}
+
+impl fmt::Debug for SpawnErrorKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_tuple("SpawnErrorKind")
+            .field(&"shutdown")
+            .finish()
+    }
+}
+
+impl SpawnErrorKind {
+    /// Spawning is failing because the executor has been shut down.
+    pub fn shutdown() -> SpawnErrorKind {
+        SpawnErrorKind { _hidden: () }
+    }
+
+    /// Check whether this error is the `shutdown` error.
+    pub fn is_shutdown(&self) -> bool {
+        true
+    }
+}
+
+/// The result of a failed spawn
+#[derive(Debug)]
+pub struct SpawnObjError {
+    /// The kind of error
+    pub kind: SpawnErrorKind,
+
+    /// The future for which spawning inside a task was attempted
+    pub future: FutureObj<'static, ()>,
+}
+
+/// The result of a failed spawn
+#[derive(Debug)]
+pub struct SpawnLocalObjError {
+    /// The kind of error
+    pub kind: SpawnErrorKind,
+
+    /// The future for which spawning inside a task was attempted
+    pub future: LocalFutureObj<'static, ()>,
+}
diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs
new file mode 100644
index 00000000000..d770536ef42
--- /dev/null
+++ b/src/libcore/task/wake.rs
@@ -0,0 +1,279 @@
+// 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.
+
+#![unstable(feature = "futures_api",
+            reason = "futures in libcore are unstable",
+            issue = "50547")]
+
+use {fmt, mem};
+use marker::Unpin;
+use ptr::NonNull;
+
+/// A `Waker` is a handle for waking up a task by notifying its executor that it
+/// is ready to be run.
+///
+/// This handle contains a trait object pointing to an instance of the `UnsafeWake`
+/// trait, allowing notifications to get routed through it.
+#[repr(transparent)]
+pub struct Waker {
+    inner: NonNull<dyn UnsafeWake>,
+}
+
+impl Unpin for Waker {}
+unsafe impl Send for Waker {}
+unsafe impl Sync for Waker {}
+
+impl Waker {
+    /// Constructs a new `Waker` directly.
+    ///
+    /// Note that most code will not need to call this. Implementers of the
+    /// `UnsafeWake` trait will typically provide a wrapper that calls this
+    /// but you otherwise shouldn't call it directly.
+    ///
+    /// If you're working with the standard library then it's recommended to
+    /// use the `Waker::from` function instead which works with the safe
+    /// `Arc` type and the safe `Wake` trait.
+    #[inline]
+    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
+        Waker { inner }
+    }
+
+    /// Wake up the task associated with this `Waker`.
+    #[inline]
+    pub fn wake(&self) {
+        unsafe { self.inner.as_ref().wake() }
+    }
+
+    /// Returns whether or not this `Waker` and `other` awaken the same task.
+    ///
+    /// This function works on a best-effort basis, and may return false even
+    /// when the `Waker`s would awaken the same task. However, if this function
+    /// returns true, it is guaranteed that the `Waker`s will awaken the same
+    /// task.
+    ///
+    /// This function is primarily used for optimization purposes.
+    #[inline]
+    pub fn will_wake(&self, other: &Waker) -> bool {
+        self.inner == other.inner
+    }
+}
+
+impl Clone for Waker {
+    #[inline]
+    fn clone(&self) -> Self {
+        unsafe {
+            self.inner.as_ref().clone_raw()
+        }
+    }
+}
+
+impl fmt::Debug for Waker {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Waker")
+            .finish()
+    }
+}
+
+impl Drop for Waker {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.inner.as_ref().drop_raw()
+        }
+    }
+}
+
+/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it
+/// is ready to be run.
+///
+/// This is similar to the `Waker` type, but cannot be sent across threads.
+/// Task executors can use this type to implement more optimized singlethreaded wakeup
+/// behavior.
+#[repr(transparent)]
+pub struct LocalWaker {
+    inner: NonNull<dyn UnsafeWake>,
+}
+
+impl Unpin for LocalWaker {}
+impl !Send for LocalWaker {}
+impl !Sync for LocalWaker {}
+
+impl LocalWaker {
+    /// Constructs a new `LocalWaker` directly.
+    ///
+    /// Note that most code will not need to call this. Implementers of the
+    /// `UnsafeWake` trait will typically provide a wrapper that calls this
+    /// but you otherwise shouldn't call it directly.
+    ///
+    /// If you're working with the standard library then it's recommended to
+    /// use the `local_waker_from_nonlocal` or `local_waker` to convert a `Waker`
+    /// into a `LocalWaker`.
+    ///
+    /// For this function to be used safely, it must be sound to call `inner.wake_local()`
+    /// on the current thread.
+    #[inline]
+    pub unsafe fn new(inner: NonNull<dyn UnsafeWake>) -> Self {
+        LocalWaker { inner }
+    }
+
+    /// Wake up the task associated with this `LocalWaker`.
+    #[inline]
+    pub fn wake(&self) {
+        unsafe { self.inner.as_ref().wake_local() }
+    }
+
+    /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task.
+    ///
+    /// This function works on a best-effort basis, and may return false even
+    /// when the `LocalWaker`s would awaken the same task. However, if this function
+    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
+    /// task.
+    ///
+    /// This function is primarily used for optimization purposes.
+    #[inline]
+    pub fn will_wake(&self, other: &LocalWaker) -> bool {
+        self.inner == other.inner
+    }
+
+    /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task.
+    ///
+    /// This function works on a best-effort basis, and may return false even
+    /// when the `Waker`s would awaken the same task. However, if this function
+    /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same
+    /// task.
+    ///
+    /// This function is primarily used for optimization purposes.
+    #[inline]
+    pub fn will_wake_nonlocal(&self, other: &Waker) -> bool {
+        self.inner == other.inner
+    }
+}
+
+impl From<LocalWaker> for Waker {
+    #[inline]
+    fn from(local_waker: LocalWaker) -> Self {
+        let inner = local_waker.inner;
+        mem::forget(local_waker);
+        Waker { inner }
+    }
+}
+
+impl Clone for LocalWaker {
+    #[inline]
+    fn clone(&self) -> Self {
+        let waker = unsafe { self.inner.as_ref().clone_raw() };
+        let inner = waker.inner;
+        mem::forget(waker);
+        LocalWaker { inner }
+    }
+}
+
+impl fmt::Debug for LocalWaker {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Waker")
+            .finish()
+    }
+}
+
+impl Drop for LocalWaker {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.inner.as_ref().drop_raw()
+        }
+    }
+}
+
+/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`.
+///
+/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is
+/// most often essentially just `Arc<dyn Wake>`. However, in some contexts
+/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some
+/// custom memory management strategy. This trait is designed to allow for such
+/// customization.
+///
+/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for
+/// `Arc<T>` where `T: Wake`.
+pub unsafe trait UnsafeWake: Send + Sync {
+    /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`.
+    ///
+    /// This function will create a new uniquely owned handle that under the
+    /// hood references the same notification instance. In other words calls
+    /// to `wake` on the returned handle should be equivalent to calls to
+    /// `wake` on this handle.
+    ///
+    /// # Unsafety
+    ///
+    /// This function is unsafe to call because it's asserting the `UnsafeWake`
+    /// value is in a consistent state, i.e. hasn't been dropped.
+    unsafe fn clone_raw(&self) -> Waker;
+
+    /// Drops this instance of `UnsafeWake`, deallocating resources
+    /// associated with it.
+    ///
+    /// FIXME(cramertj)
+    /// This method is intended to have a signature such as:
+    ///
+    /// ```ignore (not-a-doctest)
+    /// fn drop_raw(self: *mut Self);
+    /// ```
+    ///
+    /// Unfortunately in Rust today that signature is not object safe.
+    /// Nevertheless it's recommended to implement this function *as if* that
+    /// were its signature. As such it is not safe to call on an invalid
+    /// pointer, nor is the validity of the pointer guaranteed after this
+    /// function returns.
+    ///
+    /// # Unsafety
+    ///
+    /// This function is unsafe to call because it's asserting the `UnsafeWake`
+    /// value is in a consistent state, i.e. hasn't been dropped.
+    unsafe fn drop_raw(&self);
+
+    /// 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.
+    ///
+    /// # Panics
+    ///
+    /// Implementations should avoid panicking, but clients should also be prepared
+    /// for panics.
+    ///
+    /// # Unsafety
+    ///
+    /// This function is unsafe to call because it's asserting the `UnsafeWake`
+    /// value is in a consistent state, i.e. hasn't been dropped.
+    unsafe fn wake(&self);
+
+    /// Indicates that the associated task is ready to make progress and should
+    /// be `poll`ed. This function is the same as `wake`, but can only be called
+    /// from the thread that this `UnsafeWake` is "local" to. This allows for
+    /// implementors to provide specialized wakeup behavior specific to the current
+    /// thread. This function is called by `LocalWaker::wake`.
+    ///
+    /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place
+    /// the associated task onto this queue.
+    ///
+    /// # Panics
+    ///
+    /// Implementations should avoid panicking, but clients should also be prepared
+    /// for panics.
+    ///
+    /// # Unsafety
+    ///
+    /// This function is unsafe to call because it's asserting the `UnsafeWake`
+    /// value is in a consistent state, i.e. hasn't been dropped, and that the
+    /// `UnsafeWake` hasn't moved from the thread on which it was created.
+    unsafe fn wake_local(&self) {
+        self.wake()
+    }
+}