From e38739bb442263f1ef67b6c2415f932aa49e6646 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Fri, 30 Aug 2013 16:42:49 +0200 Subject: [PATCH] Convert rust_log.cpp to Rust, closes #8703 --- mk/rt.mk | 1 - src/libstd/rt/logging.rs | 263 +++++++++++++++++++++++++++++++++++--- src/rt/rust_crate_map.cpp | 38 ++++-- src/rt/rust_crate_map.h | 14 +- src/rt/rust_log.cpp | 155 ---------------------- src/rt/rustrt.def.in | 4 +- 6 files changed, 285 insertions(+), 190 deletions(-) delete mode 100644 src/rt/rust_log.cpp diff --git a/mk/rt.mk b/mk/rt.mk index c260945cbc9b0..352165d600257 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -76,7 +76,6 @@ RUNTIME_CXXS_$(1)_$(2) := \ rt/rust_upcall.cpp \ rt/rust_uv.cpp \ rt/rust_crate_map.cpp \ - rt/rust_log.cpp \ rt/isaac/randport.cpp \ rt/miniz.cpp \ rt/memory_region.cpp \ diff --git a/src/libstd/rt/logging.rs b/src/libstd/rt/logging.rs index e716549d1e69f..bcd8ef98d28f2 100644 --- a/src/libstd/rt/logging.rs +++ b/src/libstd/rt/logging.rs @@ -7,10 +7,159 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +use cast::transmute; use either::*; -use libc; +use libc::{c_void, uintptr_t, c_char, exit, STDERR_FILENO}; +use option::{Some, None}; +use rt::util::dumb_println; use str::StrSlice; +use str::raw::from_c_str; +use u32; +use unstable::raw::Closure; +use vec::ImmutableVector; + + +struct LogDirective { + name: ~str, + level: u32 +} + +// This is the Rust representation of the mod_entry struct in src/rt/rust_crate_map.h +struct ModEntry{ + name: *c_char, + log_level: *mut u32 +} + +static MAX_LOG_DIRECTIVES: u32 = 255; +static MAX_LOG_LEVEL: u32 = 255; +static DEFAULT_LOG_LEVEL: u32 = 1; + +fn iter_crate_map(map: *u8, f: &fn(*mut ModEntry)) { + unsafe { + let closure : Closure = transmute(f); + let code = transmute(closure.code); + let env = transmute(closure.env); + rust_iter_crate_map(transmute(map), iter_cb, code, env); + } + + extern fn iter_cb(code: *c_void, env: *c_void, entry: *ModEntry){ + unsafe { + let closure: Closure = Closure { + code: transmute(code), + env: transmute(env), + }; + let closure: &fn(*ModEntry) = transmute(closure); + return closure(entry); + } + } + extern { + #[cfg(not(stage0))] + #[rust_stack] + fn rust_iter_crate_map(map: *c_void, + f: extern "C" fn(*c_void, *c_void, entry: *ModEntry), + code: *c_void, + data: *c_void); + + #[cfg(stage0)] + #[rust_stack] + fn rust_iter_crate_map(map: *c_void, + f: *u8, + code: *c_void, + data: *c_void); + } +} + +/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1") +/// and return a vector with log directives. +/// Valid log levels are 0-255, with the most likely ones being 0-3 (defined in std::). +fn parse_logging_spec(spec: ~str) -> ~[LogDirective]{ + let mut dirs = ~[]; + for s in spec.split_iter(',') { + let parts: ~[&str] = s.split_iter('=').collect(); + let mut loglevel; + match parts.len() { + 1 => loglevel = MAX_LOG_LEVEL, + 2 => { + let num = u32::from_str(parts[1]); + match (num) { + Some(num) => { + if num < MAX_LOG_LEVEL { + loglevel = num; + } else { + loglevel = MAX_LOG_LEVEL; + } + } + _ => { + dumb_println(fmt!("warning: invalid logging spec \ + '%s', ignoring it", s)); + loop; + } + } + if loglevel > MAX_LOG_LEVEL { loglevel = MAX_LOG_LEVEL} + }, + _ => { + dumb_println(fmt!("warning: invalid logging spec '%s',\ + ignoring it", s)); + loop; + } + } + let dir = LogDirective {name: parts[0].to_owned(), level: loglevel}; + dirs.push(dir); + } + return dirs; +} + +/// Set the log level of an entry in the crate map depending on the vector +/// of log directives +fn update_entry(dirs: &[LogDirective], entry: *mut ModEntry) -> u32 { + let mut new_lvl: u32 = DEFAULT_LOG_LEVEL; + let mut longest_match = 0; + unsafe { + for dir in dirs.iter() { + let name = from_c_str((*entry).name); + if name.starts_with(dir.name) && dir.name.len() > longest_match { + longest_match = dir.name.len(); + new_lvl = dir.level; + } + } + *(*entry).log_level = new_lvl; + } + if longest_match > 0 { return 1; } else { return 0; } +} + +#[fixed_stack_segment] #[inline(never)] +/// Set log level for every entry in crate_map according to the sepecification +/// in settings +fn update_log_settings(crate_map: *u8, settings: ~str) { + let mut dirs = ~[]; + if settings.len() > 0 { + if settings == ~"::help" || settings == ~"?" { + dumb_println("\nCrate log map:\n"); + do iter_crate_map(crate_map) |entry: *mut ModEntry| { + unsafe { + dumb_println(" "+from_c_str((*entry).name)); + } + } + unsafe { + exit(1); + } + } + dirs = parse_logging_spec(settings); + } + + let mut n_matches: u32 = 0; + do iter_crate_map(crate_map) |entry: *mut ModEntry| { + let m = update_entry(dirs, entry); + n_matches += m; + } + + if n_matches < (dirs.len() as u32) { + dumb_println(fmt!("warning: got %u RUST_LOG specs but only matched %u of them.\n\ + You may have mistyped a RUST_LOG spec.\n\ + Use RUST_LOG=::help to see the list of crates and modules.\n", + dirs.len() as uint, n_matches as uint)); + } +} pub trait Logger { fn log(&mut self, msg: Either<~str, &'static str>); @@ -47,34 +196,26 @@ impl Logger for StdErrLogger { }; fn print(s: &str) { - let dbg = ::libc::STDERR_FILENO as ::io::fd_t; + let dbg = STDERR_FILENO as ::io::fd_t; dbg.write_str(s); dbg.write_str("\n"); dbg.flush(); } } } - /// Configure logging by traversing the crate map and setting the /// per-module global logging flags based on the logging spec #[fixed_stack_segment] #[inline(never)] pub fn init(crate_map: *u8) { - use c_str::ToCStr; use os; - use ptr; - use option::{Some, None}; let log_spec = os::getenv("RUST_LOG"); match log_spec { Some(spec) => { - do spec.with_c_str |buf| { - unsafe { rust_update_log_settings(crate_map, buf) } - } + update_log_settings(crate_map, spec); } None => { - unsafe { - rust_update_log_settings(crate_map, ptr::null()); - } + update_log_settings(crate_map, ~""); } } } @@ -89,9 +230,101 @@ pub fn console_off() { unsafe { rust_log_console_off() } } fn should_log_console() -> bool { unsafe { rust_should_log_console() != 0 } } extern { - fn rust_update_log_settings(crate_map: *u8, settings: *libc::c_char); fn rust_log_console_on(); fn rust_log_console_off(); - fn rust_should_log_console() -> libc::uintptr_t; + fn rust_should_log_console() -> uintptr_t; +} + +// Tests for parse_logging_spec() +#[test] +fn parse_logging_spec_valid() { + let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=1,crate1::mod2,crate2=4"); + assert_eq!(dirs.len(), 3); + assert!(dirs[0].name == ~"crate1::mod1"); + assert_eq!(dirs[0].level, 1); + + assert!(dirs[1].name == ~"crate1::mod2"); + assert_eq!(dirs[1].level, MAX_LOG_LEVEL); + + assert!(dirs[2].name == ~"crate2"); + assert_eq!(dirs[2].level, 4); +} + +#[test] +fn parse_logging_spec_invalid_crate() { + // test parse_logging_spec with multiple = in specification + let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=1=2,crate2=4"); + assert_eq!(dirs.len(), 1); + assert!(dirs[0].name == ~"crate2"); + assert_eq!(dirs[0].level, 4); +} + +#[test] +fn parse_logging_spec_invalid_log_level() { + // test parse_logging_spec with 'noNumber' as log level + let dirs: ~[LogDirective] = parse_logging_spec(~"crate1::mod1=noNumber,crate2=4"); + assert_eq!(dirs.len(), 1); + assert!(dirs[0].name == ~"crate2"); + assert_eq!(dirs[0].level, 4); +} + +// Tests for update_entry +#[test] +fn update_entry_match_full_path() { + use c_str::ToCStr; + let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 }, + LogDirective {name: ~"crate2", level: 3}]; + unsafe { + do "crate1::mod1".to_c_str().with_ref |ptr| { + let entry= &ModEntry {name: ptr, log_level: &mut 0}; + let m = update_entry(dirs, transmute(entry)); + assert!(*entry.log_level == 2); + assert!(m == 1); + } + } } +#[test] +fn update_entry_no_match() { + use c_str::ToCStr; + let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 }, + LogDirective {name: ~"crate2", level: 3}]; + unsafe { + do "crate3::mod1".to_c_str().with_ref |ptr| { + let entry= &ModEntry {name: ptr, log_level: &mut 0}; + let m = update_entry(dirs, transmute(entry)); + assert!(*entry.log_level == DEFAULT_LOG_LEVEL); + assert!(m == 0); + } + } +} + +#[test] +fn update_entry_match_beginning() { + use c_str::ToCStr; + let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 }, + LogDirective {name: ~"crate2", level: 3}]; + unsafe { + do "crate2::mod1".to_c_str().with_ref |ptr| { + let entry= &ModEntry {name: ptr, log_level: &mut 0}; + let m = update_entry(dirs, transmute(entry)); + assert!(*entry.log_level == 3); + assert!(m == 1); + } + } +} + +#[test] +fn update_entry_match_beginning_longest_match() { + use c_str::ToCStr; + let dirs = ~[LogDirective {name: ~"crate1::mod1", level: 2 }, + LogDirective {name: ~"crate2", level: 3}, LogDirective {name: ~"crate2::mod", level: 4}]; + unsafe { + do "crate2::mod1".to_c_str().with_ref |ptr| { + let entry = &ModEntry {name: ptr, log_level: &mut 0}; + let m = update_entry(dirs, transmute(entry)); + assert!(*entry.log_level == 4); + assert!(m == 1); + } + } +} diff --git a/src/rt/rust_crate_map.cpp b/src/rt/rust_crate_map.cpp index 7faae196000ef..e6206fd7bcb31 100644 --- a/src/rt/rust_crate_map.cpp +++ b/src/rt/rust_crate_map.cpp @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -12,36 +12,52 @@ #include void iter_module_map(const mod_entry* map, - void (*fn)(const mod_entry* entry, void *cookie), - void *cookie) { + void (*fn)(void* fptr, void* env, const mod_entry *entry), + void* fptr, + void* env + ) { for (const mod_entry* cur = map; cur->name; cur++) { - fn(cur, cookie); + fn(fptr, env, cur); } } void iter_crate_map(const cratemap* map, - void (*fn)(const mod_entry* map, void *cookie), - void *cookie, + void (*fn)(void* fptr, void* env, const mod_entry *entry), + void *fptr, + void *env, std::set& visited) { if (visited.find(map) == visited.end()) { // Mark this crate visited visited.insert(map); // First iterate this crate - iter_module_map(map->entries(), fn, cookie); + iter_module_map(map->entries(), fn, fptr, env); // Then recurse on linked crates for (cratemap::iterator i = map->begin(), e = map->end(); i != e; ++i) { - iter_crate_map(*i, fn, cookie, visited); + iter_crate_map(*i, fn, fptr, env, visited); } } } void iter_crate_map(const cratemap* map, - void (*fn)(const mod_entry* map, void *cookie), - void *cookie) { + void (*fn)(void* fptr, void* env, const mod_entry *entry), + void *fptr, + void *env + ) { std::set visited; - iter_crate_map(map, fn, cookie, visited); + iter_crate_map(map, fn, fptr, env, visited); } + +extern "C" CDECL void +rust_iter_crate_map(const cratemap* map, + void (*fn)(void* fptr, void* env, const mod_entry *entry), + void *fptr, + void *env + ) { + return iter_crate_map(map, fn, fptr, env); +} + + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_crate_map.h b/src/rt/rust_crate_map.h index 80b969d6f6d7d..1bcb2aa8f7e4d 100644 --- a/src/rt/rust_crate_map.h +++ b/src/rt/rust_crate_map.h @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -16,7 +16,7 @@ struct mod_entry { const char* name; - uint32_t* state; + uint32_t* log_level; }; class cratemap; @@ -83,12 +83,14 @@ class cratemap { }; void iter_module_map(const mod_entry* map, - void (*fn)(const mod_entry* entry, void *cookie), - void *cookie); + void (*fn)(void* fptr, void* env, const mod_entry *entry), + void *fptr, + void *env); void iter_crate_map(const cratemap* map, - void (*fn)(const mod_entry* entry, void *cookie), - void *cookie); + void (*fn)(void* fptr, void* env, const mod_entry *entry), + void *fptr, + void *env); // // Local Variables: diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp deleted file mode 100644 index 97c1135fe01d2..0000000000000 --- a/src/rt/rust_log.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/* - * Logging infrastructure that aims to support multi-threading - */ - - -#include "rust_crate_map.h" -#include "util/array_list.h" -#include "rust_util.h" - -// Reading log directives and setting log level vars - -struct log_directive { - char* name; - size_t level; -}; - - -const uint32_t log_err = 1; -const uint32_t log_warn = 2; -const uint32_t log_info = 3; -const uint32_t log_debug = 4; - -const size_t max_log_directives = 255; -const size_t max_log_level = 255; -const size_t default_log_level = log_err; - -// This is a rather ugly parser for strings in the form -// "crate1,crate2.mod3,crate3.x=1". Log levels are 0-255, -// with the most likely ones being 0-3 (defined in std::). -size_t parse_logging_spec(char* spec, log_directive* dirs) { - size_t dir = 0; - while (dir < max_log_directives && *spec) { - char* start = spec; - char cur; - while (true) { - cur = *spec; - if (cur == ',' || cur == '=' || cur == '\0') { - if (start == spec) {spec++; break;} - if (*spec != '\0') { - *spec = '\0'; - spec++; - } - size_t level = max_log_level; - if (cur == '=' && *spec != '\0') { - level = *spec - '0'; - if (level > max_log_level) level = max_log_level; - if (*spec) ++spec; - } - dirs[dir].name = start; - dirs[dir++].level = level; - break; - } else { - spec++; - } - } - } - return dir; -} - -struct update_entry_args { - log_directive* dirs; - size_t n_dirs; - size_t *n_matches; -}; - -static void update_entry(const mod_entry* entry, void *cookie) { - update_entry_args *args = (update_entry_args *)cookie; - size_t level = default_log_level, longest_match = 0; - for (size_t d = 0; d < args->n_dirs; d++) { - if (strstr(entry->name, args->dirs[d].name) == entry->name && - strlen(args->dirs[d].name) > longest_match) { - longest_match = strlen(args->dirs[d].name); - level = args->dirs[d].level; - } - } - *entry->state = level; - if (longest_match > 0) { - (*args->n_matches)++; - } -} - -void update_crate_map(const cratemap* map, log_directive* dirs, - size_t n_dirs, size_t *n_matches) { - update_entry_args args = { dirs, n_dirs, n_matches }; - iter_crate_map(map, update_entry, &args); -} - -void print_mod_name(const mod_entry* mod, void *cooke) { - printf(" %s\n", mod->name); -} - -void print_crate_log_map(const cratemap* map) { - iter_crate_map(map, print_mod_name, NULL); -} - -void update_log_settings(void* crate_map, char* settings) { - char* buffer = NULL; - log_directive dirs[256]; - size_t n_dirs = 0; - - if (settings) { - - if (strcmp(settings, "::help") == 0 || - strcmp(settings, "?") == 0) { - printf("\nCrate log map:\n\n"); - print_crate_log_map((const cratemap*)crate_map); - printf("\n"); - exit(1); - } - - size_t buflen = strlen(settings) + 1; - buffer = (char*)malloc(buflen); - strncpy(buffer, settings, buflen); - n_dirs = parse_logging_spec(buffer, &dirs[0]); - } - - size_t n_matches = 0; - update_crate_map((const cratemap*)crate_map, &dirs[0], - n_dirs, &n_matches); - - if (n_matches < n_dirs) { - fprintf(stderr, "warning: got %lu RUST_LOG specs but only matched %lu of them.\n" - "You may have mistyped a RUST_LOG spec.\n" - "Use RUST_LOG=::help to see the list of crates and modules.\n", - (unsigned long)n_dirs, (unsigned long)n_matches); - } - - free(buffer); -} - -extern "C" CDECL void -rust_update_log_settings(void* crate_map, char* settings) { - update_log_settings(crate_map, settings); -} - -// -// Local Variables: -// mode: C++ -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; -// End: -// diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index b668d39440662..c1ba0524be9bc 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -182,7 +182,7 @@ rust_valgrind_stack_register rust_valgrind_stack_deregister rust_take_env_lock rust_drop_env_lock -rust_update_log_settings +rust_iter_crate_map rust_running_on_valgrind rust_get_num_cpus rust_get_global_args_ptr @@ -191,4 +191,4 @@ rust_drop_global_args_lock rust_take_change_dir_lock rust_drop_change_dir_lock rust_get_test_int -rust_get_task \ No newline at end of file +rust_get_task