use std::{
future::Future,
pin::Pin,
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
Arc, Mutex, Weak,
},
task::{RawWaker, RawWakerVTable, Waker},
};
use crate::task::manager::TaskManager;
static TASK_TAG_NUM: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub struct TaskTag(usize);
pub struct Task {
pub future: Mutex<Option<Pin<Box<dyn Future<Output = ()> + Send + 'static>>>>, pub task_tag: TaskTag, pub manager: Weak<TaskManager>, pub abort: Arc<AtomicBool>, }
impl Task {
const WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
pub fn waker(self: Arc<Self>) -> Waker {
let opaque_ptr = Arc::into_raw(self) as *const ();
let vtable = &Self::WAKER_VTABLE;
unsafe { Waker::from_raw(RawWaker::new(opaque_ptr, vtable)) }
}
pub fn generate_tag() -> TaskTag {
TaskTag(TASK_TAG_NUM.fetch_add(1, Ordering::Relaxed))
}
pub fn has_aborted(&self) -> bool {
self.abort.load(Ordering::SeqCst)
}
}
fn clone(ptr: *const ()) -> RawWaker {
let original: Arc<Task> = unsafe { Arc::from_raw(ptr as _) };
let arc_clone = Arc::clone(&original);
std::mem::forget(original);
RawWaker::new(Arc::into_raw(arc_clone) as *const (), &Task::WAKER_VTABLE)
}
fn drop(ptr: *const ()) {
let _: Arc<Task> = unsafe { Arc::from_raw(ptr as _) };
}
fn wake(ptr: *const ()) {
let arc: Arc<Task> = unsafe { Arc::from_raw(ptr as _) };
let tm = arc.manager.upgrade().unwrap();
tm.register_or_execute_non_blocking_task(arc);
}
fn wake_by_ref(ptr: *const ()) {
let arc: Arc<Task> = unsafe { Arc::from_raw(ptr as _) };
let tm = arc.manager.upgrade().unwrap();
tm.register_or_execute_non_blocking_task(Arc::clone(&arc));
std::mem::forget(arc);
}