Skip to content

Commit eb2b25d

Browse files
committed
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.
1 parent af25f58 commit eb2b25d

File tree

7 files changed

+82
-137
lines changed

7 files changed

+82
-137
lines changed

src/libstd/logging.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010

1111
//! Logging
1212
13+
use fmt;
1314
use option::*;
1415
use os;
1516
use rt;
1617
use rt::logging::{Logger, StdErrLogger};
17-
use send_str::SendStrOwned;
1818

1919
/// Turns on logging to stdout globally
2020
pub fn console_on() {
@@ -37,7 +37,17 @@ pub fn console_off() {
3737
rt::logging::console_off();
3838
}
3939

40-
fn newsched_log_str(msg: ~str) {
40+
#[cfg(stage0)]
41+
#[doc(hidden)]
42+
pub fn log(_level: u32, s: ~str) {
43+
// this is a terrible approximation, but it gets the job done (for stage0 at
44+
// least)
45+
::io::println(s);
46+
}
47+
48+
#[allow(missing_doc)]
49+
#[cfg(not(stage0))]
50+
pub fn log(_level: u32, args: &fmt::Arguments) {
4151
use rt::task::Task;
4252
use rt::local::Local;
4353

@@ -46,20 +56,13 @@ fn newsched_log_str(msg: ~str) {
4656
match optional_task {
4757
Some(local) => {
4858
// Use the available logger
49-
(*local).logger.log(SendStrOwned(msg));
59+
(*local).logger.log(args);
5060
}
5161
None => {
5262
// There is no logger anywhere, just write to stderr
5363
let mut logger = StdErrLogger;
54-
logger.log(SendStrOwned(msg));
64+
logger.log(args);
5565
}
5666
}
5767
}
5868
}
59-
60-
// XXX: This will change soon to not require an allocation. This is an unstable
61-
// api which should not be used outside of the macros in ext/expand.
62-
#[doc(hidden)]
63-
pub fn log(_level: u32, msg: ~str) {
64-
newsched_log_str(msg);
65-
}

src/libstd/rt/logging.rs

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
10+
11+
use fmt;
1012
use from_str::from_str;
11-
use libc::{uintptr_t, exit, STDERR_FILENO};
13+
use libc::{uintptr_t, exit};
1214
use option::{Some, None, Option};
15+
use rt;
1316
use rt::util::dumb_println;
1417
use rt::crate_map::{ModEntry, iter_crate_map};
1518
use rt::crate_map::get_crate_map;
@@ -18,7 +21,6 @@ use str::raw::from_c_str;
1821
use u32;
1922
use vec::ImmutableVector;
2023
use cast::transmute;
21-
use send_str::{SendStr, SendStrOwned, SendStrStatic};
2224

2325
struct LogDirective {
2426
name: Option<~str>,
@@ -171,44 +173,33 @@ fn update_log_settings(crate_map: *u8, settings: ~str) {
171173
}
172174

173175
pub trait Logger {
174-
fn log(&mut self, msg: SendStr);
176+
fn log(&mut self, args: &fmt::Arguments);
175177
}
176178

177179
pub struct StdErrLogger;
178180

179181
impl Logger for StdErrLogger {
180-
fn log(&mut self, msg: SendStr) {
181-
use io::{Writer, WriterUtil};
182-
183-
if !should_log_console() {
184-
return;
182+
fn log(&mut self, args: &fmt::Arguments) {
183+
if should_log_console() {
184+
fmt::write(self as &mut rt::io::Writer, args);
185185
}
186+
}
187+
}
186188

187-
let s: &str = match msg {
188-
SendStrOwned(ref s) => {
189-
let slc: &str = *s;
190-
slc
191-
},
192-
SendStrStatic(s) => s,
193-
};
194-
195-
// Truncate the string
196-
let buf_bytes = 2048;
197-
if s.len() > buf_bytes {
198-
let s = s.slice(0, buf_bytes) + "[...]";
199-
print(s);
200-
} else {
201-
print(s)
202-
};
203-
204-
fn print(s: &str) {
205-
let dbg = STDERR_FILENO as ::io::fd_t;
206-
dbg.write_str(s);
207-
dbg.write_str("\n");
208-
dbg.flush();
209-
}
189+
impl rt::io::Writer for StdErrLogger {
190+
fn write(&mut self, buf: &[u8]) {
191+
// Nothing like swapping between I/O implementations! In theory this
192+
// could use the libuv bindings for writing to file descriptors, but
193+
// that may not necessarily be desirable because logging should work
194+
// outside of the uv loop. (modify with caution)
195+
use io::Writer;
196+
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
197+
dbg.write(buf);
210198
}
199+
200+
fn flush(&mut self) {}
211201
}
202+
212203
/// Configure logging by traversing the crate map and setting the
213204
/// per-module global logging flags based on the logging spec
214205
pub fn init() {

src/libstd/std.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,5 @@ mod std {
224224
pub use os;
225225
pub use fmt;
226226
pub use to_bytes;
227+
pub use logging;
227228
}

src/libstd/sys.rs

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -125,37 +125,56 @@ impl FailWithCause for &'static str {
125125
}
126126
}
127127

128-
// FIXME #4427: Temporary until rt::rt_fail_ goes away
128+
// This stage0 version is incredibly wrong.
129+
#[cfg(stage0)]
129130
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
130131
use option::{Some, None};
131132
use rt::in_green_task_context;
132133
use rt::task::Task;
133134
use rt::local::Local;
134135
use rt::logging::Logger;
135-
use send_str::SendStrOwned;
136+
use str::Str;
137+
138+
unsafe {
139+
let msg = str::raw::from_c_str(msg);
140+
let file = str::raw::from_c_str(file);
141+
if in_green_task_context() {
142+
rterrln!("task failed at '%s', %s:%i", msg, file, line as int);
143+
} else {
144+
rterrln!("failed in non-task context at '%s', %s:%i",
145+
msg, file, line as int);
146+
}
147+
148+
let task: *mut Task = Local::unsafe_borrow();
149+
if (*task).unwinder.unwinding {
150+
rtabort!("unwinding again");
151+
}
152+
(*task).unwinder.begin_unwind();
153+
}
154+
}
155+
156+
// FIXME #4427: Temporary until rt::rt_fail_ goes away
157+
#[cfg(not(stage0))]
158+
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
159+
use rt::in_green_task_context;
160+
use rt::task::Task;
161+
use rt::local::Local;
162+
use rt::logging::Logger;
136163
use str::Str;
137164

138165
unsafe {
139166
// XXX: Bad re-allocations. fail! needs some refactoring
140167
let msg = str::raw::from_c_str(msg);
141168
let file = str::raw::from_c_str(file);
142169

143-
// XXX: Logging doesn't work correctly in non-task context because it
144-
// invokes the local heap
145170
if in_green_task_context() {
146-
// XXX: Logging doesn't work here - the check to call the log
147-
// function never passes - so calling the log function directly.
171+
// Be careful not to allocate in this block, if we're failing we may
172+
// have been failing due to a lack of memory in the first place...
148173
do Local::borrow |task: &mut Task| {
149-
let msg = match task.name {
150-
Some(ref name) =>
151-
fmt!("task '%s' failed at '%s', %s:%i",
152-
name.as_slice(), msg, file, line as int),
153-
None =>
154-
fmt!("task <unnamed> failed at '%s', %s:%i",
155-
msg, file, line as int)
156-
};
157-
158-
task.logger.log(SendStrOwned(msg));
174+
let n = task.name.map(|n| n.as_slice()).unwrap_or("<unnamed>");
175+
format_args!(|args| { task.logger.log(args) },
176+
"task '{}' failed at '{}', {}:{}",
177+
n, msg.as_slice(), file.as_slice(), line);
159178
}
160179
} else {
161180
rterrln!("failed in non-task context at '%s', %s:%i",

src/libsyntax/ext/expand.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -813,13 +813,17 @@ pub fn std_macros() -> @str {
813813
($lvl:expr, $arg:expr) => ({
814814
let lvl = $lvl;
815815
if lvl <= __log_level() {
816-
::std::logging::log(lvl, fmt!(\"%?\", $arg))
816+
format_args!(|args| {
817+
::std::logging::log(lvl, args)
818+
}, \"{}\", fmt!(\"%?\", $arg))
817819
}
818820
});
819821
($lvl:expr, $($arg:expr),+) => ({
820822
let lvl = $lvl;
821823
if lvl <= __log_level() {
822-
::std::logging::log(lvl, fmt!($($arg),+))
824+
format_args!(|args| {
825+
::std::logging::log(lvl, args)
826+
}, \"{}\", fmt!($($arg),+))
823827
}
824828
})
825829
)
@@ -834,7 +838,9 @@ pub fn std_macros() -> @str {
834838
($lvl:expr, $($arg:tt)+) => ({
835839
let lvl = $lvl;
836840
if lvl <= __log_level() {
837-
::std::logging::log(lvl, format!($($arg)+))
841+
format_args!(|args| {
842+
::std::logging::log(lvl, args)
843+
}, $($arg)+)
838844
}
839845
})
840846
)

src/test/compile-fail/issue-2823.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,5 @@ impl Drop for C {
2020

2121
fn main() {
2222
let c = C{ x: 2};
23-
let d = c.clone(); //~ ERROR does not implement any method in scope
24-
error!("%?", d.x);
23+
let _d = c.clone(); //~ ERROR does not implement any method in scope
2524
}

src/test/run-fail/rt-log-trunc.rs

Lines changed: 0 additions & 74 deletions
This file was deleted.

0 commit comments

Comments
 (0)