SingleThreadValue

Struct SingleThreadValue 

Source
pub struct SingleThreadValue<T> { /* private fields */ }
Expand description

A container for objects accessible to a single thread.

This type wraps a value of type T: ?Sync, accessible to only a single thread. Only that thread can obtain references to the contained value, and that thread may obtain multiple shared (&) references to the value concurrently.

This container is Sync, regardless of whether T is Sync. This is similar to the standard library’s LocalKey, and thus appropriate for static allocations of values that are not themselves Sync. However, unlike LocalKey, it only holds a value for a single thread, determined at runtime based on the first call to SingleThreadValue::bind_to_thread.

§Example

use core::cell::Cell;
use kernel::utilities::single_thread_value::SingleThreadValue;

// Binding to a thread requires a "ThreadIdProvider", used to query the
// thread ID of the currently running thread at runtime:
enum DummyThreadIdProvider {}
unsafe impl kernel::platform::chip::ThreadIdProvider for DummyThreadIdProvider {
    fn running_thread_id() -> usize {
        // Return the current thread id. We return a constant for
        // demonstration purposes, but doing so in practice is unsound:
        42
    }
}

static FOO: SingleThreadValue<Cell<usize>> = SingleThreadValue::new();

fn main() {
    // Atomically move the value supplied in the constructor into the
    // `SingleThreadValue`, and bind it to the currently running thread:
    FOO.bind_to_thread::<DummyThreadIdProvider>(Cell::new(123));

    // Attempt to access the value. Returns `Some(&T)` if running from the
    // thread that the `SingleThreadValue` is bound to:
    let foo_ref = FOO.get().unwrap();
    foo_ref.set(foo_ref.get() + 1);
}

When creating a new SingleThreadValue instance, it is uninitialized until the bind_to_thread or bind_to_thread_unsafe methods are called. Until it is initialized, all attempts to access the shared value using get will return None.

§Single-thread Synchronization

It is possible for the same thread to get multiple, shared, references to the wrapped value concurrently. Users can use interior mutability (e.g. Cell, MapCell, or TakeCell) to allow obtaining exclusive mutable access.

§Guaranteeing Single-Thread Access

SingleThreadValue is safe because it guarantees that the contained value is only ever made accessible to the same thread from which it originated. To do this, SingleThreadValue inspects the currently running thread on every access to the wrapped value. If the active thread is different than the original thread to which the SingleThreadValue is bound, then the caller will not be able to access the value.

This requires that the system provide a correct implementation of ThreadIdProvider to identify the currently executing thread. Internally, SingleThreadValue uses the ThreadIdProvider::running_thread_id function to identify the current thread and compares it against the thread ID that the contained value is bound to.

Implementations§

Source§

impl<T> SingleThreadValue<T>

Source

pub const fn new() -> Self

Create a SingleThreadValue.

Note that the SingleThreadValue will initially be uninitialized. It must first be bound to a particular thread, which will initialize with a value originating from that thread, using the bind_to_thread or bind_to_thread_unsafe methods.

Source

pub fn bind_to_thread<P: ThreadIdProvider>(&self, value: T) -> Result<(), T>

Initialize this SingleThreadValue and bind it the currently running thread.

If this SingleThreadValue is not already bound to a thread, or if it is not currently in the process of binding to a thread, then this binds the SingleThreadValue to the current thread.

It further records the ThreadIdProvider::running_thread_id function reference, and uses this function to determine the currently running thread for any future queries.

Returns Ok(()) if this invocation successfully bound the value to the current thread. Otherwise, if the value was already bound to this same or another thread, or is concurrently being bound to a thread, it returns Err(T), returning the supplied value.

This method requires the target to support atomic operations (namely, compare_exchange) on usize-sized values, and thus relies on the cfg(target_has_atomic = "ptr") conditional.

Source

pub unsafe fn bind_to_thread_unsafe<P: ThreadIdProvider>( &self, value: T, ) -> Result<(), T>

Initialize this SingleThreadValue and bind it to the currently running thread.

If this SingleThreadValue is not already bound to a thread, or if it is not currently in the process of binding to a thread, then this binds the SingleThreadValue to the current thread.

It further records the ThreadIdProvider::running_thread_id function reference, and uses this function to determine the currently running thread for any future queries.

Returns Ok(()) if this invocation successfully bound the value to the current thread. Otherwise, if the value was already bound to this same or another thread, it returns Err(T), returning the supplied value.

This method is unsafe, and does not require the target to support atomic operations (namely, compare_exchange) on usize-sized values.

§Safety

Callers of this function must ensure that this function is never called concurrently with other calls to bind_to_thread or bind_to_thread_unsafe on the same SingleThreadValue instance.

Source

pub fn bound_to_current_thread(&self) -> bool

Check whether this SingleThreadValue instance is bound to the currently running thread ID.

Returns true if the value is bound to the thread that is currently running (as determined by the implementation of ThreadIdProvider used in bind_to_thread or bind_to_thread_unsafe). Returns false when a different thread is executing, when it is not bound to any thread yet, or currently in the process of being bound to a thread.

Source

pub fn get(&self) -> Option<&T>

Obtain a reference to the contained value.

This function checks whether the SingleThreadValue is bound to the currently running thread and, if so, returns a shared / immutable reference to its contained value.

Trait Implementations§

Source§

impl<T> Sync for SingleThreadValue<T>

Mark that SingleThreadValue is Sync to enable multiple accesses.

§Safety

This is safe because SingleThreadValue enforces that the shared value is only ever accessed from the same thread it originated from.

Auto Trait Implementations§

§

impl<T> !Freeze for SingleThreadValue<T>

§

impl<T> !RefUnwindSafe for SingleThreadValue<T>

§

impl<T> Send for SingleThreadValue<T>
where T: Send,

§

impl<T> Unpin for SingleThreadValue<T>
where T: Unpin,

§

impl<T> UnwindSafe for SingleThreadValue<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

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

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

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

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where 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, U> Into<U> for T
where 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, U> TryFrom<U> for T
where U: Into<T>,

Source§

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 T
where U: TryFrom<T>,

Source§

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.