diff options
| author | Paul Dicker <pitdicker@gmail.com> | 2019-10-23 11:44:31 +0200 |
|---|---|---|
| committer | Paul Dicker <pitdicker@gmail.com> | 2019-10-24 17:28:04 +0200 |
| commit | fbc242f1ef172f6fa5b7bc837b5c3a78a4c8f850 (patch) | |
| tree | ef803368fd1f427c948bf2910e3f1fb2ab315c3b /src/libstd/sync | |
| parent | 1479c22a390a6b95706d4280cd7be24e4410dc77 (diff) | |
| download | rust-fbc242f1ef172f6fa5b7bc837b5c3a78a4c8f850.tar.gz rust-fbc242f1ef172f6fa5b7bc837b5c3a78a4c8f850.zip | |
Turn Finish into WaiterQueue
Diffstat (limited to 'src/libstd/sync')
| -rw-r--r-- | src/libstd/sync/once.rs | 44 |
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 |
