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 | |
16 | use crate::cell::RefCell; |
17 | use crate::ptr; |
18 | use crate::sys_common::thread_local_key::StaticKey; |
19 | |
20 | pub 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 | |