use core::time::Duration;
use crate::{
runtime::service::reclaim::quiesce_irq_wait,
sync::{
WaitQueue,
irq::{IrqRegisterResult, IrqWaitCell, IrqWaitRegistration},
},
thread::{
TaskError, ThreadWakeHandle,
current::park::{CurrentParkStart, begin_current_park},
},
};
#[derive(Debug)]
pub struct IrqWorkerWaiter {
registration: IrqWaitRegistration,
}
impl IrqWorkerWaiter {
pub fn new(wake_owner: ThreadWakeHandle) -> Self {
Self {
registration: IrqWaitRegistration::new(wake_owner),
}
}
pub fn wait(&self, event: &IrqWaitCell) -> Result<(), TaskError> {
match event.register(&self.registration) {
IrqRegisterResult::Occupied => Err(TaskError::InvalidConfiguration),
IrqRegisterResult::ConsumedPending => Ok(()),
IrqRegisterResult::Registered(token)
| IrqRegisterResult::NotificationInFlight(token) => loop {
if !token.is_attached() {
return quiesce_irq_wait(token);
}
match begin_current_park()? {
CurrentParkStart::Notified => {}
CurrentParkStart::Prepared(park) => {
let _resume = park.commit()?;
}
}
},
}
}
pub fn wait_timeout(&self, event: &IrqWaitCell, timeout: Duration) -> Result<bool, TaskError> {
match event.register(&self.registration) {
IrqRegisterResult::Occupied => Err(TaskError::InvalidConfiguration),
IrqRegisterResult::ConsumedPending => Ok(false),
IrqRegisterResult::Registered(token)
| IrqRegisterResult::NotificationInFlight(token) => {
let park = WaitQueue::new();
let timed_out = park.wait_timeout_until(timeout, || !token.is_attached());
quiesce_irq_wait(token)?;
Ok(timed_out)
}
}
}
}