std/sys/thread_local/guard/
apple.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//! macOS allows registering destructors through _tlv_atexit. But since calling
//! it while TLS destructors are running is UB, we still need to keep our own
//! list of destructors.

use crate::cell::Cell;
use crate::ptr;
use crate::sys::thread_local::destructors;

pub fn enable() {
    #[thread_local]
    static REGISTERED: Cell<bool> = Cell::new(false);

    extern "C" {
        fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
    }

    if !REGISTERED.replace(true) {
        // SAFETY: Calling _tlv_atexit while TLS destructors are running is UB.
        // But as run_dtors is only called after being registered, this point
        // cannot be reached from it.
        unsafe {
            _tlv_atexit(run_dtors, ptr::null_mut());
        }
    }

    unsafe extern "C" fn run_dtors(_: *mut u8) {
        unsafe {
            destructors::run();
            crate::rt::thread_cleanup();
        }
    }
}