Skip to main content

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
205///
206/// This is safe because [`SingleThreadValue`] enforces that the shared value
207/// is only ever accessed from the same thread it originated from.
208unsafe impl<T> Sync for SingleThreadValue<T> {}
209
210impl<T> SingleThreadValue<T> {
211    /// Create a [`SingleThreadValue`].
212    ///
213    /// Note that the `SingleThreadValue` will initially be uninitialized. It
214    /// must first be bound to a particular thread, which will initialize with a
215    /// value originating from that thread, using the
216    /// `bind_to_thread` or
217    /// [`bind_to_thread_unsafe`](SingleThreadValue::bind_to_thread_unsafe)
218    /// methods.
219    pub const fn new() -> Self {
220        Self {
221            value: UnsafeCell::new(MaybeUninit::uninit()),
222            bound_to_thread: AtomicUsize::new(BoundToThreadStage::Unbound as usize),
223            thread_id_and_fn: UnsafeCell::new(MaybeUninit::uninit()),
224        }
225    }
226
227    /// Initialize this [`SingleThreadValue`] and bind it the currently running
228    /// thread.
229    ///
230    /// If this [`SingleThreadValue`] is not already bound to a thread, or if it
231    /// is not currently in the process of binding to a thread, then this binds
232    /// the [`SingleThreadValue`] to the current thread.
233    ///
234    /// It further records the [`ThreadIdProvider::running_thread_id`] function
235    /// reference, and uses this function to determine the currently running
236    /// thread for any future queries.
237    ///
238    /// Returns `Ok(())` if this invocation successfully bound the value to the
239    /// current thread. Otherwise, if the value was already bound to this same
240    /// or another thread, or is concurrently being bound to a thread, it
241    /// returns `Err(T)`, returning the supplied value.
242    ///
243    /// This method requires the target to support atomic operations
244    /// (namely, `compare_exchange`) on `usize`-sized values, and thus
245    /// relies on the `cfg(target_has_atomic = "ptr")` conditional.
246    #[cfg(target_has_atomic = "ptr")]
247    pub fn bind_to_thread<P: ThreadIdProvider>(&self, value: T) -> Result<(), T> {
248        // For the check whether we're already bound to a thread, `Relaxed`
249        // ordering is fine: we don't actually care about the value in
250        // `thread_id_and_fn`, and don't need previous writes to it to be
251        // visible to this thread.
252        //
253        // Perform a compare-exchange on the `bound_to_thread` value. If this
254        // operation is successful, the [`SingleThreadValue`] was in the
255        // `Unbound` stage, but is now in the `Binding` stage. This "reserves"
256        // to be initialized: other concurrent accesses observing a `Binding`
257        // stage must not assume that `thread_id_and_fn` is initialized, but
258        // also will not attempt to being initialization themselves:
259        if self
260            .bound_to_thread
261            .compare_exchange(
262                // Expected current value:
263                BoundToThreadStage::Unbound as usize,
264                // New value:
265                BoundToThreadStage::Binding as usize,
266                // Success memory ordering:
267                Ordering::Relaxed,
268                // Failure memory ordering:
269                Ordering::Relaxed,
270            )
271            .is_err()
272        {
273            return Err(value);
274        }
275
276        // Great, we have reserved the value for initialization!
277        //
278        // Write the current thread ID, and the function symbol used to query
279        // the currently running thread ID.
280        let ptr_thread_id_and_fn = self.thread_id_and_fn.get();
281
282        // # Safety
283        //
284        // We must ensure that there are no (mutable) aliases or concurrent
285        // reads or writes of the thread_id_and_fn value.
286        //
287        // This value is accessed in three functions: `bind_to_thread_unsafe`,
288        // `bind_to_thread`, and `bound_to_current_thread`:
289        //
290        // - `bind_to_thread_unsafe`: Callers of that function guarantee that
291        //   there are no concurrent invocations of it together with our
292        //   current function, `bind_to_thread`. Thus, no concurrent call to
293        //   that other function can hold an alias, or perform a read or write
294        //   of this value.
295        //
296        // - `bind_to_thread`: Before obtaining a reference to the
297        //   `thread_id_and_fn` value or reading/writing it, this function
298        //   performs a compare-exchange operation on the `bound_to_thread`
299        //   value, ensuring that it is currently `Unbound`, and atomtically
300        //   transitioning it towards `Binding`.
301        //
302        //   Our own compare-exchange operation on this value was successful. As
303        //   `Binding` cannot transition back to `Unbound`, there can only be a
304        //   single `bind_to_thread` call to successfully perform this
305        //   compare-exchange operation per[`SingleThreadValue`].
306        //
307        //   If another concurrent call had performed this compare-exchange
308        //   successfully, our own operation would have failed. Given that we
309        //   successfully performed this operation, all other concurrent calls
310        //   to this function must fail this operation instead, and thus will
311        //   not take this if-branch, and therefore will not attempt to access
312        //   the `thread_id_and_fn` value.
313        //
314        // - `bound_to_current_thread`: This function is allowed to run
315        //   concurrently with `bind_to_thread`. However, it only accesses the
316        //   `thread_id_and_fn` value when the `bound_to_thread` atomic
317        //   contains `Bound`.
318        //
319        //   The compare and swap has transitioned this value from `Unbound` to
320        //   `Binding`, and no concurrent call can further *modify*
321        //   `bound_to_thread` other than our own function instance. This
322        //   currently running function will only transition the
323        //   `bound_to_thread` value from `Binding` to `Bound` once it has
324        //   initialized `thread_id_and_fn` and all references to it cease to
325        //   exist. Thus, no concurrent calls to `bound_to_current_thread` will
326        //   read the `thread_id_and_fn` before that point.
327        //
328        // Hence this operation is sound.
329        unsafe {
330            *ptr_thread_id_and_fn =
331                MaybeUninit::new((P::running_thread_id, P::running_thread_id()));
332        }
333
334        // Initialize the contained value, constructed on the same (currently
335        // running) thread that we are binding the `SingleThreadValue` to. This
336        // avoids a requirement of `T: Send`.
337        //
338        // # Safety
339        //
340        // We are the only thread with access to `self.value` going forward, and
341        // this is the first time that this value is being accessed (as we're
342        // initializing it). Therefore, we can safely dereference a mutable
343        // (unique) pointer to this value:
344        unsafe {
345            *self.value.get() = MaybeUninit::new(value);
346        }
347
348        // When initializing the `SingleThreadValue`, we must use `Release`
349        // ordering on the `bound_to_thread` store. This ensures that any
350        // subsequent atomic load of this value with at least `Acquire`
351        // ordering constraints will observe the previous write to
352        // `thread_id_and_fn`).
353        self.bound_to_thread
354            .store(BoundToThreadStage::Bound as usize, Ordering::Release);
355
356        // We have successfully bound this `SingleThreadValue` to the
357        // currently running thread:
358        Ok(())
359    }
360
361    /// Initialize this [`SingleThreadValue`] and bind it to the currently
362    /// running thread.
363    ///
364    /// If this [`SingleThreadValue`] is not already bound to a thread, or if it
365    /// is not currently in the process of binding to a thread, then this binds
366    /// the [`SingleThreadValue`] to the current thread.
367    ///
368    /// It further records the [`ThreadIdProvider::running_thread_id`] function
369    /// reference, and uses this function to determine the currently running
370    /// thread for any future queries.
371    ///
372    /// Returns `Ok(())` if this invocation successfully bound the value to the
373    /// current thread. Otherwise, if the value was already bound to this same
374    /// or another thread, it returns `Err(T)`, returning the supplied value.
375    ///
376    /// This method is `unsafe`, and does not require the target to support
377    /// atomic operations (namely, `compare_exchange`) on `usize`-sized values.
378    ///
379    /// # Safety
380    ///
381    /// Callers of this function must ensure that this function is never called
382    /// concurrently with other calls to
383    /// `bind_to_thread` or
384    /// [`bind_to_thread_unsafe`](SingleThreadValue::bind_to_thread_unsafe) on
385    /// the same [`SingleThreadValue`] instance.
386    pub unsafe fn bind_to_thread_unsafe<P: ThreadIdProvider>(&self, value: T) -> Result<(), T> {
387        // For the check whether we're already bound to a thread, `Relaxed`
388        // ordering is fine: we don't actually care about the value in
389        // `thread_id_and_fn`, and don't need previous writes to it to be
390        // visible to this thread.
391        if self.bound_to_thread.load(Ordering::Relaxed) != BoundToThreadStage::Unbound as usize {
392            // This value is already bound to a thread
393            return Err(value);
394        }
395
396        // Write the current thread ID, and the function symbol used to
397        // query the currently running thread ID.
398        let ptr_thread_id_and_fn = self.thread_id_and_fn.get();
399
400        // # Safety
401        //
402        // We must ensure that there are no (mutable) aliases or concurrent
403        // reads or writes of the `thread_id_and_fn` value.
404        //
405        // This value is accessed in three functions: `bind_to_thread`,
406        // `bind_to_thread_unsafe`, and `bound_to_current_thread`:
407        //
408        // - `bind_to_thread` & `bind_to_thread_unsafe`: Callers of this current
409        //   function guarantee that there are no concurrent invocations of
410        //   either `bind_to_thread` or `bind_to_thread_unsafe` on the same
411        //   `SingleThreadValue` object. Thus, no concurrent call to either of
412        //   these functions can hold an alias, or perform a read or write of
413        //   the `thread_id_and_fn` value.
414        //
415        // - `bound_to_current_thread`: This function is allowed to run
416        //   concurrently with `bind_to_thread`. However, it only accesses this
417        //   value when the `bound_to_thread` atomic contains `Bound`.
418        //   `bound_to_current_thread` never writes to `bound_to_thread`.
419        //
420        //   This current function has, before taking this if-branch, checked
421        //   that `bound_to_thread` is currently `Unbound`, and will continue
422        //   to be `Unbound` for the duration of the write to
423        //   `thread_id_and_fn`, as there are no concurrent calls to
424        //   `bind_to_thread` or `bind_to_thread_unsafe`. It only transitions
425        //   `bound_to_thread` to `Bound` after completing the initialization
426        //   of `thread_id_and_fn` and all references to that value cease to
427        //   exist.
428        //
429        // Thus, this operation is sound.
430        unsafe {
431            *ptr_thread_id_and_fn =
432                MaybeUninit::new((P::running_thread_id, P::running_thread_id()));
433        }
434
435        // Initialize the contained value, constructed on the same (currently
436        // running) thread that we are binding the `SingleThreadValue` to. This
437        // avoids a requirement of `T: Send`.
438        //
439        // # Safety
440        //
441        // We are the only thread with access to `self.value` going forward, and
442        // this is the first time that this value is being accessed (as we're
443        // initializing it). Therefore, we can safely dereference a mutable
444        // (unique) pointer to this value:
445        unsafe {
446            *self.value.get() = MaybeUninit::new(value);
447        }
448
449        // When initializing the `SingleThreadValue`, we must use `Release`
450        // ordering on the `bound_to_thread` store. This ensures that any
451        // subsequent atomic load of this value with at least `Acquire`
452        // ordering constraints will observe the previous write to
453        // `thread_id_and_fn`).
454        self.bound_to_thread
455            .store(BoundToThreadStage::Bound as usize, Ordering::Release);
456
457        // We have successfully bound this `SingleThreadValue` to the
458        // currently running thread:
459        Ok(())
460    }
461
462    /// Check whether this `SingleThreadValue` instance is bound to the
463    /// currently running thread ID.
464    ///
465    /// Returns `true` if the value is bound to the thread that is currently
466    /// running (as determined by the implementation of `ThreadIdProvider` used
467    /// in `bind_to_thread` or
468    /// [`bind_to_thread_unsafe`](SingleThreadValue::bind_to_thread_unsafe)).
469    /// Returns `false` when a different thread is executing, when it is not
470    /// bound to any thread yet, or currently in the process of being bound to a
471    /// thread.
472    pub fn bound_to_current_thread(&self) -> bool {
473        // This function loads the `thread_id_and_fn` field, written by either
474        // `bind_to_thread` or `bind_to_thread_unsafe` before setting
475        // `bound_to_thread` to `Bound` with `Release` ordering constraints. To
476        // make those writes visible, we need to load the `bound_to_thread`
477        // value with at least `Acquire` ordering constraints:
478        if self.bound_to_thread.load(Ordering::Acquire) != BoundToThreadStage::Bound as usize {
479            // The `SingleThreadValue` value is not yet bound to any thread:
480            return false;
481        }
482
483        // The `SingleThreadValue` value is bound to _a_ thread, check whether
484        // it is the currently running thread:
485        let ptr_thread_id_and_fn: *mut MaybeUninit<(fn() -> usize, usize)> =
486            self.thread_id_and_fn.get();
487
488        // # Safety
489        //
490        // We must ensure that there are no (mutable) aliases or concurrent
491        // reads or writes of the thread_id_and_fn value.
492        //
493        // This value is accessed in three functions: `bind_to_thread`,
494        // `bind_to_thread_unsafe`, and `bound_to_current_thread`:
495        //
496        // - `bind_to_thread` / `bind_to_thread_unsafe`: Before creating a
497        //   reference to, reading from, or writing to the `bound_to_thread`
498        //   value, both functions check that `bound_to_thread` is not already
499        //   set to `Bound`. However, when reaching if-branch in this current
500        //   function, we have observed that `bound_to_thread` is set to
501        //   `Bound`. The state of `Bound` cannot be transitioned out of. Thus,
502        //   `bound_to_thread` will never be written again.
503        //
504        //   `bound_to_thread` is only ever set to `Bound`, *after*
505        //   `thread_id_and_fn` has been initialized, and all references to
506        //   `thread_id_and_fn` cease to exist.
507        //
508        //   When reaching this point, neither `bind_to_thread` nor
509        //   `bind_to_thread_unsafe` will ever read from, write to, or create a
510        //   reference to `thread_id_and_fn` again.
511        //
512        // - `bound_to_current_thread`: This function is allowed to run
513        //   concurrently with other calls to `bound_to_current_thread`.
514        //
515        //   However, this function only creates shared / immutable references
516        //   to this value that are never written. Multiple shared references
517        //   to this value are allowed to exist, so long as they are not
518        //   aliased by another exclusive / mutable reference, and the
519        //   underlying memory is not modified otherwise.
520        //
521        //   The only functions writing to `thread_id_and_fn` are
522        //   `bind_to_thread` and `bind_to_thread_unsafe`. As stated above,
523        //   when reaching this point, neither functions will ever write to
524        //   `thread_id_and_fn` again, and all of their internal references
525        //   have ceased to exist.
526        //
527        // Thus, this operation is sound.
528        let maybe_thread_id_and_fn: *const MaybeUninit<(fn() -> usize, usize)> =
529            ptr_thread_id_and_fn.cast_const();
530        let maybe_thread_id_and_fn: &MaybeUninit<(fn() -> usize, usize)> =
531            unsafe { &*maybe_thread_id_and_fn };
532
533        // # Safety
534        //
535        // Both `bind_to_thread` and `bind_to_thread_unsafe` are guaranteed to
536        // have initialized `thread_id_and_fn` *before* setting
537        // `bound_to_thread` to `Bound` with `Release` ordering constraints.
538        //
539        // In this if-branch, `bound_to_thread` has been observed to be `Bound`,
540        // a state that cannot be transitioned out of. We have loaded this
541        // value with `Acquire` ordering constraints, making all values written
542        // by other threads before a write to `bound_to_thread` with `Release`
543        // constraints visible to this thread.
544        //
545        // Thus, we can safely rely on `thread_id_and_fn` to be initialized:
546        let (running_thread_id_fn, bound_thread_id) =
547            unsafe { maybe_thread_id_and_fn.assume_init() };
548
549        // Finally, check if the thread this `SingleThreadValue` is bound to
550        // is the running thread ID:
551        bound_thread_id == running_thread_id_fn()
552    }
553
554    /// Obtain a reference to the contained value.
555    ///
556    /// This function checks whether the [`SingleThreadValue`] is bound to the
557    /// currently running thread and, if so, returns a shared / immutable
558    /// reference to its contained value.
559    pub fn get(&self) -> Option<&T> {
560        if self.bound_to_current_thread() {
561            // # Safety
562            //
563            // When `self.bound_to_current_thread()` returns true, we know that
564            // `self.value` is initialized, and that the value belongs to and is
565            // accessible to the currently running thread. We can safely
566            // construct a reference to it.
567            Some(unsafe { (&*self.value.get()).assume_init_ref() })
568        } else {
569            None
570        }
571    }
572}