@@ -764,7 +764,7 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment )
764764 if (mi_option_is_enabled (mi_option_visit_abandoned )) {
765765 has_lock = mi_lock_try_acquire (& segment -> subproc -> abandoned_os_lock );
766766 if (!has_lock ) {
767- return false; // failed to acquire the lock, we just give up
767+ return false; // failed to acquire the lock, we just give up
768768 }
769769 }
770770 // abandon it, but we need to still claim it atomically -- we use the thread_id for that.
@@ -777,9 +777,10 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment )
777777 // and remove from the abandoned os list (if needed)
778778 mi_segment_t * const next = segment -> abandoned_os_next ;
779779 mi_segment_t * const prev = segment -> abandoned_os_prev ;
780+ mi_assert_internal ((next == NULL && prev == NULL ) || mi_option_is_enabled (mi_option_visit_abandoned ));
780781 if (prev != NULL ) { prev -> abandoned_os_next = next ; }
781- else { segment -> subproc -> abandoned_os_list = next ; }
782- if (next != NULL ) { next -> abandoned_os_prev = prev ; }
782+ else { segment -> subproc -> abandoned_os_list = next ; }
783+ if (next != NULL ) { next -> abandoned_os_prev = prev ; }
783784 segment -> abandoned_os_next = NULL ;
784785 segment -> abandoned_os_prev = NULL ;
785786 }
@@ -809,41 +810,48 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment )
809810// clears the thread_id.
810811void _mi_arena_segment_mark_abandoned (mi_segment_t * segment )
811812{
812- mi_atomic_store_release (& segment -> thread_id , 0 );
813813 mi_assert_internal (segment -> used == segment -> abandoned );
814814 if mi_unlikely (segment -> memid .memkind != MI_MEM_ARENA ) {
815815 // not in an arena; count it as abandoned and return (these can be reclaimed on a `free`)
816- mi_atomic_increment_relaxed (& segment -> subproc -> abandoned_count );
817816 // if abandoned visiting is allowed, we need to take a lock on the abandoned os list to insert it
817+ bool has_lock = false;
818818 if (mi_option_is_enabled (mi_option_visit_abandoned )) {
819- if (!mi_lock_acquire (& segment -> subproc -> abandoned_os_lock )) {
819+ has_lock = mi_lock_acquire (& segment -> subproc -> abandoned_os_lock );
820+ if (!has_lock ) {
820821 _mi_error_message (EFAULT , "internal error: failed to acquire the abandoned (os) segment lock to mark abandonment" );
821- }
822- else {
823- // push on the front of the list
824- mi_segment_t * next = segment -> subproc -> abandoned_os_list ;
825- mi_assert_internal (next == NULL || next -> abandoned_os_prev == NULL );
826- mi_assert_internal (segment -> abandoned_os_prev == NULL );
827- mi_assert_internal (segment -> abandoned_os_next == NULL );
828- if (next != NULL ) { next -> abandoned_os_prev = segment ; }
829- segment -> abandoned_os_prev = NULL ;
830- segment -> abandoned_os_next = next ;
831- segment -> subproc -> abandoned_os_list = segment ;
832- mi_lock_release (& segment -> subproc -> abandoned_os_lock );
833- }
822+ }
823+ }
824+ mi_atomic_store_release (& segment -> thread_id , 0 ); // mark as abandoned (inside the lock)
825+ mi_atomic_increment_relaxed (& segment -> subproc -> abandoned_count );
826+ if (has_lock ) {
827+ // push on the front of the list
828+ mi_segment_t * next = segment -> subproc -> abandoned_os_list ;
829+ mi_assert_internal (next == NULL || next -> abandoned_os_prev == NULL );
830+ mi_assert_internal (segment -> abandoned_os_prev == NULL );
831+ mi_assert_internal (segment -> abandoned_os_next == NULL );
832+ if (next != NULL ) { next -> abandoned_os_prev = segment ; }
833+ segment -> abandoned_os_prev = NULL ;
834+ segment -> abandoned_os_next = next ;
835+ segment -> subproc -> abandoned_os_list = segment ;
836+ // and release the lock
837+ mi_lock_release (& segment -> subproc -> abandoned_os_lock );
834838 }
835839 return ;
836840 }
841+
837842 // segment is in an arena, mark it in the arena `blocks_abandoned` bitmap
843+ mi_atomic_store_release (& segment -> thread_id , 0 ); // mark as abandoned
838844 size_t arena_idx ;
839845 size_t bitmap_idx ;
840846 mi_arena_memid_indices (segment -> memid , & arena_idx , & bitmap_idx );
841847 mi_assert_internal (arena_idx < MI_MAX_ARENAS );
842848 mi_arena_t * arena = mi_atomic_load_ptr_acquire (mi_arena_t , & mi_arenas [arena_idx ]);
843849 mi_assert_internal (arena != NULL );
844850 const bool was_unmarked = _mi_bitmap_claim (arena -> blocks_abandoned , arena -> field_count , 1 , bitmap_idx , NULL );
845- if (was_unmarked ) { mi_atomic_increment_relaxed (& segment -> subproc -> abandoned_count ); }
846- mi_assert_internal (was_unmarked );
851+ if (was_unmarked ) {
852+ // note: it could be unmarked if someone reclaimed in between the thread_id=0 and the claim
853+ mi_atomic_increment_relaxed (& segment -> subproc -> abandoned_count );
854+ }
847855 mi_assert_internal (_mi_bitmap_is_claimed (arena -> blocks_inuse , arena -> field_count , 1 , bitmap_idx ));
848856}
849857
0 commit comments