Skip to content

Commit 6266f64

Browse files
committed
auto merge of #14638 : alexcrichton/rust/librustrt, r=brson
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.
2 parents e87e180 + 75014f7 commit 6266f64

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+2643
-2618
lines changed

mk/crates.mk

+4-2
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

+5-4
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/liballoc/lib.rs

+15
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,21 @@ pub mod owned;
9696
pub mod arc;
9797
pub mod rc;
9898

99+
// FIXME(#14344): When linking liballoc with libstd, this library will be linked
100+
// as an rlib (it only exists as an rlib). It turns out that an
101+
// optimized standard library doesn't actually use *any* symbols
102+
// from this library. Everything is inlined and optimized away.
103+
// This means that linkers will actually omit the object for this
104+
// file, even though it may be needed in the future.
105+
//
106+
// To get around this for now, we define a dummy symbol which
107+
// will never get inlined so the stdlib can call it. The stdlib's
108+
// reference to this symbol will cause this library's object file
109+
// to get linked in to libstd successfully (the linker won't
110+
// optimize it out).
111+
#[doc(hidden)]
112+
pub fn fixme_14344_be_sure_to_link_to_collections() {}
113+
99114
#[cfg(not(test))]
100115
#[doc(hidden)]
101116
mod std {

src/liballoc/util.rs

-17
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,3 @@ fn align_to(size: uint, align: uint) -> uint {
2828
assert!(align != 0);
2929
(size + align - 1) & !(align - 1)
3030
}
31-
32-
// FIXME(#14344): When linking liballoc with libstd, this library will be linked
33-
// as an rlib (it only exists as an rlib). It turns out that an
34-
// optimized standard library doesn't actually use *any* symbols
35-
// from this library. Everything is inlined and optimized away.
36-
// This means that linkers will actually omit the object for this
37-
// file, even though it may be needed in the future.
38-
//
39-
// To get around this for now, we define a dummy symbol which
40-
// will never get inlined so the stdlib can call it. The stdlib's
41-
// reference to this symbol will cause this library's object file
42-
// to get linked in to libstd successfully (the linker won't
43-
// optimize it out).
44-
#[deprecated]
45-
#[doc(hidden)]
46-
pub fn make_stdlib_link_work() {}
47-

src/libcollections/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ fn expect<T>(a: core::option::Option<T>, b: &str) -> T {
7272
}
7373
}
7474

75+
// FIXME(#14344) this shouldn't be necessary
76+
#[doc(hidden)]
77+
pub fn fixme_14344_be_sure_to_link_to_collections() {}
78+
7579
#[cfg(not(test))]
7680
mod std {
7781
pub use core::fmt; // necessary for fail!()

src/libcollections/slice.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ mod tests {
862862
use std::prelude::*;
863863
use std::rand::{Rng, task_rng};
864864
use std::rc::Rc;
865-
use std::unstable;
865+
use std::rt;
866866
use slice::*;
867867

868868
use vec::Vec;
@@ -1104,9 +1104,9 @@ mod tests {
11041104
#[test]
11051105
fn test_swap_remove_noncopyable() {
11061106
// Tests that we don't accidentally run destructors twice.
1107-
let mut v = vec![unstable::sync::Exclusive::new(()),
1108-
unstable::sync::Exclusive::new(()),
1109-
unstable::sync::Exclusive::new(())];
1107+
let mut v = vec![rt::exclusive::Exclusive::new(()),
1108+
rt::exclusive::Exclusive::new(()),
1109+
rt::exclusive::Exclusive::new(())];
11101110
let mut _e = v.swap_remove(0);
11111111
assert_eq!(v.len(), 2);
11121112
_e = v.swap_remove(1);

src/libcore/macros.rs

+14
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/libgreen/basic.rs

+20-33
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use std::sync::atomics;
2020
use std::mem;
2121
use std::rt::rtio::{EventLoop, IoFactory, RemoteCallback};
2222
use std::rt::rtio::{PausableIdleCallback, Callback};
23-
use std::unstable::sync::Exclusive;
23+
use std::rt::exclusive::Exclusive;
2424

2525
/// This is the only exported function from this module.
2626
pub fn event_loop() -> Box<EventLoop:Send> {
@@ -31,7 +31,7 @@ struct BasicLoop {
3131
work: Vec<proc():Send>, // pending work
3232
remotes: Vec<(uint, Box<Callback:Send>)>,
3333
next_remote: uint,
34-
messages: Exclusive<Vec<Message>>,
34+
messages: Arc<Exclusive<Vec<Message>>>,
3535
idle: Option<Box<Callback:Send>>,
3636
idle_active: Option<Arc<atomics::AtomicBool>>,
3737
}
@@ -46,7 +46,7 @@ impl BasicLoop {
4646
idle_active: None,
4747
next_remote: 0,
4848
remotes: vec![],
49-
messages: Exclusive::new(vec![]),
49+
messages: Arc::new(Exclusive::new(Vec::new())),
5050
}
5151
}
5252

@@ -61,19 +61,10 @@ impl BasicLoop {
6161

6262
fn remote_work(&mut self) {
6363
let messages = unsafe {
64-
self.messages.with(|messages| {
65-
if messages.len() > 0 {
66-
Some(mem::replace(messages, vec![]))
67-
} else {
68-
None
69-
}
70-
})
71-
};
72-
let messages = match messages {
73-
Some(m) => m, None => return
64+
mem::replace(&mut *self.messages.lock(), Vec::new())
7465
};
75-
for message in messages.iter() {
76-
self.message(*message);
66+
for message in messages.move_iter() {
67+
self.message(message);
7768
}
7869
}
7970

@@ -125,13 +116,13 @@ impl EventLoop for BasicLoop {
125116
}
126117

127118
unsafe {
119+
let mut messages = self.messages.lock();
128120
// We block here if we have no messages to process and we may
129121
// receive a message at a later date
130-
self.messages.hold_and_wait(|messages| {
131-
self.remotes.len() > 0 &&
132-
messages.len() == 0 &&
133-
self.work.len() == 0
134-
})
122+
if self.remotes.len() > 0 && messages.len() == 0 &&
123+
self.work.len() == 0 {
124+
messages.wait()
125+
}
135126
}
136127
}
137128
}
@@ -165,33 +156,29 @@ impl EventLoop for BasicLoop {
165156
}
166157

167158
struct BasicRemote {
168-
queue: Exclusive<Vec<Message>>,
159+
queue: Arc<Exclusive<Vec<Message>>>,
169160
id: uint,
170161
}
171162

172163
impl BasicRemote {
173-
fn new(queue: Exclusive<Vec<Message>>, id: uint) -> BasicRemote {
164+
fn new(queue: Arc<Exclusive<Vec<Message>>>, id: uint) -> BasicRemote {
174165
BasicRemote { queue: queue, id: id }
175166
}
176167
}
177168

178169
impl RemoteCallback for BasicRemote {
179170
fn fire(&mut self) {
180-
unsafe {
181-
self.queue.hold_and_signal(|queue| {
182-
queue.push(RunRemote(self.id));
183-
})
184-
}
171+
let mut queue = unsafe { self.queue.lock() };
172+
queue.push(RunRemote(self.id));
173+
queue.signal();
185174
}
186175
}
187176

188177
impl Drop for BasicRemote {
189178
fn drop(&mut self) {
190-
unsafe {
191-
self.queue.hold_and_signal(|queue| {
192-
queue.push(RemoveRemote(self.id));
193-
})
194-
}
179+
let mut queue = unsafe { self.queue.lock() };
180+
queue.push(RemoveRemote(self.id));
181+
queue.signal();
195182
}
196183
}
197184

@@ -216,7 +203,7 @@ impl Drop for BasicPausable {
216203

217204
#[cfg(test)]
218205
mod test {
219-
use std::task::TaskOpts;
206+
use std::rt::task::TaskOpts;
220207

221208
use basic;
222209
use PoolConfig;

src/libgreen/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@
160160
//! # Using a scheduler pool
161161
//!
162162
//! ```rust
163-
//! use std::task::TaskOpts;
163+
//! use std::rt::task::TaskOpts;
164164
//! use green::{SchedPool, PoolConfig};
165165
//! use green::sched::{PinnedTask, TaskFromFriend};
166166
//!
@@ -221,10 +221,10 @@ use std::mem::replace;
221221
use std::os;
222222
use std::rt::rtio;
223223
use std::rt::thread::Thread;
224+
use std::rt::task::TaskOpts;
224225
use std::rt;
225226
use std::sync::atomics::{SeqCst, AtomicUint, INIT_ATOMIC_UINT};
226227
use std::sync::deque;
227-
use std::task::TaskOpts;
228228

229229
use sched::{Shutdown, Scheduler, SchedHandle, TaskFromFriend, NewNeighbor};
230230
use sleeper_list::SleeperList;
@@ -319,7 +319,7 @@ pub fn run(event_loop_factory: fn() -> Box<rtio::EventLoop:Send>,
319319
let mut pool = SchedPool::new(cfg);
320320
let (tx, rx) = channel();
321321
let mut opts = TaskOpts::new();
322-
opts.notify_chan = Some(tx);
322+
opts.on_exit = Some(proc(r) tx.send(r));
323323
opts.name = Some("<main>".into_maybe_owned());
324324
pool.spawn(opts, main);
325325

src/libgreen/sched.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010

1111
use std::mem;
1212
use std::rt::local::Local;
13+
use std::rt::mutex::NativeMutex;
1314
use std::rt::rtio::{RemoteCallback, PausableIdleCallback, Callback, EventLoop};
1415
use std::rt::task::BlockedTask;
1516
use std::rt::task::Task;
1617
use std::sync::deque;
17-
use std::unstable::mutex::NativeMutex;
1818
use std::raw;
1919

2020
use std::rand::{XorShiftRng, Rng, Rand};
@@ -1022,7 +1022,7 @@ fn new_sched_rng() -> XorShiftRng {
10221022
mod test {
10231023
use rustuv;
10241024

1025-
use std::task::TaskOpts;
1025+
use std::rt::task::TaskOpts;
10261026
use std::rt::task::Task;
10271027
use std::rt::local::Local;
10281028

@@ -1475,7 +1475,7 @@ mod test {
14751475

14761476
#[test]
14771477
fn test_spawn_sched_blocking() {
1478-
use std::unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
1478+
use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
14791479
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
14801480

14811481
// Testing that a task in one scheduler can block in foreign code

src/libgreen/simple.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@ use std::any::Any;
1515
use std::mem;
1616
use std::rt::Runtime;
1717
use std::rt::local::Local;
18+
use std::rt::mutex::NativeMutex;
1819
use std::rt::rtio;
19-
use std::rt::task::{Task, BlockedTask};
20-
use std::task::TaskOpts;
21-
use std::unstable::mutex::NativeMutex;
20+
use std::rt::task::{Task, BlockedTask, TaskOpts};
2221

2322
struct SimpleTask {
2423
lock: NativeMutex,

src/libgreen/stack.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::rt::env::max_cached_stacks;
11+
use std::sync::atomics;
1212
use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable,
13-
MapNonStandardFlags, MapVirtual};
13+
MapNonStandardFlags, MapVirtual, getenv};
1414
use libc;
1515

1616
/// A task's stack. The name "Stack" is a vestige of segmented stacks.
@@ -151,6 +151,22 @@ impl StackPool {
151151
}
152152
}
153153

154+
fn max_cached_stacks() -> uint {
155+
static mut AMT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
156+
match unsafe { AMT.load(atomics::SeqCst) } {
157+
0 => {}
158+
n => return n - 1,
159+
}
160+
let amt = getenv("RUST_MAX_CACHED_STACKS").and_then(|s| from_str(s.as_slice()));
161+
// This default corresponds to 20M of cache per scheduler (at the
162+
// default size).
163+
let amt = amt.unwrap_or(10);
164+
// 0 is our sentinel value, so ensure that we'll never see 0 after
165+
// initialization has run
166+
unsafe { AMT.store(amt + 1, atomics::SeqCst); }
167+
return amt;
168+
}
169+
154170
extern {
155171
fn rust_valgrind_stack_register(start: *libc::uintptr_t,
156172
end: *libc::uintptr_t) -> libc::c_uint;

0 commit comments

Comments
 (0)