@@ -151,6 +151,10 @@ impl<'tcx> QueryJob<'tcx> {
151
151
#[ cfg( parallel_queries) ]
152
152
self . latch . set ( ) ;
153
153
}
154
+
155
+ fn as_ptr ( & self ) -> * const QueryJob < ' tcx > {
156
+ self as * const _
157
+ }
154
158
}
155
159
156
160
#[ cfg( parallel_queries) ]
@@ -233,13 +237,9 @@ impl<'tcx> QueryLatch<'tcx> {
233
237
}
234
238
}
235
239
236
- /// A pointer to an active query job. This is used to give query jobs an identity.
237
- #[ cfg( parallel_queries) ]
238
- type Ref < ' tcx > = * const QueryJob < ' tcx > ;
239
-
240
240
/// A resumable waiter of a query. The usize is the index into waiters in the query's latch
241
241
#[ cfg( parallel_queries) ]
242
- type Waiter < ' tcx > = ( Ref < ' tcx > , usize ) ;
242
+ type Waiter < ' tcx > = ( Lrc < QueryJob < ' tcx > > , usize ) ;
243
243
244
244
/// Visits all the non-resumable and resumable waiters of a query.
245
245
/// Only waiters in a query are visited.
@@ -251,25 +251,23 @@ type Waiter<'tcx> = (Ref<'tcx>, usize);
251
251
/// required information to resume the waiter.
252
252
/// If all `visit` calls returns None, this function also returns None.
253
253
#[ cfg( parallel_queries) ]
254
- fn visit_waiters < ' tcx , F > ( query_ref : Ref < ' tcx > , mut visit : F ) -> Option < Option < Waiter < ' tcx > > >
254
+ fn visit_waiters < ' tcx , F > ( query : Lrc < QueryJob < ' tcx > > , mut visit : F ) -> Option < Option < Waiter < ' tcx > > >
255
255
where
256
- F : FnMut ( Span , Ref < ' tcx > ) -> Option < Option < Waiter < ' tcx > > >
256
+ F : FnMut ( Span , Lrc < QueryJob < ' tcx > > ) -> Option < Option < Waiter < ' tcx > > >
257
257
{
258
- let query = unsafe { & * query_ref } ;
259
-
260
258
// Visit the parent query which is a non-resumable waiter since it's on the same stack
261
259
if let Some ( ref parent) = query. parent {
262
- if let Some ( cycle) = visit ( query. info . span , & * * parent as Ref ) {
260
+ if let Some ( cycle) = visit ( query. info . span , parent. clone ( ) ) {
263
261
return Some ( cycle) ;
264
262
}
265
263
}
266
264
267
265
// Visit the explict waiters which use condvars and are resumable
268
266
for ( i, waiter) in query. latch . info . lock ( ) . waiters . iter ( ) . enumerate ( ) {
269
267
if let Some ( ref waiter_query) = waiter. query {
270
- if visit ( waiter. span , & * * waiter_query) . is_some ( ) {
268
+ if visit ( waiter. span , waiter_query. clone ( ) ) . is_some ( ) {
271
269
// Return a value which indicates that this waiter can be resumed
272
- return Some ( Some ( ( query_ref , i) ) ) ;
270
+ return Some ( Some ( ( query . clone ( ) , i) ) ) ;
273
271
}
274
272
}
275
273
}
@@ -281,12 +279,13 @@ where
281
279
/// If a cycle is detected, this initial value is replaced with the span causing
282
280
/// the cycle.
283
281
#[ cfg( parallel_queries) ]
284
- fn cycle_check < ' tcx > ( query : Ref < ' tcx > ,
282
+ fn cycle_check < ' tcx > ( query : Lrc < QueryJob < ' tcx > > ,
285
283
span : Span ,
286
- stack : & mut Vec < ( Span , Ref < ' tcx > ) > ,
287
- visited : & mut HashSet < Ref < ' tcx > > ) -> Option < Option < Waiter < ' tcx > > > {
288
- if visited. contains ( & query) {
289
- return if let Some ( p) = stack. iter ( ) . position ( |q| q. 1 == query) {
284
+ stack : & mut Vec < ( Span , Lrc < QueryJob < ' tcx > > ) > ,
285
+ visited : & mut HashSet < * const QueryJob < ' tcx > >
286
+ ) -> Option < Option < Waiter < ' tcx > > > {
287
+ if visited. contains ( & query. as_ptr ( ) ) {
288
+ return if let Some ( p) = stack. iter ( ) . position ( |q| q. 1 . as_ptr ( ) == query. as_ptr ( ) ) {
290
289
// We detected a query cycle, fix up the initial span and return Some
291
290
292
291
// Remove previous stack entries
@@ -300,8 +299,8 @@ fn cycle_check<'tcx>(query: Ref<'tcx>,
300
299
}
301
300
302
301
// Mark this query is visited and add it to the stack
303
- visited. insert ( query) ;
304
- stack. push ( ( span, query) ) ;
302
+ visited. insert ( query. as_ptr ( ) ) ;
303
+ stack. push ( ( span, query. clone ( ) ) ) ;
305
304
306
305
// Visit all the waiters
307
306
let r = visit_waiters ( query, |span, successor| {
@@ -320,18 +319,21 @@ fn cycle_check<'tcx>(query: Ref<'tcx>,
320
319
/// from `query` without going through any of the queries in `visited`.
321
320
/// This is achieved with a depth first search.
322
321
#[ cfg( parallel_queries) ]
323
- fn connected_to_root < ' tcx > ( query : Ref < ' tcx > , visited : & mut HashSet < Ref < ' tcx > > ) -> bool {
322
+ fn connected_to_root < ' tcx > (
323
+ query : Lrc < QueryJob < ' tcx > > ,
324
+ visited : & mut HashSet < * const QueryJob < ' tcx > >
325
+ ) -> bool {
324
326
// We already visited this or we're deliberately ignoring it
325
- if visited. contains ( & query) {
327
+ if visited. contains ( & query. as_ptr ( ) ) {
326
328
return false ;
327
329
}
328
330
329
331
// This query is connected to the root (it has no query parent), return true
330
- if unsafe { ( * query) . parent . is_none ( ) } {
332
+ if query. parent . is_none ( ) {
331
333
return true ;
332
334
}
333
335
334
- visited. insert ( query) ;
336
+ visited. insert ( query. as_ptr ( ) ) ;
335
337
336
338
let mut connected = false ;
337
339
@@ -351,7 +353,7 @@ fn connected_to_root<'tcx>(query: Ref<'tcx>, visited: &mut HashSet<Ref<'tcx>>) -
351
353
/// the function returns false.
352
354
#[ cfg( parallel_queries) ]
353
355
fn remove_cycle < ' tcx > (
354
- jobs : & mut Vec < Ref < ' tcx > > ,
356
+ jobs : & mut Vec < Lrc < QueryJob < ' tcx > > > ,
355
357
wakelist : & mut Vec < Lrc < QueryWaiter < ' tcx > > > ,
356
358
tcx : TyCtxt < ' _ , ' tcx , ' _ >
357
359
) -> bool {
@@ -367,7 +369,7 @@ fn remove_cycle<'tcx>(
367
369
368
370
// Extract the spans and queries into separate arrays
369
371
let mut spans: Vec < _ > = stack. iter ( ) . map ( |e| e. 0 ) . collect ( ) ;
370
- let queries = stack. iter ( ) . map ( |e| e. 1 ) ;
372
+ let queries = stack. into_iter ( ) . map ( |e| e. 1 ) ;
371
373
372
374
// Shift the spans so that queries are matched with the span for their waitee
373
375
let last = spans. pop ( ) . unwrap ( ) ;
@@ -378,23 +380,25 @@ fn remove_cycle<'tcx>(
378
380
379
381
// Remove the queries in our cycle from the list of jobs to look at
380
382
for r in & stack {
381
- jobs. remove_item ( & r. 1 ) ;
383
+ if let Some ( pos) = jobs. iter ( ) . position ( |j| j. as_ptr ( ) == r. 1 . as_ptr ( ) ) {
384
+ jobs. remove ( pos) ;
385
+ }
382
386
}
383
387
384
388
// Find the queries in the cycle which are
385
389
// connected to queries outside the cycle
386
- let entry_points: Vec < Ref < ' _ > > = stack. iter ( ) . filter_map ( |query| {
390
+ let entry_points: Vec < Lrc < QueryJob < ' tcx > > > = stack. iter ( ) . filter_map ( |query| {
387
391
// Mark all the other queries in the cycle as already visited
388
392
let mut visited = HashSet :: from_iter ( stack. iter ( ) . filter_map ( |q| {
389
- if q. 1 != query. 1 {
390
- Some ( q. 1 )
393
+ if q. 1 . as_ptr ( ) != query. 1 . as_ptr ( ) {
394
+ Some ( q. 1 . as_ptr ( ) )
391
395
} else {
392
396
None
393
397
}
394
398
} ) ) ;
395
399
396
- if connected_to_root ( query. 1 , & mut visited) {
397
- Some ( query. 1 )
400
+ if connected_to_root ( query. 1 . clone ( ) , & mut visited) {
401
+ Some ( query. 1 . clone ( ) )
398
402
} else {
399
403
None
400
404
}
@@ -403,39 +407,36 @@ fn remove_cycle<'tcx>(
403
407
// Deterministically pick an entry point
404
408
// FIXME: Sort this instead
405
409
let mut hcx = tcx. create_stable_hashing_context ( ) ;
406
- let entry_point = * entry_points. iter ( ) . min_by_key ( |& & q| {
410
+ let entry_point = entry_points. iter ( ) . min_by_key ( |q| {
407
411
let mut stable_hasher = StableHasher :: < u64 > :: new ( ) ;
408
- unsafe { ( * q ) . info . query . hash_stable ( & mut hcx, & mut stable_hasher) ; }
412
+ q . info . query . hash_stable ( & mut hcx, & mut stable_hasher) ;
409
413
stable_hasher. finish ( )
410
- } ) . unwrap ( ) ;
414
+ } ) . unwrap ( ) . as_ptr ( ) ;
411
415
412
416
// Shift the stack until our entry point is first
413
- while stack[ 0 ] . 1 != entry_point {
417
+ while stack[ 0 ] . 1 . as_ptr ( ) != entry_point {
414
418
let last = stack. pop ( ) . unwrap ( ) ;
415
419
stack. insert ( 0 , last) ;
416
420
}
417
421
418
422
// Create the cycle error
419
423
let mut error = CycleError {
420
424
usage : None ,
421
- cycle : stack. iter ( ) . map ( |& ( s, q) | QueryInfo {
425
+ cycle : stack. iter ( ) . map ( |& ( s, ref q) | QueryInfo {
422
426
span : s,
423
- query : unsafe { ( * q ) . info . query . clone ( ) } ,
427
+ query : q . info . query . clone ( ) ,
424
428
} ) . collect ( ) ,
425
429
} ;
426
430
427
431
// We unwrap `waiter` here since there must always be one
428
432
// edge which is resumeable / waited using a query latch
429
433
let ( waitee_query, waiter_idx) = waiter. unwrap ( ) ;
430
- let waitee_query = unsafe { & * waitee_query } ;
431
434
432
435
// Extract the waiter we want to resume
433
436
let waiter = waitee_query. latch . extract_waiter ( waiter_idx) ;
434
437
435
438
// Set the cycle error so it will be picked up when resumed
436
- unsafe {
437
- * waiter. cycle . lock ( ) = Some ( error) ;
438
- }
439
+ * waiter. cycle . lock ( ) = Some ( error) ;
439
440
440
441
// Put the waiter on the list of things to resume
441
442
wakelist. push ( waiter) ;
@@ -448,8 +449,9 @@ fn remove_cycle<'tcx>(
448
449
449
450
/// Creates a new thread and forwards information in thread locals to it.
450
451
/// The new thread runs the deadlock handler.
452
+ /// Must only be called when a deadlock is about to happen.
451
453
#[ cfg( parallel_queries) ]
452
- pub fn handle_deadlock ( ) {
454
+ pub unsafe fn handle_deadlock ( ) {
453
455
use syntax;
454
456
use syntax_pos;
455
457
@@ -458,25 +460,23 @@ pub fn handle_deadlock() {
458
460
let gcx_ptr = tls:: GCX_PTR . with ( |gcx_ptr| {
459
461
gcx_ptr as * const _
460
462
} ) ;
461
- let gcx_ptr = unsafe { & * gcx_ptr } ;
463
+ let gcx_ptr = & * gcx_ptr;
462
464
463
465
let syntax_globals = syntax:: GLOBALS . with ( |syntax_globals| {
464
466
syntax_globals as * const _
465
467
} ) ;
466
- let syntax_globals = unsafe { & * syntax_globals } ;
468
+ let syntax_globals = & * syntax_globals;
467
469
468
470
let syntax_pos_globals = syntax_pos:: GLOBALS . with ( |syntax_pos_globals| {
469
471
syntax_pos_globals as * const _
470
472
} ) ;
471
- let syntax_pos_globals = unsafe { & * syntax_pos_globals } ;
473
+ let syntax_pos_globals = & * syntax_pos_globals;
472
474
thread:: spawn ( move || {
473
475
tls:: GCX_PTR . set ( gcx_ptr, || {
474
476
syntax_pos:: GLOBALS . set ( syntax_pos_globals, || {
475
477
syntax_pos:: GLOBALS . set ( syntax_pos_globals, || {
476
478
tls:: with_thread_locals ( || {
477
- unsafe {
478
- tls:: with_global ( |tcx| deadlock ( tcx, & registry) )
479
- }
479
+ tls:: with_global ( |tcx| deadlock ( tcx, & registry) )
480
480
} )
481
481
} )
482
482
} )
@@ -497,7 +497,7 @@ fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) {
497
497
} ) ;
498
498
499
499
let mut wakelist = Vec :: new ( ) ;
500
- let mut jobs: Vec < _ > = tcx. maps . collect_active_jobs ( ) . iter ( ) . map ( |j| & * * j as Ref ) . collect ( ) ;
500
+ let mut jobs: Vec < _ > = tcx. maps . collect_active_jobs ( ) ;
501
501
502
502
let mut found_cycle = false ;
503
503
0 commit comments