about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-08-28 01:33:48 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-09-25 16:30:05 -0700
commiteb2b25dd6d38157213742b048fad63fa4ceec691 (patch)
treee41f9af78454e8f6641dead395274419d843ab63 /src/libstd
parentaf25f58ac3da45899ed65b3af965150c8a90dcda (diff)
downloadrust-eb2b25dd6d38157213742b048fad63fa4ceec691.tar.gz
rust-eb2b25dd6d38157213742b048fad63fa4ceec691.zip
Refactor the logging system for fewer allocations
This lifts various restrictions on the runtime, for example the character limit
when logging a message. Right now the old debug!-style macros still involve
allocating (because they use fmt! syntax), but the new debug2! macros don't
involve allocating at all (unless the formatter for a type requires allocation.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/logging.rs25
-rw-r--r--src/libstd/rt/logging.rs53
-rw-r--r--src/libstd/std.rs1
-rw-r--r--src/libstd/sys.rs51
4 files changed, 72 insertions, 58 deletions
diff --git a/src/libstd/logging.rs b/src/libstd/logging.rs
index 1a463a499cb..342d0828f82 100644
--- a/src/libstd/logging.rs
+++ b/src/libstd/logging.rs
@@ -10,11 +10,11 @@
 
 //! Logging
 
+use fmt;
 use option::*;
 use os;
 use rt;
 use rt::logging::{Logger, StdErrLogger};
-use send_str::SendStrOwned;
 
 /// Turns on logging to stdout globally
 pub fn console_on() {
@@ -37,7 +37,17 @@ pub fn console_off() {
     rt::logging::console_off();
 }
 
-fn newsched_log_str(msg: ~str) {
+#[cfg(stage0)]
+#[doc(hidden)]
+pub fn log(_level: u32, s: ~str) {
+    // this is a terrible approximation, but it gets the job done (for stage0 at
+    // least)
+    ::io::println(s);
+}
+
+#[allow(missing_doc)]
+#[cfg(not(stage0))]
+pub fn log(_level: u32, args: &fmt::Arguments) {
     use rt::task::Task;
     use rt::local::Local;
 
@@ -46,20 +56,13 @@ fn newsched_log_str(msg: ~str) {
         match optional_task {
             Some(local) => {
                 // Use the available logger
-                (*local).logger.log(SendStrOwned(msg));
+                (*local).logger.log(args);
             }
             None => {
                 // There is no logger anywhere, just write to stderr
                 let mut logger = StdErrLogger;
-                logger.log(SendStrOwned(msg));
+                logger.log(args);
             }
         }
     }
 }
-
-// XXX: This will change soon to not require an allocation. This is an unstable
-//      api which should not be used outside of the macros in ext/expand.
-#[doc(hidden)]
-pub fn log(_level: u32, msg: ~str) {
-    newsched_log_str(msg);
-}
diff --git a/src/libstd/rt/logging.rs b/src/libstd/rt/logging.rs
index 3dbf7a918b7..cfbc53ad34e 100644
--- a/src/libstd/rt/logging.rs
+++ b/src/libstd/rt/logging.rs
@@ -7,9 +7,12 @@
 // <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 fmt;
 use from_str::from_str;
-use libc::{uintptr_t, exit, STDERR_FILENO};
+use libc::{uintptr_t, exit};
 use option::{Some, None, Option};
+use rt;
 use rt::util::dumb_println;
 use rt::crate_map::{ModEntry, iter_crate_map};
 use rt::crate_map::get_crate_map;
@@ -18,7 +21,6 @@ use str::raw::from_c_str;
 use u32;
 use vec::ImmutableVector;
 use cast::transmute;
-use send_str::{SendStr, SendStrOwned, SendStrStatic};
 
 struct LogDirective {
     name: Option<~str>,
@@ -171,44 +173,33 @@ fn update_log_settings(crate_map: *u8, settings: ~str) {
 }
 
 pub trait Logger {
-    fn log(&mut self, msg: SendStr);
+    fn log(&mut self, args: &fmt::Arguments);
 }
 
 pub struct StdErrLogger;
 
 impl Logger for StdErrLogger {
-    fn log(&mut self, msg: SendStr) {
-        use io::{Writer, WriterUtil};
-
-        if !should_log_console() {
-            return;
+    fn log(&mut self, args: &fmt::Arguments) {
+        if should_log_console() {
+            fmt::write(self as &mut rt::io::Writer, args);
         }
+    }
+}
 
-        let s: &str = match msg {
-            SendStrOwned(ref s) => {
-                let slc: &str = *s;
-                slc
-            },
-            SendStrStatic(s) => s,
-        };
-
-        // Truncate the string
-        let buf_bytes = 2048;
-        if s.len() > buf_bytes {
-            let s = s.slice(0, buf_bytes) + "[...]";
-            print(s);
-        } else {
-            print(s)
-        };
-
-        fn print(s: &str) {
-            let dbg = STDERR_FILENO as ::io::fd_t;
-            dbg.write_str(s);
-            dbg.write_str("\n");
-            dbg.flush();
-        }
+impl rt::io::Writer for StdErrLogger {
+    fn write(&mut self, buf: &[u8]) {
+        // Nothing like swapping between I/O implementations! In theory this
+        // could use the libuv bindings for writing to file descriptors, but
+        // that may not necessarily be desirable because logging should work
+        // outside of the uv loop. (modify with caution)
+        use io::Writer;
+        let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
+        dbg.write(buf);
     }
+
+    fn flush(&mut self) {}
 }
+
 /// Configure logging by traversing the crate map and setting the
 /// per-module global logging flags based on the logging spec
 pub fn init() {
diff --git a/src/libstd/std.rs b/src/libstd/std.rs
index 5c1bac7418e..b06385cbcf4 100644
--- a/src/libstd/std.rs
+++ b/src/libstd/std.rs
@@ -224,4 +224,5 @@ mod std {
     pub use os;
     pub use fmt;
     pub use to_bytes;
+    pub use logging;
 }
diff --git a/src/libstd/sys.rs b/src/libstd/sys.rs
index c315c3f9dfc..c38f3525867 100644
--- a/src/libstd/sys.rs
+++ b/src/libstd/sys.rs
@@ -125,14 +125,41 @@ impl FailWithCause for &'static str {
     }
 }
 
-// FIXME #4427: Temporary until rt::rt_fail_ goes away
+// This stage0 version is incredibly wrong.
+#[cfg(stage0)]
 pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
     use option::{Some, None};
     use rt::in_green_task_context;
     use rt::task::Task;
     use rt::local::Local;
     use rt::logging::Logger;
-    use send_str::SendStrOwned;
+    use str::Str;
+
+    unsafe {
+        let msg = str::raw::from_c_str(msg);
+        let file = str::raw::from_c_str(file);
+        if in_green_task_context() {
+            rterrln!("task failed at '%s', %s:%i", msg, file, line as int);
+        } else {
+            rterrln!("failed in non-task context at '%s', %s:%i",
+                     msg, file, line as int);
+        }
+
+        let task: *mut Task = Local::unsafe_borrow();
+        if (*task).unwinder.unwinding {
+            rtabort!("unwinding again");
+        }
+        (*task).unwinder.begin_unwind();
+    }
+}
+
+// FIXME #4427: Temporary until rt::rt_fail_ goes away
+#[cfg(not(stage0))]
+pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
+    use rt::in_green_task_context;
+    use rt::task::Task;
+    use rt::local::Local;
+    use rt::logging::Logger;
     use str::Str;
 
     unsafe {
@@ -140,22 +167,14 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
         let msg = str::raw::from_c_str(msg);
         let file = str::raw::from_c_str(file);
 
-        // XXX: Logging doesn't work correctly in non-task context because it
-        // invokes the local heap
         if in_green_task_context() {
-            // XXX: Logging doesn't work here - the check to call the log
-            // function never passes - so calling the log function directly.
+            // Be careful not to allocate in this block, if we're failing we may
+            // have been failing due to a lack of memory in the first place...
             do Local::borrow |task: &mut Task| {
-                let msg = match task.name {
-                    Some(ref name) =>
-                    fmt!("task '%s' failed at '%s', %s:%i",
-                         name.as_slice(), msg, file, line as int),
-                    None =>
-                    fmt!("task <unnamed> failed at '%s', %s:%i",
-                         msg, file, line as int)
-                };
-
-                task.logger.log(SendStrOwned(msg));
+                let n = task.name.map(|n| n.as_slice()).unwrap_or("<unnamed>");
+                format_args!(|args| { task.logger.log(args) },
+                             "task '{}' failed at '{}', {}:{}",
+                             n, msg.as_slice(), file.as_slice(), line);
             }
         } else {
             rterrln!("failed in non-task context at '%s', %s:%i",