about summary refs log tree commit diff
path: root/src/libstd/rt
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-06-06 17:46:45 -0700
committerBrian Anderson <banderson@mozilla.com>2013-06-06 17:53:13 -0700
commitd4de99aa6c53b0eb0d5be2ccfc62e2c89b2cd2df (patch)
tree2a482df80221611b7fc81c4709aa257624d8a95a /src/libstd/rt
parentd6ccc6bc99386ae20ac03b68e7ec504a16068242 (diff)
downloadrust-d4de99aa6c53b0eb0d5be2ccfc62e2c89b2cd2df.tar.gz
rust-d4de99aa6c53b0eb0d5be2ccfc62e2c89b2cd2df.zip
std::rt: Fix a race in the UvRemoteCallback dtor
Diffstat (limited to 'src/libstd/rt')
-rw-r--r--src/libstd/rt/uv/uvio.rs26
1 files changed, 15 insertions, 11 deletions
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index 0d9530239a3..0f98ab11513 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -24,7 +24,7 @@ use rt::sched::Scheduler;
 use rt::io::{standard_error, OtherIoError};
 use rt::tube::Tube;
 use rt::local::Local;
-use unstable::sync::{UnsafeAtomicRcBox, AtomicInt};
+use unstable::sync::{Exclusive, exclusive};
 
 #[cfg(test)] use container::Container;
 #[cfg(test)] use uint;
@@ -105,21 +105,20 @@ fn test_callback_run_once() {
 pub struct UvRemoteCallback {
     // The uv async handle for triggering the callback
     async: AsyncWatcher,
-    // An atomic flag to tell the callback to exit,
-    // set from the dtor.
-    exit_flag: UnsafeAtomicRcBox<AtomicInt>
+    // A flag to tell the callback to exit, set from the dtor. This is
+    // almost never contested - only in rare races with the dtor.
+    exit_flag: Exclusive<bool>
 }
 
 impl UvRemoteCallback {
     pub fn new(loop_: &mut Loop, f: ~fn()) -> UvRemoteCallback {
-        let exit_flag = UnsafeAtomicRcBox::new(AtomicInt::new(0));
+        let exit_flag = exclusive(false);
         let exit_flag_clone = exit_flag.clone();
         let async = do AsyncWatcher::new(loop_) |watcher, status| {
             assert!(status.is_none());
             f();
-            let exit_flag_ptr = exit_flag_clone.get();
-            unsafe {
-                if (*exit_flag_ptr).load() == 1 {
+            do exit_flag_clone.with_imm |&should_exit| {
+                if should_exit {
                     watcher.close(||());
                 }
             }
@@ -139,9 +138,14 @@ impl Drop for UvRemoteCallback {
     fn finalize(&self) {
         unsafe {
             let this: &mut UvRemoteCallback = cast::transmute_mut(self);
-            let exit_flag_ptr = this.exit_flag.get();
-            (*exit_flag_ptr).store(1);
-            this.async.send();
+            do this.exit_flag.with |should_exit| {
+                // NB: These two things need to happen atomically. Otherwise
+                // the event handler could wake up due to a *previous*
+                // signal and see the exit flag, destroying the handle
+                // before the final send.
+                *should_exit = true;
+                this.async.send();
+            }
         }
     }
 }