use core::{fmt, task::Waker};
#[cfg(feature = "debugging")]
use std::cell::Cell;
use std::sync::{
atomic::{AtomicI16, Ordering},
Arc,
};
use crate::{
sys::SleepNotifier,
task::{raw::TaskVTable, state::*, utils::abort_on_panic},
};
pub(crate) struct Header {
pub(crate) notifier: Arc<SleepNotifier>,
pub(crate) state: u8,
pub(crate) latency_matters: bool,
pub(crate) references: AtomicI16,
pub(crate) awaiter: Option<Waker>,
pub(crate) vtable: &'static TaskVTable,
#[cfg(feature = "debugging")]
pub(crate) debugging: Cell<bool>,
}
impl Header {
pub(crate) fn cancel(&mut self) {
if self.state & (COMPLETED | CLOSED) != 0 {
return;
}
self.state |= CLOSED;
}
#[inline]
pub(crate) fn notify(&mut self, current: Option<&Waker>) {
let waker = self.awaiter.take();
if let Some(w) = waker {
abort_on_panic(|| match current {
None => w.wake(),
Some(c) if !w.will_wake(c) => w.wake(),
Some(_) => {}
});
}
}
#[inline]
pub(crate) fn register(&mut self, waker: &Waker) {
abort_on_panic(|| self.awaiter = Some(waker.clone()));
}
#[cfg(feature = "debugging")]
pub(crate) fn to_compact_string(&self) -> String {
let state = self.state;
macro_rules! test {
($flag:tt) => {
if state & $flag != 0 {
stringify!($flag)
} else {
""
}
};
}
format!(
"thread:{}|{:>9}|{:>7}|{:>9}|{:>6}|{:>6}|refs:{}",
self.notifier.id(),
test!(SCHEDULED),
test!(RUNNING),
test!(COMPLETED),
test!(CLOSED),
test!(HANDLE),
self.references.load(Ordering::Relaxed)
)
}
}
impl fmt::Debug for Header {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let state = self.state;
let refcount = self.references.load(Ordering::Relaxed);
f.debug_struct("Header")
.field("ptr", &(self as *const Self))
.field(
"current_thread_id",
&crate::executor::executor_id().unwrap_or(usize::MAX),
)
.field("thread_id", &self.notifier.id())
.field("scheduled", &(state & SCHEDULED != 0))
.field("running", &(state & RUNNING != 0))
.field("completed", &(state & COMPLETED != 0))
.field("closed", &(state & CLOSED != 0))
.field("handle", &(state & HANDLE != 0))
.field("refcount", &refcount)
.finish()
}
}