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(Cell::new(123));

fn main() {
    // Bind the value contained in the `SingleThreadValue` to the currently
    // running thread:
    FOO.bind_to_thread::<DummyThreadIdProvider>();

    // 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);
}

After creating the SingleThreadValue and before trying to access the wrapped value, the SingleThreadValue must have its bind_to_thread method called. Failing to bind it to a thread will prevent any access to the wrapped value.

§Single-thread Synchronization

It is possible for the same thread to get multiple, shared, references. As a result, users must 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 value is only ever accessed from a single thread. 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 then the caller will not be able to access the value.

This requires that the system provides 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(value: T) -> Self

Create a SingleThreadValue.

Note, the value will not be accessible immediately after new() runs. It must first be bound to a particular thread, using the bind_to_thread or bind_to_thread_unsafe methods.

Source

pub fn bind_to_thread<P: ThreadIdProvider>(&self) -> bool

Bind this SingleThreadValue 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 true 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 false.

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) -> bool

Bind this SingleThreadValue 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 true 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 false.

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 a single thread.

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.