Skip to main content

ksync/
raw_spin_lock.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_kernel_mutex::LockEntryStorage;
6use crate::raw_lock::RawLock;
7use core::ffi::c_void;
8use pin_init::{PinInit, pin_data};
9
10#[cfg(target_arch = "x86_64")]
11type InnerSavedState = u64;
12#[cfg(not(target_arch = "x86_64"))]
13type InnerSavedState = bool;
14
15/// Opaque token representing the saved interrupt state.
16#[repr(transparent)]
17#[derive(Copy, Clone, Default)]
18pub struct InterruptSavedState(InnerSavedState);
19
20unsafe extern "C" {
21    fn cpp_spinlock_init(lock: *mut c_void);
22    fn cpp_spinlock_destroy(lock: *mut c_void);
23    fn cpp_spinlock_acquire_irqsave(
24        lock: *mut c_void,
25        lcid: *mut c_void,
26        entry_storage: *mut c_void,
27    ) -> InterruptSavedState;
28    fn cpp_spinlock_release_irqrestore(
29        lock: *mut c_void,
30        entry_storage: *mut c_void,
31        state: InterruptSavedState,
32    );
33}
34
35#[cfg(feature = "spin_lock_tracing")]
36const RAW_SPINLOCK_SIZE: usize = 16;
37#[cfg(not(feature = "spin_lock_tracing"))]
38const RAW_SPINLOCK_SIZE: usize = 4;
39
40#[repr(C, align(8))]
41struct RawSpinlockStorage(zr::OpaqueBytes<RAW_SPINLOCK_SIZE>);
42
43/// Opaque layout block matching the Zircon C++ SpinLock exactly.
44#[pin_data(PinnedDrop)]
45#[repr(C)]
46pub struct RawSpinlock {
47    #[cfg(feature = "lock_dep")]
48    class_id: *const c_void,
49    storage: RawSpinlockStorage,
50}
51
52// SAFETY: RawSpinlock is safe to share and access across threads.
53unsafe impl Sync for RawSpinlock {}
54unsafe impl Send for RawSpinlock {}
55
56zr::unsafe_pinned_drop_ffi!(RawSpinlock, cpp_spinlock_destroy);
57
58impl crate::RawLock for RawSpinlock {
59    type LockEntry = LockEntryStorage;
60    type GuardState = InterruptSavedState;
61
62    #[inline]
63    fn init() -> impl PinInit<Self, core::convert::Infallible> {
64        zr::pin_init_ffi!(cpp_spinlock_init)
65    }
66
67    #[inline]
68    fn as_mut_ptr(&self) -> *mut c_void {
69        self as *const Self as *mut Self as *mut c_void
70    }
71
72    #[inline]
73    unsafe fn acquire(&self, lcid: *mut c_void, entry: *mut Self::LockEntry) -> Self::GuardState {
74        unsafe { cpp_spinlock_acquire_irqsave(self.as_mut_ptr(), lcid, entry as *mut c_void) }
75    }
76
77    #[inline]
78    unsafe fn release(&self, entry: *mut Self::LockEntry, state: Self::GuardState) {
79        unsafe {
80            cpp_spinlock_release_irqrestore(self.as_mut_ptr(), entry as *mut c_void, state);
81        }
82    }
83}
84
85const _: () = {
86    #[cfg(feature = "lock_dep")]
87    const BASE_SIZE: usize = 8;
88    #[cfg(not(feature = "lock_dep"))]
89    const BASE_SIZE: usize = 0;
90
91    const EXPECTED_SPINLOCK_SIZE: usize = BASE_SIZE + if RAW_SPINLOCK_SIZE == 4 { 8 } else { 16 };
92
93    assert!(core::mem::size_of::<RawSpinlock>() == EXPECTED_SPINLOCK_SIZE);
94    assert!(core::mem::align_of::<RawSpinlock>() == 8);
95};