use core::{
cell::UnsafeCell,
mem::MaybeUninit,
panic::Location,
sync::atomic::{AtomicBool, AtomicPtr, AtomicU8, AtomicU32, AtomicU64, AtomicUsize},
};
pub const CONTEXT_RAW: u8 = 0;
pub const CONTEXT_PREEMPT: u8 = 1;
pub const CONTEXT_IRQSAVE: u8 = 2;
pub const CONTEXT_PREEMPT_IRQSAVE: u8 = 3;
pub const LOCK_KIND_SPIN: u8 = 0;
pub const LOCK_KIND_RW: u8 = 1;
pub const LOCK_KIND_MUTEX: u8 = 2;
pub const LOCK_MODE_EXCLUSIVE: u8 = 0;
pub const LOCK_MODE_READ: u8 = 1;
pub const LOCK_MODE_WRITE: u8 = 2;
pub const PI_MUTEX_WAIT_STORAGE_WORDS: usize = 5;
#[repr(C)]
pub struct PiMutexStorage {
owner_word: AtomicU64,
generation: AtomicU64,
wait_state: AtomicU8,
wait_storage: UnsafeCell<[MaybeUninit<usize>; PI_MUTEX_WAIT_STORAGE_WORDS]>,
}
#[doc(hidden)]
pub struct PiMutexStoragePartsMut<'lock> {
pub owner_word: &'lock mut AtomicU64,
pub generation: &'lock mut AtomicU64,
pub wait_state: &'lock mut AtomicU8,
pub wait_storage: &'lock mut UnsafeCell<[MaybeUninit<usize>; PI_MUTEX_WAIT_STORAGE_WORDS]>,
}
impl PiMutexStorage {
pub const fn new() -> Self {
Self {
owner_word: AtomicU64::new(0),
generation: AtomicU64::new(0),
wait_state: AtomicU8::new(0),
wait_storage: UnsafeCell::new([MaybeUninit::uninit(); PI_MUTEX_WAIT_STORAGE_WORDS]),
}
}
#[doc(hidden)]
pub const fn owner_word(&self) -> &AtomicU64 {
&self.owner_word
}
#[doc(hidden)]
pub const fn generation(&self) -> &AtomicU64 {
&self.generation
}
#[doc(hidden)]
pub const fn wait_state(&self) -> &AtomicU8 {
&self.wait_state
}
#[doc(hidden)]
pub const fn wait_storage(
&self,
) -> &UnsafeCell<[MaybeUninit<usize>; PI_MUTEX_WAIT_STORAGE_WORDS]> {
&self.wait_storage
}
#[doc(hidden)]
pub fn parts_mut(&mut self) -> PiMutexStoragePartsMut<'_> {
PiMutexStoragePartsMut {
owner_word: &mut self.owner_word,
generation: &mut self.generation,
wait_state: &mut self.wait_state,
wait_storage: &mut self.wait_storage,
}
}
}
impl Default for PiMutexStorage {
fn default() -> Self {
Self::new()
}
}
unsafe impl Sync for PiMutexStorage {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(C)]
pub struct ContextState {
preempt: usize,
irq: usize,
}
impl ContextState {
#[doc(hidden)]
pub const fn new(preempt: usize, irq: usize) -> Self {
Self { preempt, irq }
}
#[doc(hidden)]
pub const fn preempt(self) -> usize {
self.preempt
}
#[doc(hidden)]
pub const fn irq(self) -> usize {
self.irq
}
}
#[derive(Clone, Copy)]
#[repr(C)]
pub struct AcquireResult {
acquired: u8,
_reserved: [u8; 7],
context_state: ContextState,
}
impl AcquireResult {
#[doc(hidden)]
pub const fn new(acquired: bool, context_state: ContextState) -> Self {
Self {
acquired: acquired as u8,
_reserved: [0; 7],
context_state,
}
}
pub(crate) const fn acquired(self) -> bool {
self.acquired != 0
}
pub(crate) const fn context_state(self) -> ContextState {
self.context_state
}
}
#[repr(C)]
pub struct LockMetadata {
class_id: AtomicU32,
class_key: AtomicPtr<Location<'static>>,
}
impl LockMetadata {
#[track_caller]
pub const fn new() -> Self {
Self {
class_id: AtomicU32::new(0),
class_key: AtomicPtr::new(
Location::caller() as *const Location<'static> as *mut Location<'static>
),
}
}
#[doc(hidden)]
pub const fn class_id(&self) -> &AtomicU32 {
&self.class_id
}
#[doc(hidden)]
pub const fn class_key(&self) -> &AtomicPtr<Location<'static>> {
&self.class_key
}
}
impl Default for LockMetadata {
fn default() -> Self {
Self::new()
}
}
#[ax_crate_interface::def_interface]
pub trait ContextOps {
fn enter(context: u8) -> ContextState;
fn exit(context: u8, state: ContextState);
fn irq_return_preempt_enter() -> usize;
fn irq_return_preempt_exit(state: usize);
fn hardirq_enter();
fn hardirq_exit();
}
#[ax_crate_interface::def_interface]
pub trait SpinOps {
fn acquire(
locked: &AtomicBool,
metadata: &LockMetadata,
lock_addr: usize,
context: u8,
subclass: u32,
caller: &'static Location<'static>,
) -> ContextState;
fn try_acquire(
locked: &AtomicBool,
metadata: &LockMetadata,
lock_addr: usize,
context: u8,
subclass: u32,
caller: &'static Location<'static>,
) -> AcquireResult;
fn release(locked: &AtomicBool, lock_addr: usize, context: u8, context_state: ContextState);
fn force_release(locked: &AtomicBool, lock_addr: usize, context: u8);
fn is_locked(locked: &AtomicBool) -> bool;
}
#[ax_crate_interface::def_interface]
pub trait RwLockOps {
fn acquire(
state: &AtomicUsize,
metadata: &LockMetadata,
lock_addr: usize,
context: u8,
mode: u8,
caller: &'static Location<'static>,
) -> ContextState;
fn try_acquire(
state: &AtomicUsize,
metadata: &LockMetadata,
lock_addr: usize,
context: u8,
mode: u8,
caller: &'static Location<'static>,
) -> AcquireResult;
fn release(
state: &AtomicUsize,
lock_addr: usize,
context: u8,
context_state: ContextState,
mode: u8,
);
fn force_read_decrement(state: &AtomicUsize, lock_addr: usize, context: u8);
}
#[ax_crate_interface::def_interface]
pub trait MutexOps {
fn acquire(
storage: &PiMutexStorage,
next_waiter_sequence: &AtomicU64,
metadata: &LockMetadata,
lock_addr: usize,
subclass: u32,
caller: &'static Location<'static>,
);
fn try_acquire(
storage: &PiMutexStorage,
next_waiter_sequence: &AtomicU64,
metadata: &LockMetadata,
lock_addr: usize,
subclass: u32,
caller: &'static Location<'static>,
) -> bool;
fn release(storage: &PiMutexStorage, lock_addr: usize);
fn force_release(storage: &PiMutexStorage, lock_addr: usize);
fn is_owned_by_current(storage: &PiMutexStorage) -> bool;
fn is_locked(storage: &PiMutexStorage) -> bool;
fn destroy(storage: &mut PiMutexStorage);
}
#[ax_crate_interface::def_interface]
pub trait LockdepOps {
fn set_trace_enabled(enabled: bool);
fn dump_trace();
}
pub(crate) fn context_enter(context: u8) -> ContextState {
ax_crate_interface::call_interface!(ContextOps::enter, context)
}
pub(crate) fn context_exit(context: u8, state: ContextState) {
ax_crate_interface::call_interface!(ContextOps::exit, context, state);
}
pub(crate) fn irq_return_preempt_enter() -> usize {
ax_crate_interface::call_interface!(ContextOps::irq_return_preempt_enter)
}
pub(crate) fn irq_return_preempt_exit(state: usize) {
ax_crate_interface::call_interface!(ContextOps::irq_return_preempt_exit, state);
}
pub(crate) fn hardirq_enter() {
ax_crate_interface::call_interface!(ContextOps::hardirq_enter);
}
pub(crate) fn hardirq_exit() {
ax_crate_interface::call_interface!(ContextOps::hardirq_exit);
}
pub(crate) fn spin_acquire(
locked: &AtomicBool,
metadata: &LockMetadata,
lock_addr: usize,
context: u8,
subclass: u32,
caller: &'static Location<'static>,
) -> ContextState {
ax_crate_interface::call_interface!(
SpinOps::acquire,
locked,
metadata,
lock_addr,
context,
subclass,
caller
)
}
pub(crate) fn spin_try_acquire(
locked: &AtomicBool,
metadata: &LockMetadata,
lock_addr: usize,
context: u8,
subclass: u32,
caller: &'static Location<'static>,
) -> AcquireResult {
ax_crate_interface::call_interface!(
SpinOps::try_acquire,
locked,
metadata,
lock_addr,
context,
subclass,
caller
)
}
pub(crate) fn spin_release(
locked: &AtomicBool,
lock_addr: usize,
context: u8,
context_state: ContextState,
) {
ax_crate_interface::call_interface!(
SpinOps::release,
locked,
lock_addr,
context,
context_state
);
}
pub(crate) fn spin_force_release(locked: &AtomicBool, lock_addr: usize, context: u8) {
ax_crate_interface::call_interface!(SpinOps::force_release, locked, lock_addr, context);
}
pub(crate) fn spin_is_locked(locked: &AtomicBool) -> bool {
ax_crate_interface::call_interface!(SpinOps::is_locked, locked)
}
pub(crate) fn rwlock_acquire(
state: &AtomicUsize,
metadata: &LockMetadata,
lock_addr: usize,
context: u8,
mode: u8,
caller: &'static Location<'static>,
) -> ContextState {
ax_crate_interface::call_interface!(
RwLockOps::acquire,
state,
metadata,
lock_addr,
context,
mode,
caller
)
}
pub(crate) fn rwlock_try_acquire(
state: &AtomicUsize,
metadata: &LockMetadata,
lock_addr: usize,
context: u8,
mode: u8,
caller: &'static Location<'static>,
) -> AcquireResult {
ax_crate_interface::call_interface!(
RwLockOps::try_acquire,
state,
metadata,
lock_addr,
context,
mode,
caller
)
}
pub(crate) fn rwlock_release(
state: &AtomicUsize,
lock_addr: usize,
context: u8,
context_state: ContextState,
mode: u8,
) {
ax_crate_interface::call_interface!(
RwLockOps::release,
state,
lock_addr,
context,
context_state,
mode
);
}
pub(crate) fn rwlock_force_read_decrement(state: &AtomicUsize, lock_addr: usize, context: u8) {
ax_crate_interface::call_interface!(RwLockOps::force_read_decrement, state, lock_addr, context);
}
#[cfg(feature = "sleep")]
pub(crate) fn mutex_acquire(
storage: &PiMutexStorage,
next_waiter_sequence: &AtomicU64,
metadata: &LockMetadata,
lock_addr: usize,
subclass: u32,
caller: &'static Location<'static>,
) {
ax_crate_interface::call_interface!(
MutexOps::acquire,
storage,
next_waiter_sequence,
metadata,
lock_addr,
subclass,
caller
);
}
#[cfg(feature = "sleep")]
pub(crate) fn mutex_try_acquire(
storage: &PiMutexStorage,
next_waiter_sequence: &AtomicU64,
metadata: &LockMetadata,
lock_addr: usize,
subclass: u32,
caller: &'static Location<'static>,
) -> bool {
ax_crate_interface::call_interface!(
MutexOps::try_acquire,
storage,
next_waiter_sequence,
metadata,
lock_addr,
subclass,
caller
)
}
#[cfg(feature = "sleep")]
pub(crate) fn mutex_release(storage: &PiMutexStorage, lock_addr: usize) {
ax_crate_interface::call_interface!(MutexOps::release, storage, lock_addr);
}
#[cfg(feature = "sleep")]
pub(crate) fn mutex_force_release(storage: &PiMutexStorage, lock_addr: usize) {
ax_crate_interface::call_interface!(MutexOps::force_release, storage, lock_addr);
}
#[cfg(feature = "sleep")]
pub(crate) fn mutex_is_owned_by_current(storage: &PiMutexStorage) -> bool {
ax_crate_interface::call_interface!(MutexOps::is_owned_by_current, storage)
}
#[cfg(feature = "sleep")]
pub(crate) fn mutex_is_locked(storage: &PiMutexStorage) -> bool {
ax_crate_interface::call_interface!(MutexOps::is_locked, storage)
}
#[cfg(feature = "sleep")]
pub(crate) fn mutex_destroy(storage: &mut PiMutexStorage) {
ax_crate_interface::call_interface!(MutexOps::destroy, storage);
}
pub(crate) fn set_trace_enabled(enabled: bool) {
ax_crate_interface::call_interface!(LockdepOps::set_trace_enabled, enabled);
}
pub(crate) fn dump_trace() {
ax_crate_interface::call_interface!(LockdepOps::dump_trace);
}