blob: 97356457057761014502ea74885732e75b42b248 [file] [log] [blame]
#![cfg(target_thread_local)]
#![unstable(feature = "thread_local_internals", issue = "none")]
// Simplify dtor registration by using a list of destructors.
use super::{abi, itron::task};
use crate::cell::Cell;
use crate::ptr;
#[thread_local]
static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
if DTORS.get().is_null() {
let tid = task::current_task_id_aborting();
let v: Box<List> = box Vec::new();
DTORS.set(Box::into_raw(v));
// Register `tls_dtor` to make sure the TLS destructors are called
// for tasks created by other means than `std::thread`
unsafe { abi::SOLID_TLS_AddDestructor(tid as i32, tls_dtor) };
}
let list: &mut List = unsafe { &mut *DTORS.get() };
list.push((t, dtor));
}
pub unsafe fn run_dtors() {
let ptr = DTORS.get();
if !ptr.is_null() {
// Swap the destructor list, call all registered destructors,
// and repeat this until the list becomes permanently empty.
while let Some(list) = Some(crate::mem::replace(unsafe { &mut *ptr }, Vec::new()))
.filter(|list| !list.is_empty())
{
for (ptr, dtor) in list.into_iter() {
unsafe { dtor(ptr) };
}
}
// Drop the destructor list
unsafe { Box::from_raw(DTORS.replace(ptr::null_mut())) };
}
}
unsafe extern "C" fn tls_dtor(_unused: *mut u8) {
unsafe { run_dtors() };
}