ed86b48cc9
Whenever the runtime is shut down, add a few hooks to clean up some of the statically initialized data of the runtime. Note that this is an unsafe operation because there's no guarantee on behalf of the runtime that there's no other code running which is using the runtime. This helps turn down the noise a bit in the valgrind output related to statically initialized mutexes. It doesn't turn the noise down to 0 because there are still statically initialized mutexes in dynamic_lib and os::with_env_lock, but I believe that it would be easy enough to add exceptions for those cases and I don't think that it's the runtime's job to go and clean up that data.
109 lines
2.7 KiB
Rust
109 lines
2.7 KiB
Rust
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
|
// file at the top-level directory of this distribution and at
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
// option. This file may not be copied, modified, or distributed
|
|
// except according to those terms.
|
|
|
|
use libc::c_void;
|
|
#[cfg(unix)]
|
|
use libc::c_int;
|
|
#[cfg(unix)]
|
|
use ptr::null;
|
|
#[cfg(windows)]
|
|
use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
|
|
|
|
#[cfg(unix)]
|
|
pub type Key = pthread_key_t;
|
|
|
|
#[cfg(unix)]
|
|
pub unsafe fn create(key: &mut Key) {
|
|
assert_eq!(0, pthread_key_create(key, null()));
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
pub unsafe fn set(key: Key, value: *mut c_void) {
|
|
assert_eq!(0, pthread_setspecific(key, value));
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
pub unsafe fn get(key: Key) -> *mut c_void {
|
|
pthread_getspecific(key)
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
pub unsafe fn destroy(key: Key) {
|
|
assert_eq!(0, pthread_key_delete(key));
|
|
}
|
|
|
|
#[cfg(target_os="macos")]
|
|
#[allow(non_camel_case_types)] // foreign type
|
|
type pthread_key_t = ::libc::c_ulong;
|
|
|
|
#[cfg(target_os="linux")]
|
|
#[cfg(target_os="freebsd")]
|
|
#[cfg(target_os="android")]
|
|
#[allow(non_camel_case_types)] // foreign type
|
|
type pthread_key_t = ::libc::c_uint;
|
|
|
|
#[cfg(unix)]
|
|
extern {
|
|
fn pthread_key_create(key: *mut pthread_key_t, dtor: *u8) -> c_int;
|
|
fn pthread_key_delete(key: pthread_key_t) -> c_int;
|
|
fn pthread_getspecific(key: pthread_key_t) -> *mut c_void;
|
|
fn pthread_setspecific(key: pthread_key_t, value: *mut c_void) -> c_int;
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
pub type Key = DWORD;
|
|
|
|
#[cfg(windows)]
|
|
pub unsafe fn create(key: &mut Key) {
|
|
static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
|
|
*key = TlsAlloc();
|
|
assert!(*key != TLS_OUT_OF_INDEXES);
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
pub unsafe fn set(key: Key, value: *mut c_void) {
|
|
assert!(0 != TlsSetValue(key, value))
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
pub unsafe fn get(key: Key) -> *mut c_void {
|
|
TlsGetValue(key)
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
pub unsafe fn destroy(key: Key) {
|
|
assert!(TlsFree(key) != 0);
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
extern "system" {
|
|
fn TlsAlloc() -> DWORD;
|
|
fn TlsFree(dwTlsIndex: DWORD) -> BOOL;
|
|
fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID;
|
|
fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL;
|
|
}
|
|
|
|
#[test]
|
|
fn tls_smoke_test() {
|
|
use cast::transmute;
|
|
unsafe {
|
|
let mut key = 0;
|
|
let value = ~20;
|
|
create(&mut key);
|
|
set(key, transmute(value));
|
|
let value: ~int = transmute(get(key));
|
|
assert_eq!(value, ~20);
|
|
let value = ~30;
|
|
set(key, transmute(value));
|
|
let value: ~int = transmute(get(key));
|
|
assert_eq!(value, ~30);
|
|
}
|
|
}
|