use core::{fmt, future::Future, marker::PhantomData, mem, ptr::NonNull};
#[cfg(feature = "debugging")]
use crate::task::debugging::TaskDebugger;
use crate::{
dbg_context,
task::{header::Header, raw::RawTask, state::*, JoinHandle},
};
use std::sync::atomic::Ordering;
pub(crate) fn spawn_local<F, R, S>(
executor_id: usize,
future: F,
schedule: S,
latency_matters: bool,
) -> (Task, JoinHandle<R>)
where
F: Future<Output = R>,
S: Fn(Task),
{
let raw_task = if mem::size_of::<F>() >= 2048 {
let future = alloc::boxed::Box::pin(future);
RawTask::<_, R, S>::allocate(future, schedule, executor_id, latency_matters)
} else {
RawTask::<_, R, S>::allocate(future, schedule, executor_id, latency_matters)
};
let task = Task { raw_task };
let handle = JoinHandle {
raw_task,
_marker: PhantomData,
};
(task, handle)
}
pub struct Task {
pub(crate) raw_task: NonNull<()>,
}
impl Task {
pub(crate) fn schedule(self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
mem::forget(self);
unsafe {
((*header).vtable.schedule)(ptr);
}
}
pub(crate) fn run(self) -> bool {
let ptr = self.raw_task.as_ptr();
dbg_context!(ptr, "run", {
let header = ptr as *const Header;
mem::forget(self);
#[cfg(feature = "debugging")]
TaskDebugger::set_current_task(ptr);
unsafe { ((*header).vtable.run)(ptr) }
})
}
pub(crate) fn run_right_away(self) -> bool {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
mem::forget(self);
unsafe {
let refs = (*header).references.fetch_add(1, Ordering::Relaxed);
assert_ne!(refs, i16::max_value());
((*header).vtable.run)(ptr)
}
}
}
impl Drop for Task {
fn drop(&mut self) {
let ptr = self.raw_task.as_ptr();
let header = ptr as *mut Header;
unsafe {
(*header).cancel();
((*header).vtable.drop_future)(ptr);
(*header).state &= !SCHEDULED;
(*header).notify(None);
((*header).vtable.drop_task)(ptr);
}
}
}
impl fmt::Debug for Task {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ptr = self.raw_task.as_ptr();
let header = ptr as *const Header;
f.debug_struct("Task")
.field("header", unsafe { &(*header) })
.finish()
}
}