sync: add spin_loop_hint to atomic waker (#1608)

The algorithm backing `AtomicWaker` effectively uses a spin lock backed
by notifying & yielding the current task. This adds a `spin_lock_hint`
annotation to cover this case.

While, in practice, the omission of `spin_lock_hint` would not cause
problems, there are platforms that do not handle spin locks very well
and could enter a deadlock in pathological cases.
This commit is contained in:
Carl Lerche
2019-09-26 15:16:34 -04:00
committed by Jon Gjengset
parent b71b7b36be
commit 032b39487c
+7 -1
View File
@@ -1,4 +1,5 @@
use crate::loom::{sync::atomic::AtomicUsize, sync::CausalCell}; use crate::loom::sync::atomic::{self, AtomicUsize};
use crate::loom::sync::CausalCell;
use std::fmt; use std::fmt;
use std::sync::atomic::Ordering::{AcqRel, Acquire, Release}; use std::sync::atomic::Ordering::{AcqRel, Acquire, Release};
@@ -171,6 +172,7 @@ impl AtomicWaker {
debug!(" + register_task"); debug!(" + register_task");
match self.state.compare_and_swap(WAITING, REGISTERING, Acquire) { match self.state.compare_and_swap(WAITING, REGISTERING, Acquire) {
WAITING => { WAITING => {
debug!(" + WAITING");
unsafe { unsafe {
// Locked acquired, update the waker cell // Locked acquired, update the waker cell
self.waker.with_mut(|t| *t = Some(waker.into_waker())); self.waker.with_mut(|t| *t = Some(waker.into_waker()));
@@ -211,10 +213,14 @@ impl AtomicWaker {
} }
} }
WAKING => { WAKING => {
debug!(" + WAKING");
// Currently in the process of waking the task, i.e., // Currently in the process of waking the task, i.e.,
// `wake` is currently being called on the old waker. // `wake` is currently being called on the old waker.
// So, we call wake on the new waker. // So, we call wake on the new waker.
waker.wake(); waker.wake();
// This is equivalent to a spin lock, so use a spin hint.
atomic::spin_loop_hint();
} }
state => { state => {
// In this case, a concurrent thread is holding the // In this case, a concurrent thread is holding the