about summary refs log tree commit diff
path: root/library/std/src/sys/sync
diff options
context:
space:
mode:
authorjoboet <jonasboettiger@icloud.com>2024-07-12 13:17:43 +0200
committerjoboet <jonasboettiger@icloud.com>2024-07-31 17:44:10 +0200
commit1d49aad8445881ac060cfae0e351207c05f82dfd (patch)
treea9e70337c173b5423c56b599c19fc68fb8047cff /library/std/src/sys/sync
parentcf11f499b37e557e41f5eeac157c623d08e0068d (diff)
std: fix busy-waiting in `Once::wait_force`, add more tests
Diffstat (limited to 'library/std/src/sys/sync')
-rw-r--r--library/std/src/sys/sync/once/queue.rs12
1 files changed, 8 insertions, 4 deletions
diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs
index 7a020c94080..86f72c82008 100644
--- a/library/std/src/sys/sync/once/queue.rs
+++ b/library/std/src/sys/sync/once/queue.rs
@@ -153,7 +153,7 @@ impl Once {
                     panic!("Once instance has previously been poisoned");
                 }
                 _ => {
-                    current = wait(&self.state_and_queue, current);
+                    current = wait(&self.state_and_queue, current, !ignore_poisoning);
                 }
             }
         }
@@ -216,14 +216,18 @@ impl Once {
                     // All other values must be RUNNING with possibly a
                     // pointer to the waiter queue in the more significant bits.
                     assert!(state == RUNNING);
-                    current = wait(&self.state_and_queue, current);
+                    current = wait(&self.state_and_queue, current, true);
                 }
             }
         }
     }
 }
 
-fn wait(state_and_queue: &AtomicPtr<()>, mut current: StateAndQueue) -> StateAndQueue {
+fn wait(
+    state_and_queue: &AtomicPtr<()>,
+    mut current: StateAndQueue,
+    return_on_poisoned: bool,
+) -> StateAndQueue {
     let node = &Waiter {
         thread: Cell::new(Some(thread::current())),
         signaled: AtomicBool::new(false),
@@ -235,7 +239,7 @@ fn wait(state_and_queue: &AtomicPtr<()>, mut current: StateAndQueue) -> StateAnd
         let queue = to_queue(current);
 
         // If initialization has finished, return.
-        if matches!(state, POISONED | COMPLETE) {
+        if state == COMPLETE || (return_on_poisoned && state == POISONED) {
             return current;
         }