about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-07-23 22:49:19 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-07-30 07:06:44 -0700
commit355c798ac3eba15bb2d53a6c553c6149391f9615 (patch)
tree7426185c4107170da393d78489638b505b7994cb
parente156d001c6577593295f6eee417ea8758fbc4a84 (diff)
downloadrust-355c798ac3eba15bb2d53a6c553c6149391f9615.tar.gz
rust-355c798ac3eba15bb2d53a6c553c6149391f9615.zip
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.
-rw-r--r--src/libnative/task.rs4
-rw-r--r--src/librustrt/bookkeeping.rs12
2 files changed, 13 insertions, 3 deletions
diff --git a/src/libnative/task.rs b/src/libnative/task.rs
index 35367ff2efa..c72d6c24a7c 100644
--- a/src/libnative/task.rs
+++ b/src/libnative/task.rs
@@ -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);
     })
 }
 
diff --git a/src/librustrt/bookkeeping.rs b/src/librustrt/bookkeeping.rs
index fd290491eaf..ba9995e34ca 100644
--- a/src/librustrt/bookkeeping.rs
+++ b/src/librustrt/bookkeeping.rs
@@ -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() {