#[ax_crate_interface::def_interface]
pub trait RuntimePreemption {
fn enter() -> usize;
fn exit(token: usize);
fn exit_from_irq_return(token: usize);
fn depth() -> usize;
fn enter_scheduler_frame();
fn transfer_scheduler_frame();
fn finish_scheduler_frame(result: SchedulerFrameResult);
fn finish_initial_context_switch();
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SchedulerFrameResult {
Stayed,
Resumed,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum SchedulerFrameOwnership {
Active,
Transferred,
}
pub(crate) struct SchedulerFrame {
ownership: SchedulerFrameOwnership,
}
impl SchedulerFrame {
pub(crate) fn enter() -> Self {
enter_scheduler_frame();
Self {
ownership: SchedulerFrameOwnership::Active,
}
}
pub(crate) fn transfer(&mut self) {
assert_eq!(
self.ownership,
SchedulerFrameOwnership::Active,
"scheduler frame can be transferred only once"
);
transfer_scheduler_frame();
self.ownership = SchedulerFrameOwnership::Transferred;
}
pub(crate) fn finish(self, result: SchedulerFrameResult) {
let expected = match result {
SchedulerFrameResult::Stayed => SchedulerFrameOwnership::Active,
SchedulerFrameResult::Resumed => SchedulerFrameOwnership::Transferred,
};
assert_eq!(
self.ownership, expected,
"scheduler return does not match task-layer frame ownership"
);
finish_scheduler_frame(result);
}
}
#[inline(always)]
#[cfg(feature = "preempt")]
pub(crate) fn enter() -> usize {
ax_crate_interface::call_interface!(RuntimePreemption::enter)
}
#[inline(always)]
#[cfg(feature = "preempt")]
pub(crate) fn exit(token: usize) {
ax_crate_interface::call_interface!(RuntimePreemption::exit, token)
}
#[inline(always)]
#[cfg(feature = "preempt")]
pub(crate) fn exit_from_irq_return(token: usize) {
ax_crate_interface::call_interface!(RuntimePreemption::exit_from_irq_return, token)
}
#[inline(always)]
#[cfg(all(feature = "preempt", not(feature = "host-test")))]
pub(crate) fn depth() -> usize {
ax_crate_interface::call_interface!(RuntimePreemption::depth)
}
#[inline(always)]
pub(crate) fn enter_scheduler_frame() {
#[cfg(all(feature = "preempt", not(feature = "host-test")))]
ax_crate_interface::call_interface!(RuntimePreemption::enter_scheduler_frame);
}
#[inline(always)]
pub(crate) fn transfer_scheduler_frame() {
#[cfg(all(feature = "preempt", not(feature = "host-test")))]
ax_crate_interface::call_interface!(RuntimePreemption::transfer_scheduler_frame);
}
#[inline(always)]
pub(crate) fn finish_scheduler_frame(result: SchedulerFrameResult) {
#[cfg(all(feature = "preempt", not(feature = "host-test")))]
ax_crate_interface::call_interface!(RuntimePreemption::finish_scheduler_frame, result);
#[cfg(any(not(feature = "preempt"), feature = "host-test"))]
let _ = result;
}
#[inline(always)]
pub(crate) fn finish_initial_context_switch() {
#[cfg(all(feature = "preempt", not(feature = "host-test")))]
ax_crate_interface::call_interface!(RuntimePreemption::finish_initial_context_switch);
#[cfg(all(feature = "preempt", feature = "host-test"))]
crate::sync::finish_initial_host_context_switch();
}