use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
-use mem;
+use ptr;
use rt;
-use sys_common::mutex::{MUTEX_INIT, Mutex};
+use sys_common::mutex::Mutex;
pub type Key = DWORD;
pub type Dtor = unsafe extern fn(*mut u8);
// somewhere to run arbitrary code on thread termination. With this in place
// we'll be able to run anything we like, including all TLS destructors!
//
-// To accomplish this feat, we perform a number of tasks, all contained
+// To accomplish this feat, we perform a number of threads, all contained
// within this module:
//
// * All TLS destructors are tracked by *us*, not the windows runtime. This
// on poisoning and this module needs to operate at a lower level than requiring
// the thread infrastructure to be in place (useful on the borders of
// initialization/destruction).
-static DTOR_LOCK: Mutex = MUTEX_INIT;
+static DTOR_LOCK: Mutex = Mutex::new();
static mut DTORS: *mut Vec<(Key, Dtor)> = 0 as *mut _;
// -------------------------------------------------------------------------
if !DTORS.is_null() { return }
let dtors = box Vec::<(Key, Dtor)>::new();
- DTORS = mem::transmute(dtors);
- rt::at_exit(move|| {
+ let res = rt::at_exit(move|| {
DTOR_LOCK.lock();
let dtors = DTORS;
- DTORS = 0 as *mut _;
- mem::transmute::<_, Box<Vec<(Key, Dtor)>>>(dtors);
- assert!(DTORS.is_null()); // can't re-init after destructing
+ DTORS = 1 as *mut _;
+ Box::from_raw(dtors);
+ assert!(DTORS as usize == 1); // can't re-init after destructing
DTOR_LOCK.unlock();
});
+ if res.is_ok() {
+ DTORS = Box::into_raw(dtors);
+ } else {
+ DTORS = 1 as *mut _;
+ }
}
unsafe fn register_dtor(key: Key, dtor: Dtor) {
DTOR_LOCK.lock();
init_dtors();
+ assert!(DTORS as usize != 0);
+ assert!(DTORS as usize != 1,
+ "cannot create new TLS keys after the main thread has exited");
(*DTORS).push((key, dtor));
DTOR_LOCK.unlock();
}
unsafe fn unregister_dtor(key: Key) -> bool {
DTOR_LOCK.lock();
init_dtors();
+ assert!(DTORS as usize != 0);
+ assert!(DTORS as usize != 1,
+ "cannot unregister destructors after the main thread has exited");
let ret = {
let dtors = &mut *DTORS;
let before = dtors.len();
// # What's up with this callback?
//
// The callback specified receives a number of parameters from... someone!
-// (the kernel? the runtime? I'm not qute sure!) There are a few events that
+// (the kernel? the runtime? I'm not quite sure!) There are a few events that
// this gets invoked for, but we're currently only interested on when a
// thread or a process "detaches" (exits). The process part happens for the
// last thread and the thread part happens for any normal thread.
}
}
+#[allow(dead_code)] // actually called above
unsafe fn run_dtors() {
let mut any_run = true;
- for _ in range(0, 5i) {
+ for _ in 0..5 {
if !any_run { break }
any_run = false;
let dtors = {
DTOR_LOCK.lock();
- let ret = if DTORS.is_null() {
+ let ret = if DTORS as usize <= 1 {
Vec::new()
} else {
(*DTORS).iter().map(|s| *s).collect()
DTOR_LOCK.unlock();
ret
};
- for &(key, dtor) in dtors.iter() {
+ for &(key, dtor) in &dtors {
let ptr = TlsGetValue(key);
if !ptr.is_null() {
- TlsSetValue(key, 0 as *mut _);
+ TlsSetValue(key, ptr::null_mut());
dtor(ptr as *mut _);
any_run = true;
}