kernel/utilities/single_thread_value.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2025.
4
5//! A container for objects accessible to a single thread.
6
7use core::cell::UnsafeCell;
8use core::mem::MaybeUninit;
9use core::sync::atomic::AtomicUsize;
10use core::sync::atomic::Ordering;
11
12use crate::platform::chip::ThreadIdProvider;
13
14/// Stages of binding a [`SingleThreadValue`] to a given thread.
15///
16/// The [`SingleThreadValue`] starts out not being bound to, and thus not being
17/// usable by any thread. A `SingleThreadValue` instance is instead bound to
18/// particular thread using either the `SingleThreadValue::bind_to_thread`, or
19/// the [`SingleThreadValue::bind_to_thread_unsafe`] methods. These methods can
20/// be used exactly once, after which the instance is permanently bound to the
21/// given thread that called these methods.
22///
23/// For these and other methods to know whether a [`SingleThreadValue`] has been
24/// bound to a thread already, and thus whether its `thread_id_and_fn` field is
25/// initialized and holds a stable value, it contains an `AtomicUsize` type to
26/// indicate its current "binding stage". Over its lifetime, this stage value is
27/// strictly increasing, transitioning through the [`BoundToThreadStage`] enum
28/// variants as per their documentation.
29#[repr(usize)]
30enum BoundToThreadStage {
31 /// This stage means that the [`SingleThreadValue`] has not been bound to a
32 /// particular thread yet, and its `thread_id_and_fn` field is not
33 /// initialized.
34 ///
35 /// For the `bind_to_thread` and `bind_to_thread_unsafe` methods, this value
36 /// further means that the instance can be bound to the currently running
37 /// thread.
38 Unbound = 0,
39
40 /// To bind a [`SingleThreadValue`] to the currently running thread, the
41 /// `bind_to_thread` function atomically transitions it from the `Unbound`
42 /// stage to the `Binding` stage, through a compare-exchange operation.
43 ///
44 /// When this stage is active, the `thread_id_and_fn` field is not
45 /// initialized, similar to `Unbound`. However, it prevents other,
46 /// concurrent calls to `bind_to_thread` from attempting to bind the value
47 /// to another thread concurrently.
48 ///
49 /// Targets without support for compare-exchange atomic operations on
50 /// `usize` types can utilize `bind_to_thread_unsafe` instead: this method
51 /// requires callers to externally guarantee that there are no concurrent
52 /// calls to either `bind_to_thread` OR `bind_to_thread_unsafe`. Thus, it
53 /// can skip this intermediate state: it can directly transition from
54 /// `Unbound` into `Bound`.
55 #[allow(dead_code)]
56 Binding = 1,
57
58 /// This value indicates that the [`SingleThreadValue`] is bound to a
59 /// particular thread. The `thread_id_and_fn` value is initialized and
60 /// sealed: it must not be modified beyond this point, and no mutable
61 /// references to it may exist. The `Bound` stage is final and cannot be
62 /// transitioned out of.
63 Bound = 2,
64}
65
66/// A container for objects accessible to a single thread.
67///
68/// This type wraps a value of type `T: ?Sync`, accessible to only a single
69/// thread. Only that thread can obtain references to the contained value, and
70/// that thread may obtain multiple _shared_ (`&`) references to the value
71/// concurrently.
72///
73/// This container is [`Sync`], regardless of whether `T` is `Sync`. This is
74/// similar to the standard library's `LocalKey`, and thus appropriate for
75/// static allocations of values that are not themselves [`Sync`]. However,
76/// unlike `LocalKey`, it only holds a value for a single thread, determined at
77/// runtime based on the first call to `SingleThreadValue::bind_to_thread`.
78///
79/// # Example
80///
81/// ```
82/// use core::cell::Cell;
83/// use kernel::utilities::single_thread_value::SingleThreadValue;
84///
85/// // Binding to a thread requires a "ThreadIdProvider", used to query the
86/// // thread ID of the currently running thread at runtime:
87/// enum DummyThreadIdProvider {}
88/// unsafe impl kernel::platform::chip::ThreadIdProvider for DummyThreadIdProvider {
89/// fn running_thread_id() -> usize {
90/// // Return the current thread id. We return a constant for
91/// // demonstration purposes, but doing so in practice is unsound:
92/// 42
93/// }
94/// }
95///
96/// static FOO: SingleThreadValue<Cell<usize>> = SingleThreadValue::new();
97///
98/// fn main() {
99/// // Atomically move the value supplied in the constructor into the
100/// // `SingleThreadValue`, and bind it to the currently running thread:
101/// FOO.bind_to_thread::<DummyThreadIdProvider>(Cell::new(123));
102///
103/// // Attempt to access the value. Returns `Some(&T)` if running from the
104/// // thread that the `SingleThreadValue` is bound to:
105/// let foo_ref = FOO.get().unwrap();
106/// foo_ref.set(foo_ref.get() + 1);
107/// }
108/// ```
109///
110/// When creating a new [`SingleThreadValue`] instance, it is uninitialized
111/// until the `bind_to_thread` or
112/// [`bind_to_thread_unsafe`](SingleThreadValue::bind_to_thread_unsafe) methods
113/// are called. Until it is initialized, all attempts to access the shared value
114/// using [`get`](SingleThreadValue::get) will return `None`.
115///
116/// # Single-thread Synchronization
117///
118/// It is possible for the same thread to get multiple, shared, references to
119/// the wrapped value concurrently. Users can use interior mutability (e.g.
120/// [`Cell`](core::cell::Cell), [`MapCell`](tock_cells::map_cell::MapCell), or
121/// [`TakeCell`](tock_cells::take_cell::TakeCell)) to allow obtaining exclusive
122/// mutable access.
123///
124/// # Guaranteeing Single-Thread Access
125///
126/// [`SingleThreadValue`] is safe because it guarantees that the contained value
127/// is only ever made accessible to the same thread from which it originated. To
128/// do this, [`SingleThreadValue`] inspects the currently running thread on
129/// every access to the wrapped value. If the active thread is different than
130/// the original thread to which the [`SingleThreadValue`] is bound, then the
131/// caller will not be able to access the value.
132///
133/// This requires that the system provide a correct implementation of
134/// [`ThreadIdProvider`] to identify the currently executing thread. Internally,
135/// [`SingleThreadValue`] uses the [`ThreadIdProvider::running_thread_id`]
136/// function to identify the current thread and compares it against the thread
137/// ID that the contained value is bound to.
138//
139// # Implementation Trade-Offs
140//
141// Correctly implementing a type which can be safely shared within a single
142// thread requires balancing the following trade-offs:
143//
144// 1. Automated enforcement (either by the compiler or at runtime) vs.
145// programmer-checked correctness.
146// 2. Runtime overhead vs. compile-time checks.
147// 3. Simplicity for users vs. easy-to-make mistakes.
148//
149// Ideally, the guarantees this type provides would be verified at compile time
150// and be simple for users to use. However, as of July 2025, we don't know how
151// to realistically meet those goals.
152//
153// This approach first chooses to have automated enforcement rather than have
154// correctness (and avoiding unsoundness) based only on carefully written code
155// and scrutiny during code reviews. This is generally consistent with the Tock
156// ethos with using Rust and APIs to enforce correctness, even if the check
157// occurs at runtime.
158//
159// To implement the automated check, this type uses runtime checks. We don't
160// know a realistic way to move those checks to compile time.
161//
162// One downside to these decisions is the need to bind the value to a thread
163// _after_ the type is created. While this is conceptually similar to providing
164// a callback client after an object is constructed, which is widely used in
165// Tock, forgetting this operation will lead to the runtime check always failing
166// and will break the desired functionality of using the wrapped value.
167// However, passing in the type later is needed because the thread identifier is
168// likely not available where users want to construct this type.
169//
170// Ultimately, these trade-offs, runtime checks and an interface where missing a
171// call leads to failures, were deemed acceptable and worth the upside
172// (guaranteed soundness). In part, this is because this type should be used and
173// accessed sparingly within Tock. The complexity of creating this type stems
174// from its general risky-ness: enabling sharing static global variables. While
175// necessary for certain use cases within Tock, this should not be used lightly.
176pub struct SingleThreadValue<T> {
177 /// The contained value, made accessible to a single thread only.
178 ///
179 /// To avoid imposing a constraint of `T: Send`, this value is not populated
180 /// when the [`SingleThreadValue`] is constructed. It is instead initialized
181 /// by moving a value originating from the same thread that the
182 /// `SingleThreadValue` is ultimately bound to, within the
183 /// `bind_to_thread()` function.
184 value: UnsafeCell<MaybeUninit<T>>,
185
186 /// Shared atomic state to indicate whether this type is already bound to a
187 /// particular thread, or in the process of being bound to a particular
188 /// thread. Assumes values of [`BoundToThreadStage`]. Consider that type's
189 /// documentation for how the `bound_to_thread` value is used.
190 bound_to_thread: AtomicUsize,
191
192 /// Context used to determine which thread ID this type is bound to, and how
193 /// to determine the currently running thread ID.
194 ///
195 /// This value must only be used in accordance with the rules around
196 /// [`BoundToThreadStage`]. Consider that type's documentation for more
197 /// information. Whether this value is initialized, and when it is safe to
198 /// read and write depend on the value of `bound_to_thread`.
199 thread_id_and_fn: UnsafeCell<MaybeUninit<(fn() -> usize, usize)>>,
200}
201
202/// Mark that [`SingleThreadValue`] is [`Sync`] to enable multiple accesses.
203///
204/// SAFETY: This is safe because [`SingleThreadValue`] enforces that the shared value
205/// is only ever accessed from the same thread it originated from.
206unsafe impl<T> Sync for SingleThreadValue<T> {}
207
208impl<T> SingleThreadValue<T> {
209 /// Create a [`SingleThreadValue`].
210 ///
211 /// Note that the `SingleThreadValue` will initially be uninitialized. It
212 /// must first be bound to a particular thread, which will initialize with a
213 /// value originating from that thread, using the
214 /// `bind_to_thread` or
215 /// [`bind_to_thread_unsafe`](SingleThreadValue::bind_to_thread_unsafe)
216 /// methods.
217 pub const fn new() -> Self {
218 Self {
219 value: UnsafeCell::new(MaybeUninit::uninit()),
220 bound_to_thread: AtomicUsize::new(BoundToThreadStage::Unbound as usize),
221 thread_id_and_fn: UnsafeCell::new(MaybeUninit::uninit()),
222 }
223 }
224
225 /// Initialize this [`SingleThreadValue`] and bind it the currently running
226 /// thread.
227 ///
228 /// If this [`SingleThreadValue`] is not already bound to a thread, or if it
229 /// is not currently in the process of binding to a thread, then this binds
230 /// the [`SingleThreadValue`] to the current thread.
231 ///
232 /// It further records the [`ThreadIdProvider::running_thread_id`] function
233 /// reference, and uses this function to determine the currently running
234 /// thread for any future queries.
235 ///
236 /// Returns `Ok(())` if this invocation successfully bound the value to the
237 /// current thread. Otherwise, if the value was already bound to this same
238 /// or another thread, or is concurrently being bound to a thread, it
239 /// returns `Err(T)`, returning the supplied value.
240 ///
241 /// This method requires the target to support atomic operations
242 /// (namely, `compare_exchange`) on `usize`-sized values, and thus
243 /// relies on the `cfg(target_has_atomic = "ptr")` conditional.
244 #[cfg(target_has_atomic = "ptr")]
245 pub fn bind_to_thread<P: ThreadIdProvider>(&self, value: T) -> Result<(), T> {
246 // For the check whether we're already bound to a thread, `Relaxed`
247 // ordering is fine: we don't actually care about the value in
248 // `thread_id_and_fn`, and don't need previous writes to it to be
249 // visible to this thread.
250 //
251 // Perform a compare-exchange on the `bound_to_thread` value. If this
252 // operation is successful, the [`SingleThreadValue`] was in the
253 // `Unbound` stage, but is now in the `Binding` stage. This "reserves"
254 // to be initialized: other concurrent accesses observing a `Binding`
255 // stage must not assume that `thread_id_and_fn` is initialized, but
256 // also will not attempt to being initialization themselves:
257 if self
258 .bound_to_thread
259 .compare_exchange(
260 // Expected current value:
261 BoundToThreadStage::Unbound as usize,
262 // New value:
263 BoundToThreadStage::Binding as usize,
264 // Success memory ordering:
265 Ordering::Relaxed,
266 // Failure memory ordering:
267 Ordering::Relaxed,
268 )
269 .is_err()
270 {
271 return Err(value);
272 }
273
274 // Great, we have reserved the value for initialization!
275 //
276 // Write the current thread ID, and the function symbol used to query
277 // the currently running thread ID.
278 let ptr_thread_id_and_fn = self.thread_id_and_fn.get();
279
280 // SAFETY: We must ensure that there are no (mutable) aliases or concurrent
281 // reads or writes of the thread_id_and_fn value.
282 //
283 // This value is accessed in three functions: `bind_to_thread_unsafe`,
284 // `bind_to_thread`, and `bound_to_current_thread`:
285 //
286 // - `bind_to_thread_unsafe`: Callers of that function guarantee that
287 // there are no concurrent invocations of it together with our
288 // current function, `bind_to_thread`. Thus, no concurrent call to
289 // that other function can hold an alias, or perform a read or write
290 // of this value.
291 //
292 // - `bind_to_thread`: Before obtaining a reference to the
293 // `thread_id_and_fn` value or reading/writing it, this function
294 // performs a compare-exchange operation on the `bound_to_thread`
295 // value, ensuring that it is currently `Unbound`, and atomtically
296 // transitioning it towards `Binding`.
297 //
298 // Our own compare-exchange operation on this value was successful. As
299 // `Binding` cannot transition back to `Unbound`, there can only be a
300 // single `bind_to_thread` call to successfully perform this
301 // compare-exchange operation per[`SingleThreadValue`].
302 //
303 // If another concurrent call had performed this compare-exchange
304 // successfully, our own operation would have failed. Given that we
305 // successfully performed this operation, all other concurrent calls
306 // to this function must fail this operation instead, and thus will
307 // not take this if-branch, and therefore will not attempt to access
308 // the `thread_id_and_fn` value.
309 //
310 // - `bound_to_current_thread`: This function is allowed to run
311 // concurrently with `bind_to_thread`. However, it only accesses the
312 // `thread_id_and_fn` value when the `bound_to_thread` atomic
313 // contains `Bound`.
314 //
315 // The compare and swap has transitioned this value from `Unbound` to
316 // `Binding`, and no concurrent call can further *modify*
317 // `bound_to_thread` other than our own function instance. This
318 // currently running function will only transition the
319 // `bound_to_thread` value from `Binding` to `Bound` once it has
320 // initialized `thread_id_and_fn` and all references to it cease to
321 // exist. Thus, no concurrent calls to `bound_to_current_thread` will
322 // read the `thread_id_and_fn` before that point.
323 //
324 // Hence this operation is sound.
325 unsafe {
326 *ptr_thread_id_and_fn =
327 MaybeUninit::new((P::running_thread_id, P::running_thread_id()));
328 }
329
330 // Initialize the contained value, constructed on the same (currently
331 // running) thread that we are binding the `SingleThreadValue` to. This
332 // avoids a requirement of `T: Send`.
333 //
334 // SAFETY: We are the only thread with access to `self.value` going forward, and
335 // this is the first time that this value is being accessed (as we're
336 // initializing it). Therefore, we can safely dereference a mutable
337 // (unique) pointer to this value:
338 unsafe {
339 *self.value.get() = MaybeUninit::new(value);
340 }
341
342 // When initializing the `SingleThreadValue`, we must use `Release`
343 // ordering on the `bound_to_thread` store. This ensures that any
344 // subsequent atomic load of this value with at least `Acquire`
345 // ordering constraints will observe the previous write to
346 // `thread_id_and_fn`).
347 self.bound_to_thread
348 .store(BoundToThreadStage::Bound as usize, Ordering::Release);
349
350 // We have successfully bound this `SingleThreadValue` to the
351 // currently running thread:
352 Ok(())
353 }
354
355 /// Initialize this [`SingleThreadValue`] and bind it to the currently
356 /// running thread.
357 ///
358 /// If this [`SingleThreadValue`] is not already bound to a thread, or if it
359 /// is not currently in the process of binding to a thread, then this binds
360 /// the [`SingleThreadValue`] to the current thread.
361 ///
362 /// It further records the [`ThreadIdProvider::running_thread_id`] function
363 /// reference, and uses this function to determine the currently running
364 /// thread for any future queries.
365 ///
366 /// Returns `Ok(())` if this invocation successfully bound the value to the
367 /// current thread. Otherwise, if the value was already bound to this same
368 /// or another thread, it returns `Err(T)`, returning the supplied value.
369 ///
370 /// This method is `unsafe`, and does not require the target to support
371 /// atomic operations (namely, `compare_exchange`) on `usize`-sized values.
372 ///
373 /// # Safety
374 ///
375 /// Callers of this function must ensure that this function is never called
376 /// concurrently with other calls to
377 /// `bind_to_thread` or
378 /// [`bind_to_thread_unsafe`](SingleThreadValue::bind_to_thread_unsafe) on
379 /// the same [`SingleThreadValue`] instance.
380 pub unsafe fn bind_to_thread_unsafe<P: ThreadIdProvider>(&self, value: T) -> Result<(), T> {
381 // For the check whether we're already bound to a thread, `Relaxed`
382 // ordering is fine: we don't actually care about the value in
383 // `thread_id_and_fn`, and don't need previous writes to it to be
384 // visible to this thread.
385 if self.bound_to_thread.load(Ordering::Relaxed) != BoundToThreadStage::Unbound as usize {
386 // This value is already bound to a thread
387 return Err(value);
388 }
389
390 // Write the current thread ID, and the function symbol used to
391 // query the currently running thread ID.
392 let ptr_thread_id_and_fn = self.thread_id_and_fn.get();
393
394 // SAFETY: We must ensure that there are no (mutable) aliases or concurrent
395 // reads or writes of the `thread_id_and_fn` value.
396 //
397 // This value is accessed in three functions: `bind_to_thread`,
398 // `bind_to_thread_unsafe`, and `bound_to_current_thread`:
399 //
400 // - `bind_to_thread` & `bind_to_thread_unsafe`: Callers of this current
401 // function guarantee that there are no concurrent invocations of
402 // either `bind_to_thread` or `bind_to_thread_unsafe` on the same
403 // `SingleThreadValue` object. Thus, no concurrent call to either of
404 // these functions can hold an alias, or perform a read or write of
405 // the `thread_id_and_fn` value.
406 //
407 // - `bound_to_current_thread`: This function is allowed to run
408 // concurrently with `bind_to_thread`. However, it only accesses this
409 // value when the `bound_to_thread` atomic contains `Bound`.
410 // `bound_to_current_thread` never writes to `bound_to_thread`.
411 //
412 // This current function has, before taking this if-branch, checked
413 // that `bound_to_thread` is currently `Unbound`, and will continue
414 // to be `Unbound` for the duration of the write to
415 // `thread_id_and_fn`, as there are no concurrent calls to
416 // `bind_to_thread` or `bind_to_thread_unsafe`. It only transitions
417 // `bound_to_thread` to `Bound` after completing the initialization
418 // of `thread_id_and_fn` and all references to that value cease to
419 // exist.
420 //
421 // Thus, this operation is sound.
422 unsafe {
423 *ptr_thread_id_and_fn =
424 MaybeUninit::new((P::running_thread_id, P::running_thread_id()));
425 }
426
427 // Initialize the contained value, constructed on the same (currently
428 // running) thread that we are binding the `SingleThreadValue` to. This
429 // avoids a requirement of `T: Send`.
430 //
431 // SAFETY: We are the only thread with access to `self.value` going forward, and
432 // this is the first time that this value is being accessed (as we're
433 // initializing it). Therefore, we can safely dereference a mutable
434 // (unique) pointer to this value:
435 unsafe {
436 *self.value.get() = MaybeUninit::new(value);
437 }
438
439 // When initializing the `SingleThreadValue`, we must use `Release`
440 // ordering on the `bound_to_thread` store. This ensures that any
441 // subsequent atomic load of this value with at least `Acquire`
442 // ordering constraints will observe the previous write to
443 // `thread_id_and_fn`).
444 self.bound_to_thread
445 .store(BoundToThreadStage::Bound as usize, Ordering::Release);
446
447 // We have successfully bound this `SingleThreadValue` to the
448 // currently running thread:
449 Ok(())
450 }
451
452 /// Check whether this `SingleThreadValue` instance is bound to the
453 /// currently running thread ID.
454 ///
455 /// Returns `true` if the value is bound to the thread that is currently
456 /// running (as determined by the implementation of `ThreadIdProvider` used
457 /// in `bind_to_thread` or
458 /// [`bind_to_thread_unsafe`](SingleThreadValue::bind_to_thread_unsafe)).
459 /// Returns `false` when a different thread is executing, when it is not
460 /// bound to any thread yet, or currently in the process of being bound to a
461 /// thread.
462 pub fn bound_to_current_thread(&self) -> bool {
463 // This function loads the `thread_id_and_fn` field, written by either
464 // `bind_to_thread` or `bind_to_thread_unsafe` before setting
465 // `bound_to_thread` to `Bound` with `Release` ordering constraints. To
466 // make those writes visible, we need to load the `bound_to_thread`
467 // value with at least `Acquire` ordering constraints:
468 if self.bound_to_thread.load(Ordering::Acquire) != BoundToThreadStage::Bound as usize {
469 // The `SingleThreadValue` value is not yet bound to any thread:
470 return false;
471 }
472
473 // The `SingleThreadValue` value is bound to _a_ thread, check whether
474 // it is the currently running thread:
475 let ptr_thread_id_and_fn: *mut MaybeUninit<(fn() -> usize, usize)> =
476 self.thread_id_and_fn.get();
477
478 let maybe_thread_id_and_fn: *const MaybeUninit<(fn() -> usize, usize)> =
479 ptr_thread_id_and_fn.cast_const();
480 // SAFETY: We must ensure that there are no (mutable) aliases or concurrent
481 // reads or writes of the thread_id_and_fn value.
482 //
483 // This value is accessed in three functions: `bind_to_thread`,
484 // `bind_to_thread_unsafe`, and `bound_to_current_thread`:
485 //
486 // - `bind_to_thread` / `bind_to_thread_unsafe`: Before creating a
487 // reference to, reading from, or writing to the `bound_to_thread`
488 // value, both functions check that `bound_to_thread` is not already
489 // set to `Bound`. However, when reaching if-branch in this current
490 // function, we have observed that `bound_to_thread` is set to
491 // `Bound`. The state of `Bound` cannot be transitioned out of. Thus,
492 // `bound_to_thread` will never be written again.
493 //
494 // `bound_to_thread` is only ever set to `Bound`, *after*
495 // `thread_id_and_fn` has been initialized, and all references to
496 // `thread_id_and_fn` cease to exist.
497 //
498 // When reaching this point, neither `bind_to_thread` nor
499 // `bind_to_thread_unsafe` will ever read from, write to, or create a
500 // reference to `thread_id_and_fn` again.
501 //
502 // - `bound_to_current_thread`: This function is allowed to run
503 // concurrently with other calls to `bound_to_current_thread`.
504 //
505 // However, this function only creates shared / immutable references
506 // to this value that are never written. Multiple shared references
507 // to this value are allowed to exist, so long as they are not
508 // aliased by another exclusive / mutable reference, and the
509 // underlying memory is not modified otherwise.
510 //
511 // The only functions writing to `thread_id_and_fn` are
512 // `bind_to_thread` and `bind_to_thread_unsafe`. As stated above,
513 // when reaching this point, neither functions will ever write to
514 // `thread_id_and_fn` again, and all of their internal references
515 // have ceased to exist.
516 //
517 // Thus, this operation is sound.
518 let maybe_thread_id_and_fn: &MaybeUninit<(fn() -> usize, usize)> =
519 unsafe { &*maybe_thread_id_and_fn };
520
521 // SAFETY: Both `bind_to_thread` and `bind_to_thread_unsafe` are guaranteed to
522 // have initialized `thread_id_and_fn` *before* setting
523 // `bound_to_thread` to `Bound` with `Release` ordering constraints.
524 //
525 // In this if-branch, `bound_to_thread` has been observed to be `Bound`,
526 // a state that cannot be transitioned out of. We have loaded this
527 // value with `Acquire` ordering constraints, making all values written
528 // by other threads before a write to `bound_to_thread` with `Release`
529 // constraints visible to this thread.
530 //
531 // Thus, we can safely rely on `thread_id_and_fn` to be initialized:
532 let (running_thread_id_fn, bound_thread_id) =
533 unsafe { maybe_thread_id_and_fn.assume_init() };
534
535 // Finally, check if the thread this `SingleThreadValue` is bound to
536 // is the running thread ID:
537 bound_thread_id == running_thread_id_fn()
538 }
539
540 /// Obtain a reference to the contained value.
541 ///
542 /// This function checks whether the [`SingleThreadValue`] is bound to the
543 /// currently running thread and, if so, returns a shared / immutable
544 /// reference to its contained value.
545 pub fn get(&self) -> Option<&T> {
546 if self.bound_to_current_thread() {
547 // SAFETY: When `self.bound_to_current_thread()` returns true, we know that
548 // `self.value` is initialized, and that the value belongs to and is
549 // accessible to the currently running thread. We can safely
550 // construct a reference to it.
551 Some(unsafe { (&*self.value.get()).assume_init_ref() })
552 } else {
553 None
554 }
555 }
556}