-
Notifications
You must be signed in to change notification settings - Fork 13.4k
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
Changes from 1 commit
1f9aa13
433e6b3
c055fef
b39ea1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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::<SpawnLocalObjError, SpawnObjError>(self) | ||
} | ||
} | ||
|
||
impl From<SpawnObjError> for SpawnLocalObjError { | ||
fn from(error: SpawnObjError) -> SpawnLocalObjError { | ||
unsafe { | ||
// Safety: Both structs have the same memory layout | ||
mem::transmute::<SpawnObjError, SpawnLocalObjError>(error) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will it have the same performance? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup. |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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: UnsafeTask>(t: T) -> TaskObj { | ||
pub fn new<T: UnsafeTask + Send>(t: T) -> TaskObj { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than repeating all the logic between There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current way was inspired by the way it is done for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok good point. Anyhow I think the current waker code is good. At closer inspection it really shows that a lot of considerations went into it. |
||
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<Future<Output = ()>>`. | ||
/// 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: UnsafeTask>(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::<LocalTaskObj, TaskObj>(self) | ||
} | ||
} | ||
|
||
impl fmt::Debug for LocalTaskObj { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
f.debug_struct("LocalTaskObj") | ||
.finish() | ||
} | ||
} | ||
|
||
impl From<TaskObj> for LocalTaskObj { | ||
fn from(task: TaskObj) -> LocalTaskObj { | ||
unsafe { | ||
// Safety: Both structs have the same memory layout | ||
mem::transmute::<TaskObj, LocalTaskObj>(task) | ||
} | ||
} | ||
} | ||
|
||
impl Future for LocalTaskObj { | ||
type Output = (); | ||
|
||
#[inline] | ||
fn poll(self: PinMut<Self>, 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 (); | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this for? This seems like a pretty big footgun.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/rust-lang-nursery/futures-rs/pull/1046/files#diff-9c6376c5ce46d9e39358812a3269ab6bR259
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need anything
unsafe
to implement that. You can implementspawn_obj
by inlining the body ofspawn_local_obj
and usinginto
only ifupgrade
succeeds.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean copy paste?