use super::{RawTask, TaskRef, Worker};
use crate::event::Scheduler;
use core::ptr::NonNull;
use core::task::{Context, Waker};
use hioff::container_of_mut;
pub trait TaskContext {
fn sched(&mut self) -> &mut Scheduler;
fn set_affinity(&mut self);
fn aborted(&mut self) -> bool;
fn set_aborted(&mut self, aborted: bool);
fn exit(&mut self);
}
#[allow(dead_code)]
pub(crate) trait RawTaskContext: TaskContext {
fn task(&mut self) -> &mut RawTask;
fn task_ref(&mut self) -> TaskRef;
fn freeze_local(&mut self);
fn unfreeze_local(&mut self);
fn set_private(&mut self, data: *const ());
fn get_private(&mut self) -> *const ();
}
pub(crate) struct TaskWaker<'a> {
waker: Waker,
task: NonNull<RawTask>,
sched: &'a mut Scheduler,
aborted: bool,
}
impl<'a> TaskWaker<'a> {
pub(crate) fn new(task: &mut RawTask, sched: &'a mut Scheduler) -> Self {
let worker = unsafe { Worker::from_sched(sched) };
worker.set_current_task(Some(NonNull::from(&*task)));
Self {
waker: task.task_waker(),
task: NonNull::from(task),
sched,
aborted: false,
}
}
pub(crate) fn from_ctx(ctx: &mut Context<'a>) -> &'a mut Self {
unsafe { container_of_mut!(ctx.waker(), Self, waker) }
}
pub(crate) fn waker(&self) -> &Waker {
&self.waker
}
}
impl Drop for TaskWaker<'_> {
fn drop(&mut self) {
let worker = unsafe { Worker::from_sched(self.sched) };
worker.set_current_task(None);
}
}
impl RawTaskContext for Context<'_> {
fn task(&mut self) -> &mut RawTask {
let this = TaskWaker::from_ctx(self);
unsafe { this.task.as_mut() }
}
fn task_ref(&mut self) -> TaskRef {
self.task().task_ref()
}
fn unfreeze_local(&mut self) {
self.task().status.unfreeze_local();
}
fn freeze_local(&mut self) {
let worker = unsafe { Worker::from_sched(self.sched()) };
self.task().status.freeze_local(worker.worker_id());
}
fn set_private(&mut self, data: *const ()) {
self.task().private = data;
}
fn get_private(&mut self) -> *const () {
self.task().private
}
}
impl TaskContext for Context<'_> {
fn exit(&mut self) {
let this = TaskWaker::from_ctx(self);
let task = unsafe { this.task.as_mut() };
task.exit();
}
fn set_aborted(&mut self, aborted: bool) {
let this = TaskWaker::from_ctx(self);
this.aborted = aborted;
}
fn aborted(&mut self) -> bool {
let this = TaskWaker::from_ctx(self);
this.aborted
}
fn sched(&mut self) -> &mut Scheduler {
let this = TaskWaker::from_ctx(self);
this.sched
}
fn set_affinity(&mut self) {
if self.task().status.get_local().is_none() {
let worker = unsafe { Worker::from_sched(self.sched()) };
self.task().status.set_local(worker.worker_id());
}
}
}