use ax_std::os::arceos::{
task as scheduler,
task::{
sync::irq::{IrqRegisterResult, IrqWaitToken},
thread::TaskError,
},
};
pub(super) fn complete_irq_service_cycle<'cell, P, F>(
registration: IrqRegisterResult<'cell>,
park: P,
fanout: F,
) -> Result<bool, TaskError>
where
P: FnOnce(&IrqWaitToken<'cell>),
F: FnOnce(),
{
match registration {
IrqRegisterResult::ConsumedPending => {
fanout();
Ok(true)
}
IrqRegisterResult::Registered(token) | IrqRegisterResult::NotificationInFlight(token) => {
park(&token);
scheduler::sync::irq::quiesce_irq_wait(token)?;
fanout();
Ok(true)
}
IrqRegisterResult::Occupied => Ok(false),
}
}
#[cfg(all(test, not(axtest)))]
mod tests {
use core::cell::Cell;
use super::*;
#[test]
fn pending_before_register_fans_out_without_parking() {
let step = Cell::new(0);
let completed = complete_irq_service_cycle(
IrqRegisterResult::ConsumedPending,
|_| panic!("a synchronously consumed IRQ must not park"),
|| {
assert_eq!(step.get(), 0);
step.set(1);
},
)
.unwrap();
assert!(completed);
assert_eq!(step.get(), 1);
}
#[test]
fn occupied_registration_does_not_run_callbacks() {
let step = Cell::new(0);
let completed = complete_irq_service_cycle(
IrqRegisterResult::Occupied,
|_| step.set(1),
|| step.set(2),
)
.unwrap();
assert!(!completed);
assert_eq!(step.get(), 0);
}
}