about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-04-23 15:11:28 -0700
committerBrian Anderson <banderson@mozilla.com>2013-04-23 15:11:28 -0700
commit2a819ae465c5f375df00ead0b3f4c9009da23f25 (patch)
tree7b0653aeac4be8708634ea0887713fe8a72811e3
parentf4af40a1db4862cfe1f17311e3e39cfff3324d82 (diff)
downloadrust-2a819ae465c5f375df00ead0b3f4c9009da23f25.tar.gz
rust-2a819ae465c5f375df00ead0b3f4c9009da23f25.zip
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.
-rw-r--r--src/libcore/core.rc3
-rw-r--r--src/libcore/macros.rs39
-rw-r--r--src/libcore/rt/local_services.rs30
-rw-r--r--src/libcore/rt/mod.rs20
-rw-r--r--src/libcore/rt/sched/mod.rs10
-rw-r--r--src/libcore/rt/test.rs42
-rw-r--r--src/libcore/rt/uvio.rs12
-rw-r--r--src/libcore/sys.rs6
-rw-r--r--src/libcore/task/mod.rs11
9 files changed, 126 insertions, 47 deletions
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index e7a5cfbaf4b..a3b2cb4aaf9 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -114,6 +114,9 @@ pub mod linkhack {
     }
 }
 
+// Internal macros
+mod macros;
+
 /* The Prelude. */
 
 pub mod prelude;
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
new file mode 100644
index 00000000000..e1276a75e05
--- /dev/null
+++ b/src/libcore/macros.rs
@@ -0,0 +1,39 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[macro_escape];
+
+// Some basic logging
+macro_rules! rtdebug (
+    ($( $arg:expr),+) => ( {
+        dumb_println(fmt!( $($arg),+ ));
+
+        fn dumb_println(s: &str) {
+            use io::WriterUtil;
+            let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
+            dbg.write_str(s);
+            dbg.write_str("\n");
+        }
+
+    } )
+)
+
+// An alternate version with no output, for turning off logging
+macro_rules! rtdebug_ (
+    ($( $arg:expr),+) => ( $(let _ = $arg)*; )
+)
+
+macro_rules! abort(
+    ($( $msg:expr),+) => ( {
+        rtdebug!($($msg),+);
+
+        unsafe { ::libc::abort(); }
+    } )
+)
diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs
index fc75a256428..d09d082c858 100644
--- a/src/libcore/rt/local_services.rs
+++ b/src/libcore/rt/local_services.rs
@@ -29,7 +29,7 @@ pub struct LocalServices {
     gc: GarbageCollector,
     storage: LocalStorage,
     logger: Logger,
-    unwinder: Unwinder,
+    unwinder: Option<Unwinder>,
     destroyed: bool
 }
 
@@ -48,7 +48,18 @@ impl LocalServices {
             gc: GarbageCollector,
             storage: LocalStorage(ptr::null(), None),
             logger: Logger,
-            unwinder: Unwinder { unwinding: false },
+            unwinder: Some(Unwinder { unwinding: false }),
+            destroyed: false
+        }
+    }
+
+    pub fn without_unwinding() -> LocalServices {
+        LocalServices {
+            heap: LocalHeap::new(),
+            gc: GarbageCollector,
+            storage: LocalStorage(ptr::null(), None),
+            logger: Logger,
+            unwinder: None,
             destroyed: false
         }
     }
@@ -60,7 +71,16 @@ impl LocalServices {
             assert!(ptr::ref_eq(sched, self));
         }
 
-        self.unwinder.try(f);
+        match self.unwinder {
+            Some(ref mut unwinder) => {
+                // If there's an unwinder then set up the catch block
+                unwinder.try(f);
+            }
+            None => {
+                // Otherwise, just run the body
+                f()
+            }
+        }
         self.destroy();
     }
 
@@ -189,9 +209,9 @@ mod test {
     #[test]
     fn unwind() {
         do run_in_newsched_task() {
-            let result = spawn_try(||());
+            let result = spawntask_try(||());
             assert!(result.is_ok());
-            let result = spawn_try(|| fail!());
+            let result = spawntask_try(|| fail!());
             assert!(result.is_err());
         }
     }
diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs
index 4a767d61f74..ab89a4c26a5 100644
--- a/src/libcore/rt/mod.rs
+++ b/src/libcore/rt/mod.rs
@@ -12,26 +12,6 @@
 
 use libc::c_char;
 
-// Some basic logging
-macro_rules! rtdebug_ (
-    ($( $arg:expr),+) => ( {
-        dumb_println(fmt!( $($arg),+ ));
-
-        fn dumb_println(s: &str) {
-            use io::WriterUtil;
-            let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
-            dbg.write_str(s);
-            dbg.write_str("\n");
-        }
-
-    } )
-)
-
-// An alternate version with no output, for turning off logging
-macro_rules! rtdebug (
-    ($( $arg:expr),+) => ( $(let _ = $arg)*; )
-)
-
 #[path = "sched/mod.rs"]
 mod sched;
 mod rtio;
diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs
index 65456c30fee..f7b9bd82668 100644
--- a/src/libcore/rt/sched/mod.rs
+++ b/src/libcore/rt/sched/mod.rs
@@ -149,7 +149,7 @@ pub impl Scheduler {
             }
         }
 
-        // Control never reaches here
+        abort!("control reached end of task");
     }
 
     fn schedule_new_task(~self, task: ~Task) {
@@ -333,6 +333,12 @@ pub struct Task {
 
 pub impl Task {
     fn new(stack_pool: &mut StackPool, start: ~fn()) -> Task {
+        Task::with_local(stack_pool, LocalServices::new(), start)
+    }
+
+    fn with_local(stack_pool: &mut StackPool,
+                  local_services: LocalServices,
+                  start: ~fn()) -> Task {
         let start = Task::build_start_wrapper(start);
         let mut stack = stack_pool.take_segment(TASK_MIN_STACK_SIZE);
         // NB: Context holds a pointer to that ~fn
@@ -340,7 +346,7 @@ pub impl Task {
         return Task {
             current_stack_segment: stack,
             saved_context: initial_context,
-            local_services: LocalServices::new()
+            local_services: local_services
         };
     }
 
diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs
index f3d73c91bd6..f7ba881f84e 100644
--- a/src/libcore/rt/test.rs
+++ b/src/libcore/rt/test.rs
@@ -8,38 +8,56 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use cell::Cell;
 use result::{Result, Ok, Err};
 use super::io::net::ip::{IpAddr, Ipv4};
+use rt::local_services::LocalServices;
 
 /// Creates a new scheduler in a new thread and runs a task in it,
-/// then waits for the scheduler to exit.
+/// then waits for the scheduler to exit. Failure of the task
+/// will abort the process.
 pub fn run_in_newsched_task(f: ~fn()) {
-    use cell::Cell;
     use unstable::run_in_bare_thread;
     use super::sched::Task;
     use super::uvio::UvEventLoop;
 
-    let f = Cell(Cell(f));
+    let f = Cell(f);
 
     do run_in_bare_thread {
         let mut sched = ~UvEventLoop::new_scheduler();
-        let f = f.take();
-        let task = ~do Task::new(&mut sched.stack_pool) {
-            (f.take())();
-        };
+        let task = ~Task::with_local(&mut sched.stack_pool,
+                                     LocalServices::without_unwinding(),
+                                     f.take());
         sched.task_queue.push_back(task);
         sched.run();
     }
 }
 
-/// Create a new task and run it right now
-pub fn spawn_immediately(f: ~fn()) {
-    use cell::Cell;
+/// Test tasks will abort on failure instead of unwinding
+pub fn spawntask(f: ~fn()) {
+    use super::*;
+    use super::sched::*;
+
+    let mut sched = local_sched::take();
+    let task = ~Task::with_local(&mut sched.stack_pool,
+                                 LocalServices::without_unwinding(),
+                                 f);
+    do sched.switch_running_tasks_and_then(task) |task| {
+        let task = Cell(task);
+        let sched = local_sched::take();
+        sched.schedule_new_task(task.take());
+    }
+}
+
+/// Create a new task and run it right now. Aborts on failure
+pub fn spawntask_immediately(f: ~fn()) {
     use super::*;
     use super::sched::*;
 
     let mut sched = local_sched::take();
-    let task = ~Task::new(&mut sched.stack_pool, f);
+    let task = ~Task::with_local(&mut sched.stack_pool,
+                                 LocalServices::without_unwinding(),
+                                 f);
     do sched.switch_running_tasks_and_then(task) |task| {
         let task = Cell(task);
         do local_sched::borrow |sched| {
@@ -49,7 +67,7 @@ pub fn spawn_immediately(f: ~fn()) {
 }
 
 /// Spawn a task and wait for it to finish, returning whether it completed successfully or failed
-pub fn spawn_try(f: ~fn()) -> Result<(), ()> {
+pub fn spawntask_try(f: ~fn()) -> Result<(), ()> {
     use cell::Cell;
     use super::sched::*;
     use task;
diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs
index e7b2880b74b..4cceb048cbc 100644
--- a/src/libcore/rt/uvio.rs
+++ b/src/libcore/rt/uvio.rs
@@ -350,7 +350,7 @@ fn test_simple_tcp_server_and_client() {
         let addr = next_test_ip4();
 
         // Start the server first so it's listening when we connect
-        do spawn_immediately {
+        do spawntask_immediately {
             unsafe {
                 let io = local_sched::unsafe_borrow_io();
                 let mut listener = io.bind(addr).unwrap();
@@ -367,7 +367,7 @@ fn test_simple_tcp_server_and_client() {
             }
         }
 
-        do spawn_immediately {
+        do spawntask_immediately {
             unsafe {
                 let io = local_sched::unsafe_borrow_io();
                 let mut stream = io.connect(addr).unwrap();
@@ -383,7 +383,7 @@ fn test_read_and_block() {
     do run_in_newsched_task {
         let addr = next_test_ip4();
 
-        do spawn_immediately {
+        do spawntask_immediately {
             let io = unsafe { local_sched::unsafe_borrow_io() };
             let mut listener = io.bind(addr).unwrap();
             let mut stream = listener.listen().unwrap();
@@ -421,7 +421,7 @@ fn test_read_and_block() {
             listener.close();
         }
 
-        do spawn_immediately {
+        do spawntask_immediately {
             let io = unsafe { local_sched::unsafe_borrow_io() };
             let mut stream = io.connect(addr).unwrap();
             stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
@@ -440,7 +440,7 @@ fn test_read_read_read() {
         let addr = next_test_ip4();
         static MAX: uint = 500000;
         
-        do spawn_immediately {
+        do spawntask_immediately {
             unsafe {
                 let io = local_sched::unsafe_borrow_io();
                 let mut listener = io.bind(addr).unwrap();
@@ -456,7 +456,7 @@ fn test_read_read_read() {
             }
         }
 
-        do spawn_immediately {
+        do spawntask_immediately {
             let io = unsafe { local_sched::unsafe_borrow_io() };
             let mut stream = io.connect(addr).unwrap();
             let mut buf = [0, .. 2048];
diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs
index c50bc03517f..2c3670ad498 100644
--- a/src/libcore/sys.rs
+++ b/src/libcore/sys.rs
@@ -10,6 +10,7 @@
 
 //! Misc low level stuff
 
+use option::{Some, None};
 use cast;
 use cmp::{Eq, Ord};
 use gc;
@@ -154,7 +155,10 @@ pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! {
             gc::cleanup_stack_for_failure();
             unsafe {
                 let local_services = unsafe_borrow_local_services();
-                local_services.unwinder.begin_unwind();
+                match local_services.unwinder {
+                    Some(ref mut unwinder) => unwinder.begin_unwind(),
+                    None => abort!("failure without unwinder. aborting process")
+                }
             }
         }
     }
diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs
index e1f4805a692..d31a511eca8 100644
--- a/src/libcore/task/mod.rs
+++ b/src/libcore/task/mod.rs
@@ -570,7 +570,16 @@ pub fn failing() -> bool {
         _ => {
             let mut unwinding = false;
             do borrow_local_services |local| {
-                unwinding = local.unwinder.unwinding;
+                unwinding = match local.unwinder {
+                    Some(unwinder) => {
+                        unwinder.unwinding
+                    }
+                    None => {
+                        // Because there is no unwinder we can't be unwinding.
+                        // (The process will abort on failure)
+                        false
+                    }
+                }
             }
             return unwinding;
         }