Skip to main content

ax_task/sync/bridge/
mutex.rs

1//! Complete external PI-mutex transactions backed by native scheduler state.
2
3use core::{
4    cell::UnsafeCell,
5    mem::MaybeUninit,
6    panic::Location,
7    sync::atomic::{AtomicU8, AtomicU64},
8};
9
10#[cfg(feature = "lockdep")]
11use {
12    crate::sync::lockdep::LockdepMapView, crate::sync::mutex::lockdep::LockdepAcquire,
13    crate::sync::mutex::lockdep::LockdepAcquireRequest,
14};
15
16use super::lockdep::LockClass;
17use crate::sync::mutex::{
18    PI_MUTEX_WAIT_STORAGE_WORDS, PiMutexAlgorithm, PiMutexCoreView, destroy_pi_mutex_storage,
19};
20
21/// Borrowed fixed storage for one external PI mutex.
22#[derive(Clone, Copy)]
23pub struct PiMutexStorage<'lock> {
24    pub owner: &'lock AtomicU64,
25    pub generation: &'lock AtomicU64,
26    pub wait_state: &'lock AtomicU8,
27    pub wait_words: &'lock UnsafeCell<[MaybeUninit<usize>; PI_MUTEX_WAIT_STORAGE_WORDS]>,
28}
29
30impl<'lock> PiMutexStorage<'lock> {
31    fn core(self) -> PiMutexCoreView<'lock> {
32        PiMutexCoreView::from_parts(
33            self.owner,
34            self.generation,
35            self.wait_state,
36            self.wait_words,
37        )
38    }
39}
40
41/// Exclusive fixed storage borrowed while an external PI mutex is destroyed.
42pub struct PiMutexStorageMut<'lock> {
43    pub owner: &'lock mut AtomicU64,
44    pub generation: &'lock mut AtomicU64,
45    pub wait_state: &'lock mut AtomicU8,
46    pub wait_words: &'lock mut UnsafeCell<[MaybeUninit<usize>; PI_MUTEX_WAIT_STORAGE_WORDS]>,
47}
48
49/// One complete external PI-mutex acquisition request.
50pub struct MutexAcquireRequest<'lock> {
51    pub storage: PiMutexStorage<'lock>,
52    pub next_waiter_sequence: &'lock AtomicU64,
53    pub class: LockClass<'lock>,
54    pub lock_addr: usize,
55    pub subclass: u32,
56    pub caller: &'static Location<'static>,
57}
58
59/// Acquires an external PI mutex through the native Linux-RT-style blocking path.
60pub fn mutex_acquire(request: MutexAcquireRequest<'_>) {
61    let lockdep = prepare_lockdep(&request, false);
62    let algorithm = PiMutexAlgorithm::new(request.storage.core(), request.next_waiter_sequence);
63    algorithm.lock_pi();
64    finish_lockdep(lockdep, true);
65}
66
67/// Tries to acquire an external PI mutex without blocking.
68pub fn mutex_try_acquire(request: MutexAcquireRequest<'_>) -> bool {
69    let lockdep = prepare_lockdep(&request, true);
70    let algorithm = PiMutexAlgorithm::new(request.storage.core(), request.next_waiter_sequence);
71    let acquired = algorithm.try_lock_pi();
72    finish_lockdep(lockdep, acquired);
73    acquired
74}
75
76/// Releases an external PI mutex and completes any scheduler-owned handoff.
77pub fn mutex_release(storage: PiMutexStorage<'_>, lock_addr: usize) {
78    release_lockdep(lock_addr);
79    unsafe {
80        // SAFETY: the external raw-mutex guard proves current owns this lock
81        // through the complete scheduler handoff transaction.
82        PiMutexAlgorithm::unlock_core(storage.core());
83    }
84}
85
86/// Releases one deliberately leaked external PI-mutex guard.
87pub fn mutex_force_release(storage: PiMutexStorage<'_>, lock_addr: usize) {
88    mutex_release(storage, lock_addr);
89}
90
91/// Returns whether the current task owns an external PI mutex.
92pub fn mutex_is_owned_by_current(storage: PiMutexStorage<'_>) -> bool {
93    PiMutexAlgorithm::core_is_owned_by_current(storage.core())
94}
95
96/// Returns whether an external PI mutex has an owner or pending handoff.
97pub fn mutex_is_locked(storage: PiMutexStorage<'_>) -> bool {
98    PiMutexAlgorithm::core_is_locked(storage.core())
99}
100
101/// Destroys scheduler-owned inline waiter state after the wrapper is unique.
102pub fn mutex_destroy(storage: PiMutexStorageMut<'_>) {
103    destroy_pi_mutex_storage(
104        storage.owner,
105        storage.generation,
106        storage.wait_state,
107        storage.wait_words,
108    );
109}
110
111#[cfg(feature = "lockdep")]
112fn prepare_lockdep(request: &MutexAcquireRequest<'_>, is_try: bool) -> LockdepAcquire {
113    LockdepAcquire::prepare_view(LockdepAcquireRequest {
114        map: LockdepMapView::new(request.class.class_id, request.class.class_key),
115        addr: request.lock_addr,
116        subclass: request.subclass,
117        is_try,
118        caller: request.caller,
119    })
120}
121
122#[cfg(not(feature = "lockdep"))]
123#[derive(Clone, Copy)]
124struct LockdepAcquire;
125
126#[cfg(not(feature = "lockdep"))]
127fn prepare_lockdep(request: &MutexAcquireRequest<'_>, is_try: bool) -> LockdepAcquire {
128    let _ = (request, is_try);
129    LockdepAcquire
130}
131
132fn finish_lockdep(lockdep: LockdepAcquire, acquired: bool) {
133    #[cfg(feature = "lockdep")]
134    lockdep.finish(acquired);
135
136    #[cfg(not(feature = "lockdep"))]
137    let _ = (lockdep, acquired);
138}
139
140fn release_lockdep(lock_addr: usize) {
141    #[cfg(feature = "lockdep")]
142    crate::sync::mutex::lockdep::release_external(lock_addr);
143
144    #[cfg(not(feature = "lockdep"))]
145    let _ = lock_addr;
146}