about summary refs log tree commit diff
path: root/src/libstd/sync
diff options
context:
space:
mode:
authorPaul Dicker <pitdicker@gmail.com>2019-10-23 11:44:31 +0200
committerPaul Dicker <pitdicker@gmail.com>2019-10-24 17:28:04 +0200
commitfbc242f1ef172f6fa5b7bc837b5c3a78a4c8f850 (patch)
treeef803368fd1f427c948bf2910e3f1fb2ab315c3b /src/libstd/sync
parent1479c22a390a6b95706d4280cd7be24e4410dc77 (diff)
downloadrust-fbc242f1ef172f6fa5b7bc837b5c3a78a4c8f850.tar.gz
rust-fbc242f1ef172f6fa5b7bc837b5c3a78a4c8f850.zip
Turn Finish into WaiterQueue
Diffstat (limited to 'src/libstd/sync')
-rw-r--r--src/libstd/sync/once.rs44
1 files changed, 21 insertions, 23 deletions
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index d8565e55ab2..01cb7582d38 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -139,13 +139,15 @@ struct Waiter {
     next: *const Waiter,
 }
 
-// Helper struct used to clean up after a closure call with a `Drop`
-// implementation to also run on panic.
-struct Finish<'a> {
-    panicked: bool,
-    me: &'a Once,
+// Head of a linked list of waiters.
+// Every node is a struct on the stack of a waiting thread.
+// Will wake up the waiters when it gets dropped, i.e. also on panic.
+struct WaiterQueue<'a> {
+    state_and_queue: &'a AtomicUsize,
+    set_state_on_drop_to: usize,
 }
 
+
 impl Once {
     /// Creates a new `Once` value.
     #[stable(feature = "once_new", since = "1.2.0")]
@@ -379,18 +381,16 @@ impl Once {
                         state_and_queue = old;
                         continue
                     }
-
-                    // Run the initialization routine, letting it know if we're
-                    // poisoned or not. The `Finish` struct is then dropped, and
-                    // the `Drop` implementation here is responsible for waking
-                    // up other waiters both in the normal return and panicking
-                    // case.
-                    let mut complete = Finish {
-                        panicked: true,
-                        me: self,
+                    // `waiter_queue` will manage other waiting threads, and
+                    // wake them up on drop.
+                    let mut waiter_queue = WaiterQueue {
+                        state_and_queue: &self.state_and_queue,
+                        set_state_on_drop_to: POISONED,
                     };
+                    // Run the initialization function, letting it know if we're
+                    // poisoned or not.
                     init(state_and_queue == POISONED);
-                    complete.panicked = false;
+                    waiter_queue.set_state_on_drop_to = COMPLETE;
                     return
                 }
 
@@ -453,15 +453,13 @@ impl fmt::Debug for Once {
     }
 }
 
-impl Drop for Finish<'_> {
+impl Drop for WaiterQueue<'_> {
     fn drop(&mut self) {
-        // Swap out our state with however we finished. We should only ever see
-        // an old state which was RUNNING.
-        let state_and_queue = if self.panicked {
-            self.me.state_and_queue.swap(POISONED, Ordering::SeqCst)
-        } else {
-            self.me.state_and_queue.swap(COMPLETE, Ordering::SeqCst)
-        };
+        // Swap out our state with however we finished.
+        let state_and_queue = self.state_and_queue.swap(self.set_state_on_drop_to,
+                                                        Ordering::SeqCst);
+
+        // We should only ever see an old state which was RUNNING.
         assert_eq!(state_and_queue & STATE_MASK, RUNNING);
 
         // Decode the RUNNING to a list of waiters, then walk that entire list