rust/kernel/sync/lock.rs

Source file repositories/reference/linux-study-clean/rust/kernel/sync/lock.rs

File Facts

System
Linux kernel
Corpus path
rust/kernel/sync/lock.rs
Extension
.rs
Size
11037 bytes
Lines
325
Domain
Rust Kernel Layer
Bucket
Rust API Membrane
Inferred role
Rust Kernel Layer: implementation source
Status
source implementation candidate

Why This File Exists

Rust-side wrappers and abstractions around kernel C APIs, ownership contracts, allocation, synchronization, and module integration.

Dependency Surface

Detected Declarations

Annotated Snippet

unsafe fn relock(ptr: *mut Self::State, guard_state: &mut Self::GuardState) {
        // SAFETY: The safety requirements ensure that the lock is initialised.
        *guard_state = unsafe { Self::lock(ptr) };
    }

    /// Asserts that the lock is held using lockdep.
    ///
    /// # Safety
    ///
    /// Callers must ensure that [`Backend::init`] has been previously called.
    unsafe fn assert_is_held(ptr: *mut Self::State);
}

/// A mutual exclusion primitive.
///
/// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock
/// [`Backend`] specified as the generic parameter `B`.
#[repr(C)]
#[pin_data]
pub struct Lock<T: ?Sized, B: Backend> {
    /// The kernel lock object.
    #[pin]
    state: Opaque<B::State>,

    /// Some locks are known to be self-referential (e.g., mutexes), while others are architecture
    /// or config defined (e.g., spinlocks). So we conservatively require them to be pinned in case
    /// some architecture uses self-references now or in the future.
    #[pin]
    _pin: PhantomPinned,

    /// The data protected by the lock.
    #[pin]
    pub(crate) data: UnsafeCell<T>,
}

// SAFETY: `Lock` can be transferred across thread boundaries iff the data it protects can.
unsafe impl<T: ?Sized + Send, B: Backend> Send for Lock<T, B> {}

// SAFETY: `Lock` serialises the interior mutability it provides, so it is `Sync` as long as the
// data it protects is `Send`.
unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}

impl<T, B: Backend> Lock<T, B> {
    /// Constructs a new lock initialiser.
    pub fn new(
        t: impl PinInit<T>,
        name: &'static CStr,
        key: Pin<&'static LockClassKey>,
    ) -> impl PinInit<Self> {
        pin_init!(Self {
            data <- UnsafeCell::pin_init(t),
            _pin: PhantomPinned,
            // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have
            // static lifetimes so they live indefinitely.
            state <- Opaque::ffi_init(|slot| unsafe {
                B::init(slot, name.as_char_ptr(), key.as_ptr())
            }),
        })
    }
}

impl<B: Backend> Lock<(), B> {
    /// Constructs a [`Lock`] from a raw pointer.
    ///
    /// This can be useful for interacting with a lock which was initialised outside of Rust.
    ///
    /// # Safety
    ///
    /// The caller promises that `ptr` points to a valid initialised instance of [`State`] during
    /// the whole lifetime of `'a`.
    ///
    /// [`State`]: Backend::State
    #[inline]
    pub unsafe fn from_raw<'a>(ptr: *mut B::State) -> &'a Self {
        // SAFETY:
        // - By the safety contract `ptr` must point to a valid initialised instance of `B::State`
        // - Since the lock data type is `()` which is a ZST, `state` is the only non-ZST member of
        //   the struct
        // - Combined with `#[repr(C)]`, this guarantees `Self` has an equivalent data layout to
        //   `B::State`.
        unsafe { &*ptr.cast() }
    }
}

impl<T: ?Sized, B: Backend> Lock<T, B> {
    /// Acquires the lock and gives the caller access to the data protected by it.
    #[inline]
    pub fn lock(&self) -> Guard<'_, T, B> {
        // SAFETY: The constructor of the type calls `init`, so the existence of the object proves
        // that `init` was called.

Annotation

Implementation Notes