std/sys/thread_local/guard/
apple.rs

1//! macOS allows registering destructors through _tlv_atexit. But since calling
2//! it while TLS destructors are running is UB, we still need to keep our own
3//! list of destructors.
4
5use crate::cell::Cell;
6use crate::ptr;
7use crate::sys::thread_local::destructors;
8
9pub fn enable() {
10    #[thread_local]
11    static REGISTERED: Cell<bool> = Cell::new(false);
12
13    unsafe extern "C" {
14        fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
15    }
16
17    if !REGISTERED.replace(true) {
18        // SAFETY: Calling _tlv_atexit while TLS destructors are running is UB.
19        // But as run_dtors is only called after being registered, this point
20        // cannot be reached from it.
21        unsafe {
22            _tlv_atexit(run_dtors, ptr::null_mut());
23        }
24    }
25
26    unsafe extern "C" fn run_dtors(_: *mut u8) {
27        unsafe {
28            destructors::run();
29            crate::rt::thread_cleanup();
30        }
31    }
32}