Struct kernel::sync::LockedBy

source ·
pub struct LockedBy<T: ?Sized, U: ?Sized> { /* private fields */ }
Expand description

Allows access to some data to be serialised by a lock that does not wrap it.

In most cases, data protected by a lock is wrapped by the appropriate lock type, e.g., super::Mutex or super::SpinLock. LockedBy is meant for cases when this is not possible. For example, if a container has a lock and some data in the contained elements needs to be protected by the same lock.

LockedBy wraps the data in lieu of another locking primitive, and only allows access to it when the caller shows evidence that the ‘external’ lock is locked. It panics if the evidence refers to the wrong instance of the lock.

Examples

The following is an example for illustrative purposes: InnerDirectory::bytes_used is an aggregate of all InnerFile::bytes_used and must be kept consistent; so we wrap InnerFile in a LockedBy so that it shares a lock with InnerDirectory. This allows us to enforce at compile-time that access to InnerFile is only granted when an InnerDirectory is also locked; we enforce at run time that the right InnerDirectory is locked.

use kernel::sync::{LockedBy, Mutex};

struct InnerFile {
    bytes_used: u64,
}

struct File {
    _ino: u32,
    inner: LockedBy<InnerFile, InnerDirectory>,
}

struct InnerDirectory {
    /// The sum of the bytes used by all files.
    bytes_used: u64,
    _files: Vec<File>,
}

struct Directory {
    _ino: u32,
    inner: Mutex<InnerDirectory>,
}

/// Prints `bytes_used` from both the directory and file.
fn print_bytes_used(dir: &Directory, file: &File) {
    let guard = dir.inner.lock();
    let inner_file = file.inner.access(&guard);
    pr_info!("{} {}", guard.bytes_used, inner_file.bytes_used);
}

/// Increments `bytes_used` for both the directory and file.
fn inc_bytes_used(dir: &Directory, file: &File) {
    let mut guard = dir.inner.lock();
    guard.bytes_used += 10;

    let file_inner = file.inner.access_mut(&mut guard);
    file_inner.bytes_used += 10;
}

/// Creates a new file.
fn new_file(ino: u32, dir: &Directory) -> File {
    File {
        _ino: ino,
        inner: LockedBy::new(&dir.inner, InnerFile { bytes_used: 0 }),
    }
}

Implementations§

source§

impl<T, U> LockedBy<T, U>

source

pub fn new<B: Backend>(owner: &Lock<U, B>, data: T) -> Self

Constructs a new instance of LockedBy.

It stores a raw pointer to the owner that is never dereferenced. It is only used to ensure that the right owner is being used to access the protected data. If the owner is freed, the data becomes inaccessible; if another instance of the owner is allocated on the same memory location, the data becomes accessible again: none of this affects memory safety because in any case at most one thread (or CPU) can access the protected data at a time.

source§

impl<T: ?Sized, U> LockedBy<T, U>

source

pub fn access<'a>(&'a self, owner: &'a U) -> &'a T

Returns a reference to the protected data when the caller provides evidence (via a reference) that the owner is locked.

U cannot be a zero-sized type (ZST) because there are ways to get an &U that matches the data protected by the lock without actually holding it.

Panics

Panics if owner is different from the data protected by the lock used in new.

source

pub fn access_mut<'a>(&'a self, owner: &'a mut U) -> &'a mut T

Returns a mutable reference to the protected data when the caller provides evidence (via a mutable owner) that the owner is locked mutably.

U cannot be a zero-sized type (ZST) because there are ways to get an &mut U that matches the data protected by the lock without actually holding it.

Showing a mutable reference to the owner is sufficient because we know no other references can exist to it.

Panics

Panics if owner is different from the data protected by the lock used in new.

Trait Implementations§

source§

impl<T: ?Sized + Send, U: ?Sized> Send for LockedBy<T, U>

source§

impl<T: ?Sized + Send, U: ?Sized> Sync for LockedBy<T, U>

Auto Trait Implementations§

§

impl<T, U> !RefUnwindSafe for LockedBy<T, U>

§

impl<T: ?Sized, U: ?Sized> Unpin for LockedBy<T, U>where T: Unpin,

§

impl<T: ?Sized, U: ?Sized> UnwindSafe for LockedBy<T, U>where T: UnwindSafe, U: RefUnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, E> Init<T, E> for T

source§

unsafe fn __init(self, slot: *mut T) -> Result<(), E>

Initializes slot. Read more
source§

fn chain<F>(self, f: F) -> ChainInit<Self, F, T, E>where F: FnOnce(&mut T) -> Result<(), E>,

First initializes the value using self then calls the function f with the initialized value. Read more
source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, E> PinInit<T, E> for T

source§

unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>

Initializes slot. Read more
source§

fn pin_chain<F>(self, f: F) -> ChainPinInit<Self, F, T, E>where F: FnOnce(Pin<&mut T>) -> Result<(), E>,

First initializes the value using self then calls the function f with the initialized value. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
This documentation is an old archive. Please see https://rust.docs.kernel.org instead.