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