mod core; use self::core::Cell; pub(crate) use self::core::Header; mod error; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::error::JoinError; mod harness; use self::harness::Harness; mod join; #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 pub use self::join::JoinHandle; mod raw; use self::raw::RawTask; mod state; use self::state::State; mod waker; cfg_rt_multi_thread! { mod stack; pub(crate) use self::stack::TransferStack; } use crate::future::Future; use crate::util::linked_list; use std::marker::PhantomData; use std::ptr::NonNull; use std::{fmt, mem}; /// An owned handle to the task, tracked by ref count #[repr(transparent)] pub(crate) struct Task { raw: RawTask, _p: PhantomData, } unsafe impl Send for Task {} unsafe impl Sync for Task {} /// A task was notified #[repr(transparent)] pub(crate) struct Notified(Task); unsafe impl Send for Notified {} unsafe impl Sync for Notified {} /// Task result sent back pub(crate) type Result = std::result::Result; pub(crate) trait Schedule: Sync + Sized + 'static { /// Bind a task to the executor. /// /// Guaranteed to be called from the thread that called `poll` on the task. /// The returned `Schedule` instance is associated with the task and is used /// as `&self` in the other methods on this trait. fn bind(task: Task) -> Self; /// The task has completed work and is ready to be released. The scheduler /// is free to drop it whenever. /// /// If the scheduler can immediately release the task, it should return /// it as part of the function. This enables the task module to batch /// the ref-dec with other options. fn release(&self, task: &Task) -> Option>; /// Schedule the task fn schedule(&self, task: Notified); /// Schedule the task to run in the near future, yielding the thread to /// other tasks. fn yield_now(&self, task: Notified) { self.schedule(task); } } cfg_rt! { /// Create a new task with an associated join handle pub(crate) fn joinable(task: T) -> (Notified, JoinHandle) where T: Future + Send + 'static, S: Schedule, { let raw = RawTask::new::<_, S>(task); let task = Task { raw, _p: PhantomData, }; let join = JoinHandle::new(raw); (Notified(task), join) } } cfg_rt! { /// Create a new `!Send` task with an associated join handle pub(crate) unsafe fn joinable_local(task: T) -> (Notified, JoinHandle) where T: Future + 'static, S: Schedule, { let raw = RawTask::new::<_, S>(task); let task = Task { raw, _p: PhantomData, }; let join = JoinHandle::new(raw); (Notified(task), join) } } impl Task { pub(crate) unsafe fn from_raw(ptr: NonNull
) -> Task { Task { raw: RawTask::from_raw(ptr), _p: PhantomData, } } pub(crate) fn header(&self) -> &Header { self.raw.header() } } cfg_rt_multi_thread! { impl Notified { pub(crate) unsafe fn from_raw(ptr: NonNull
) -> Notified { Notified(Task::from_raw(ptr)) } pub(crate) fn header(&self) -> &Header { self.0.header() } } impl Task { pub(crate) fn into_raw(self) -> NonNull
{ let ret = self.header().into(); mem::forget(self); ret } } impl Notified { pub(crate) fn into_raw(self) -> NonNull
{ self.0.into_raw() } } } impl Task { /// Pre-emptively cancel the task as part of the shutdown process. pub(crate) fn shutdown(&self) { self.raw.shutdown(); } } impl Notified { /// Run the task pub(crate) fn run(self) { self.0.raw.poll(); mem::forget(self); } /// Pre-emptively cancel the task as part of the shutdown process. pub(crate) fn shutdown(self) { self.0.shutdown(); } } impl Drop for Task { fn drop(&mut self) { // Decrement the ref count if self.header().state.ref_dec() { // Deallocate if this is the final ref count self.raw.dealloc(); } } } impl fmt::Debug for Task { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "Task({:p})", self.header()) } } impl fmt::Debug for Notified { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "task::Notified({:p})", self.0.header()) } } /// # Safety /// /// Tasks are pinned unsafe impl linked_list::Link for Task { type Handle = Task; type Target = Header; fn as_raw(handle: &Task) -> NonNull
{ handle.header().into() } unsafe fn from_raw(ptr: NonNull
) -> Task { Task::from_raw(ptr) } unsafe fn pointers(target: NonNull
) -> NonNull> { // Not super great as it avoids some of looms checking... NonNull::from(target.as_ref().owned.with_mut(|ptr| &mut *ptr)) } }