Skip to content

Add LocalTaskObj to core::task #51814

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ use core::marker::{Unpin, Unsize};
use core::mem::{self, PinMut};
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
use core::ptr::{self, NonNull, Unique};
use core::task::{Context, Poll, UnsafeTask, TaskObj};
use core::task::{Context, Poll, UnsafeTask, TaskObj, LocalTaskObj};
use core::convert::From;

use raw_vec::RawVec;
Expand Down Expand Up @@ -933,7 +933,7 @@ impl<'a, F: ?Sized + Future> Future for PinBox<F> {
}

#[unstable(feature = "futures_api", issue = "50547")]
unsafe impl<F: Future<Output = ()> + Send + 'static> UnsafeTask for PinBox<F> {
unsafe impl<F: Future<Output = ()> + 'static> UnsafeTask for PinBox<F> {
fn into_raw(self) -> *mut () {
PinBox::into_raw(self) as *mut ()
}
Expand Down Expand Up @@ -962,3 +962,17 @@ impl<F: Future<Output = ()> + Send + 'static> From<Box<F>> for TaskObj {
TaskObj::new(PinBox::from(boxed))
}
}

#[unstable(feature = "futures_api", issue = "50547")]
impl<F: Future<Output = ()> + 'static> From<PinBox<F>> for LocalTaskObj {
fn from(boxed: PinBox<F>) -> Self {
LocalTaskObj::new(boxed)
}
}

#[unstable(feature = "futures_api", issue = "50547")]
impl<F: Future<Output = ()> + 'static> From<Box<F>> for LocalTaskObj {
fn from(boxed: Box<F>) -> Self {
LocalTaskObj::new(PinBox::from(boxed))
}
}
92 changes: 92 additions & 0 deletions src/libcore/task/context.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
}
90 changes: 90 additions & 0 deletions src/libcore/task/executor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// 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, LocalTaskObj};

/// 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(())
}
}

/// 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,
}

/// The result of a failed spawn
#[derive(Debug)]
pub struct SpawnLocalObjError {
/// The kind of error
pub kind: SpawnErrorKind,

/// The task for which spawning was attempted
pub task: LocalTaskObj,
}
32 changes: 32 additions & 0 deletions src/libcore/task/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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, SpawnErrorKind, SpawnObjError, SpawnLocalObjError
};

mod poll;
pub use self::poll::Poll;

mod task;
pub use self::task::{TaskObj, LocalTaskObj, UnsafeTask};

mod wake;
pub use self::wake::{Waker, LocalWaker, UnsafeWake};
83 changes: 83 additions & 0 deletions src/libcore/task/poll.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
Loading