Skip to main content

ksync/
lib.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
5#![no_std]
6#![deny(
7    dead_code,
8    unused_parens,
9    unused_results,
10    unsafe_op_in_unsafe_fn,
11    missing_unsafe_on_extern,
12    unsafe_attr_outside_unsafe,
13    non_local_definitions,
14    mismatched_lifetime_syntaxes,
15    clippy::all,
16    clippy::missing_safety_doc,
17    clippy::undocumented_unsafe_blocks,
18    clippy::not_unsafe_ptr_arg_deref,
19    clippy::new_without_default
20)]
21
22#[cfg(test)]
23extern crate self as ksync;
24
25pub use kstring::declare_interned_string;
26pub use ksync_macro::{declare_singleton_lock, guarded};
27pub use pin_init;
28
29/// Locks a mutex.
30///
31/// Usage:
32///   `ksync::lock!(let mut guard = self.lock_mu());`
33///   Locks the mutex and binds a mutable pin to `guard`. Useful when you need to mutate
34///   guarded fields via `guard.as_mut().fields_mut()`.
35///
36///   `ksync::lock!(let guard = self.lock_mu());`
37///   Locks the mutex and binds an immutable pin to `guard`. Useful for read-only access
38///   to guarded fields via `guard.fields()`.
39///
40///   `ksync::lock!(self.lock_mu());`
41///   Locks the mutex and keeps it locked until the end of the scope, without binding the guard.
42#[macro_export]
43macro_rules! lock {
44    (let mut $guard:ident = $lock_init:expr) => {
45        $crate::pin_init::stack_pin_init!(let $guard = $lock_init);
46        let mut $guard = $guard;
47    };
48    (let $guard:ident = $lock_init:expr) => {
49        $crate::pin_init::stack_pin_init!(let $guard = $lock_init);
50    };
51    ($lock_init:expr) => {
52        $crate::pin_init::stack_pin_init!(let _guard = $lock_init);
53    };
54}
55
56/// A static C-string tag identifying the source location (`"file:line"`) where a lock is acquired.
57///
58/// Used with `RawMonitoredSpinlock` to pass critical section names to the kernel lockup detector.
59/// Construct via the [`source_tag!`] macro, which is the Rust equivalent of C++ `SOURCE_TAG`.
60#[repr(transparent)]
61#[derive(Copy, Clone, Debug, PartialEq, Eq)]
62pub struct SourceTag(&'static core::ffi::CStr);
63
64impl SourceTag {
65    /// Creates a `SourceTag` from a static null-terminated byte slice without checking for
66    /// interior null bytes.
67    ///
68    /// # Safety
69    ///
70    /// `bytes` must be a valid null-terminated C string (ending in `\0` with no interior `\0`
71    /// bytes).
72    #[inline]
73    pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &'static [u8]) -> Self {
74        // SAFETY: The caller guarantees `bytes` is a valid null-terminated byte slice.
75        Self(unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(bytes) })
76    }
77
78    /// Creates a `SourceTag` from a static `CStr`.
79    #[inline]
80    pub const fn from_cstr(cstr: &'static core::ffi::CStr) -> Self {
81        Self(cstr)
82    }
83
84    /// Returns a pointer to the underlying null-terminated C string.
85    #[inline]
86    pub const fn as_ptr(&self) -> *const core::ffi::c_char {
87        self.0.as_ptr()
88    }
89
90    /// Returns the underlying `CStr`.
91    #[inline]
92    pub const fn as_cstr(&self) -> &'static core::ffi::CStr {
93        self.0
94    }
95}
96
97impl Default for SourceTag {
98    #[inline]
99    fn default() -> Self {
100        Self(c"<unknown>")
101    }
102}
103
104/// Expands to a [`SourceTag`] containing the file path and line number (`"file:line"`) of the
105/// call site, equivalent to C++ `SOURCE_TAG`.
106#[macro_export]
107macro_rules! source_tag {
108    () => {{
109        // SAFETY: `concat!(file!(), ":", line!(), "\0")` produces a static string literal ending
110        // in a single NUL byte and containing no interior NUL bytes.
111        const TAG: $crate::SourceTag = unsafe {
112            $crate::SourceTag::from_bytes_with_nul_unchecked(
113                concat!(file!(), ":", line!(), "\0").as_bytes(),
114            )
115        };
116        TAG
117    }};
118}
119
120mod kcell;
121mod kmutex;
122mod konce_cell;
123mod lock_token;
124mod lockdep_tracked;
125mod phantom_mutex;
126mod raw_lock;
127mod singleton;
128
129#[cfg(not(feature = "kernel"))]
130mod raw_userspace_mutex;
131
132#[cfg(feature = "kernel")]
133mod raw_kernel_mutex;
134#[cfg(feature = "kernel")]
135mod raw_spin_lock;
136
137pub use kcell::{KCell, KCellInit, kcell_init};
138pub use konce_cell::{KOnceCell, KOnceCellGuard};
139#[cfg(any(feature = "kernel", test))]
140mod brwlock;
141
142#[cfg(feature = "kernel")]
143mod raw_kernel_brwlock;
144
145#[cfg(all(not(feature = "kernel"), test))]
146mod raw_userspace_brwlock;
147
148pub use kmutex::{
149    AliasedLock, KMutex, KMutexAliasedGuard, KMutexGuard, KMutexGuardMultiple, aliased_lock,
150    aliased_lock_policy, aliased_lock_policy_with, aliased_lock_with, guard_multiple,
151    guard_multiple_policy, guard_multiple_policy_with, guard_multiple_with,
152};
153pub use lock_token::{ExclusiveLockToken, LockToken, LockTokenRead, LockTokenWrite};
154pub use lockdep::{
155    LOCK_FLAGS_MULTI_ACQUIRE, LOCK_FLAGS_SINGLETON_LOCK, LockClass, LockClassRegistration,
156    LockFlags,
157};
158pub use lockdep_tracked::{LockdepTracked, LockdepTrackedGuardState};
159pub use phantom_mutex::PhantomMutex;
160pub use raw_lock::{ConstRawLock, ExclusiveLockPolicy, LockPolicy, RawLock};
161pub use singleton::SingletonMutex;
162
163#[cfg(not(feature = "kernel"))]
164pub use raw_userspace_mutex::{RawMutex, RawMutexStorage};
165
166#[cfg(feature = "kernel")]
167pub use raw_spin_lock::{
168    InterruptSavedState, IrqSavePolicy, MonitoredSpinlockGuardState, NoIrqSavePolicy,
169    RawMonitoredSpinlock, RawMonitoredSpinlockStorage, RawSpinlock, RawSpinlockStorage,
170};
171#[cfg(feature = "kernel")]
172pub type KSpinlock<Class> = KMutex<Class, RawSpinlock>;
173#[cfg(feature = "kernel")]
174pub type KMonitoredSpinlock<Class> = KMutex<Class, RawMonitoredSpinlock>;
175#[cfg(any(feature = "kernel", test))]
176pub use brwlock::{BrwLockPi, BrwLockPiReadGuard, BrwLockPiWriteGuard};
177#[cfg(feature = "kernel")]
178pub use raw_kernel_brwlock::{
179    RawBrwLockPi, RawBrwLockPiReadPolicy, RawBrwLockPiStorage, RawBrwLockPiWritePolicy,
180};
181#[cfg(feature = "kernel")]
182pub use raw_kernel_mutex::{RawCriticalMutex, RawCriticalMutexPolicy, RawMutex, RawMutexStorage};
183#[cfg(all(not(feature = "kernel"), test))]
184pub use raw_userspace_brwlock::{
185    RawBrwLockPi, RawBrwLockPiReadPolicy, RawBrwLockPiStorage, RawBrwLockPiWritePolicy,
186};