diff options
| author | Brian Anderson <banderson@mozilla.com> | 2013-06-06 17:46:45 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2013-06-06 17:53:13 -0700 |
| commit | d4de99aa6c53b0eb0d5be2ccfc62e2c89b2cd2df (patch) | |
| tree | 2a482df80221611b7fc81c4709aa257624d8a95a /src/libstd/rt | |
| parent | d6ccc6bc99386ae20ac03b68e7ec504a16068242 (diff) | |
| download | rust-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.rs | 26 |
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(); + } } } } |
