about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/args.rs9
-rw-r--r--src/libstd/rt/local_ptr.rs31
-rw-r--r--src/libstd/rt/mod.rs17
-rw-r--r--src/libstd/rt/thread_local_storage.rs12
4 files changed, 55 insertions, 14 deletions
diff --git a/src/libstd/rt/args.rs b/src/libstd/rt/args.rs
index 43e8096a8b1..7b27161ab5d 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<T>(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 e0e8750e146..86f0f643c99 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 860b65b20c6..79b7dbf2aab 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 8fa64852846..62e1b6c50d6 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;
 }
@@ -72,8 +78,14 @@ pub unsafe fn get(key: Key) -> *mut c_void {
 }
 
 #[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;
 }