@@ -225,6 +225,9 @@ void _mi_page_free_collect(mi_page_t* page, bool force) {
225
225
226
226
// and the local free list
227
227
if (page -> local_free != NULL ) {
228
+ // any previous QSBR goals are no longer valid because we reused the page
229
+ _PyMem_mi_page_clear_qsbr (page );
230
+
228
231
if mi_likely (page -> free == NULL ) {
229
232
// usual case
230
233
page -> free = page -> local_free ;
@@ -267,6 +270,9 @@ void _mi_page_reclaim(mi_heap_t* heap, mi_page_t* page) {
267
270
// TODO: push on full queue immediately if it is full?
268
271
mi_page_queue_t * pq = mi_page_queue (heap , mi_page_block_size (page ));
269
272
mi_page_queue_push (heap , pq , page );
273
+
274
+ _PyMem_mi_page_reclaimed (page );
275
+
270
276
mi_assert_expensive (_mi_page_is_valid (page ));
271
277
}
272
278
@@ -383,6 +389,13 @@ void _mi_page_abandon(mi_page_t* page, mi_page_queue_t* pq) {
383
389
384
390
mi_heap_t * pheap = mi_page_heap (page );
385
391
392
+ #ifdef Py_GIL_DISABLED
393
+ if (page -> qsbr_node .next != NULL ) {
394
+ // remove from QSBR queue, but keep the goal
395
+ llist_remove (& page -> qsbr_node );
396
+ }
397
+ #endif
398
+
386
399
// remove from our page list
387
400
mi_segments_tld_t * segments_tld = & pheap -> tld -> segments ;
388
401
mi_page_queue_remove (pq , page );
@@ -417,6 +430,11 @@ void _mi_page_free(mi_page_t* page, mi_page_queue_t* pq, bool force) {
417
430
418
431
mi_heap_t * heap = mi_page_heap (page );
419
432
433
+ #ifdef Py_GIL_DISABLED
434
+ mi_assert_internal (page -> qsbr_goal == 0 );
435
+ mi_assert_internal (page -> qsbr_node .next == NULL );
436
+ #endif
437
+
420
438
// remove from the page list
421
439
// (no need to do _mi_heap_delayed_free first as all blocks are already free)
422
440
mi_segments_tld_t * segments_tld = & heap -> tld -> segments ;
@@ -465,7 +483,7 @@ void _mi_page_retire(mi_page_t* page) mi_attr_noexcept {
465
483
return ; // dont't free after all
466
484
}
467
485
}
468
- _mi_page_free (page , pq , false);
486
+ _PyMem_mi_page_maybe_free (page , pq , false);
469
487
}
470
488
471
489
// free retired pages: we don't need to look at the entire queues
@@ -480,7 +498,7 @@ void _mi_heap_collect_retired(mi_heap_t* heap, bool force) {
480
498
if (mi_page_all_free (page )) {
481
499
page -> retire_expire -- ;
482
500
if (force || page -> retire_expire == 0 ) {
483
- _mi_page_free ( pq -> first , pq , force );
501
+ _PyMem_mi_page_maybe_free ( page , pq , false );
484
502
}
485
503
else {
486
504
// keep retired, update min/max
@@ -661,6 +679,7 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi
661
679
// set fields
662
680
mi_page_set_heap (page , heap );
663
681
page -> tag = heap -> tag ;
682
+ page -> delay_free = heap -> page_delay_free ;
664
683
page -> debug_offset = heap -> debug_offset ;
665
684
page -> xblock_size = (block_size < MI_HUGE_BLOCK_SIZE ? (uint32_t )block_size : MI_HUGE_BLOCK_SIZE ); // initialize before _mi_segment_page_start
666
685
size_t page_size ;
@@ -691,6 +710,10 @@ static void mi_page_init(mi_heap_t* heap, mi_page_t* page, size_t block_size, mi
691
710
mi_assert_internal (page -> xthread_free == 0 );
692
711
mi_assert_internal (page -> next == NULL );
693
712
mi_assert_internal (page -> prev == NULL );
713
+ #ifdef Py_GIL_DISABLED
714
+ mi_assert_internal (page -> qsbr_goal == 0 );
715
+ mi_assert_internal (page -> qsbr_node .next == NULL );
716
+ #endif
694
717
mi_assert_internal (page -> retire_expire == 0 );
695
718
mi_assert_internal (!mi_page_has_aligned (page ));
696
719
#if (MI_PADDING || MI_ENCODE_FREELIST )
@@ -750,6 +773,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p
750
773
mi_heap_stat_counter_increase (heap , searches , count );
751
774
752
775
if (page == NULL ) {
776
+ _PyMem_mi_heap_collect_qsbr (heap ); // some pages might be safe to free now
753
777
_mi_heap_collect_retired (heap , false); // perhaps make a page available?
754
778
page = mi_page_fresh (heap , pq );
755
779
if (page == NULL && first_try ) {
@@ -760,6 +784,7 @@ static mi_page_t* mi_page_queue_find_free_ex(mi_heap_t* heap, mi_page_queue_t* p
760
784
else {
761
785
mi_assert (pq -> first == page );
762
786
page -> retire_expire = 0 ;
787
+ _PyMem_mi_page_clear_qsbr (page );
763
788
}
764
789
mi_assert_internal (page == NULL || mi_page_immediate_available (page ));
765
790
return page ;
@@ -785,6 +810,7 @@ static inline mi_page_t* mi_find_free_page(mi_heap_t* heap, size_t size) {
785
810
786
811
if (mi_page_immediate_available (page )) {
787
812
page -> retire_expire = 0 ;
813
+ _PyMem_mi_page_clear_qsbr (page );
788
814
return page ; // fast path
789
815
}
790
816
}
@@ -878,6 +904,7 @@ static mi_page_t* mi_find_page(mi_heap_t* heap, size_t size, size_t huge_alignme
878
904
return NULL ;
879
905
}
880
906
else {
907
+ _PyMem_mi_heap_collect_qsbr (heap );
881
908
return mi_large_huge_page_alloc (heap ,size ,huge_alignment );
882
909
}
883
910
}
0 commit comments