@@ -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+
149151impl 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