1//! Thread-local destructor
2//!
3//! Besides thread-local "keys" (pointer-sized non-addressable thread-local store
4//! with an associated destructor), many platforms also provide thread-local
5//! destructors that are not associated with any particular data. These are
6//! often more efficient.
7//!
8//! This module provides a fallback implementation for that interface, based
9//! on the less efficient thread-local "keys". Each platform provides
10//! a `thread_local_dtor` module which will either re-export the fallback,
11//! or implement something more efficient.
12
13#![unstable(feature = "thread_local_internals", issue = "none")]
14#![allow(dead_code)]
15
16use crate::cell::RefCell;
17use crate::ptr;
18use crate::sys_common::thread_local_key::StaticKey;
19
20pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
21 // The fallback implementation uses a vanilla OS-based TLS key to track
22 // the list of destructors that need to be run for this thread. The key
23 // then has its own destructor which runs all the other destructors.
24 //
25 // The destructor for DTORS is a little special in that it has a `while`
26 // loop to continuously drain the list of registered destructors. It
27 // *should* be the case that this loop always terminates because we
28 // provide the guarantee that a TLS key cannot be set after it is
29 // flagged for destruction.
30
31 static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
32 // FIXME(joboet): integrate RefCell into pointer to avoid infinite recursion
33 // when the global allocator tries to register a destructor and just panic
34 // instead.
35 type List = RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>>;
36 if DTORS.get().is_null() {
37 let v: Box<List> = Box::new(RefCell::new(Vec::new()));
38 DTORS.set(Box::into_raw(v) as *mut u8);
39 }
40 let list = &*(DTORS.get() as *const List);
41 match list.try_borrow_mut() {
42 Ok(mut dtors) => dtors.push((t, dtor)),
43 Err(_) => rtabort!("global allocator may not use TLS"),
44 }
45
46 unsafe extern "C" fn run_dtors(mut ptr: *mut u8) {
47 while !ptr.is_null() {
48 let list = Box::from_raw(ptr as *mut List).into_inner();
49 for (ptr, dtor) in list.into_iter() {
50 dtor(ptr);
51 }
52 ptr = DTORS.get();
53 DTORS.set(ptr::null_mut());
54 }
55 }
56}
57