diff options
| author | bors <bors@rust-lang.org> | 2014-12-19 08:28:52 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-12-19 08:28:52 +0000 |
| commit | 0efafac398ff7f28c5f0fe756c15b9008b3e0534 (patch) | |
| tree | 2e8279b94829b65868049d2e3df0b9a6c3365a8f /src/libstd/rt/mod.rs | |
| parent | 6bdce25e155d846bb9252fa4a18baef7e74cf8bf (diff) | |
| parent | 903c5a8f69714382ec9fc22745f902c3e219cb68 (diff) | |
auto merge of #19654 : aturon/rust/merge-rt, r=alexcrichton
This PR substantially narrows the notion of a "runtime" in Rust, and allows calling into Rust code directly without any setup or teardown. After this PR, the basic "runtime support" in Rust will consist of: * Unwinding and backtrace support * Stack guards Other support, such as helper threads for timers or the notion of a "current thread" are initialized automatically upon first use. When using Rust in an embedded context, it should now be possible to call a Rust function directly as a C function with absolutely no setup, though in that case panics will cause the process to abort. In this regard, the C/Rust interface will look much like the C/C++ interface. In more detail, this PR: * Merges `librustrt` back into `std::rt`, undoing the facade. While doing so, it removes a substantial amount of redundant functionality (such as mutexes defined in the `rt` module). Code using `librustrt` can now call into `std::rt` to e.g. start executing Rust code with unwinding support. * Allows all runtime data to be initialized lazily, including the "current thread", the "at_exit" infrastructure, and the "args" storage. * Deprecates and largely removes `std::task` along with the widespread requirement that there be a "current task" for many APIs in `std`. The entire task infrastructure is replaced with `std::thread`, which provides a more standard API for manipulating and creating native OS threads. In particular, it's possible to join on a created thread, and to get a handle to the currently-running thread. In addition, threads are equipped with some basic blocking support in the form of `park`/`unpark` operations (following a tradition in some OSes as well as the JVM). See the `std::thread` documentation for more details. * Channels are refactored to use a new internal blocking infrastructure that itself sits on top of `park`/`unpark`. One important change here is that a Rust program ends when its main thread does, following most threading models. On the other hand, threads will often be created with an RAII-style join handle that will re-institute blocking semantics naturally (and with finer control). This is very much a: [breaking-change] Closes #18000 r? @alexcrichton
Diffstat (limited to 'src/libstd/rt/mod.rs')
| -rw-r--r-- | src/libstd/rt/mod.rs | 204 |
1 files changed, 103 insertions, 101 deletions
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index eb517047ddc..8d9c1268e7e 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -8,38 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Runtime services, including the task scheduler and I/O dispatcher +//! Runtime services //! -//! The `rt` module provides the private runtime infrastructure necessary to support core language -//! features like the exchange and local heap, logging, local data and unwinding. It also -//! implements the default task scheduler and task model. Initialization routines are provided for -//! setting up runtime resources in common configurations, including that used by `rustc` when -//! generating executables. -//! -//! It is intended that the features provided by `rt` can be factored in a way such that the core -//! library can be built with different 'profiles' for different use cases, e.g. excluding the task -//! scheduler. A number of runtime features though are critical to the functioning of the language -//! and an implementation must be provided regardless of the execution environment. -//! -//! Of foremost importance is the global exchange heap, in the module `heap`. Very little practical -//! Rust code can be written without access to the global heap. Unlike most of `rt` the global heap -//! is truly a global resource and generally operates independently of the rest of the runtime. -//! -//! All other runtime features are task-local, including the local heap, local storage, logging and -//! the stack unwinder. -//! -//! The relationship between `rt` and the rest of the core library is not entirely clear yet and -//! some modules will be moving into or out of `rt` as development proceeds. -//! -//! Several modules in `core` are clients of `rt`: -//! -//! * `std::task` - The user-facing interface to the Rust task model. -//! * `std::local_data` - The interface to local data. -//! * `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`. -//! * `std::cleanup` - Local heap destruction. -//! * `std::io` - In the future `std::io` will use an `rt` implementation. -//! * `std::logging` -//! * `std::comm` +//! The `rt` module provides a narrow set of runtime services, +//! including the global heap (exported in `heap`) and unwinding and +//! backtrace support. The APIs in this module are highly unstable, +//! and should be considered as private implementation details for the +//! time being. #![experimental] @@ -48,65 +23,51 @@ #![allow(dead_code)] -use borrow::IntoCow; -use failure; -use rustrt; use os; use thunk::Thunk; +use kinds::Send; +use thread::Thread; +use ops::FnOnce; +use sys; +use sys_common; +use sys_common::thread_info::{mod, NewThread}; // Reexport some of our utilities which are expected by other crates. pub use self::util::{default_sched_threads, min_stack, running_on_valgrind}; +pub use self::unwind::{begin_unwind, begin_unwind_fmt}; -// Reexport functionality from librustrt and other crates underneath the -// standard library which work together to create the entire runtime. +// Reexport some functionality from liballoc. pub use alloc::heap; -pub use rustrt::{begin_unwind, begin_unwind_fmt, at_exit}; // Simple backtrace functionality (to print on panic) pub mod backtrace; -// Just stuff -mod util; +// Internals +mod macros; -/// One-time runtime initialization. -/// -/// Initializes global state, including frobbing -/// the crate's logging flags, registering GC -/// metadata, and storing the process arguments. -#[allow(experimental)] -pub fn init(argc: int, argv: *const *const u8) { - rustrt::init(argc, argv); - unsafe { rustrt::unwind::register(failure::on_fail); } -} +// These should be refactored/moved/made private over time +pub mod util; +pub mod unwind; +pub mod args; + +mod at_exit_imp; +mod libunwind; + +/// The default error code of the rust runtime if the main task panics instead +/// of exiting cleanly. +pub const DEFAULT_ERROR_CODE: int = 101; #[cfg(any(windows, android))] -static OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20; +const OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20; #[cfg(all(unix, not(android)))] -static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20); +const OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20); #[cfg(not(test))] #[lang = "start"] fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { use mem; - start(argc, argv, Thunk::new(move|| { - let main: extern "Rust" fn() = unsafe { mem::transmute(main) }; - main(); - })) -} - -/// Executes the given procedure after initializing the runtime with the given -/// argc/argv. -/// -/// This procedure is guaranteed to run on the thread calling this function, but -/// the stack bounds for this rust task will *not* be set. Care must be taken -/// for this function to not overflow its stack. -/// -/// This function will only return once *all* native threads in the system have -/// exited. -pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int { use prelude::*; use rt; - use rustrt::task::Task; let something_around_the_top_of_the_stack = 1; let addr = &something_around_the_top_of_the_stack as *const int; @@ -117,40 +78,76 @@ pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int { // frames above our current position. let my_stack_bottom = my_stack_top + 20000 - OS_DEFAULT_STACK_ESTIMATE; - // When using libgreen, one of the first things that we do is to turn off - // the SIGPIPE signal (set it to ignore). By default, some platforms will - // send a *signal* when a EPIPE error would otherwise be delivered. This - // runtime doesn't install a SIGPIPE handler, causing it to kill the - // program, which isn't exactly what we want! - // - // Hence, we set SIGPIPE to ignore when the program starts up in order to - // prevent this problem. - #[cfg(windows)] fn ignore_sigpipe() {} - #[cfg(unix)] fn ignore_sigpipe() { - use libc; - use libc::funcs::posix01::signal::signal; - unsafe { - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1); + let failed = unsafe { + // First, make sure we don't trigger any __morestack overflow checks, + // and next set up our stack to have a guard page and run through our + // own fault handlers if we hit it. + sys_common::stack::record_os_managed_stack_bounds(my_stack_bottom, + my_stack_top); + sys::thread::guard::init(); + sys::stack_overflow::init(); + + // Next, set up the current Thread with the guard information we just + // created. Note that this isn't necessary in general for new threads, + // but we just do this to name the main thread and to give it correct + // info about the stack bounds. + let thread: Thread = NewThread::new(Some("<main>".into_string())); + thread_info::set((my_stack_bottom, my_stack_top), + sys::thread::guard::main(), + thread); + + // By default, some platforms will send a *signal* when a EPIPE error + // would otherwise be delivered. This runtime doesn't install a SIGPIPE + // handler, causing it to kill the program, which isn't exactly what we + // want! + // + // Hence, we set SIGPIPE to ignore when the program starts up in order + // to prevent this problem. + #[cfg(windows)] fn ignore_sigpipe() {} + #[cfg(unix)] fn ignore_sigpipe() { + use libc; + use libc::funcs::posix01::signal::signal; + unsafe { + assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1); + } } + ignore_sigpipe(); + + // Store our args if necessary in a squirreled away location + args::init(argc, argv); + + // And finally, let's run some code! + let res = unwind::try(|| { + let main: fn() = mem::transmute(main); + main(); + }); + cleanup(); + res.is_err() + }; + + // If the exit code wasn't set, then the try block must have panicked. + if failed { + rt::DEFAULT_ERROR_CODE + } else { + os::get_exit_status() } - ignore_sigpipe(); - - init(argc, argv); - let mut exit_code = None; - let mut main = Some(main); - let mut task = box Task::new(Some((my_stack_bottom, my_stack_top)), - Some(rustrt::thread::main_guard_page())); - task.name = Some("<main>".into_cow()); - drop(task.run(|| { - unsafe { - rustrt::stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); - } - (main.take().unwrap()).invoke(()); - exit_code = Some(os::get_exit_status()); - }).destroy()); - unsafe { rt::cleanup(); } - // If the exit code wasn't set, then the task block must have panicked. - return exit_code.unwrap_or(rustrt::DEFAULT_ERROR_CODE); +} + +/// Enqueues a procedure to run when the runtime is cleaned up +/// +/// The procedure passed to this function will be executed as part of the +/// runtime cleanup phase. For normal rust programs, this means that it will run +/// after all other tasks have exited. +/// +/// The procedure is *not* executed with a local `Task` available to it, so +/// primitives like logging, I/O, channels, spawning, etc, are *not* available. +/// This is meant for "bare bones" usage to clean up runtime details, this is +/// not meant as a general-purpose "let's clean everything up" function. +/// +/// It is forbidden for procedures to register more `at_exit` handlers when they +/// are running, and doing so will lead to a process abort. +pub fn at_exit<F:FnOnce()+Send>(f: F) { + at_exit_imp::push(Thunk::new(f)); } /// One-time runtime cleanup. @@ -163,5 +160,10 @@ pub fn start(argc: int, argv: *const *const u8, main: Thunk) -> int { /// Invoking cleanup while portions of the runtime are still in use may cause /// undefined behavior. pub unsafe fn cleanup() { - rustrt::cleanup(); + args::cleanup(); + sys::stack_overflow::cleanup(); + // FIXME: (#20012): the resources being cleaned up by at_exit + // currently are not prepared for cleanup to happen asynchronously + // with detached threads using the resources; for now, we leak. + // at_exit_imp::cleanup(); } |
