diff options
| author | Josef Reinhard Brandl <mail@josefbrandl.de> | 2018-06-26 16:40:42 +0200 |
|---|---|---|
| committer | Josef Reinhard Brandl <mail@josefbrandl.de> | 2018-06-26 16:40:42 +0200 |
| commit | 1f9aa1332fc9f0194bac1761ef04e54564e26fc8 (patch) | |
| tree | 50740ba0d7a3ea05d100ab2b52df077e26b78a68 | |
| parent | 764232cb2a8407c72b9fea68835e686240e30ef3 (diff) | |
| download | rust-1f9aa1332fc9f0194bac1761ef04e54564e26fc8.tar.gz rust-1f9aa1332fc9f0194bac1761ef04e54564e26fc8.zip | |
Split libcore/task.rs into submodules
| -rw-r--r-- | src/libcore/task/context.rs | 92 | ||||
| -rw-r--r-- | src/libcore/task/executor.rs | 44 | ||||
| -rw-r--r-- | src/libcore/task/mod.rs | 33 | ||||
| -rw-r--r-- | src/libcore/task/poll.rs | 83 | ||||
| -rw-r--r-- | src/libcore/task/spawn_error.rs | 51 | ||||
| -rw-r--r-- | src/libcore/task/task.rs | 98 | ||||
| -rw-r--r-- | src/libcore/task/wake.rs (renamed from src/libcore/task.rs) | 294 |
7 files changed, 401 insertions, 294 deletions
diff --git a/src/libcore/task/context.rs b/src/libcore/task/context.rs new file mode 100644 index 00000000000..c69d45248a5 --- /dev/null +++ b/src/libcore/task/context.rs @@ -0,0 +1,92 @@ +// 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::{Executor, 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, + executor: &'a mut Executor, +} + +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 `executor`. + #[inline] + pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> { + Context { + local_waker, + executor, + } + } + + /// 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 default executor associated with this task. + /// + /// This method is useful primarily if you want to explicitly handle + /// spawn failures. + #[inline] + pub fn executor(&mut self) -> &mut Executor { + self.executor + } + + /// 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, + executor: self.executor, + } + } + + /// Produce a context like the current one, but using the given executor + /// instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task. + #[inline] + pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> + where E: Executor + { + Context { + local_waker: self.local_waker, + executor: executor, + } + } +} diff --git a/src/libcore/task/executor.rs b/src/libcore/task/executor.rs new file mode 100644 index 00000000000..fcef6d5ffc8 --- /dev/null +++ b/src/libcore/task/executor.rs @@ -0,0 +1,44 @@ +// 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 super::{TaskObj, SpawnObjError, SpawnErrorKind}; + +/// A task executor. +/// +/// A *task* is a `()`-producing async value that runs at the top level, and will +/// be `poll`ed until completion. It's also the unit at which wake-up +/// notifications occur. Executors, such as thread pools, allow tasks to be +/// spawned and are responsible for putting tasks onto ready queues when +/// they are woken up, and polling them when they are ready. +pub trait Executor { + /// Spawn the given task, polling it 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, task: TaskObj) -> Result<(), SpawnObjError>; + + /// Determine 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(()) + } +} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs new file mode 100644 index 00000000000..66ab21d177d --- /dev/null +++ b/src/libcore/task/mod.rs @@ -0,0 +1,33 @@ +// 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 executor; +pub use self::executor::Executor; + +mod poll; +pub use self::poll::Poll; + +mod spawn_error; +pub use self::spawn_error::{SpawnErrorKind, SpawnObjError}; + +mod task; +pub use self::task::{TaskObj, UnsafeTask}; + +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..10c954f0e80 --- /dev/null +++ b/src/libcore/task/poll.rs @@ -0,0 +1,83 @@ +// 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")] + +/// 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` + pub fn is_ready(&self) -> bool { + match *self { + Poll::Ready(_) => true, + Poll::Pending => false, + } + } + + /// Returns whether this is `Poll::Pending` + 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) + } +} diff --git a/src/libcore/task/spawn_error.rs b/src/libcore/task/spawn_error.rs new file mode 100644 index 00000000000..5dd9c5be689 --- /dev/null +++ b/src/libcore/task/spawn_error.rs @@ -0,0 +1,51 @@ +// 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::TaskObj; + +/// 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 task for which spawning was attempted + pub task: TaskObj, +} diff --git a/src/libcore/task/task.rs b/src/libcore/task/task.rs new file mode 100644 index 00000000000..dc4ff314e5b --- /dev/null +++ b/src/libcore/task/task.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 future::Future; +use mem::PinMut; +use super::{Context, Poll}; + +/// A custom trait object for polling tasks, roughly akin to +/// `Box<Future<Output = ()> + Send>`. +pub struct TaskObj { + ptr: *mut (), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, + drop_fn: unsafe fn(*mut ()), +} + +unsafe impl Send for TaskObj {} + +impl TaskObj { + /// Create a `TaskObj` from a custom trait object representation. + #[inline] + pub fn new<T: UnsafeTask>(t: T) -> TaskObj { + TaskObj { + ptr: t.into_raw(), + poll_fn: T::poll, + drop_fn: T::drop, + } + } +} + +impl fmt::Debug for TaskObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TaskObj") + .finish() + } +} + +impl Future for TaskObj { + type Output = (); + + #[inline] + fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<()> { + unsafe { + (self.poll_fn)(self.ptr, cx) + } + } +} + +impl Drop for TaskObj { + fn drop(&mut self) { + unsafe { + (self.drop_fn)(self.ptr) + } + } +} + +/// A custom implementation of a task trait object for `TaskObj`, providing +/// a hand-rolled vtable. +/// +/// This custom representation is typically used only in `no_std` contexts, +/// where the default `Box`-based implementation is not available. +/// +/// The implementor must guarantee that it is safe to call `poll` repeatedly (in +/// a non-concurrent fashion) with the result of `into_raw` until `drop` is +/// called. +pub unsafe trait UnsafeTask: Send + 'static { + /// Convert a owned instance into a (conceptually owned) void pointer. + fn into_raw(self) -> *mut (); + + /// Poll the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to repeatedly call + /// `poll` with the result of `into_raw` until `drop` is called; such calls + /// are not, however, allowed to race with each other or with calls to `drop`. + unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; + + /// Drops the task represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to call this + /// function once per `into_raw` invocation; that call cannot race with + /// other calls to `drop` or `poll`. + unsafe fn drop(task: *mut ()); +} diff --git a/src/libcore/task.rs b/src/libcore/task/wake.rs index 1a6018ffb65..4fd45be56fb 100644 --- a/src/libcore/task.rs +++ b/src/libcore/task/wake.rs @@ -12,82 +12,8 @@ reason = "futures in libcore are unstable", issue = "50547")] -//! Types and Traits for working with asynchronous tasks. - use fmt; use ptr::NonNull; -use future::Future; -use mem::PinMut; - -/// 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` - pub fn is_ready(&self) -> bool { - match *self { - Poll::Ready(_) => true, - Poll::Pending => false, - } - } - - /// Returns whether this is `Poll::Pending` - 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) - } -} /// A `Waker` is a handle for waking up a task by notifying its executor that it /// is ready to be run. @@ -347,223 +273,3 @@ pub unsafe trait UnsafeWake: Send + Sync { self.wake() } } - -/// 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, - executor: &'a mut Executor, -} - -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 `executor`. - #[inline] - pub fn new(local_waker: &'a LocalWaker, executor: &'a mut Executor) -> Context<'a> { - Context { - local_waker, - executor, - } - } - - /// 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 default executor associated with this task. - /// - /// This method is useful primarily if you want to explicitly handle - /// spawn failures. - #[inline] - pub fn executor(&mut self) -> &mut Executor { - self.executor - } - - /// 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, - executor: self.executor, - } - } - - /// Produce a context like the current one, but using the given executor - /// instead. - /// - /// This advanced method is primarily used when building "internal - /// schedulers" within a task. - #[inline] - pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> - where E: Executor - { - Context { - local_waker: self.local_waker, - executor: executor, - } - } -} - -/// A task executor. -/// -/// A *task* is a `()`-producing async value that runs at the top level, and will -/// be `poll`ed until completion. It's also the unit at which wake-up -/// notifications occur. Executors, such as thread pools, allow tasks to be -/// spawned and are responsible for putting tasks onto ready queues when -/// they are woken up, and polling them when they are ready. -pub trait Executor { - /// Spawn the given task, polling it 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, task: TaskObj) -> Result<(), SpawnObjError>; - - /// Determine 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(()) - } -} - -/// A custom trait object for polling tasks, roughly akin to -/// `Box<Future<Output = ()> + Send>`. -pub struct TaskObj { - ptr: *mut (), - poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, - drop_fn: unsafe fn(*mut ()), -} - -impl fmt::Debug for TaskObj { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TaskObj") - .finish() - } -} - -unsafe impl Send for TaskObj {} - -/// A custom implementation of a task trait object for `TaskObj`, providing -/// a hand-rolled vtable. -/// -/// This custom representation is typically used only in `no_std` contexts, -/// where the default `Box`-based implementation is not available. -/// -/// The implementor must guarantee that it is safe to call `poll` repeatedly (in -/// a non-concurrent fashion) with the result of `into_raw` until `drop` is -/// called. -pub unsafe trait UnsafeTask: Send + 'static { - /// Convert a owned instance into a (conceptually owned) void pointer. - fn into_raw(self) -> *mut (); - - /// Poll the task represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to repeatedly call - /// `poll` with the result of `into_raw` until `drop` is called; such calls - /// are not, however, allowed to race with each other or with calls to `drop`. - unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>; - - /// Drops the task represented by the given void pointer. - /// - /// # Safety - /// - /// The trait implementor must guarantee that it is safe to call this - /// function once per `into_raw` invocation; that call cannot race with - /// other calls to `drop` or `poll`. - unsafe fn drop(task: *mut ()); -} - -impl TaskObj { - /// Create a `TaskObj` from a custom trait object representation. - #[inline] - pub fn new<T: UnsafeTask>(t: T) -> TaskObj { - TaskObj { - ptr: t.into_raw(), - poll_fn: T::poll, - drop_fn: T::drop, - } - } -} - -impl Future for TaskObj { - type Output = (); - - #[inline] - fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<()> { - unsafe { - (self.poll_fn)(self.ptr, cx) - } - } -} - -impl Drop for TaskObj { - fn drop(&mut self) { - unsafe { - (self.drop_fn)(self.ptr) - } - } -} - -/// 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 task for which spawning was attempted - pub task: TaskObj, -} |
