From ab1dd09d736fd443883ea4c1d8ec73ff285f6308 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 11 Mar 2014 13:38:36 -0700 Subject: [PATCH] rustc: Switch defaults from libgreen to libnative The compiler will no longer inject libgreen as the default runtime for rust programs, this commit switches it over to libnative by default. Now that libnative has baked for some time, it is ready enough to start getting more serious usage as the default runtime for rustc generated binaries. We've found that there isn't really a correct decision in choosing a 1:1 or M:N runtime as a default for all applications, but it seems that a larger number of programs today would work more reasonable with a native default rather than a green default. With this commit come a number of bugfixes: * The main native task is now named "
" * The main native task has the stack bounds set up properly * #[no_uv] was renamed to #[no_start] * The core-run-destroy test was rewritten for both libnative and libgreen and one of the tests was modified to be more robust. * The process-detach test was locked to libgreen because it uses signal handling --- src/compiletest/compiletest.rs | 5 + src/driver/driver.rs | 8 +- src/libgreen/lib.rs | 2 +- src/libnative/lib.rs | 18 ++- src/librustc/front/std_inject.rs | 18 +-- src/librustc/middle/lint.rs | 2 +- src/librustuv/lib.rs | 11 ++ src/libstd/lib.rs | 10 ++ src/test/run-fail/native-failure.rs | 2 - .../bootstrap-from-c-with-green/lib.rs | 1 - .../bootstrap-from-c-with-native/lib.rs | 1 - src/test/run-pass/capturing-logging.rs | 3 +- src/test/run-pass/core-run-destroy.rs | 125 ++++++++++-------- src/test/run-pass/native-print-no-runtime.rs | 2 - src/test/run-pass/process-detach.rs | 6 + 15 files changed, 130 insertions(+), 84 deletions(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index da21db6e5d5..e86309f81af 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -19,6 +19,8 @@ extern crate test; extern crate getopts; #[phase(link, syntax)] extern crate log; +extern crate green; +extern crate rustuv; use std::os; use std::io; @@ -41,6 +43,9 @@ pub mod runtest; pub mod common; pub mod errors; +#[start] +fn start(argc: int, argv: **u8) -> int { green::start(argc, argv, main) } + pub fn main() { let args = os::args(); let config = parse_config(args.move_iter().collect()); diff --git a/src/driver/driver.rs b/src/driver/driver.rs index 0ceb12064b0..bd7096cda03 100644 --- a/src/driver/driver.rs +++ b/src/driver/driver.rs @@ -8,7 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[no_uv]; +#[no_uv]; // remove this after stage0 +#[allow(attribute_usage)]; // remove this after stage0 +extern crate native; // remove this after stage0 #[cfg(rustdoc)] extern crate this = "rustdoc"; @@ -16,7 +18,9 @@ extern crate this = "rustdoc"; #[cfg(rustc)] extern crate this = "rustc"; -extern crate native; +#[cfg(not(stage0))] +fn main() { this::main() } +#[cfg(stage0)] #[start] fn start(argc: int, argv: **u8) -> int { native::start(argc, argv, this::main) } diff --git a/src/libgreen/lib.rs b/src/libgreen/lib.rs index b9846c9c3a2..926b9028a7a 100644 --- a/src/libgreen/lib.rs +++ b/src/libgreen/lib.rs @@ -209,7 +209,7 @@ pub mod stack; pub mod task; #[lang = "start"] -#[cfg(not(test))] +#[cfg(not(test), stage0)] pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int { use std::cast; start(argc, argv, proc() { diff --git a/src/libnative/lib.rs b/src/libnative/lib.rs index f50cf727864..afe440cc1e0 100644 --- a/src/libnative/lib.rs +++ b/src/libnative/lib.rs @@ -58,6 +58,7 @@ use std::os; use std::rt; +use std::str; pub mod io; pub mod task; @@ -68,6 +69,16 @@ static OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20; #[cfg(unix, not(android))] static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20); +#[lang = "start"] +#[cfg(not(test), not(stage0))] +pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int { + use std::cast; + start(argc, argv, proc() { + let main: extern "Rust" fn() = unsafe { cast::transmute(main) }; + main(); + }) +} + /// Executes the given procedure after initializing the runtime with the given /// argc/argv. /// @@ -90,7 +101,12 @@ pub fn start(argc: int, argv: **u8, main: proc()) -> int { rt::init(argc, argv); let mut exit_code = None; let mut main = Some(main); - let t = task::new((my_stack_bottom, my_stack_top)).run(|| { + let mut task = task::new((my_stack_bottom, my_stack_top)); + task.name = Some(str::Slice("
")); + let t = task.run(|| { + unsafe { + rt::stack::record_stack_bounds(my_stack_bottom, my_stack_top); + } exit_code = Some(run(main.take_unwrap())); }); drop(t); diff --git a/src/librustc/front/std_inject.rs b/src/librustc/front/std_inject.rs index 6a6819ae516..a78f90cbe87 100644 --- a/src/librustc/front/std_inject.rs +++ b/src/librustc/front/std_inject.rs @@ -46,8 +46,8 @@ fn use_std(krate: &ast::Crate) -> bool { !attr::contains_name(krate.attrs.as_slice(), "no_std") } -fn use_uv(krate: &ast::Crate) -> bool { - !attr::contains_name(krate.attrs.as_slice(), "no_uv") +fn use_start(krate: &ast::Crate) -> bool { + !attr::contains_name(krate.attrs.as_slice(), "no_start") } fn no_prelude(attrs: &[ast::Attribute]) -> bool { @@ -87,18 +87,10 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> { span: DUMMY_SP }); - if use_uv(&krate) && !self.sess.building_library.get() { + if use_start(&krate) && !self.sess.building_library.get() { vis.push(ast::ViewItem { - node: ast::ViewItemExternCrate(token::str_to_ident("green"), - with_version("green"), - ast::DUMMY_NODE_ID), - attrs: Vec::new(), - vis: ast::Inherited, - span: DUMMY_SP - }); - vis.push(ast::ViewItem { - node: ast::ViewItemExternCrate(token::str_to_ident("rustuv"), - with_version("rustuv"), + node: ast::ViewItemExternCrate(token::str_to_ident("native"), + with_version("native"), ast::DUMMY_NODE_ID), attrs: Vec::new(), vis: ast::Inherited, diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 6c13d496166..286ecbd6c8f 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -961,7 +961,7 @@ fn check_heap_item(cx: &Context, it: &ast::Item) { } static crate_attrs: &'static [&'static str] = &[ - "crate_type", "feature", "no_uv", "no_main", "no_std", "crate_id", + "crate_type", "feature", "no_start", "no_main", "no_std", "crate_id", "desc", "comment", "license", "copyright", // not used in rustc now ]; diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index ee4f15e7954..42ccdaf9562 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -45,6 +45,7 @@ via `close` and `delete` methods. #[allow(deprecated_owned_vector)]; // NOTE: remove after stage0 #[cfg(test)] extern crate green; +#[cfg(test)] extern crate realrustuv = "rustuv"; use std::cast; use std::fmt; @@ -69,6 +70,16 @@ pub use self::signal::SignalWatcher; pub use self::timer::TimerWatcher; pub use self::tty::TtyWatcher; +// Run tests with libgreen instead of libnative. +// +// FIXME: This egregiously hacks around starting the test runner in a different +// threading mode than the default by reaching into the auto-generated +// '__test' module. +#[cfg(test)] #[start] +fn start(argc: int, argv: **u8) -> int { + green::start(argc, argv, __test::main) +} + mod macros; mod access; diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 433400cc9f0..7d734469b12 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -81,6 +81,16 @@ #[cfg(stage0)] pub use vec_ng = vec; +// Run tests with libgreen instead of libnative. +// +// FIXME: This egregiously hacks around starting the test runner in a different +// threading mode than the default by reaching into the auto-generated +// '__test' module. +#[cfg(test)] #[start] +fn start(argc: int, argv: **u8) -> int { + green::start(argc, argv, __test::main) +} + pub mod macros; mod rtdeps; diff --git a/src/test/run-fail/native-failure.rs b/src/test/run-fail/native-failure.rs index da00bdf5e0a..377057a75ff 100644 --- a/src/test/run-fail/native-failure.rs +++ b/src/test/run-fail/native-failure.rs @@ -11,8 +11,6 @@ // ignore-android (FIXME #11419) // error-pattern:explicit failure -#[no_uv]; - extern crate native; #[start] diff --git a/src/test/run-make/bootstrap-from-c-with-green/lib.rs b/src/test/run-make/bootstrap-from-c-with-green/lib.rs index 920474ea9bd..62c5a06dbbf 100644 --- a/src/test/run-make/bootstrap-from-c-with-green/lib.rs +++ b/src/test/run-make/bootstrap-from-c-with-green/lib.rs @@ -10,7 +10,6 @@ #[crate_id="boot#0.1"]; #[crate_type="dylib"]; -#[no_uv]; extern crate rustuv; extern crate green; diff --git a/src/test/run-make/bootstrap-from-c-with-native/lib.rs b/src/test/run-make/bootstrap-from-c-with-native/lib.rs index 2bc0dbb7770..33c8d4ffab7 100644 --- a/src/test/run-make/bootstrap-from-c-with-native/lib.rs +++ b/src/test/run-make/bootstrap-from-c-with-native/lib.rs @@ -10,7 +10,6 @@ #[crate_id="boot#0.1"]; #[crate_type="dylib"]; -#[no_uv]; extern crate native; diff --git a/src/test/run-pass/capturing-logging.rs b/src/test/run-pass/capturing-logging.rs index b1db8ad9223..97dfbb0d8e2 100644 --- a/src/test/run-pass/capturing-logging.rs +++ b/src/test/run-pass/capturing-logging.rs @@ -14,10 +14,9 @@ #[feature(phase)]; -#[no_uv]; -extern crate native; #[phase(syntax, link)] extern crate log; +extern crate native; use std::fmt; use std::io::{ChanReader, ChanWriter}; diff --git a/src/test/run-pass/core-run-destroy.rs b/src/test/run-pass/core-run-destroy.rs index db7b2803c71..bda7a30762a 100644 --- a/src/test/run-pass/core-run-destroy.rs +++ b/src/test/run-pass/core-run-destroy.rs @@ -9,19 +9,50 @@ // except according to those terms. // ignore-fast +// ignore-pretty // compile-flags:--test // NB: These tests kill child processes. Valgrind sees these children as leaking // memory, which makes for some *confusing* logs. That's why these are here // instead of in std. -use std::io::timer; -use std::libc; -use std::str; -use std::io::process::{Process, ProcessOutput}; +#[feature(macro_rules)]; -#[test] -fn test_destroy_once() { +extern crate native; +extern crate green; +extern crate rustuv; + +macro_rules! iotest ( + { fn $name:ident() $b:block $($a:attr)* } => ( + mod $name { + #[allow(unused_imports)]; + + use std::io::timer; + use std::libc; + use std::str; + use std::io::process::{Process, ProcessOutput}; + use native; + use super::*; + + fn f() $b + + $($a)* #[test] fn green() { f() } + $($a)* #[test] fn native() { + use native; + let (tx, rx) = channel(); + native::task::spawn(proc() { tx.send(f()) }); + rx.recv(); + } + } + ) +) + +#[cfg(test)] #[start] +fn start(argc: int, argv: **u8) -> int { + green::start(argc, argv, __test::main) +} + +iotest!(fn test_destroy_once() { #[cfg(not(target_os="android"))] static mut PROG: &'static str = "echo"; @@ -30,10 +61,9 @@ fn test_destroy_once() { let mut p = unsafe {Process::new(PROG, []).unwrap()}; p.signal_exit().unwrap(); // this shouldn't crash (and nor should the destructor) -} +}) -#[test] -fn test_destroy_twice() { +iotest!(fn test_destroy_twice() { #[cfg(not(target_os="android"))] static mut PROG: &'static str = "echo"; #[cfg(target_os="android")] @@ -45,56 +75,27 @@ fn test_destroy_twice() { }; p.signal_exit().unwrap(); // this shouldnt crash... p.signal_exit().unwrap(); // ...and nor should this (and nor should the destructor) -} +}) -fn test_destroy_actually_kills(force: bool) { +pub fn test_destroy_actually_kills(force: bool) { + use std::io::process::{Process, ProcessOutput, ExitStatus, ExitSignal}; + use std::io::timer; + use std::libc; + use std::str; #[cfg(unix,not(target_os="android"))] - static mut BLOCK_COMMAND: &'static str = "cat"; + static BLOCK_COMMAND: &'static str = "cat"; #[cfg(unix,target_os="android")] - static mut BLOCK_COMMAND: &'static str = "/system/bin/cat"; + static BLOCK_COMMAND: &'static str = "/system/bin/cat"; #[cfg(windows)] - static mut BLOCK_COMMAND: &'static str = "cmd"; - - #[cfg(unix,not(target_os="android"))] - fn process_exists(pid: libc::pid_t) -> bool { - let ProcessOutput {output, ..} = Process::output("ps", [~"-p", pid.to_str()]) - .unwrap(); - str::from_utf8_owned(output).unwrap().contains(pid.to_str()) - } - - #[cfg(unix,target_os="android")] - fn process_exists(pid: libc::pid_t) -> bool { - let ProcessOutput {output, ..} = Process::output("/system/bin/ps", [pid.to_str()]) - .unwrap(); - str::from_utf8_owned(output).unwrap().contains(~"root") - } - - #[cfg(windows)] - fn process_exists(pid: libc::pid_t) -> bool { - use std::libc::types::os::arch::extra::DWORD; - use std::libc::funcs::extra::kernel32::{CloseHandle, GetExitCodeProcess, OpenProcess}; - use std::libc::consts::os::extra::{FALSE, PROCESS_QUERY_INFORMATION, STILL_ACTIVE }; - - unsafe { - let process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD); - if process.is_null() { - return false; - } - // process will be non-null if the process is alive, or if it died recently - let mut status = 0; - GetExitCodeProcess(process, &mut status); - CloseHandle(process); - return status == STILL_ACTIVE; - } - } + static BLOCK_COMMAND: &'static str = "cmd"; // this process will stay alive indefinitely trying to read from stdin - let mut p = unsafe {Process::new(BLOCK_COMMAND, []).unwrap()}; + let mut p = Process::new(BLOCK_COMMAND, []).unwrap(); - assert!(process_exists(p.id())); + assert!(p.signal(0).is_ok()); if force { p.signal_kill().unwrap(); @@ -102,18 +103,26 @@ fn test_destroy_actually_kills(force: bool) { p.signal_exit().unwrap(); } - if process_exists(p.id()) { - timer::sleep(500); - assert!(!process_exists(p.id())); + // Don't let this test time out, this should be quick + let (tx, rx1) = channel(); + let mut t = timer::Timer::new().unwrap(); + let rx2 = t.oneshot(1000); + spawn(proc() { + select! { + () = rx2.recv() => unsafe { libc::exit(1) }, + () = rx1.recv() => {} + } + }); + match p.wait() { + ExitStatus(..) => fail!("expected a signal"), + ExitSignal(..) => tx.send(()), } } -#[test] -fn test_unforced_destroy_actually_kills() { +iotest!(fn test_unforced_destroy_actually_kills() { test_destroy_actually_kills(false); -} +}) -#[test] -fn test_forced_destroy_actually_kills() { +iotest!(fn test_forced_destroy_actually_kills() { test_destroy_actually_kills(true); -} +}) diff --git a/src/test/run-pass/native-print-no-runtime.rs b/src/test/run-pass/native-print-no-runtime.rs index 67de65cea9f..150435959e4 100644 --- a/src/test/run-pass/native-print-no-runtime.rs +++ b/src/test/run-pass/native-print-no-runtime.rs @@ -10,8 +10,6 @@ // ignore-fast -#[no_uv]; - #[start] pub fn main(_: int, _: **u8) -> int { println!("hello"); diff --git a/src/test/run-pass/process-detach.rs b/src/test/run-pass/process-detach.rs index ffb446d1b33..319c2682013 100644 --- a/src/test/run-pass/process-detach.rs +++ b/src/test/run-pass/process-detach.rs @@ -20,10 +20,16 @@ // Note that the first thing we do is put ourselves in our own process group so // we don't interfere with other running tests. +extern crate green; +extern crate rustuv; + use std::libc; use std::io::process; use std::io::signal::{Listener, Interrupt}; +#[start] +fn start(argc: int, argv: **u8) -> int { green::start(argc, argv, main) } + fn main() { unsafe { libc::setsid(); }