native: Don't deadlock the runtime on spawn failure

Previously, the call to bookkeeping::increment() was never paired with a
decrement when the spawn failed (due to unwinding). This fixes the problem by
returning a "bomb" from increment() which will decrement on drop, and then
moving the bomb into the child task's procedure which will be dropped naturally.
This commit is contained in:
Alex Crichton 2014-07-23 22:49:19 -07:00
parent e156d001c6
commit 355c798ac3
2 changed files with 13 additions and 3 deletions

View File

@ -71,7 +71,7 @@ pub fn spawn_opts(opts: TaskOpts, f: proc():Send) {
// Note that this increment must happen *before* the spawn in order to
// guarantee that if this task exits it will always end up waiting for the
// spawned task to exit.
bookkeeping::increment();
let token = bookkeeping::increment();
// Spawning a new OS thread guarantees that __morestack will never get
// triggered, but we must manually set up the actual stack bounds once this
@ -93,7 +93,7 @@ pub fn spawn_opts(opts: TaskOpts, f: proc():Send) {
let mut task = task;
task.put_runtime(ops);
drop(task.run(|| { f.take_unwrap()() }).destroy());
bookkeeping::decrement();
drop(token);
})
}

View File

@ -19,14 +19,24 @@
//! decrement() manually.
use core::atomics;
use core::ops::Drop;
use mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
static mut TASK_COUNT: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
static mut TASK_LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
pub fn increment() {
pub struct Token(());
impl Drop for Token {
fn drop(&mut self) { decrement() }
}
/// Increment the number of live tasks, returning a token which will decrement
/// the count when dropped.
pub fn increment() -> Token {
let _ = unsafe { TASK_COUNT.fetch_add(1, atomics::SeqCst) };
Token(())
}
pub fn decrement() {