@@ -410,18 +410,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> {
410410 None
411411 }
412412
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.
418431 for ( i, thread) in self . threads . iter_enumerated_mut ( ) {
419- // Check if we need to unblock any threads.
420432 if thread. state == ThreadState :: BlockedOnJoin ( self . active_thread ) {
421433 trace ! ( "unblocking {:?} because {:?} terminated" , i, self . active_thread) ;
422434 thread. state = ThreadState :: Enabled ;
423435 }
424436 }
437+ return free_tls_statics;
425438 }
426439
427440 /// 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
503516pub trait EvalContextExt < ' mir , ' tcx : ' mir > : crate :: MiriEvalContextExt < ' mir , ' tcx > {
504517 /// Get a thread-specific allocation id for the given thread-local static.
505518 /// 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 ( ) ;
508521 let tcx = this. tcx ;
509522 if let Some ( new_alloc_id) = this. machine . threads . get_thread_local_alloc_id ( def_id) {
510523 // We already have a thread-specific allocation id for this
@@ -513,21 +526,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
513526 } else {
514527 // We need to allocate a thread-specific allocation id for this
515528 // 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.
522530 if tcx. is_foreign_item ( def_id) {
523531 throw_unsup_format ! ( "foreign thread-local statics are not supported" ) ;
524532 }
525533 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 ;
531536 this. machine . threads . set_thread_local_alloc_id ( def_id, new_alloc_id) ;
532537 Ok ( new_alloc_id)
533538 }
@@ -668,8 +673,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
668673 this. machine . threads . schedule ( )
669674 }
670675
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.
671680 #[ 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 ( ( ) )
674688 }
675689}
0 commit comments