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 phantom_mutex;
125mod raw_lock;
126mod singleton;
127
128#[cfg(not(feature = "kernel"))]
129mod raw_userspace_mutex;
130
131#[cfg(feature = "kernel")]
132mod raw_kernel_mutex;
133#[cfg(feature = "kernel")]
134mod raw_spin_lock;
135
136pub use kcell::{KCell, KCellInit, kcell_init};
137pub use konce_cell::{KOnceCell, KOnceCellGuard};
138#[cfg(any(feature = "kernel", test))]
139mod brwlock;
140
141#[cfg(feature = "kernel")]
142mod raw_kernel_brwlock;
143
144#[cfg(all(not(feature = "kernel"), test))]
145mod raw_userspace_brwlock;
146
147pub use kmutex::{
148    AliasedLock, KMutex, KMutexAliasedGuard, KMutexGuard, KMutexGuardMultiple, aliased_lock,
149    aliased_lock_policy, aliased_lock_policy_with, aliased_lock_with, guard_multiple,
150    guard_multiple_policy, guard_multiple_policy_with, guard_multiple_with,
151};
152pub use lock_token::{ExclusiveLockToken, LockToken, LockTokenRead, LockTokenWrite};
153pub use lockdep::{LOCK_FLAGS_SINGLETON_LOCK, LockClass, LockClassRegistration, LockFlags};
154pub use phantom_mutex::PhantomMutex;
155pub use raw_lock::{LockPolicy, RawLock};
156pub use singleton::SingletonMutex;
157
158#[cfg(not(feature = "kernel"))]
159pub use raw_userspace_mutex::RawMutex;
160
161#[cfg(not(feature = "kernel"))]
162pub type LockEntryStorage = ();
163
164#[cfg(feature = "kernel")]
165pub use raw_spin_lock::{
166    InterruptSavedState, IrqSavePolicy, MonitoredSpinlockGuardState, NoIrqSavePolicy,
167    RawMonitoredSpinlock, RawSpinlock,
168};
169#[cfg(feature = "kernel")]
170pub type KSpinlock<Class> = KMutex<Class, RawSpinlock>;
171#[cfg(feature = "kernel")]
172pub type KMonitoredSpinlock<Class> = KMutex<Class, RawMonitoredSpinlock>;
173#[cfg(any(feature = "kernel", test))]
174pub use brwlock::{BrwLockPi, BrwLockPiReadGuard, BrwLockPiWriteGuard};
175#[cfg(feature = "kernel")]
176pub use raw_kernel_brwlock::RawBrwLockPi;
177#[cfg(feature = "kernel")]
178pub use raw_kernel_mutex::{LockEntryStorage, RawCriticalMutex, RawMutex};
179#[cfg(all(not(feature = "kernel"), test))]
180pub use raw_userspace_brwlock::RawBrwLockPi;