about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-08-18 19:03:38 +0000
committerbors <bors@rust-lang.org>2023-08-18 19:03:38 +0000
commitd06ca0ffaf4ac72732665f99dd9ad962194cd0b3 (patch)
tree1b6580c5664d6689388b4ec11d9501cf40c12733 /library/std/src
parentee5cb9e3a608b58a21889c77733564b48b74544f (diff)
parentfd9fcc580a40bdf398576199c5e8c3ebe12de9c6 (diff)
downloadrust-d06ca0ffaf4ac72732665f99dd9ad962194cd0b3.tar.gz
rust-d06ca0ffaf4ac72732665f99dd9ad962194cd0b3.zip
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`.
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/sys_common/thread_parking/id.rs17
1 files changed, 6 insertions, 11 deletions
diff --git a/library/std/src/sys_common/thread_parking/id.rs b/library/std/src/sys_common/thread_parking/id.rs
index 15042fc3bee..04667439660 100644
--- a/library/std/src/sys_common/thread_parking/id.rs
+++ b/library/std/src/sys_common/thread_parking/id.rs
@@ -56,18 +56,14 @@ impl Parker {
         self.init_tid();
 
         // Changes NOTIFIED to EMPTY and EMPTY to PARKED.
-        let mut state = self.state.fetch_sub(1, Acquire).wrapping_sub(1);
-        if state == PARKED {
+        let state = self.state.fetch_sub(1, Acquire);
+        if state == EMPTY {
             // 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());
-                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 {
             park_timeout(dur, self.state.as_ptr().addr());
             // Swap to ensure that we observe all state changes with acquire
-            // ordering, even if the state has been changed after the timeout
-            // occurred.
+            // ordering.
             self.state.swap(EMPTY, Acquire);
         }
     }