diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs index 43e8096a8b11..7b27161ab5d7 100644 --- a/src/libstd/rt/args.rs +++ b/src/libstd/rt/args.rs @@ -32,8 +32,8 @@ pub unsafe fn init(argc: int, argv: **u8) { imp::init(argc, argv) } pub unsafe fn init(argc: int, argv: **u8) { realargs::init(argc, argv) } /// One-time global cleanup. -#[cfg(not(test))] pub fn cleanup() { imp::cleanup() } -#[cfg(test)] pub fn cleanup() { realargs::cleanup() } +#[cfg(not(test))] pub unsafe fn cleanup() { imp::cleanup() } +#[cfg(test)] pub unsafe fn cleanup() { realargs::cleanup() } /// Take the global arguments from global storage. #[cfg(not(test))] pub fn take() -> Option<~[~str]> { imp::take() } @@ -74,14 +74,16 @@ mod imp { use vec; static mut global_args_ptr: uint = 0; + static mut lock: Mutex = MUTEX_INIT; pub unsafe fn init(argc: int, argv: **u8) { let args = load_argc_and_argv(argc, argv); put(args); } - pub fn cleanup() { + pub unsafe fn cleanup() { rtassert!(take().is_some()); + lock.destroy(); } pub fn take() -> Option<~[~str]> { @@ -108,7 +110,6 @@ mod imp { } fn with_lock(f: || -> T) -> T { - static mut lock: Mutex = MUTEX_INIT; (|| { unsafe { lock.lock(); diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs index e0e8750e146f..86f0f643c996 100644 --- a/src/libstd/rt/local_ptr.rs +++ b/src/libstd/rt/local_ptr.rs @@ -41,28 +41,45 @@ pub static mut RT_TLS_PTR: *mut c_void = 0 as *mut c_void; #[cfg(stage0)] #[cfg(windows)] static mut RT_TLS_KEY: tls::Key = -1; +static mut tls_lock: Mutex = MUTEX_INIT; +static mut tls_initialized: bool = false; /// Initialize the TLS key. Other ops will fail if this isn't executed first. #[inline(never)] #[cfg(stage0)] #[cfg(windows)] pub fn init_tls_key() { - static mut lock: Mutex = MUTEX_INIT; - static mut initialized: bool = false; - unsafe { - lock.lock(); - if !initialized { + tls_lock.lock(); + if !tls_initialized { tls::create(&mut RT_TLS_KEY); - initialized = true; + tls_initialized = true; } - lock.unlock(); + tls_lock.unlock(); } } #[cfg(not(stage0), not(windows))] pub fn init_tls_key() {} +#[cfg(windows)] +pub unsafe fn cleanup() { + // No real use to acquiring a lock around these operations. All we're + // going to do is destroy the lock anyway which races locking itself. This + // is why the whole function is labeled as 'unsafe' + assert!(tls_initialized); + tls::destroy(RT_TLS_KEY); + tls_lock.destroy(); + tls_initialized = false; +} + +#[cfg(not(windows))] +pub unsafe fn cleanup() { + assert!(tls_initialized); + tls_lock.destroy(); + tls_initialized = false; +} + /// Give a pointer to thread-local storage. /// /// # Safety note diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 860b65b20c66..79b7dbf2aabf 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -215,7 +215,8 @@ pub fn start(argc: int, argv: **u8, main: proc()) -> int { init(argc, argv); let exit_code = run(main); - cleanup(); + // unsafe is ok b/c we're sure that the runtime is gone + unsafe { cleanup(); } return exit_code; } @@ -228,7 +229,8 @@ pub fn start(argc: int, argv: **u8, main: proc()) -> int { pub fn start_on_main_thread(argc: int, argv: **u8, main: proc()) -> int { init(argc, argv); let exit_code = run_on_main_thread(main); - cleanup(); + // unsafe is ok b/c we're sure that the runtime is gone + unsafe { cleanup(); } return exit_code; } @@ -249,8 +251,17 @@ pub fn init(argc: int, argv: **u8) { } /// One-time runtime cleanup. -pub fn cleanup() { +/// +/// This function is unsafe because it performs no checks to ensure that the +/// runtime has completely ceased running. It is the responsibility of the +/// caller to ensure that the runtime is entirely shut down and nothing will be +/// poking around at the internal components. +/// +/// Invoking cleanup while portions of the runtime are still in use may cause +/// undefined behavior. +pub unsafe fn cleanup() { args::cleanup(); + local_ptr::cleanup(); } /// Execute the main function in a scheduler. diff --git a/src/libstd/rt/thread_local_storage.rs b/src/libstd/rt/thread_local_storage.rs index 8fa64852846a..62e1b6c50d65 100644 --- a/src/libstd/rt/thread_local_storage.rs +++ b/src/libstd/rt/thread_local_storage.rs @@ -34,6 +34,11 @@ 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; @@ -47,6 +52,7 @@ 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; } @@ -71,9 +77,15 @@ 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; }