Skip to content

Commit fbc242f

Browse files
committed
Turn Finish into WaiterQueue
1 parent 1479c22 commit fbc242f

File tree

1 file changed

+21
-23
lines changed

1 file changed

+21
-23
lines changed

src/libstd/sync/once.rs

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,15 @@ struct Waiter {
139139
next: *const Waiter,
140140
}
141141

142-
// Helper struct used to clean up after a closure call with a `Drop`
143-
// implementation to also run on panic.
144-
struct Finish<'a> {
145-
panicked: bool,
146-
me: &'a Once,
142+
// Head of a linked list of waiters.
143+
// Every node is a struct on the stack of a waiting thread.
144+
// Will wake up the waiters when it gets dropped, i.e. also on panic.
145+
struct WaiterQueue<'a> {
146+
state_and_queue: &'a AtomicUsize,
147+
set_state_on_drop_to: usize,
147148
}
148149

150+
149151
impl Once {
150152
/// Creates a new `Once` value.
151153
#[stable(feature = "once_new", since = "1.2.0")]
@@ -379,18 +381,16 @@ impl Once {
379381
state_and_queue = old;
380382
continue
381383
}
382-
383-
// Run the initialization routine, letting it know if we're
384-
// poisoned or not. The `Finish` struct is then dropped, and
385-
// the `Drop` implementation here is responsible for waking
386-
// up other waiters both in the normal return and panicking
387-
// case.
388-
let mut complete = Finish {
389-
panicked: true,
390-
me: self,
384+
// `waiter_queue` will manage other waiting threads, and
385+
// wake them up on drop.
386+
let mut waiter_queue = WaiterQueue {
387+
state_and_queue: &self.state_and_queue,
388+
set_state_on_drop_to: POISONED,
391389
};
390+
// Run the initialization function, letting it know if we're
391+
// poisoned or not.
392392
init(state_and_queue == POISONED);
393-
complete.panicked = false;
393+
waiter_queue.set_state_on_drop_to = COMPLETE;
394394
return
395395
}
396396

@@ -453,15 +453,13 @@ impl fmt::Debug for Once {
453453
}
454454
}
455455

456-
impl Drop for Finish<'_> {
456+
impl Drop for WaiterQueue<'_> {
457457
fn drop(&mut self) {
458-
// Swap out our state with however we finished. We should only ever see
459-
// an old state which was RUNNING.
460-
let state_and_queue = if self.panicked {
461-
self.me.state_and_queue.swap(POISONED, Ordering::SeqCst)
462-
} else {
463-
self.me.state_and_queue.swap(COMPLETE, Ordering::SeqCst)
464-
};
458+
// Swap out our state with however we finished.
459+
let state_and_queue = self.state_and_queue.swap(self.set_state_on_drop_to,
460+
Ordering::SeqCst);
461+
462+
// We should only ever see an old state which was RUNNING.
465463
assert_eq!(state_and_queue & STATE_MASK, RUNNING);
466464

467465
// Decode the RUNNING to a list of waiters, then walk that entire list

0 commit comments

Comments
 (0)