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