@@ -77,22 +77,15 @@ pub struct QueryWaiter<'tcx> {
7777 pub cycle : Mutex < Option < CycleError < QueryStackDeferred < ' tcx > > > > ,
7878}
7979
80- #[ derive( Debug ) ]
81- pub struct QueryLatchInfo < ' tcx > {
82- pub complete : bool ,
83- pub waiters : Vec < Arc < QueryWaiter < ' tcx > > > ,
84- }
85-
8680#[ derive( Clone , Debug ) ]
8781pub struct QueryLatch < ' tcx > {
88- pub info : Arc < Mutex < QueryLatchInfo < ' tcx > > > ,
82+ /// The `Option` is `Some(..)` when the job is active, and `None` once completed.
83+ pub waiters : Arc < Mutex < Option < Vec < Arc < QueryWaiter < ' tcx > > > > > > ,
8984}
9085
9186impl < ' tcx > QueryLatch < ' tcx > {
9287 fn new ( ) -> Self {
93- QueryLatch {
94- info : Arc :: new ( Mutex :: new ( QueryLatchInfo { complete : false , waiters : Vec :: new ( ) } ) ) ,
95- }
88+ QueryLatch { waiters : Arc :: new ( Mutex :: new ( Some ( Vec :: new ( ) ) ) ) }
9689 }
9790
9891 /// Awaits for the query job to complete.
@@ -102,10 +95,10 @@ impl<'tcx> QueryLatch<'tcx> {
10295 query : Option < QueryJobId > ,
10396 span : Span ,
10497 ) -> Result < ( ) , CycleError < QueryStackDeferred < ' tcx > > > {
105- let mut info = self . info . lock ( ) ;
106- if info . complete {
107- return Ok ( ( ) ) ;
108- }
98+ let mut waiters_guard = self . waiters . lock ( ) ;
99+ let Some ( waiters ) = & mut * waiters_guard else {
100+ return Ok ( ( ) ) ; // already complete
101+ } ;
109102
110103 let waiter =
111104 Arc :: new ( QueryWaiter { query, span, cycle : Mutex :: new ( None ) , condvar : Condvar :: new ( ) } ) ;
@@ -114,17 +107,17 @@ impl<'tcx> QueryLatch<'tcx> {
114107 // the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
115108 // Both of these will remove it from the `waiters` list before resuming
116109 // this thread.
117- info . waiters . push ( Arc :: clone ( & waiter) ) ;
110+ waiters. push ( Arc :: clone ( & waiter) ) ;
118111
119112 // Awaits the caller on this latch by blocking the current thread.
120113 // If this detects a deadlock and the deadlock handler wants to resume this thread
121114 // we have to be in the `wait` call. This is ensured by the deadlock handler
122115 // getting the self.info lock.
123116 rustc_thread_pool:: mark_blocked ( ) ;
124117 tcx. jobserver_proxy . release_thread ( ) ;
125- waiter. condvar . wait ( & mut info ) ;
118+ waiter. condvar . wait ( & mut waiters_guard ) ;
126119 // Release the lock before we potentially block in `acquire_thread`
127- drop ( info ) ;
120+ drop ( waiters_guard ) ;
128121 tcx. jobserver_proxy . acquire_thread ( ) ;
129122
130123 // FIXME: Get rid of this lock. We have ownership of the QueryWaiter
@@ -139,11 +132,10 @@ impl<'tcx> QueryLatch<'tcx> {
139132
140133 /// Sets the latch and resumes all waiters on it
141134 fn set ( & self ) {
142- let mut info = self . info . lock ( ) ;
143- debug_assert ! ( !info. complete) ;
144- info. complete = true ;
135+ let mut waiters_guard = self . waiters . lock ( ) ;
136+ let waiters = waiters_guard. take ( ) . unwrap ( ) ; // mark the latch as complete
145137 let registry = rustc_thread_pool:: Registry :: current ( ) ;
146- for waiter in info . waiters . drain ( .. ) {
138+ for waiter in waiters {
147139 rustc_thread_pool:: mark_unblocked ( & registry) ;
148140 waiter. condvar . notify_one ( ) ;
149141 }
@@ -152,9 +144,9 @@ impl<'tcx> QueryLatch<'tcx> {
152144 /// Removes a single waiter from the list of waiters.
153145 /// This is used to break query cycles.
154146 pub fn extract_waiter ( & self , waiter : usize ) -> Arc < QueryWaiter < ' tcx > > {
155- let mut info = self . info . lock ( ) ;
156- debug_assert ! ( !info . complete ) ;
147+ let mut waiters_guard = self . waiters . lock ( ) ;
148+ let waiters = waiters_guard . as_mut ( ) . expect ( "non-empty waiters vec" ) ;
157149 // Remove the waiter from the list of waiters
158- info . waiters . remove ( waiter)
150+ waiters. remove ( waiter)
159151 }
160152}
0 commit comments