@@ -588,32 +588,40 @@ impl<T: Types> Drop for Cache<T> {
588
588
let Some ( handle_inner_arc) = handle_inner_weak. upgrade ( ) else {
589
589
continue ;
590
590
} ;
591
- let handle_timeline = handle_inner_arc
591
+ let Some ( handle_timeline) = handle_inner_arc
592
592
// locking rules: drop lock before acquiring other lock below
593
593
. lock ( )
594
594
. expect ( "poisoned" )
595
- . shutdown ( ) ;
595
+ . shutdown ( )
596
+ else {
597
+ // Concurrent PerTimelineState::shutdown.
598
+ continue ;
599
+ } ;
600
+ // Clean up per_timeline_state so the HandleInner allocation can be dropped.
596
601
let per_timeline_state = handle_timeline. per_timeline_state ( ) ;
597
602
let mut handles_lock_guard = per_timeline_state. handles . lock ( ) . expect ( "mutex poisoned" ) ;
598
603
let Some ( handles) = & mut * handles_lock_guard else {
599
604
continue ;
600
605
} ;
601
606
let Some ( removed_handle_inner_arc) = handles. remove ( & self . id ) else {
602
- // There could have been a shutdown inbetween us upgrading the weak and locking the mutex .
607
+ // Concurrent PerTimelineState:: shutdown.
603
608
continue ;
604
609
} ;
605
- drop ( handles_lock_guard) ; // locking rules: remember them when !
606
- assert ! ( Arc :: ptr_eq( & removed_handle_inner_arc, & handle_inner_arc, ) ) ;
610
+ drop ( handles_lock_guard) ; // locking rules!
611
+ assert ! ( Arc :: ptr_eq( & removed_handle_inner_arc, & handle_inner_arc) ) ;
607
612
}
608
613
}
609
614
}
610
615
611
616
impl < T : Types > HandleInner < T > {
612
- fn shutdown ( & mut self ) -> Arc < T :: Timeline > {
617
+ fn shutdown ( & mut self ) -> Option < Arc < T :: Timeline > > {
613
618
match std:: mem:: replace ( self , HandleInner :: ShutDown ) {
614
- HandleInner :: KeepingTimelineGateOpen { timeline, .. } => timeline,
619
+ HandleInner :: KeepingTimelineGateOpen { timeline, .. } => Some ( timeline) ,
615
620
HandleInner :: ShutDown => {
616
- unreachable ! ( "handles are only shut down once in their lifetime" ) ;
621
+ // Duplicate shutdowns are possible because both Cache::drop and PerTimelineState::shutdown
622
+ // may do it concurrently, but locking rules disallow holding per-timeline-state lock and
623
+ // the handle lock at the same time.
624
+ None
617
625
}
618
626
}
619
627
}
0 commit comments