Skip to content

Commit 2a819ae

Browse files
committed
core::rt: Tasks to not require an unwinder
A task without an unwinder will abort the process on failure. I'm using this in the runtime tests to guarantee that a call to `assert!` actually triggers some kind of failure (an abort) instead of silently doing nothing. This is essentially in lieu of a working linked failure implementation.
1 parent f4af40a commit 2a819ae

File tree

9 files changed

+126
-47
lines changed

9 files changed

+126
-47
lines changed

src/libcore/core.rc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ pub mod linkhack {
114114
}
115115
}
116116

117+
// Internal macros
118+
mod macros;
119+
117120
/* The Prelude. */
118121

119122
pub mod prelude;

src/libcore/macros.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2012 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+
#[macro_escape];
12+
13+
// Some basic logging
14+
macro_rules! rtdebug (
15+
($( $arg:expr),+) => ( {
16+
dumb_println(fmt!( $($arg),+ ));
17+
18+
fn dumb_println(s: &str) {
19+
use io::WriterUtil;
20+
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
21+
dbg.write_str(s);
22+
dbg.write_str("\n");
23+
}
24+
25+
} )
26+
)
27+
28+
// An alternate version with no output, for turning off logging
29+
macro_rules! rtdebug_ (
30+
($( $arg:expr),+) => ( $(let _ = $arg)*; )
31+
)
32+
33+
macro_rules! abort(
34+
($( $msg:expr),+) => ( {
35+
rtdebug!($($msg),+);
36+
37+
unsafe { ::libc::abort(); }
38+
} )
39+
)

src/libcore/rt/local_services.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub struct LocalServices {
2929
gc: GarbageCollector,
3030
storage: LocalStorage,
3131
logger: Logger,
32-
unwinder: Unwinder,
32+
unwinder: Option<Unwinder>,
3333
destroyed: bool
3434
}
3535

@@ -48,7 +48,18 @@ impl LocalServices {
4848
gc: GarbageCollector,
4949
storage: LocalStorage(ptr::null(), None),
5050
logger: Logger,
51-
unwinder: Unwinder { unwinding: false },
51+
unwinder: Some(Unwinder { unwinding: false }),
52+
destroyed: false
53+
}
54+
}
55+
56+
pub fn without_unwinding() -> LocalServices {
57+
LocalServices {
58+
heap: LocalHeap::new(),
59+
gc: GarbageCollector,
60+
storage: LocalStorage(ptr::null(), None),
61+
logger: Logger,
62+
unwinder: None,
5263
destroyed: false
5364
}
5465
}
@@ -60,7 +71,16 @@ impl LocalServices {
6071
assert!(ptr::ref_eq(sched, self));
6172
}
6273

63-
self.unwinder.try(f);
74+
match self.unwinder {
75+
Some(ref mut unwinder) => {
76+
// If there's an unwinder then set up the catch block
77+
unwinder.try(f);
78+
}
79+
None => {
80+
// Otherwise, just run the body
81+
f()
82+
}
83+
}
6484
self.destroy();
6585
}
6686

@@ -189,9 +209,9 @@ mod test {
189209
#[test]
190210
fn unwind() {
191211
do run_in_newsched_task() {
192-
let result = spawn_try(||());
212+
let result = spawntask_try(||());
193213
assert!(result.is_ok());
194-
let result = spawn_try(|| fail!());
214+
let result = spawntask_try(|| fail!());
195215
assert!(result.is_err());
196216
}
197217
}

src/libcore/rt/mod.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,6 @@
1212

1313
use libc::c_char;
1414

15-
// Some basic logging
16-
macro_rules! rtdebug_ (
17-
($( $arg:expr),+) => ( {
18-
dumb_println(fmt!( $($arg),+ ));
19-
20-
fn dumb_println(s: &str) {
21-
use io::WriterUtil;
22-
let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
23-
dbg.write_str(s);
24-
dbg.write_str("\n");
25-
}
26-
27-
} )
28-
)
29-
30-
// An alternate version with no output, for turning off logging
31-
macro_rules! rtdebug (
32-
($( $arg:expr),+) => ( $(let _ = $arg)*; )
33-
)
34-
3515
#[path = "sched/mod.rs"]
3616
mod sched;
3717
mod rtio;

src/libcore/rt/sched/mod.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ pub impl Scheduler {
149149
}
150150
}
151151

152-
// Control never reaches here
152+
abort!("control reached end of task");
153153
}
154154

155155
fn schedule_new_task(~self, task: ~Task) {
@@ -333,14 +333,20 @@ pub struct Task {
333333

334334
pub impl Task {
335335
fn new(stack_pool: &mut StackPool, start: ~fn()) -> Task {
336+
Task::with_local(stack_pool, LocalServices::new(), start)
337+
}
338+
339+
fn with_local(stack_pool: &mut StackPool,
340+
local_services: LocalServices,
341+
start: ~fn()) -> Task {
336342
let start = Task::build_start_wrapper(start);
337343
let mut stack = stack_pool.take_segment(TASK_MIN_STACK_SIZE);
338344
// NB: Context holds a pointer to that ~fn
339345
let initial_context = Context::new(start, &mut stack);
340346
return Task {
341347
current_stack_segment: stack,
342348
saved_context: initial_context,
343-
local_services: LocalServices::new()
349+
local_services: local_services
344350
};
345351
}
346352

src/libcore/rt/test.rs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,56 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use cell::Cell;
1112
use result::{Result, Ok, Err};
1213
use super::io::net::ip::{IpAddr, Ipv4};
14+
use rt::local_services::LocalServices;
1315

1416
/// Creates a new scheduler in a new thread and runs a task in it,
15-
/// then waits for the scheduler to exit.
17+
/// then waits for the scheduler to exit. Failure of the task
18+
/// will abort the process.
1619
pub fn run_in_newsched_task(f: ~fn()) {
17-
use cell::Cell;
1820
use unstable::run_in_bare_thread;
1921
use super::sched::Task;
2022
use super::uvio::UvEventLoop;
2123

22-
let f = Cell(Cell(f));
24+
let f = Cell(f);
2325

2426
do run_in_bare_thread {
2527
let mut sched = ~UvEventLoop::new_scheduler();
26-
let f = f.take();
27-
let task = ~do Task::new(&mut sched.stack_pool) {
28-
(f.take())();
29-
};
28+
let task = ~Task::with_local(&mut sched.stack_pool,
29+
LocalServices::without_unwinding(),
30+
f.take());
3031
sched.task_queue.push_back(task);
3132
sched.run();
3233
}
3334
}
3435

35-
/// Create a new task and run it right now
36-
pub fn spawn_immediately(f: ~fn()) {
37-
use cell::Cell;
36+
/// Test tasks will abort on failure instead of unwinding
37+
pub fn spawntask(f: ~fn()) {
38+
use super::*;
39+
use super::sched::*;
40+
41+
let mut sched = local_sched::take();
42+
let task = ~Task::with_local(&mut sched.stack_pool,
43+
LocalServices::without_unwinding(),
44+
f);
45+
do sched.switch_running_tasks_and_then(task) |task| {
46+
let task = Cell(task);
47+
let sched = local_sched::take();
48+
sched.schedule_new_task(task.take());
49+
}
50+
}
51+
52+
/// Create a new task and run it right now. Aborts on failure
53+
pub fn spawntask_immediately(f: ~fn()) {
3854
use super::*;
3955
use super::sched::*;
4056

4157
let mut sched = local_sched::take();
42-
let task = ~Task::new(&mut sched.stack_pool, f);
58+
let task = ~Task::with_local(&mut sched.stack_pool,
59+
LocalServices::without_unwinding(),
60+
f);
4361
do sched.switch_running_tasks_and_then(task) |task| {
4462
let task = Cell(task);
4563
do local_sched::borrow |sched| {
@@ -49,7 +67,7 @@ pub fn spawn_immediately(f: ~fn()) {
4967
}
5068

5169
/// Spawn a task and wait for it to finish, returning whether it completed successfully or failed
52-
pub fn spawn_try(f: ~fn()) -> Result<(), ()> {
70+
pub fn spawntask_try(f: ~fn()) -> Result<(), ()> {
5371
use cell::Cell;
5472
use super::sched::*;
5573
use task;

src/libcore/rt/uvio.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ fn test_simple_tcp_server_and_client() {
350350
let addr = next_test_ip4();
351351

352352
// Start the server first so it's listening when we connect
353-
do spawn_immediately {
353+
do spawntask_immediately {
354354
unsafe {
355355
let io = local_sched::unsafe_borrow_io();
356356
let mut listener = io.bind(addr).unwrap();
@@ -367,7 +367,7 @@ fn test_simple_tcp_server_and_client() {
367367
}
368368
}
369369

370-
do spawn_immediately {
370+
do spawntask_immediately {
371371
unsafe {
372372
let io = local_sched::unsafe_borrow_io();
373373
let mut stream = io.connect(addr).unwrap();
@@ -383,7 +383,7 @@ fn test_read_and_block() {
383383
do run_in_newsched_task {
384384
let addr = next_test_ip4();
385385

386-
do spawn_immediately {
386+
do spawntask_immediately {
387387
let io = unsafe { local_sched::unsafe_borrow_io() };
388388
let mut listener = io.bind(addr).unwrap();
389389
let mut stream = listener.listen().unwrap();
@@ -421,7 +421,7 @@ fn test_read_and_block() {
421421
listener.close();
422422
}
423423

424-
do spawn_immediately {
424+
do spawntask_immediately {
425425
let io = unsafe { local_sched::unsafe_borrow_io() };
426426
let mut stream = io.connect(addr).unwrap();
427427
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
@@ -440,7 +440,7 @@ fn test_read_read_read() {
440440
let addr = next_test_ip4();
441441
static MAX: uint = 500000;
442442

443-
do spawn_immediately {
443+
do spawntask_immediately {
444444
unsafe {
445445
let io = local_sched::unsafe_borrow_io();
446446
let mut listener = io.bind(addr).unwrap();
@@ -456,7 +456,7 @@ fn test_read_read_read() {
456456
}
457457
}
458458

459-
do spawn_immediately {
459+
do spawntask_immediately {
460460
let io = unsafe { local_sched::unsafe_borrow_io() };
461461
let mut stream = io.connect(addr).unwrap();
462462
let mut buf = [0, .. 2048];

src/libcore/sys.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
//! Misc low level stuff
1212
13+
use option::{Some, None};
1314
use cast;
1415
use cmp::{Eq, Ord};
1516
use gc;
@@ -154,7 +155,10 @@ pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! {
154155
gc::cleanup_stack_for_failure();
155156
unsafe {
156157
let local_services = unsafe_borrow_local_services();
157-
local_services.unwinder.begin_unwind();
158+
match local_services.unwinder {
159+
Some(ref mut unwinder) => unwinder.begin_unwind(),
160+
None => abort!("failure without unwinder. aborting process")
161+
}
158162
}
159163
}
160164
}

src/libcore/task/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,16 @@ pub fn failing() -> bool {
570570
_ => {
571571
let mut unwinding = false;
572572
do borrow_local_services |local| {
573-
unwinding = local.unwinder.unwinding;
573+
unwinding = match local.unwinder {
574+
Some(unwinder) => {
575+
unwinder.unwinding
576+
}
577+
None => {
578+
// Because there is no unwinder we can't be unwinding.
579+
// (The process will abort on failure)
580+
false
581+
}
582+
}
574583
}
575584
return unwinding;
576585
}

0 commit comments

Comments
 (0)