auto merge of #9742 : alexcrichton/rust/issue-9739, r=brson
This changes an `assert_once_ever!` assertion to just a plain old assertion around an atomic boolean to ensure that one particular runtime doesn't attempt to exit twice. Closes #9739
This commit is contained in:
commit
11d5670647
@ -42,41 +42,3 @@ macro_rules! rtabort(
|
||||
::rt::util::abort(format!($($msg)*));
|
||||
} )
|
||||
)
|
||||
|
||||
macro_rules! assert_once_ever(
|
||||
($($msg:tt)+) => ( {
|
||||
// FIXME(#8472) extra function should not be needed to hide unsafe
|
||||
fn assert_once_ever() {
|
||||
unsafe {
|
||||
static mut already_happened: int = 0;
|
||||
// Double-check lock to avoid a swap in the common case.
|
||||
if already_happened != 0 ||
|
||||
::unstable::intrinsics::atomic_xchg_relaxed(&mut already_happened, 1) != 0 {
|
||||
fail2!("assert_once_ever happened twice: {}",
|
||||
format!($($msg)+));
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_once_ever();
|
||||
} )
|
||||
)
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_assert_once_ever_ok() {
|
||||
assert_once_ever!("help i'm stuck in an");
|
||||
assert_once_ever!("assertion error message");
|
||||
}
|
||||
|
||||
#[test] #[ignore(cfg(windows))] #[should_fail]
|
||||
fn test_assert_once_ever_fail() {
|
||||
use task;
|
||||
|
||||
fn f() { assert_once_ever!("if you're seeing this... good!") }
|
||||
|
||||
// linked & watched, naturally
|
||||
task::spawn(f);
|
||||
task::spawn(f);
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
use rt::sleeper_list::SleeperList;
|
||||
use rt::task::{Task, SchedTask, GreenTask, Sched};
|
||||
use rt::uv::uvio::UvEventLoop;
|
||||
use unstable::atomics::{AtomicInt, SeqCst};
|
||||
use unstable::atomics::{AtomicInt, AtomicBool, SeqCst};
|
||||
use unstable::sync::UnsafeArc;
|
||||
use vec;
|
||||
use vec::{OwnedVector, MutableVector, ImmutableVector};
|
||||
@ -311,11 +311,17 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
|
||||
let exit_code = UnsafeArc::new(AtomicInt::new(0));
|
||||
let exit_code_clone = exit_code.clone();
|
||||
|
||||
// Used to sanity check that the runtime only exits once
|
||||
let exited_already = UnsafeArc::new(AtomicBool::new(false));
|
||||
|
||||
// When the main task exits, after all the tasks in the main
|
||||
// task tree, shut down the schedulers and set the exit code.
|
||||
let handles = Cell::new(handles);
|
||||
let on_exit: ~fn(bool) = |exit_success| {
|
||||
assert_once_ever!("last task exiting");
|
||||
unsafe {
|
||||
assert!(!(*exited_already.get()).swap(true, SeqCst),
|
||||
"the runtime already exited");
|
||||
}
|
||||
|
||||
let mut handles = handles.take();
|
||||
for handle in handles.mut_iter() {
|
||||
|
26
src/test/run-pass/rt-run-twice.rs
Normal file
26
src/test/run-pass/rt-run-twice.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2013 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.
|
||||
|
||||
// xfail-fast windows uses a different test runner
|
||||
|
||||
use std::rt;
|
||||
|
||||
#[start]
|
||||
fn start(argc: int, argv: **u8) -> int {
|
||||
do rt::start(argc, argv) {
|
||||
println("First invocation");
|
||||
};
|
||||
|
||||
do rt::start(argc, argv) {
|
||||
println("Second invocation");
|
||||
};
|
||||
|
||||
0
|
||||
}
|
Loading…
Reference in New Issue
Block a user