use core::marker::PhantomData;
use crate::runtime::{
PreemptGuardSource,
cpu::{LocalIrqState, PreemptGuardToken},
enter_preempt_guard, task_runtime,
};
pub(crate) trait ContextBackend {
type PreemptState: Copy;
type IrqState: Copy;
fn preempt_enter(&self) -> Self::PreemptState;
fn preempt_exit(&self, state: Self::PreemptState);
fn preempt_exit_irq_return(&self, state: Self::PreemptState);
fn irq_save_and_disable(&self) -> Self::IrqState;
fn irq_restore(&self, state: Self::IrqState);
}
pub(crate) struct TaskRuntimeContext;
impl ContextBackend for TaskRuntimeContext {
type PreemptState = PreemptGuardToken;
type IrqState = LocalIrqState;
fn preempt_enter(&self) -> Self::PreemptState {
enter_preempt_guard(PreemptGuardSource::SyncContext)
}
fn preempt_exit(&self, state: Self::PreemptState) {
if state.is_none() {
return;
}
unsafe { task_runtime::preempt_guard_exit(state) };
}
fn preempt_exit_irq_return(&self, state: Self::PreemptState) {
if state.is_none() {
return;
}
unsafe { task_runtime::preempt_guard_exit_irq_return(state) };
}
fn irq_save_and_disable(&self) -> Self::IrqState {
task_runtime::local_irq_save_and_disable()
}
fn irq_restore(&self, state: Self::IrqState) {
unsafe { task_runtime::local_irq_restore(state) };
}
}
struct PendingPreempt<'backend, B: ContextBackend> {
backend: &'backend B,
state: Option<B::PreemptState>,
}
impl<'backend, B: ContextBackend> PendingPreempt<'backend, B> {
fn acquire(backend: &'backend B) -> Self {
Self {
backend,
state: Some(backend.preempt_enter()),
}
}
fn into_state(mut self) -> B::PreemptState {
self.state
.take()
.expect("pending preemption state must be owned")
}
}
impl<B: ContextBackend> Drop for PendingPreempt<'_, B> {
fn drop(&mut self) {
if let Some(state) = self.state.take() {
self.backend.preempt_exit(state);
}
}
}
pub(crate) fn enter_preempt_irqsave<B: ContextBackend>(
backend: &B,
) -> (B::PreemptState, B::IrqState) {
let preempt = PendingPreempt::acquire(backend);
let irq = backend.irq_save_and_disable();
(preempt.into_state(), irq)
}
pub(crate) fn exit_preempt_irqsave<B: ContextBackend>(
(preempt, irq): (B::PreemptState, B::IrqState),
backend: &B,
) {
backend.irq_restore(irq);
backend.preempt_exit(preempt);
}
pub trait GuardState {
type State: Copy;
fn acquire() -> Self::State;
fn release(state: Self::State);
#[cfg(feature = "lockdep")]
fn lockdep_enabled() -> bool {
false
}
}
pub struct RawState;
pub struct PreemptState;
pub struct IrqSaveState;
pub struct PreemptIrqSaveState;
impl GuardState for RawState {
type State = ();
#[inline(always)]
fn acquire() -> Self::State {}
#[inline(always)]
fn release(_state: Self::State) {}
}
impl GuardState for PreemptState {
type State = PreemptGuardToken;
#[inline(always)]
fn acquire() -> Self::State {
TaskRuntimeContext.preempt_enter()
}
#[inline(always)]
fn release(state: Self::State) {
TaskRuntimeContext.preempt_exit(state);
}
#[cfg(feature = "lockdep")]
fn lockdep_enabled() -> bool {
true
}
}
impl GuardState for IrqSaveState {
type State = LocalIrqState;
#[inline(always)]
fn acquire() -> Self::State {
TaskRuntimeContext.irq_save_and_disable()
}
#[inline(always)]
fn release(state: Self::State) {
TaskRuntimeContext.irq_restore(state);
}
}
impl GuardState for PreemptIrqSaveState {
type State = (PreemptGuardToken, LocalIrqState);
#[inline(always)]
fn acquire() -> Self::State {
enter_preempt_irqsave(&TaskRuntimeContext)
}
#[inline(always)]
fn release((preempt, irq): Self::State) {
exit_preempt_irqsave((preempt, irq), &TaskRuntimeContext);
}
#[cfg(feature = "lockdep")]
fn lockdep_enabled() -> bool {
true
}
}
pub struct PreemptGuard {
state: <PreemptState as GuardState>::State,
_not_send: PhantomData<*mut ()>,
}
impl PreemptGuard {
pub fn new() -> Self {
Self {
state: PreemptState::acquire(),
_not_send: PhantomData,
}
}
}
impl Default for PreemptGuard {
fn default() -> Self {
Self::new()
}
}
impl Drop for PreemptGuard {
fn drop(&mut self) {
PreemptState::release(self.state);
}
}
pub struct IrqSaveGuard {
state: <IrqSaveState as GuardState>::State,
_not_send: PhantomData<*mut ()>,
}
impl IrqSaveGuard {
pub fn new() -> Self {
Self {
state: IrqSaveState::acquire(),
_not_send: PhantomData,
}
}
pub fn disable_preempt_for_irq_return(&mut self) -> IrqReturnPreemptGuard<'_> {
IrqReturnPreemptGuard {
token: enter_preempt_guard(PreemptGuardSource::IrqReturn),
_irq_guard: PhantomData,
_not_send: PhantomData,
}
}
}
impl Default for IrqSaveGuard {
fn default() -> Self {
Self::new()
}
}
impl Drop for IrqSaveGuard {
fn drop(&mut self) {
IrqSaveState::release(self.state);
}
}
#[must_use = "dropping the guard completes the IRQ-return preemption exit"]
pub struct IrqReturnPreemptGuard<'irq> {
token: PreemptGuardToken,
_irq_guard: PhantomData<&'irq mut IrqSaveGuard>,
_not_send: PhantomData<*mut ()>,
}
impl Drop for IrqReturnPreemptGuard<'_> {
fn drop(&mut self) {
TaskRuntimeContext.preempt_exit_irq_return(self.token);
}
}
#[inline(always)]
pub fn hardirq_enter() {
task_runtime::hardirq_enter();
}
#[inline(always)]
pub fn hardirq_exit() {
task_runtime::hardirq_exit();
}
pub struct PreemptIrqSaveGuard {
state: <PreemptIrqSaveState as GuardState>::State,
_not_send: PhantomData<*mut ()>,
}
impl PreemptIrqSaveGuard {
pub fn new() -> Self {
Self {
state: PreemptIrqSaveState::acquire(),
_not_send: PhantomData,
}
}
}
impl Default for PreemptIrqSaveGuard {
fn default() -> Self {
Self::new()
}
}
impl Drop for PreemptIrqSaveGuard {
fn drop(&mut self) {
PreemptIrqSaveState::release(self.state);
}
}