use alloc::sync::Arc;
use ax_hal::context::InstalledAddressSpace;
use super::TaskError;
#[derive(Debug)]
pub struct AddressSpaceSwitchProof {
cpu: usize,
}
impl AddressSpaceSwitchProof {
#[cfg(feature = "uspace")]
pub(super) const fn new(cpu: usize) -> Self {
Self { cpu }
}
pub const fn cpu(&self) -> usize {
self.cpu
}
}
pub trait SchedulerAddressSpaceOwner: Send + Sync {
fn release_after_root_switch(self: Arc<Self>, proof: AddressSpaceSwitchProof);
fn cancel_before_install(self: Arc<Self>, cpu: usize);
fn abandon(self: Arc<Self>, cpu: usize);
}
pub unsafe trait UserAddressSpaceOwner: Send + Sync {
fn prepare_activation(&self, cpu: usize) -> Result<SchedulerAddressSpaceActivation, TaskError>;
fn detach_from_task(&self);
}
pub struct SchedulerAddressSpaceActivation {
installed: InstalledAddressSpace,
cpu: usize,
owner: Option<Arc<dyn SchedulerAddressSpaceOwner>>,
committed: bool,
}
impl SchedulerAddressSpaceActivation {
pub fn new(
installed: InstalledAddressSpace,
cpu: usize,
owner: Arc<dyn SchedulerAddressSpaceOwner>,
) -> Self {
Self {
installed,
cpu,
owner: Some(owner),
committed: false,
}
}
pub const fn installed(&self) -> InstalledAddressSpace {
self.installed
}
#[cfg(feature = "uspace")]
pub(super) fn commit(&mut self, cpu: usize) {
assert_eq!(self.cpu, cpu);
assert!(!self.committed);
self.committed = true;
}
#[cfg(feature = "uspace")]
pub(super) fn release(mut self, proof: AddressSpaceSwitchProof) {
assert_eq!(self.cpu, proof.cpu());
assert!(self.committed);
self.owner
.take()
.expect("activation is consumed once")
.release_after_root_switch(proof);
}
}
impl Drop for SchedulerAddressSpaceActivation {
fn drop(&mut self) {
if let Some(owner) = self.owner.take() {
if self.committed {
owner.abandon(self.cpu);
} else {
owner.cancel_before_install(self.cpu);
}
}
}
}