use super::{ActiveWorker, Attr, RawTask, TaskRef, WaitContext, Worker};
use crate::event::{Event, Scheduler, Timer};
use crate::Result;
use core::future::Future;
use core::ptr::NonNull;
use core::task::{Context, Waker};
use core::time::Duration;
use hioff::{container_of, container_of_mut};
pub trait TaskContext {
fn set_affinity(&mut self);
fn aborted(&mut self) -> bool;
fn set_aborted(&mut self, aborted: bool);
fn exit(&mut self);
fn yield_now(&mut self);
}
#[allow(dead_code)]
pub(crate) trait RawTaskContext: TaskContext {
fn worker_id(&mut self) -> u16;
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 ();
fn exited(&mut self) -> bool;
fn cache(&mut self, task: TaskRef);
fn spawn<T>(&mut self, future: T, attr: &Attr) -> Result<TaskRef>
where
T: Future + Send + 'static,
T::Output: Send + 'static;
fn spawn_local<T>(&mut self, future: T, attr: &Attr) -> Result<TaskRef>
where
T: Future + 'static,
T::Output: 'static;
}
pub(crate) struct TaskWaker<'a> {
waker: Waker,
task: NonNull<RawTask>,
worker: &'a mut ActiveWorker,
aborted: bool,
exited: bool,
}
impl<'a> TaskWaker<'a> {
pub(crate) fn new(task: &mut RawTask, worker: &'a mut ActiveWorker) -> Self {
worker.set_current_task(Some(NonNull::from(&*task)));
Self {
waker: task.task_waker(),
task: NonNull::from(task),
worker,
aborted: false,
exited: false,
}
}
fn from_ctx_mut(ctx: &mut Context<'a>) -> &'a mut Self {
unsafe { container_of_mut!(ctx.waker(), Self, waker) }
}
fn from_ctx(ctx: &Context<'a>) -> &'a Self {
unsafe { container_of!(ctx.waker(), Self, waker) }
}
pub(crate) fn waker(&self) -> &Waker {
&self.waker
}
}
impl Drop for TaskWaker<'_> {
fn drop(&mut self) {
self.worker.set_current_task(None);
}
}
impl RawTaskContext for Context<'_> {
fn task(&mut self) -> &mut RawTask {
let this = TaskWaker::from_ctx_mut(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 id = self.worker_id();
self.task().status.freeze_local(id);
}
fn set_private(&mut self, data: *const ()) {
self.task().private = data;
}
fn get_private(&mut self) -> *const () {
self.task().private
}
fn exited(&mut self) -> bool {
let this = TaskWaker::from_ctx_mut(self);
this.exited
}
fn worker_id(&mut self) -> u16 {
let this = TaskWaker::from_ctx_mut(self);
this.worker.worker_id()
}
fn cache(&mut self, task: TaskRef) {
let this = TaskWaker::from_ctx_mut(self);
task.cache(this.worker);
}
fn spawn<T>(&mut self, future: T, attr: &Attr) -> Result<TaskRef>
where
T: Future + Send + 'static,
T::Output: Send + 'static,
{
let this = TaskWaker::from_ctx_mut(self);
this.worker.spawn(future, attr)
}
fn spawn_local<T>(&mut self, future: T, attr: &Attr) -> Result<TaskRef>
where
T: Future + 'static,
T::Output: 'static,
{
let this = TaskWaker::from_ctx_mut(self);
this.worker.spawn_local(future, attr)
}
}
impl TaskContext for Context<'_> {
fn exit(&mut self) {
let this = TaskWaker::from_ctx_mut(self);
this.exited = true;
}
fn set_aborted(&mut self, aborted: bool) {
let this = TaskWaker::from_ctx_mut(self);
this.aborted = aborted;
}
fn aborted(&mut self) -> bool {
let this = TaskWaker::from_ctx_mut(self);
this.aborted
}
fn set_affinity(&mut self) {
if self.task().status.get_local().is_none() {
let id = self.worker_id();
self.task().status.set_local(id);
}
}
fn yield_now(&mut self) {
self.task().status.yield_now();
}
}
impl Scheduler for Context<'_> {
unsafe fn add_event(&mut self, e: &Event, priority: i32) {
let this = TaskWaker::from_ctx_mut(self);
this.worker.add_event(e, priority)
}
unsafe fn del_event(&mut self, e: &Event) {
let this = TaskWaker::from_ctx_mut(self);
this.worker.del_event(e)
}
unsafe fn add_fd_event(&mut self, e: &Event, events: u32, fd: i32, flags: u16) -> Result<()> {
let this = TaskWaker::from_ctx_mut(self);
this.worker.add_fd_event(e, events, fd, flags)
}
unsafe fn mod_fd_event(&mut self, e: &Event, events: u32, fd: i32, flags: u16) -> Result<()> {
let this = TaskWaker::from_ctx_mut(self);
this.worker.mod_fd_event(e, events, fd, flags)
}
unsafe fn del_fd_event(&mut self, fd: i32) -> Result<()> {
let this = TaskWaker::from_ctx_mut(self);
this.worker.del_fd_event(fd)
}
unsafe fn set_timer(&mut self, t: &Timer, msecs: u32) {
let this = TaskWaker::from_ctx_mut(self);
this.worker.set_timer(t, msecs)
}
unsafe fn del_timer(&mut self, t: &Timer) {
let this = TaskWaker::from_ctx_mut(self);
this.worker.del_timer(t)
}
fn private_data(&self) -> *const () {
let this = TaskWaker::from_ctx(self);
this.worker.private_data()
}
fn set_private_data(&mut self, private: *const ()) {
let this = TaskWaker::from_ctx_mut(self);
this.worker.set_private_data(private);
}
fn stop(&self) {
let this = TaskWaker::from_ctx(self);
this.worker.stop()
}
fn now(&self) -> Duration {
let this = TaskWaker::from_ctx(self);
this.worker.now()
}
}
impl WaitContext for Context<'_> {
fn fd_wait(&mut self, fd: i32, index: usize, events: u32) -> Result<usize> {
let this = TaskWaker::from_ctx_mut(self);
let task = self.task();
let old_size = task.fdset.fd_capacity();
let index = task.fdset.fd_wait(
fd,
index,
events,
&task.event,
this.worker,
)?;
if old_size == 0 {
task.status.inc_ref();
self.freeze_local();
}
Ok(index)
}
fn fd_awaked(&mut self, index: usize, events: u32) -> Option<u32> {
let task = self.task();
task.fdset.fd_awaked(index, events)
}
fn fd_abort(&mut self, index: usize) {
let task = self.task();
task.fdset.fd_abort(index)
}
fn fd_del(&mut self, fd: i32, index: usize) {
let this = TaskWaker::from_ctx_mut(self);
let task = self.task();
task.fdset.fd_del(fd, index, this.worker);
}
}