@@ -172,15 +172,15 @@ static void* mi_arena_static_zalloc(size_t size, size_t alignment, mi_memid_t* m
172172 return p ;
173173}
174174
175- static void * mi_arena_meta_zalloc (size_t size , mi_memid_t * memid , mi_stats_t * stats ) {
175+ void * _mi_arena_meta_zalloc (size_t size , mi_memid_t * memid ) {
176176 * memid = _mi_memid_none ();
177177
178178 // try static
179179 void * p = mi_arena_static_zalloc (size , MI_MAX_ALIGN_SIZE , memid );
180180 if (p != NULL ) return p ;
181181
182182 // or fall back to the OS
183- p = _mi_os_alloc (size , memid , stats );
183+ p = _mi_os_alloc (size , memid , & _mi_stats_main );
184184 if (p == NULL ) return NULL ;
185185
186186 // zero the OS memory if needed
@@ -191,9 +191,9 @@ static void* mi_arena_meta_zalloc(size_t size, mi_memid_t* memid, mi_stats_t* st
191191 return p ;
192192}
193193
194- static void mi_arena_meta_free (void * p , mi_memid_t memid , size_t size , mi_stats_t * stats ) {
194+ void _mi_arena_meta_free (void * p , mi_memid_t memid , size_t size ) {
195195 if (mi_memkind_is_os (memid .memkind )) {
196- _mi_os_free (p , size , memid , stats );
196+ _mi_os_free (p , size , memid , & _mi_stats_main );
197197 }
198198 else {
199199 mi_assert (memid .memkind == MI_MEM_STATIC );
@@ -709,7 +709,7 @@ static void mi_arenas_unsafe_destroy(void) {
709709 else {
710710 new_max_arena = i ;
711711 }
712- mi_arena_meta_free (arena , arena -> meta_memid , arena -> meta_size , & _mi_stats_main );
712+ _mi_arena_meta_free (arena , arena -> meta_memid , arena -> meta_size );
713713 }
714714 }
715715
@@ -752,13 +752,6 @@ bool _mi_arena_contains(const void* p) {
752752 the arena bitmaps.
753753----------------------------------------------------------- */
754754
755- // Maintain a count of all abandoned segments
756- static mi_decl_cache_align _Atomic(size_t )abandoned_count ;
757-
758- size_t _mi_arena_segment_abandoned_count (void ) {
759- return mi_atomic_load_relaxed (& abandoned_count );
760- }
761-
762755// reclaim a specific abandoned segment; `true` on success.
763756// sets the thread_id.
764757bool _mi_arena_segment_clear_abandoned (mi_segment_t * segment )
@@ -768,7 +761,7 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment )
768761 // but we need to still claim it atomically -- we use the thread_id for that.
769762 size_t expected = 0 ;
770763 if (mi_atomic_cas_strong_acq_rel (& segment -> thread_id , & expected , _mi_thread_id ())) {
771- mi_atomic_decrement_relaxed (& abandoned_count );
764+ mi_atomic_decrement_relaxed (& segment -> subproc -> abandoned_count );
772765 return true;
773766 }
774767 else {
@@ -785,7 +778,7 @@ bool _mi_arena_segment_clear_abandoned(mi_segment_t* segment )
785778 bool was_marked = _mi_bitmap_unclaim (arena -> blocks_abandoned , arena -> field_count , 1 , bitmap_idx );
786779 if (was_marked ) {
787780 mi_assert_internal (mi_atomic_load_relaxed (& segment -> thread_id ) == 0 );
788- mi_atomic_decrement_relaxed (& abandoned_count );
781+ mi_atomic_decrement_relaxed (& segment -> subproc -> abandoned_count );
789782 mi_atomic_store_release (& segment -> thread_id , _mi_thread_id ());
790783 }
791784 // mi_assert_internal(was_marked);
@@ -802,35 +795,38 @@ void _mi_arena_segment_mark_abandoned(mi_segment_t* segment)
802795 mi_assert_internal (segment -> used == segment -> abandoned );
803796 if (segment -> memid .memkind != MI_MEM_ARENA ) {
804797 // not in an arena; count it as abandoned and return
805- mi_atomic_increment_relaxed (& abandoned_count );
798+ mi_atomic_increment_relaxed (& segment -> subproc -> abandoned_count );
806799 return ;
807800 }
801+ // segment is in an arena
808802 size_t arena_idx ;
809803 size_t bitmap_idx ;
810804 mi_arena_memid_indices (segment -> memid , & arena_idx , & bitmap_idx );
811805 mi_assert_internal (arena_idx < MI_MAX_ARENAS );
812806 mi_arena_t * arena = mi_atomic_load_ptr_acquire (mi_arena_t , & mi_arenas [arena_idx ]);
813807 mi_assert_internal (arena != NULL );
814808 const bool was_unmarked = _mi_bitmap_claim (arena -> blocks_abandoned , arena -> field_count , 1 , bitmap_idx , NULL );
815- if (was_unmarked ) { mi_atomic_increment_relaxed (& abandoned_count ); }
809+ if (was_unmarked ) { mi_atomic_increment_relaxed (& segment -> subproc -> abandoned_count ); }
816810 mi_assert_internal (was_unmarked );
817811 mi_assert_internal (_mi_bitmap_is_claimed (arena -> blocks_inuse , arena -> field_count , 1 , bitmap_idx ));
818812}
819813
820814// start a cursor at a randomized arena
821- void _mi_arena_field_cursor_init (mi_heap_t * heap , mi_arena_field_cursor_t * current ) {
815+ void _mi_arena_field_cursor_init (mi_heap_t * heap , mi_subproc_t * subproc , mi_arena_field_cursor_t * current ) {
816+ mi_assert_internal (heap -> tld -> segments .subproc == subproc );
822817 const size_t max_arena = mi_atomic_load_relaxed (& mi_arena_count );
823818 current -> start = (max_arena == 0 ? 0 : (mi_arena_id_t )( _mi_heap_random_next (heap ) % max_arena ));
824819 current -> count = 0 ;
825820 current -> bitmap_idx = 0 ;
821+ current -> subproc = subproc ;
826822}
827823
828824// reclaim abandoned segments
829825// this does not set the thread id (so it appears as still abandoned)
830826mi_segment_t * _mi_arena_segment_clear_abandoned_next (mi_arena_field_cursor_t * previous )
831827{
832828 const int max_arena = (int )mi_atomic_load_relaxed (& mi_arena_count );
833- if (max_arena <= 0 || mi_atomic_load_relaxed (& abandoned_count ) == 0 ) return NULL ;
829+ if (max_arena <= 0 || mi_atomic_load_relaxed (& previous -> subproc -> abandoned_count ) == 0 ) return NULL ;
834830
835831 int count = previous -> count ;
836832 size_t field_idx = mi_bitmap_index_field (previous -> bitmap_idx );
@@ -853,14 +849,24 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr
853849 mi_bitmap_index_t bitmap_idx = mi_bitmap_index_create (field_idx , bit_idx );
854850 // try to reclaim it atomically
855851 if (_mi_bitmap_unclaim (arena -> blocks_abandoned , arena -> field_count , 1 , bitmap_idx )) {
856- mi_atomic_decrement_relaxed (& abandoned_count );
857- previous -> bitmap_idx = bitmap_idx ;
858- previous -> count = count ;
859852 mi_assert_internal (_mi_bitmap_is_claimed (arena -> blocks_inuse , arena -> field_count , 1 , bitmap_idx ));
860853 mi_segment_t * segment = (mi_segment_t * )mi_arena_block_start (arena , bitmap_idx );
861854 mi_assert_internal (mi_atomic_load_relaxed (& segment -> thread_id ) == 0 );
862- //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx));
863- return segment ;
855+ // check that belongs to our sub-process
856+ if (segment -> subproc != previous -> subproc ) {
857+ // it is from another subprocess, re-mark it and continue searching
858+ const bool was_zero = _mi_bitmap_claim (arena -> blocks_abandoned , arena -> field_count , 1 , bitmap_idx , NULL );
859+ mi_assert_internal (was_zero );
860+ }
861+ else {
862+ // success, we unabandoned a segment in our sub-process
863+ mi_atomic_decrement_relaxed (& previous -> subproc -> abandoned_count );
864+ previous -> bitmap_idx = bitmap_idx ;
865+ previous -> count = count ;
866+
867+ //mi_assert_internal(arena->blocks_committed == NULL || _mi_bitmap_is_claimed(arena->blocks_committed, arena->field_count, 1, bitmap_idx));
868+ return segment ;
869+ }
864870 }
865871 }
866872 }
@@ -911,7 +917,7 @@ static bool mi_manage_os_memory_ex2(void* start, size_t size, bool is_large, int
911917 const size_t bitmaps = (memid .is_pinned ? 3 : 5 );
912918 const size_t asize = sizeof (mi_arena_t ) + (bitmaps * fields * sizeof (mi_bitmap_field_t ));
913919 mi_memid_t meta_memid ;
914- mi_arena_t * arena = (mi_arena_t * )mi_arena_meta_zalloc (asize , & meta_memid , & _mi_stats_main ); // TODO: can we avoid allocating from the OS?
920+ mi_arena_t * arena = (mi_arena_t * )_mi_arena_meta_zalloc (asize , & meta_memid );
915921 if (arena == NULL ) return false;
916922
917923 // already zero'd due to zalloc
0 commit comments