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}