Skip to main content

ksync/
raw_kernel_mutex.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::raw_lock::RawLock;
6use core::ffi::c_void;
7use pin_init::{PinInit, pin_data};
8
9#[cfg(feature = "lock_name_tracing")]
10const RAW_MUTEX_SIZE: usize = 32;
11#[cfg(not(feature = "lock_name_tracing"))]
12const RAW_MUTEX_SIZE: usize = 24;
13
14unsafe extern "C" {
15    fn cpp_mutex_init(mutex: *mut c_void);
16    fn cpp_mutex_destroy(mutex: *mut c_void);
17    fn cpp_mutex_acquire(mutex: *mut c_void, lcid: *mut c_void, entry_storage: *mut c_void);
18    fn cpp_mutex_release(mutex: *mut c_void, entry_storage: *mut c_void);
19
20    fn cpp_critical_mutex_init(mutex: *mut c_void);
21    fn cpp_critical_mutex_destroy(mutex: *mut c_void);
22    fn cpp_critical_mutex_acquire(
23        mutex: *mut c_void,
24        lcid: *mut c_void,
25        entry_storage: *mut c_void,
26    ) -> bool;
27    fn cpp_critical_mutex_release(
28        mutex: *mut c_void,
29        entry_storage: *mut c_void,
30        should_clear: bool,
31    );
32}
33
34#[repr(C, align(8))]
35struct RawMutexStorage(zr::OpaqueBytes<RAW_MUTEX_SIZE>);
36
37#[derive(Default)]
38#[repr(C, align(8))]
39pub struct LockEntryStorage(zr::OpaqueBytes<40>);
40
41/// Opaque layout block matching the Zircon C++ Mutex exactly.
42#[pin_data(PinnedDrop)]
43#[repr(C)]
44pub struct RawMutex {
45    #[cfg(feature = "lock_dep")]
46    class_id: *const c_void,
47    storage: RawMutexStorage,
48}
49
50// SAFETY: RawMutex is safe to share and access across threads.
51unsafe impl Sync for RawMutex {}
52unsafe impl Send for RawMutex {}
53
54zr::unsafe_pinned_drop_ffi!(RawMutex, cpp_mutex_destroy);
55
56impl crate::RawLock for RawMutex {
57    type LockEntry = LockEntryStorage;
58    type GuardState = ();
59
60    #[inline]
61    fn init() -> impl PinInit<Self, core::convert::Infallible> {
62        zr::pin_init_ffi!(cpp_mutex_init)
63    }
64
65    #[inline]
66    fn as_mut_ptr(&self) -> *mut c_void {
67        self as *const Self as *mut Self as *mut c_void
68    }
69
70    #[inline]
71    unsafe fn acquire(&self, lcid: *mut c_void, entry: *mut Self::LockEntry) -> Self::GuardState {
72        unsafe {
73            cpp_mutex_acquire(self.as_mut_ptr(), lcid, entry as *mut c_void);
74        }
75    }
76
77    #[inline]
78    unsafe fn release(&self, entry: *mut Self::LockEntry, _state: Self::GuardState) {
79        unsafe {
80            cpp_mutex_release(self.as_mut_ptr(), entry as *mut c_void);
81        }
82    }
83}
84
85/// Opaque layout block matching the Zircon C++ CriticalMutex exactly.
86#[pin_data(PinnedDrop)]
87#[repr(C)]
88pub struct RawCriticalMutex {
89    #[cfg(feature = "lock_dep")]
90    class_id: *const c_void,
91    storage: RawMutexStorage,
92}
93
94// SAFETY: RawCriticalMutex is safe to share and access across threads.
95unsafe impl Sync for RawCriticalMutex {}
96unsafe impl Send for RawCriticalMutex {}
97
98zr::unsafe_pinned_drop_ffi!(RawCriticalMutex, cpp_critical_mutex_destroy);
99
100impl crate::RawLock for RawCriticalMutex {
101    type LockEntry = LockEntryStorage;
102    type GuardState = bool;
103
104    #[inline]
105    fn init() -> impl PinInit<Self, core::convert::Infallible> {
106        zr::pin_init_ffi!(cpp_critical_mutex_init)
107    }
108
109    #[inline]
110    fn as_mut_ptr(&self) -> *mut c_void {
111        self as *const Self as *mut Self as *mut c_void
112    }
113
114    #[inline]
115    unsafe fn acquire(&self, lcid: *mut c_void, entry: *mut Self::LockEntry) -> Self::GuardState {
116        unsafe { cpp_critical_mutex_acquire(self.as_mut_ptr(), lcid, entry as *mut c_void) }
117    }
118
119    #[inline]
120    unsafe fn release(&self, entry: *mut Self::LockEntry, should_clear: Self::GuardState) {
121        unsafe {
122            cpp_critical_mutex_release(self.as_mut_ptr(), entry as *mut c_void, should_clear);
123        }
124    }
125}
126
127const _: () = {
128    #[cfg(feature = "lock_dep")]
129    const EXPECTED_SIZE: usize = if cfg!(feature = "lock_name_tracing") { 40 } else { 32 };
130    #[cfg(not(feature = "lock_dep"))]
131    const EXPECTED_SIZE: usize = if cfg!(feature = "lock_name_tracing") { 32 } else { 24 };
132
133    assert!(core::mem::size_of::<RawMutex>() == EXPECTED_SIZE);
134    assert!(core::mem::align_of::<RawMutex>() == 8);
135
136    assert!(core::mem::size_of::<RawCriticalMutex>() == EXPECTED_SIZE);
137    assert!(core::mem::align_of::<RawCriticalMutex>() == 8);
138};