use core::{
marker::PhantomData,
ops::{Deref, DerefMut},
};
use super::{IrqScope, RawTicketBaton, RawTicketGuard, RawTicketLock};
use crate::runtime::IrqGuardSource;
#[derive(Debug)]
pub(crate) struct IrqTicketLock<T> {
raw: RawTicketLock<T>,
}
pub(crate) struct IrqOwner<'a> {
_guard: PhantomData<&'a mut ()>,
_not_send: PhantomData<*mut ()>,
}
impl<T> IrqTicketLock<T> {
pub(crate) const fn new(value: T) -> Self {
Self {
raw: RawTicketLock::new(value),
}
}
pub(crate) fn lock(&self, source: IrqGuardSource) -> IrqTicketGuard<'_, T> {
let irq = IrqScope::enter_ticket_lock(source);
let raw = self.raw.lock();
IrqTicketGuard {
raw: Some(raw),
irq: Some(irq),
_not_send: PhantomData,
}
}
pub(crate) unsafe fn lock_irq_disabled(&self) -> IrqTicketGuard<'_, T> {
IrqTicketGuard {
raw: Some(self.raw.lock()),
irq: None,
_not_send: PhantomData,
}
}
pub(crate) unsafe fn try_lock_irq_disabled(&self) -> Option<IrqTicketGuard<'_, T>> {
self.raw.try_lock().map(|raw| IrqTicketGuard {
raw: Some(raw),
irq: None,
_not_send: PhantomData,
})
}
pub(crate) fn lock_nested<'a>(&'a self, _owner: &'a IrqOwner<'_>) -> IrqTicketGuard<'a, T> {
IrqTicketGuard {
raw: Some(self.raw.lock()),
irq: None,
_not_send: PhantomData,
}
}
}
pub(crate) struct IrqTicketGuard<'a, T> {
raw: Option<RawTicketGuard<'a, T>>,
irq: Option<IrqScope>,
_not_send: PhantomData<*mut ()>,
}
impl<T> Deref for IrqTicketGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.raw
.as_deref()
.expect("IRQ ticket guard always owns its raw guard")
}
}
impl<T> IrqTicketGuard<'_, T> {
pub(crate) fn split_irq_owner(&mut self) -> (&mut T, IrqOwner<'_>) {
let state = self
.raw
.as_deref_mut()
.expect("IRQ ticket guard always owns its raw guard");
(
state,
IrqOwner {
_guard: PhantomData,
_not_send: PhantomData,
},
)
}
pub(crate) unsafe fn into_raw_baton(mut self) -> RawTicketBaton<T> {
if self.irq.is_some() {
panic!("an irqsave ticket cannot cross a context switch");
}
let raw = self
.raw
.take()
.expect("IRQ ticket guard always owns its raw guard");
unsafe { raw.into_baton() }
}
}
impl<T> DerefMut for IrqTicketGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.raw
.as_deref_mut()
.expect("IRQ ticket guard always owns its raw guard")
}
}
impl<T> Drop for IrqTicketGuard<'_, T> {
fn drop(&mut self) {
drop(self.raw.take());
drop(self.irq.take());
}
}