Skip to content

Commit bbf5469

Browse files
committed
Merge remote-tracking branch 'brson/io-wip' into io
2 parents b548c78 + 391bb0b commit bbf5469

File tree

4 files changed

+72
-23
lines changed

4 files changed

+72
-23
lines changed

src/libstd/rt/mod.rs

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,19 @@ use cell::Cell;
6363
use clone::Clone;
6464
use container::Container;
6565
use from_str::FromStr;
66+
use iter::Times;
6667
use iterator::IteratorUtil;
6768
use option::{Some, None};
6869
use os;
6970
use ptr::RawPtr;
70-
use uint;
7171
use rt::sched::{Scheduler, Coroutine, Shutdown};
7272
use rt::sleeper_list::SleeperList;
7373
use rt::task::Task;
7474
use rt::thread::Thread;
7575
use rt::work_queue::WorkQueue;
7676
use rt::uv::uvio::UvEventLoop;
77+
use unstable::atomics::{AtomicInt, SeqCst};
78+
use unstable::sync::UnsafeAtomicRcBox;
7779
use vec::{OwnedVector, MutableVector};
7880

7981
/// The global (exchange) heap.
@@ -148,7 +150,7 @@ pub mod local_ptr;
148150
/// Bindings to pthread/windows thread-local storage.
149151
pub mod thread_local_storage;
150152

151-
/// A concurrent data structure with which parent tasks wait on child tasks.
153+
/// For waiting on child tasks.
152154
pub mod join_latch;
153155

154156
pub mod metrics;
@@ -174,68 +176,95 @@ pub mod util;
174176
pub fn start(_argc: int, _argv: **u8, crate_map: *u8, main: ~fn()) -> int {
175177

176178
init(crate_map);
177-
run(main);
179+
let exit_code = run(main);
178180
cleanup();
179181

180-
return 0;
182+
return exit_code;
181183
}
182184

183185
/// One-time runtime initialization. Currently all this does is set up logging
184186
/// based on the RUST_LOG environment variable.
185187
pub fn init(crate_map: *u8) {
186188
logging::init(crate_map);
189+
unsafe { rust_update_gc_metadata(crate_map) }
190+
191+
extern {
192+
fn rust_update_gc_metadata(crate_map: *u8);
193+
}
187194
}
188195

196+
/// One-time runtime cleanup.
189197
pub fn cleanup() {
190198
global_heap::cleanup();
191199
}
192200

193-
pub fn run(main: ~fn()) {
201+
/// Execute the main function in a scheduler.
202+
///
203+
/// Configures the runtime according to the environment, by default
204+
/// using a task scheduler with the same number of threads as cores.
205+
/// Returns a process exit code.
206+
pub fn run(main: ~fn()) -> int {
207+
208+
static DEFAULT_ERROR_CODE: int = 101;
209+
194210
let nthreads = match os::getenv("RUST_THREADS") {
195211
Some(nstr) => FromStr::from_str(nstr).get(),
196-
None => unsafe {
197-
// Using more threads than cores in test code
198-
// to force the OS to preempt them frequently.
199-
// Assuming that this help stress test concurrent types.
200-
util::num_cpus() * 2
201-
}
212+
None => unsafe { util::num_cpus() }
202213
};
203214

215+
// The shared list of sleeping schedulers. Schedulers wake each other
216+
// occassionally to do new work.
204217
let sleepers = SleeperList::new();
218+
// The shared work queue. Temporary until work stealing is implemented.
205219
let work_queue = WorkQueue::new();
206220

207-
let mut handles = ~[];
221+
// The schedulers.
208222
let mut scheds = ~[];
223+
// Handles to the schedulers. When the main task ends these will be
224+
// sent the Shutdown message to terminate the schedulers.
225+
let mut handles = ~[];
209226

210-
for uint::range(0, nthreads) |_| {
227+
for nthreads.times {
228+
// Every scheduler is driven by an I/O event loop.
211229
let loop_ = ~UvEventLoop::new();
212230
let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
213231
let handle = sched.make_handle();
214232

215-
handles.push(handle);
216233
scheds.push(sched);
234+
handles.push(handle);
217235
}
218236

219-
let main_cell = Cell::new(main);
237+
// Create a shared cell for transmitting the process exit
238+
// code from the main task to this function.
239+
let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
240+
let exit_code_clone = exit_code.clone();
241+
242+
// When the main task exits, after all the tasks in the main
243+
// task tree, shut down the schedulers and set the exit code.
220244
let handles = Cell::new(handles);
221-
let mut new_task = ~Task::new_root();
222-
let on_exit: ~fn(bool) = |exit_status| {
245+
let on_exit: ~fn(bool) = |exit_success| {
223246

224247
let mut handles = handles.take();
225-
// Tell schedulers to exit
226248
for handles.mut_iter().advance |handle| {
227249
handle.send(Shutdown);
228250
}
229251

230-
rtassert!(exit_status);
252+
unsafe {
253+
let exit_code = if exit_success { 0 } else { DEFAULT_ERROR_CODE };
254+
(*exit_code_clone.get()).store(exit_code, SeqCst);
255+
}
231256
};
257+
258+
// Create and enqueue the main task.
259+
let main_cell = Cell::new(main);
260+
let mut new_task = ~Task::new_root();
232261
new_task.on_exit = Some(on_exit);
233262
let main_task = ~Coroutine::with_task(&mut scheds[0].stack_pool,
234263
new_task, main_cell.take());
235264
scheds[0].enqueue_task(main_task);
236265

266+
// Run each scheduler in a thread.
237267
let mut threads = ~[];
238-
239268
while !scheds.is_empty() {
240269
let sched = scheds.pop();
241270
let sched_cell = Cell::new(sched);
@@ -248,7 +277,12 @@ pub fn run(main: ~fn()) {
248277
}
249278

250279
// Wait for schedulers
251-
let _threads = threads;
280+
{ let _threads = threads; }
281+
282+
// Return the exit code
283+
unsafe {
284+
(*exit_code.get()).load(SeqCst)
285+
}
252286
}
253287

254288
/// Possible contexts in which Rust code may be executing.

src/libstd/sys.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,13 @@ impl FailWithCause for &'static str {
180180

181181
// FIXME #4427: Temporary until rt::rt_fail_ goes away
182182
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
183+
use cell::Cell;
183184
use option::Option;
185+
use either::Left;
184186
use rt::{context, OldTaskContext, TaskContext};
185187
use rt::task::{Task, Unwinder};
186188
use rt::local::Local;
189+
use rt::logging::Logger;
187190

188191
let context = context();
189192
match context {
@@ -200,12 +203,18 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
200203
let msg = str::raw::from_c_str(msg);
201204
let file = str::raw::from_c_str(file);
202205

203-
let outmsg = fmt!("%s at line %i of file %s", msg, line as int, file);
206+
let outmsg = fmt!("task failed: '%s' at line %i of file %s",
207+
msg, line as int, file);
204208

205209
// XXX: Logging doesn't work correctly in non-task context because it
206210
// invokes the local heap
207211
if context == TaskContext {
208-
error!(outmsg);
212+
// XXX: Logging doesn't work here - the check to call the log
213+
// function never passes - so calling the log function directly.
214+
let outmsg = Cell::new(outmsg);
215+
do Local::borrow::<Task, ()> |task| {
216+
task.logger.log(Left(outmsg.take()));
217+
}
209218
} else {
210219
rtdebug!("%s", outmsg);
211220
}

src/rt/rust_gc_metadata.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ rust_gc_metadata() {
7979
return (void *)global_safe_points;
8080
}
8181

82+
extern "C" CDECL void
83+
rust_update_gc_metadata(const void* map) {
84+
update_gc_metadata(map);
85+
}
86+
8287
//
8388
// Local Variables:
8489
// mode: C++

src/rt/rustrt.def.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ rust_call_tydesc_glue
178178
tdefl_compress_mem_to_heap
179179
tinfl_decompress_mem_to_heap
180180
rust_gc_metadata
181+
rust_update_gc_metadata
181182
rust_uv_ip4_port
182183
rust_uv_ip6_port
183184
rust_uv_tcp_getpeername

0 commit comments

Comments
 (0)