From 433e6b31a75eea5ce45493acc63eae462d740338 Mon Sep 17 00:00:00 2001 From: Josef Reinhard Brandl Date: Tue, 26 Jun 2018 17:06:20 +0200 Subject: [PATCH] Add `LocalTaskObj` --- src/liballoc/boxed.rs | 18 ++++++++- src/libcore/task/mod.rs | 4 +- src/libcore/task/spawn_error.rs | 33 ++++++++++++++- src/libcore/task/task.rs | 71 +++++++++++++++++++++++++++++++-- 4 files changed, 118 insertions(+), 8 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index ea60c7775af5..6a05ef680889 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -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; @@ -933,7 +933,7 @@ impl<'a, F: ?Sized + Future> Future for PinBox { } #[unstable(feature = "futures_api", issue = "50547")] -unsafe impl + Send + 'static> UnsafeTask for PinBox { +unsafe impl + 'static> UnsafeTask for PinBox { fn into_raw(self) -> *mut () { PinBox::into_raw(self) as *mut () } @@ -962,3 +962,17 @@ impl + Send + 'static> From> for TaskObj { TaskObj::new(PinBox::from(boxed)) } } + +#[unstable(feature = "futures_api", issue = "50547")] +impl + 'static> From> for LocalTaskObj { + fn from(boxed: PinBox) -> Self { + LocalTaskObj::new(boxed) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl + 'static> From> for LocalTaskObj { + fn from(boxed: Box) -> Self { + LocalTaskObj::new(PinBox::from(boxed)) + } +} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 66ab21d177d8..36370b6b37c3 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -24,10 +24,10 @@ mod poll; pub use self::poll::Poll; mod spawn_error; -pub use self::spawn_error::{SpawnErrorKind, SpawnObjError}; +pub use self::spawn_error::{SpawnErrorKind, SpawnObjError, SpawnLocalObjError}; mod task; -pub use self::task::{TaskObj, UnsafeTask}; +pub use self::task::{TaskObj, LocalTaskObj, UnsafeTask}; mod wake; pub use self::wake::{Waker, LocalWaker, UnsafeWake}; diff --git a/src/libcore/task/spawn_error.rs b/src/libcore/task/spawn_error.rs index 5dd9c5be6892..57bb9ebeb30d 100644 --- a/src/libcore/task/spawn_error.rs +++ b/src/libcore/task/spawn_error.rs @@ -13,7 +13,8 @@ issue = "50547")] use fmt; -use super::TaskObj; +use mem; +use super::{TaskObj, LocalTaskObj}; /// Provides the reason that an executor was unable to spawn. pub struct SpawnErrorKind { @@ -49,3 +50,33 @@ pub struct SpawnObjError { /// 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, +} + +impl SpawnLocalObjError { + /// Converts the `SpawnLocalObjError` into a `SpawnObjError` + /// To make this operation safe one has to ensure that the `UnsafeTask` + /// instance from which the `LocalTaskObj` stored inside was created + /// actually implements `Send`. + pub unsafe fn as_spawn_obj_error(self) -> SpawnObjError { + // Safety: Both structs have the same memory layout + mem::transmute::(self) + } +} + +impl From for SpawnLocalObjError { + fn from(error: SpawnObjError) -> SpawnLocalObjError { + unsafe { + // Safety: Both structs have the same memory layout + mem::transmute::(error) + } + } +} diff --git a/src/libcore/task/task.rs b/src/libcore/task/task.rs index dc4ff314e5bd..9896d7f5ff22 100644 --- a/src/libcore/task/task.rs +++ b/src/libcore/task/task.rs @@ -14,7 +14,7 @@ use fmt; use future::Future; -use mem::PinMut; +use mem::{self, PinMut}; use super::{Context, Poll}; /// A custom trait object for polling tasks, roughly akin to @@ -30,7 +30,7 @@ unsafe impl Send for TaskObj {} impl TaskObj { /// Create a `TaskObj` from a custom trait object representation. #[inline] - pub fn new(t: T) -> TaskObj { + pub fn new(t: T) -> TaskObj { TaskObj { ptr: t.into_raw(), poll_fn: T::poll, @@ -65,6 +65,71 @@ impl Drop for TaskObj { } } +/// A custom trait object for polling tasks, roughly akin to +/// `Box>`. +/// Contrary to `TaskObj`, `LocalTaskObj` does not have a `Send` bound. +pub struct LocalTaskObj { + ptr: *mut (), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>, + drop_fn: unsafe fn(*mut ()), +} + +impl LocalTaskObj { + /// Create a `LocalTaskObj` from a custom trait object representation. + #[inline] + pub fn new(t: T) -> LocalTaskObj { + LocalTaskObj { + ptr: t.into_raw(), + poll_fn: T::poll, + drop_fn: T::drop, + } + } + + /// Converts the `LocalTaskObj` into a `TaskObj` + /// To make this operation safe one has to ensure that the `UnsafeTask` + /// instance from which this `LocalTaskObj` was created actually implements + /// `Send`. + pub unsafe fn as_task_obj(self) -> TaskObj { + // Safety: Both structs have the same memory layout + mem::transmute::(self) + } +} + +impl fmt::Debug for LocalTaskObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("LocalTaskObj") + .finish() + } +} + +impl From for LocalTaskObj { + fn from(task: TaskObj) -> LocalTaskObj { + unsafe { + // Safety: Both structs have the same memory layout + mem::transmute::(task) + } + } +} + +impl Future for LocalTaskObj { + type Output = (); + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll<()> { + unsafe { + (self.poll_fn)(self.ptr, cx) + } + } +} + +impl Drop for LocalTaskObj { + 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. /// @@ -74,7 +139,7 @@ impl Drop for TaskObj { /// 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 { +pub unsafe trait UnsafeTask: 'static { /// Convert a owned instance into a (conceptually owned) void pointer. fn into_raw(self) -> *mut ();