Skip to content

Commit 5ec36c3

Browse files
committed
std: Extract librustrt out of libstd
As part of the libstd facade efforts, this commit extracts the runtime interface out of the standard library into a standalone crate, librustrt. This crate will provide the following services: * Definition of the rtio interface * Definition of the Runtime interface * Implementation of the Task structure * Implementation of task-local-data * Implementation of task failure via unwinding via libunwind * Implementation of runtime initialization and shutdown * Implementation of thread-local-storage for the local rust Task Notably, this crate avoids the following services: * Thread creation and destruction. The crate does not require the knowledge of an OS threading system, and as a result it seemed best to leave out the `rt::thread` module from librustrt. The librustrt module does depend on mutexes, however. * Implementation of backtraces. There is no inherent requirement for the runtime to be able to generate backtraces. As will be discussed later, this functionality continues to live in libstd rather than librustrt. As usual, a number of architectural changes were required to make this crate possible. Users of "stable" functionality will not be impacted by this change, but users of the `std::rt` module will likely note the changes. A list of architectural changes made is: * The stdout/stderr handles no longer live directly inside of the `Task` structure. This is a consequence of librustrt not knowing about `std::io`. These two handles are now stored inside of task-local-data. The handles were originally stored inside of the `Task` for perf reasons, and TLD is not currently as fast as it could be. For comparison, 100k prints goes from 59ms to 68ms (a 15% slowdown). This appeared to me to be an acceptable perf loss for the successful extraction of a librustrt crate. * The `rtio` module was forced to duplicate more functionality of `std::io`. As the module no longer depends on `std::io`, `rtio` now defines structures such as socket addresses, addrinfo fiddly bits, etc. The primary change made was that `rtio` now defines its own `IoError` type. This type is distinct from `std::io::IoError` in that it does not have an enum for what error occurred, but rather a platform-specific error code. The native and green libraries will be updated in later commits for this change, and the bulk of this effort was put behind updating the two libraries for this change (with `rtio`). * Printing a message on task failure (along with the backtrace) continues to live in libstd, not in librustrt. This is a consequence of the above decision to move the stdout/stderr handles to TLD rather than inside the `Task` itself. The unwinding API now supports registration of global callback functions which will be invoked when a task fails, allowing for libstd to register a function to print a message and a backtrace. The API for registering a callback is experimental and unsafe, as the ramifications of running code on unwinding is pretty hairy. * The `std::unstable::mutex` module has moved to `std::rt::mutex`. * The `std::unstable::sync` module has been moved to `std::rt::exclusive` and the type has been rewritten to not internally have an Arc and to have an RAII guard structure when locking. Old code should stop using `Exclusive` in favor of the primitives in `libsync`, but if necessary, old code should port to `Arc<Exclusive<T>>`. * The local heap has been stripped down to have fewer debugging options. None of these were tested, and none of these have been used in a very long time. [breaking-change]
1 parent a3f9aa9 commit 5ec36c3

30 files changed

+1300
-1253
lines changed

mk/crates.mk

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252
TARGET_CRATES := libc std green rustuv native flate arena glob term semver \
5353
uuid serialize sync getopts collections num test time rand \
54-
url log regex graphviz core rlibc alloc debug
54+
url log regex graphviz core rlibc alloc debug rustrt
5555
HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros fmt_macros
5656
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
5757
TOOLS := compiletest rustdoc rustc
@@ -60,7 +60,9 @@ DEPS_core :=
6060
DEPS_rlibc :=
6161
DEPS_alloc := core libc native:jemalloc
6262
DEPS_debug := std
63-
DEPS_std := core rand libc alloc collections native:rustrt native:backtrace
63+
DEPS_rustrt := alloc core libc collections native:rustrt_native
64+
DEPS_std := core libc rand alloc collections rustrt \
65+
native:rust_builtin native:backtrace
6466
DEPS_graphviz := std
6567
DEPS_green := std native:context_switch
6668
DEPS_rustuv := std native:uv native:uv_support

mk/rt.mk

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
# that's per-target so you're allowed to conditionally add files based on the
3636
# target.
3737
################################################################################
38-
NATIVE_LIBS := rustrt hoedown uv_support morestack miniz context_switch \
39-
rust_test_helpers
38+
NATIVE_LIBS := rust_builtin hoedown uv_support morestack miniz context_switch \
39+
rustrt_native rust_test_helpers
4040

4141
# $(1) is the target triple
4242
define NATIVE_LIBRARIES
@@ -52,8 +52,9 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \
5252
hoedown/src/version.c
5353
NATIVE_DEPS_uv_support_$(1) := rust_uv.c
5454
NATIVE_DEPS_miniz_$(1) = miniz.c
55-
NATIVE_DEPS_rustrt_$(1) := rust_builtin.c \
56-
rust_android_dummy.c \
55+
NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
56+
rust_android_dummy.c
57+
NATIVE_DEPS_rustrt_native_$(1) := \
5758
rust_try.ll \
5859
arch/$$(HOST_$(1))/record_sp.S
5960
NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c

src/libcore/macros.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,20 @@ macro_rules! try(
9898
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
9999
)
100100

101+
/// Writing a formatted string into a writer
102+
#[macro_export]
103+
macro_rules! write(
104+
($dst:expr, $($arg:tt)*) => (format_args_method!($dst, write_fmt, $($arg)*))
105+
)
106+
107+
/// Writing a formatted string plus a newline into a writer
108+
#[macro_export]
109+
macro_rules! writeln(
110+
($dst:expr, $fmt:expr $($arg:tt)*) => (
111+
write!($dst, concat!($fmt, "\n") $($arg)*)
112+
)
113+
)
114+
101115
#[cfg(test)]
102116
macro_rules! vec( ($($e:expr),*) => ({
103117
let mut _v = ::std::vec::Vec::new();

src/libstd/rt/args.rs renamed to src/librustrt/args.rs

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@
1818
//! discover the command line arguments.
1919
//!
2020
//! FIXME #7756: Would be nice for this to not exist.
21-
//! FIXME #7756: This has a lot of C glue for lack of globals.
2221
23-
use option::Option;
24-
use vec::Vec;
22+
use core::prelude::*;
23+
use collections::vec::Vec;
2524

2625
/// One-time global initialization.
2726
pub unsafe fn init(argc: int, argv: **u8) { imp::init(argc, argv) }
@@ -44,14 +43,14 @@ pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() }
4443
#[cfg(target_os = "android")]
4544
#[cfg(target_os = "freebsd")]
4645
mod imp {
47-
use clone::Clone;
48-
use iter::Iterator;
49-
use option::{Option, Some, None};
50-
use owned::Box;
51-
use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
52-
use mem;
53-
use vec::Vec;
54-
use ptr::RawPtr;
46+
use core::prelude::*;
47+
48+
use alloc::owned::Box;
49+
use collections::vec::Vec;
50+
use core::mem;
51+
use core::slice;
52+
53+
use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
5554

5655
static mut global_args_ptr: uint = 0;
5756
static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
@@ -100,24 +99,23 @@ mod imp {
10099
unsafe { mem::transmute(&global_args_ptr) }
101100
}
102101

103-
// Copied from `os`.
104102
unsafe fn load_argc_and_argv(argc: int, argv: **u8) -> Vec<Vec<u8>> {
105-
use c_str::CString;
106-
use ptr::RawPtr;
107-
use libc;
108-
use vec::Vec;
109-
110103
Vec::from_fn(argc as uint, |i| {
111-
let cs = CString::new(*(argv as **libc::c_char).offset(i as int), false);
112-
Vec::from_slice(cs.as_bytes_no_nul())
104+
let base = *argv.offset(i as int);
105+
let mut len = 0;
106+
while *base.offset(len) != 0 { len += 1; }
107+
slice::raw::buf_as_slice(base, len as uint, |slice| {
108+
Vec::from_slice(slice)
109+
})
113110
})
114111
}
115112

116113
#[cfg(test)]
117114
mod tests {
118-
use prelude::*;
115+
use std::prelude::*;
116+
use std::finally::Finally;
117+
119118
use super::*;
120-
use finally::Finally;
121119

122120
#[test]
123121
fn smoke_test() {
@@ -149,8 +147,8 @@ mod imp {
149147
#[cfg(target_os = "macos")]
150148
#[cfg(target_os = "win32")]
151149
mod imp {
152-
use option::Option;
153-
use vec::Vec;
150+
use core::prelude::*;
151+
use collections::vec::Vec;
154152

155153
pub unsafe fn init(_argc: int, _argv: **u8) {
156154
}

src/librustrt/at_exit_imp.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Implementation of running at_exit routines
12+
//!
13+
//! Documentation can be found on the `rt::at_exit` function.
14+
15+
use core::prelude::*;
16+
17+
use alloc::owned::Box;
18+
use collections::vec::Vec;
19+
use core::atomics;
20+
use core::mem;
21+
22+
use exclusive::Exclusive;
23+
24+
type Queue = Exclusive<Vec<proc():Send>>;
25+
26+
static mut QUEUE: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
27+
static mut RUNNING: atomics::AtomicBool = atomics::INIT_ATOMIC_BOOL;
28+
29+
pub fn init() {
30+
let state: Box<Queue> = box Exclusive::new(Vec::new());
31+
unsafe {
32+
rtassert!(!RUNNING.load(atomics::SeqCst));
33+
rtassert!(QUEUE.swap(mem::transmute(state), atomics::SeqCst) == 0);
34+
}
35+
}
36+
37+
pub fn push(f: proc():Send) {
38+
unsafe {
39+
// Note that the check against 0 for the queue pointer is not atomic at
40+
// all with respect to `run`, meaning that this could theoretically be a
41+
// use-after-free. There's not much we can do to protect against that,
42+
// however. Let's just assume a well-behaved runtime and go from there!
43+
rtassert!(!RUNNING.load(atomics::SeqCst));
44+
let queue = QUEUE.load(atomics::SeqCst);
45+
rtassert!(queue != 0);
46+
(*(queue as *Queue)).lock().push(f);
47+
}
48+
}
49+
50+
pub fn run() {
51+
let cur = unsafe {
52+
rtassert!(!RUNNING.load(atomics::SeqCst));
53+
let queue = QUEUE.swap(0, atomics::SeqCst);
54+
rtassert!(queue != 0);
55+
56+
let queue: Box<Queue> = mem::transmute(queue);
57+
mem::replace(&mut *queue.lock(), Vec::new())
58+
};
59+
60+
for to_run in cur.move_iter() {
61+
to_run();
62+
}
63+
}

src/libstd/rt/bookkeeping.rs renamed to src/librustrt/bookkeeping.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@
1818
//! each respective runtime to make sure that they call increment() and
1919
//! decrement() manually.
2020
21-
#![experimental] // this is a massive code smell
22-
#![doc(hidden)]
21+
use core::atomics;
2322

24-
use sync::atomics;
25-
use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
23+
use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
2624

2725
static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
2826
static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;

src/libstd/c_str.rs renamed to src/librustrt/c_str.rs

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -65,24 +65,17 @@ fn main() {
6565
6666
*/
6767

68-
use clone::Clone;
69-
use cmp::PartialEq;
70-
use container::Container;
71-
use iter::{Iterator, range};
72-
use kinds::marker;
68+
use core::prelude::*;
69+
70+
use alloc::libc_heap::malloc_raw;
71+
use collections::string::String;
72+
use core::kinds::marker;
73+
use core::mem;
74+
use core::ptr;
75+
use core::raw::Slice;
76+
use core::slice;
77+
use core::str;
7378
use libc;
74-
use mem;
75-
use ops::Drop;
76-
use option::{Option, Some, None};
77-
use ptr::RawPtr;
78-
use ptr;
79-
use raw::Slice;
80-
use rt::libc_heap::malloc_raw;
81-
use slice::{ImmutableVector, MutableVector};
82-
use slice;
83-
use str::StrSlice;
84-
use str;
85-
use string::String;
8679

8780
/// The representation of a C String.
8881
///
@@ -454,11 +447,12 @@ pub unsafe fn from_c_multistring(buf: *libc::c_char,
454447

455448
#[cfg(test)]
456449
mod tests {
457-
use prelude::*;
458-
use super::*;
450+
use std::prelude::*;
451+
use std::ptr;
452+
use std::task;
459453
use libc;
460-
use ptr;
461-
use str::StrSlice;
454+
455+
use super::*;
462456

463457
#[test]
464458
fn test_str_multistring_parsing() {
@@ -574,7 +568,6 @@ mod tests {
574568

575569
#[test]
576570
fn test_to_c_str_fail() {
577-
use task;
578571
assert!(task::try(proc() { "he\x00llo".to_c_str() }).is_err());
579572
}
580573

@@ -700,10 +693,9 @@ mod tests {
700693

701694
#[cfg(test)]
702695
mod bench {
703-
extern crate test;
704-
use self::test::Bencher;
696+
use test::Bencher;
705697
use libc;
706-
use prelude::*;
698+
use std::prelude::*;
707699

708700
#[inline]
709701
fn check(s: &str, c_str: *libc::c_char) {

0 commit comments

Comments
 (0)