about summary refs log tree commit diff
path: root/src/liblog
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-12-19 11:29:39 -0800
committerAlex Crichton <alex@alexcrichton.com>2014-12-30 14:33:59 -0800
commit9e224c2bf18ebf8f871efb2e1aba43ed7970ebb7 (patch)
treeda18d5791e6841a1aa6a9469baca155d4ca9828d /src/liblog
parentd2368c3c11ddab9d812c4ddec2e44579326ad347 (diff)
downloadrust-9e224c2bf18ebf8f871efb2e1aba43ed7970ebb7.tar.gz
rust-9e224c2bf18ebf8f871efb2e1aba43ed7970ebb7.zip
std: Re-enable at_exit()
The new semantics of this function are that the callbacks are run when the *main
thread* exits, not when all threads have exited. This implies that other threads
may still be running when the `at_exit` callbacks are invoked and users need to
be prepared for this situation.

Users in the standard library have been audited in accordance to these new rules
as well.

Closes #20012
Diffstat (limited to 'src/liblog')
-rw-r--r--src/liblog/lib.rs34
1 files changed, 26 insertions, 8 deletions
diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs
index 1d865868f18..6ee8ae25f1b 100644
--- a/src/liblog/lib.rs
+++ b/src/liblog/lib.rs
@@ -177,7 +177,7 @@ use std::mem;
 use std::os;
 use std::rt;
 use std::slice;
-use std::sync::{Once, ONCE_INIT};
+use std::sync::{Once, ONCE_INIT, StaticMutex, MUTEX_INIT};
 
 use regex::Regex;
 
@@ -193,6 +193,8 @@ pub const MAX_LOG_LEVEL: u32 = 255;
 /// The default logging level of a crate if no other is specified.
 const DEFAULT_LOG_LEVEL: u32 = 1;
 
+static LOCK: StaticMutex = MUTEX_INIT;
+
 /// An unsafe constant that is the maximum logging level of any module
 /// specified. This is the first line of defense to determining whether a
 /// logging statement should be run.
@@ -281,9 +283,18 @@ impl Drop for DefaultLogger {
 pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
     // Test the literal string from args against the current filter, if there
     // is one.
-    match unsafe { FILTER.as_ref() } {
-        Some(filter) if !filter.is_match(args.to_string()[]) => return,
-        _ => {}
+    unsafe {
+        let _g = LOCK.lock();
+        match FILTER as uint {
+            0 => {}
+            1 => panic!("cannot log after main thread has exited"),
+            n => {
+                let filter = mem::transmute::<_, &Regex>(n);
+                if !filter.is_match(args.to_string().as_slice()) {
+                    return
+                }
+            }
+        }
     }
 
     // Completely remove the local logger from TLS in case anyone attempts to
@@ -401,9 +412,15 @@ pub fn mod_enabled(level: u32, module: &str) -> bool {
 
     // This assertion should never get tripped unless we're in an at_exit
     // handler after logging has been torn down and a logging attempt was made.
-    assert!(unsafe { !DIRECTIVES.is_null() });
 
-    enabled(level, module, unsafe { (*DIRECTIVES).iter() })
+    let _g = LOCK.lock();
+    unsafe {
+        assert!(DIRECTIVES as uint != 0);
+        assert!(DIRECTIVES as uint != 1,
+                "cannot log after the main thread has exited");
+
+        enabled(level, module, (*DIRECTIVES).iter())
+    }
 }
 
 fn enabled(level: u32,
@@ -459,14 +476,15 @@ fn init() {
 
         // Schedule the cleanup for the globals for when the runtime exits.
         rt::at_exit(move |:| {
+            let _g = LOCK.lock();
             assert!(!DIRECTIVES.is_null());
             let _directives: Box<Vec<directive::LogDirective>> =
                 mem::transmute(DIRECTIVES);
-            DIRECTIVES = 0 as *const Vec<directive::LogDirective>;
+            DIRECTIVES = 1 as *const Vec<directive::LogDirective>;
 
             if !FILTER.is_null() {
                 let _filter: Box<Regex> = mem::transmute(FILTER);
-                FILTER = 0 as *const _;
+                FILTER = 1 as *const _;
             }
         });
     }