| 1 | use crate::cell::{Cell, UnsafeCell}; |
| 2 | use crate::ptr::{self, drop_in_place}; |
| 3 | use crate::sys::thread_local::{abort_on_dtor_unwind, destructors}; |
| 4 | |
| 5 | #[derive (Clone, Copy)] |
| 6 | enum State { |
| 7 | Initial, |
| 8 | Alive, |
| 9 | Destroyed, |
| 10 | } |
| 11 | |
| 12 | #[allow (missing_debug_implementations)] |
| 13 | #[repr (C)] |
| 14 | pub struct Storage<T> { |
| 15 | // This field must be first, for correctness of `#[rustc_align_static]` |
| 16 | val: UnsafeCell<T>, |
| 17 | state: Cell<State>, |
| 18 | } |
| 19 | |
| 20 | impl<T> Storage<T> { |
| 21 | pub const fn new(val: T) -> Storage<T> { |
| 22 | Storage { state: Cell::new(State::Initial), val: UnsafeCell::new(val) } |
| 23 | } |
| 24 | |
| 25 | /// Gets a pointer to the TLS value. If the TLS variable has been destroyed, |
| 26 | /// a null pointer is returned. |
| 27 | /// |
| 28 | /// The resulting pointer may not be used after thread destruction has |
| 29 | /// occurred. |
| 30 | /// |
| 31 | /// # Safety |
| 32 | /// The `self` reference must remain valid until the TLS destructor is run. |
| 33 | #[inline ] |
| 34 | pub unsafe fn get(&self) -> *const T { |
| 35 | match self.state.get() { |
| 36 | State::Alive => self.val.get(), |
| 37 | State::Destroyed => ptr::null(), |
| 38 | State::Initial => unsafe { self.initialize() }, |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | #[cold ] |
| 43 | unsafe fn initialize(&self) -> *const T { |
| 44 | // Register the destructor |
| 45 | |
| 46 | // SAFETY: |
| 47 | // The caller guarantees that `self` will be valid until thread destruction. |
| 48 | unsafe { |
| 49 | destructors::register(ptr::from_ref(self).cast_mut().cast(), destroy::<T>); |
| 50 | } |
| 51 | |
| 52 | self.state.set(State::Alive); |
| 53 | self.val.get() |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | /// Transition an `Alive` TLS variable into the `Destroyed` state, dropping its |
| 58 | /// value. |
| 59 | /// |
| 60 | /// # Safety |
| 61 | /// * Must only be called at thread destruction. |
| 62 | /// * `ptr` must point to an instance of `Storage` with `Alive` state and be |
| 63 | /// valid for accessing that instance. |
| 64 | unsafe extern "C" fn destroy<T>(ptr: *mut u8) { |
| 65 | // Print a nice abort message if a panic occurs. |
| 66 | abort_on_dtor_unwind(|| { |
| 67 | let storage: &Storage = unsafe { &*(ptr as *const Storage<T>) }; |
| 68 | // Update the state before running the destructor as it may attempt to |
| 69 | // access the variable. |
| 70 | storage.state.set(val:State::Destroyed); |
| 71 | unsafe { |
| 72 | drop_in_place(to_drop:storage.val.get()); |
| 73 | } |
| 74 | }) |
| 75 | } |
| 76 | |