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>
impl<T> SingleThreadValue<T>
Sourcepub const fn new() -> Self
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.
Sourcepub fn bind_to_thread<P: ThreadIdProvider>(&self, value: T) -> Result<(), T>
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.
Sourcepub unsafe fn bind_to_thread_unsafe<P: ThreadIdProvider>(
&self,
value: T,
) -> Result<(), T>
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.
Sourcepub fn bound_to_current_thread(&self) -> bool
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.
Sourcepub fn get(&self) -> Option<&T>
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§
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.