@@ -410,18 +410,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
410
410
None
411
411
}
412
412
413
- /// Handles thread termination of the active thread: wakes up threads joining on this one,
414
- /// and deallocated thread-local statics.
415
- ///
416
- /// This is called from `tls.rs` after handling the TLS dtors.
417
- fn thread_terminated ( & mut self ) {
413
+ /// Wakes up threads joining on the active one and deallocates thread-local statics.
414
+ /// The `AllocId` that can now be freed is returned.
415
+ fn thread_terminated ( & mut self ) -> Vec < AllocId > {
416
+ let mut free_tls_statics = Vec :: new ( ) ;
417
+ {
418
+ let mut thread_local_statics = self . thread_local_alloc_ids . borrow_mut ( ) ;
419
+ thread_local_statics. retain ( |& ( _def_id, thread) , & mut alloc_id| {
420
+ if thread != self . active_thread {
421
+ // Keep this static around.
422
+ return true ;
423
+ }
424
+ // Delete this static from the map and from memory.
425
+ // We cannot free directly here as we cannot use `?` in this context.
426
+ free_tls_statics. push ( alloc_id) ;
427
+ return false ;
428
+ } ) ;
429
+ }
430
+ // Check if we need to unblock any threads.
418
431
for ( i, thread) in self . threads . iter_enumerated_mut ( ) {
419
- // Check if we need to unblock any threads.
420
432
if thread. state == ThreadState :: BlockedOnJoin ( self . active_thread ) {
421
433
trace ! ( "unblocking {:?} because {:?} terminated" , i, self . active_thread) ;
422
434
thread. state = ThreadState :: Enabled ;
423
435
}
424
436
}
437
+ return free_tls_statics;
425
438
}
426
439
427
440
/// Decide which action to take next and on which thread.
@@ -503,8 +516,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
503
516
pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
504
517
/// Get a thread-specific allocation id for the given thread-local static.
505
518
/// If needed, allocate a new one.
506
- fn get_or_create_thread_local_alloc_id ( & self , def_id : DefId ) -> InterpResult < ' tcx , AllocId > {
507
- let this = self . eval_context_ref ( ) ;
519
+ fn get_or_create_thread_local_alloc_id ( & mut self , def_id : DefId ) -> InterpResult < ' tcx , AllocId > {
520
+ let this = self . eval_context_mut ( ) ;
508
521
let tcx = this. tcx ;
509
522
if let Some ( new_alloc_id) = this. machine . threads . get_thread_local_alloc_id ( def_id) {
510
523
// We already have a thread-specific allocation id for this
@@ -513,21 +526,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
513
526
} else {
514
527
// We need to allocate a thread-specific allocation id for this
515
528
// thread-local static.
516
- //
517
- // At first, we compute the initial value for this static.
518
- // Then we store the retrieved allocation back into the `alloc_map`
519
- // to get a fresh allocation id, which we can use as a
520
- // thread-specific allocation id for the thread-local static.
521
- // On first access to that allocation, it will be copied over to the machine memory.
529
+ // First, we compute the initial value for this static.
522
530
if tcx. is_foreign_item ( def_id) {
523
531
throw_unsup_format ! ( "foreign thread-local statics are not supported" ) ;
524
532
}
525
533
let allocation = interpret:: get_static ( * tcx, def_id) ?;
526
- // Create a new allocation id for the same allocation in this hacky
527
- // way. Internally, `alloc_map` deduplicates allocations, but this
528
- // is fine because Miri will make a copy before a first mutable
529
- // access.
530
- let new_alloc_id = tcx. create_memory_alloc ( allocation) ;
534
+ // Create a fresh allocation with this content.
535
+ let new_alloc_id = this. memory . allocate_with ( allocation. clone ( ) , MiriMemoryKind :: Tls . into ( ) ) . alloc_id ;
531
536
this. machine . threads . set_thread_local_alloc_id ( def_id, new_alloc_id) ;
532
537
Ok ( new_alloc_id)
533
538
}
@@ -668,8 +673,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
668
673
this. machine . threads . schedule ( )
669
674
}
670
675
676
+ /// Handles thread termination of the active thread: wakes up threads joining on this one,
677
+ /// and deallocated thread-local statics.
678
+ ///
679
+ /// This is called from `tls.rs` after handling the TLS dtors.
671
680
#[ inline]
672
- fn thread_terminated ( & mut self ) {
673
- self . eval_context_mut ( ) . machine . threads . thread_terminated ( )
681
+ fn thread_terminated ( & mut self ) -> InterpResult < ' tcx > {
682
+ let this = self . eval_context_mut ( ) ;
683
+ for alloc_id in this. machine . threads . thread_terminated ( ) {
684
+ let ptr = this. memory . global_base_pointer ( alloc_id. into ( ) ) ?;
685
+ this. memory . deallocate ( ptr, None , MiriMemoryKind :: Tls . into ( ) ) ?;
686
+ }
687
+ Ok ( ( ) )
674
688
}
675
689
}
0 commit comments