Auto merge of #114591 - joboet:thread_parking_ordering_fix, r=thomcc
Synchronize with all calls to `unpark` in id-based thread parker [The documentation for `thread::park`](https://doc.rust-lang.org/nightly/std/thread/fn.park.html#memory-ordering) guarantees that "park synchronizes-with all prior unpark operations". In the id-based thread parking implementation, this is not implemented correctly, as the state variable is reset with a simple store, so there will not be a *synchronizes-with* edge if an `unpark` happens just before the reset. This PR corrects this, replacing the load-check-reset sequence with a single `compare_exchange`.
This commit is contained in:
commit
d06ca0ffaf
@ -56,18 +56,14 @@ impl Parker {
|
|||||||
self.init_tid();
|
self.init_tid();
|
||||||
|
|
||||||
// Changes NOTIFIED to EMPTY and EMPTY to PARKED.
|
// Changes NOTIFIED to EMPTY and EMPTY to PARKED.
|
||||||
let mut state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
|
let state = self.state.fetch_sub(1, Acquire);
|
||||||
if state == PARKED {
|
if state == EMPTY {
|
||||||
// Loop to guard against spurious wakeups.
|
// Loop to guard against spurious wakeups.
|
||||||
while state == PARKED {
|
// The state must be reset with acquire ordering to ensure that all
|
||||||
|
// calls to `unpark` synchronize with this thread.
|
||||||
|
while self.state.compare_exchange(NOTIFIED, EMPTY, Acquire, Relaxed).is_err() {
|
||||||
park(self.state.as_ptr().addr());
|
park(self.state.as_ptr().addr());
|
||||||
state = self.state.load(Acquire);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since the state change has already been observed with acquire
|
|
||||||
// ordering, the state can be reset with a relaxed store instead
|
|
||||||
// of a swap.
|
|
||||||
self.state.store(EMPTY, Relaxed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,8 +74,7 @@ impl Parker {
|
|||||||
if state == PARKED {
|
if state == PARKED {
|
||||||
park_timeout(dur, self.state.as_ptr().addr());
|
park_timeout(dur, self.state.as_ptr().addr());
|
||||||
// Swap to ensure that we observe all state changes with acquire
|
// Swap to ensure that we observe all state changes with acquire
|
||||||
// ordering, even if the state has been changed after the timeout
|
// ordering.
|
||||||
// occurred.
|
|
||||||
self.state.swap(EMPTY, Acquire);
|
self.state.swap(EMPTY, Acquire);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user