diff options
| author | James Duley <james.duley@arm.com> | 2018-09-11 18:04:33 +0100 |
|---|---|---|
| committer | James Duley <james.duley@arm.com> | 2018-09-12 18:55:44 +0100 |
| commit | 204d9608e35f7dc56e179d4539e931766fd88f28 (patch) | |
| tree | ec8b05190dd4caa304adbb892b19d623fceeacdc /src/libstd/thread | |
| parent | 7ee72070bdb789f58f272fab50d49bd48dd9c11f (diff) | |
| download | rust-204d9608e35f7dc56e179d4539e931766fd88f28.tar.gz rust-204d9608e35f7dc56e179d4539e931766fd88f28.zip | |
Fix `thread` `park`/`unpark` synchronization
Previously the code below would not be guaranteed to exit when the first
spawned thread took the `return, // already unparked` path because there
was no write to synchronize with a read in `park`.
```
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::{current, spawn, park};
static FLAG: AtomicBool = AtomicBool::new(false);
fn main() {
let thread_0 = current();
spawn(move || {
FLAG.store(true, Ordering::Relaxed);
thread_0.unpark();
});
let thread_0 = current();
spawn(move || {
thread_0.unpark();
});
while !FLAG.load(Ordering::Relaxed) {
park();
}
}
```
Diffstat (limited to 'src/libstd/thread')
| -rw-r--r-- | src/libstd/thread/mod.rs | 29 |
1 files changed, 11 insertions, 18 deletions
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index a7c7dbb1b40..020ea09db2a 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -800,7 +800,7 @@ pub fn park() { match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} Err(NOTIFIED) => { - thread.inner.state.store(EMPTY, SeqCst); + thread.inner.state.swap(EMPTY, SeqCst); return; } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => panic!("inconsistent park state"), @@ -889,7 +889,7 @@ pub fn park_timeout(dur: Duration) { match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { Ok(_) => {} Err(NOTIFIED) => { - thread.inner.state.store(EMPTY, SeqCst); + thread.inner.state.swap(EMPTY, SeqCst); return; } // should consume this notification, so prohibit spurious wakeups in next park. Err(_) => panic!("inconsistent park_timeout state"), @@ -1058,23 +1058,16 @@ impl Thread { /// [park]: fn.park.html #[stable(feature = "rust1", since = "1.0.0")] pub fn unpark(&self) { - loop { - match self.inner.state.compare_exchange(EMPTY, NOTIFIED, SeqCst, SeqCst) { - Ok(_) => return, // no one was waiting - Err(NOTIFIED) => return, // already unparked - Err(PARKED) => {} // gotta go wake someone up - _ => panic!("inconsistent state in unpark"), - } - - // Coordinate wakeup through the mutex and a condvar notification - let _lock = self.inner.lock.lock().unwrap(); - match self.inner.state.compare_exchange(PARKED, NOTIFIED, SeqCst, SeqCst) { - Ok(_) => return self.inner.cvar.notify_one(), - Err(NOTIFIED) => return, // a different thread unparked - Err(EMPTY) => {} // parked thread went away, try again - _ => panic!("inconsistent state in unpark"), - } + match self.inner.state.swap(NOTIFIED, SeqCst) { + EMPTY => return, // no one was waiting + NOTIFIED => return, // already unparked + PARKED => {} // gotta go wake someone up + _ => panic!("inconsistent state in unpark"), } + + // Coordinate wakeup through the mutex and a condvar notification + let _lock = self.inner.lock.lock().unwrap(); + self.inner.cvar.notify_one() } /// Gets the thread's unique identifier. |
