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>
impl<T> SingleThreadValue<T>
Sourcepub const fn new(value: T) -> Self
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.
Sourcepub fn bind_to_thread<P: ThreadIdProvider>(&self) -> bool
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.
Sourcepub unsafe fn bind_to_thread_unsafe<P: ThreadIdProvider>(&self) -> bool
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.
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 a single thread.