use ax_lazyinit::OnceLock;
use ax_task::{
sync::irq::{IrqWaitCell, IrqWorkerWaiter},
thread::{TaskError, ThreadId, current::current_thread_handle},
};
pub struct FixedIrqWorkerSignal {
doorbell: IrqWaitCell,
waiter: OnceLock<FixedIrqWorkerWaiter>,
}
impl FixedIrqWorkerSignal {
pub const fn new() -> Self {
Self {
doorbell: IrqWaitCell::new(),
waiter: OnceLock::new(),
}
}
pub fn notify(&self) {
let _result = self.doorbell.notify();
}
pub fn wait(&self) -> Result<(), TaskError> {
let current = current_thread_handle()?;
let waiter = self.waiter.call_once(|| FixedIrqWorkerWaiter {
owner: current.id(),
irq: IrqWorkerWaiter::new(current.wake_handle()),
});
if waiter.owner != current.id() {
return Err(TaskError::InvalidConfiguration);
}
waiter.irq.wait(&self.doorbell)
}
#[cfg(test)]
pub(crate) fn is_pending(&self) -> bool {
self.doorbell.is_pending()
}
}
impl Default for FixedIrqWorkerSignal {
fn default() -> Self {
Self::new()
}
}
struct FixedIrqWorkerWaiter {
owner: ThreadId,
irq: IrqWorkerWaiter,
}