blob: 15578bbba5c1cc695f6aac3642be2e49b21d0c35 [file] [log] [blame]
// Copyright 2024 The percore Authors.
// This project is dual-licensed under Apache 2.0 and MIT terms.
// See LICENSE-APACHE and LICENSE-MIT for details.
#[cfg(target_arch = "aarch64")]
mod aarch64;
#[cfg(target_arch = "aarch64")]
use aarch64::{mask, restore};
use core::marker::PhantomData;
/// Runs the given function with exceptions masked.
///
/// Only IRQs, FIQs and SErrors can be masked. Synchronous exceptions cannot be masked and so may
/// still occur.
#[cfg(target_arch = "aarch64")]
pub fn exception_free<T>(f: impl FnOnce(ExceptionFree<'_>) -> T) -> T {
// Mask all exceptions and save previous mask state.
let prev = mask();
// SAFETY: We just masked exceptions.
let token = unsafe { ExceptionFree::new() };
let result = f(token);
// SAFETY: `token` has been dropped by now, as its lifetime prevents `f` from storing it.
unsafe {
// Restore previous exception mask state.
restore(prev);
}
result
}
/// A token proving that exceptions are currently masked.
///
/// Note that synchronous exceptions cannot be masked and so may still occur.
#[derive(Clone, Copy, Debug)]
pub struct ExceptionFree<'cs> {
_private: PhantomData<&'cs ()>,
}
impl<'cs> ExceptionFree<'cs> {
/// Constructs a new instance of `ExceptionFree`, promising that exceptions will remain masked
/// for at least its lifetime.
///
/// This usually should not be called directly; instead use [`exception_free`].
///
/// # Safety
///
/// `ExceptionFree` must only be constructed while exceptions are masked, and they must not be
/// unmasked until after it is dropped.
pub unsafe fn new() -> Self {
Self {
_private: PhantomData,
}
}
}