@@ -502,10 +502,12 @@ typedef struct rb_heap_struct {
502502 rb_atomic_t background_sweep_steps ; // only incremented/checked by sweep thread
503503 rb_nativethread_cond_t sweep_page_cond ; // associated with global sweep lock
504504 rb_nativethread_lock_t swept_pages_lock ;
505+ rb_nativethread_lock_t sweeping_page_lock ;
505506 size_t pre_swept_slots_deferred ;
506507 bool is_finished_sweeping ;
507508 bool done_background_sweep ;
508509 bool skip_sweep_continue ; // skip current sweep continue
510+ bool dequeued_last_page ;
509511} rb_heap_t ;
510512
511513enum {
@@ -1088,6 +1090,7 @@ typedef struct lock_stats {
10881090
10891091static lock_stats_t sweep_lock_stats = {"objspace->sweep_lock" , {{0 }}, 0 };
10901092static lock_stats_t swept_pages_lock_stats = {"heap->swept_pages_lock" , {{0 }}, 0 };
1093+ static lock_stats_t sweeping_page_lock_stats = {"heap->sweeping_page_lock" , {{0 }}, 0 };
10911094
10921095
10931096static lock_callsite_stats_t *
@@ -1139,9 +1142,9 @@ print_lock_stats(void)
11391142 fprintf (stderr , "%-40s %-30s %12s %12s %10s\n" , "Lock Name" , "Callsite" , "Uncontended" , "Contended" , "Ratio" );
11401143 fprintf (stderr , "%-40s %-30s %12s %12s %10s\n" , "---------" , "--------" , "-----------" , "---------" , "-----" );
11411144
1142- lock_stats_t * all_stats [] = {& sweep_lock_stats , & swept_pages_lock_stats };
1145+ lock_stats_t * all_stats [] = {& sweep_lock_stats , & swept_pages_lock_stats , & sweeping_page_lock_stats };
11431146
1144- for (int i = 0 ; i < 2 ; i ++ ) {
1147+ for (int i = 0 ; i < 3 ; i ++ ) {
11451148 lock_stats_t * stats = all_stats [i ];
11461149
11471150 /* Sort callsites by total contentions (descending) */
@@ -4624,8 +4627,14 @@ gc_sweep_step_worker(rb_objspace_t *objspace, rb_heap_t *heap)
46244627 return ;
46254628 }
46264629 while (1 ) {
4630+ #if PSWEEP_LOCK_STATS > 0
4631+ instrumented_lock_acquire (& heap -> sweeping_page_lock , & sweeping_page_lock_stats );
4632+ #else
4633+ rb_native_mutex_lock (& heap -> sweeping_page_lock );
4634+ #endif
46274635 struct heap_page * sweep_page = heap -> sweeping_page ;
46284636 if (!sweep_page ) {
4637+ rb_native_mutex_unlock (& heap -> sweeping_page_lock );
46294638 GC_ASSERT (!heap -> done_background_sweep );
46304639 GC_ASSERT (objspace -> heaps_done_background_sweep < HEAP_COUNT );
46314640 heap -> done_background_sweep = true;
@@ -4637,6 +4646,7 @@ gc_sweep_step_worker(rb_objspace_t *objspace, rb_heap_t *heap)
46374646 struct heap_page * next = ccan_list_next (& heap -> pages , sweep_page , page_node );
46384647
46394648 if (!next ) {
4649+ rb_native_mutex_unlock (& heap -> sweeping_page_lock );
46404650 GC_ASSERT (!heap -> done_background_sweep );
46414651 GC_ASSERT (objspace -> heaps_done_background_sweep < HEAP_COUNT );
46424652 heap -> done_background_sweep = true;
@@ -4647,6 +4657,7 @@ gc_sweep_step_worker(rb_objspace_t *objspace, rb_heap_t *heap)
46474657 }
46484658
46494659 heap -> sweeping_page = next ;
4660+ rb_native_mutex_unlock (& heap -> sweeping_page_lock );
46504661 heap -> pre_sweeping_page = sweep_page ;
46514662
46524663 sweep_lock_unlock (& objspace -> sweep_lock );
@@ -4782,6 +4793,7 @@ gc_sweep_start_heap(rb_objspace_t *objspace, rb_heap_t *heap)
47824793 heap -> is_finished_sweeping = false;
47834794 heap -> done_background_sweep = false;
47844795 heap -> skip_sweep_continue = false;
4796+ heap -> dequeued_last_page = false;
47854797
47864798 struct heap_page * page = NULL ;
47874799
@@ -5037,14 +5049,17 @@ gc_sweep_dequeue_page(rb_objspace_t *objspace, rb_heap_t *heap, bool free_in_use
50375049 return cur ;
50385050 }
50395051 }
5052+ else if (heap -> dequeued_last_page ) {
5053+ return NULL ;
5054+ }
50405055
50415056 struct heap_page * page = NULL ;
50425057
50435058 // Avoid taking the global sweep_lock if we can
5044- #if PSWEEP_LOCK_STATS > 0
5059+ #if PSWEEP_LOCK_STATS > 3
50455060 instrumented_lock_acquire (& heap -> swept_pages_lock , & swept_pages_lock_stats );
50465061#else
5047- rb_native_mutex_lock (& heap -> swept_pages_lock );
5062+ rb_native_mutex_trylock (& heap -> swept_pages_lock );
50485063#endif
50495064 {
50505065 if (heap -> swept_pages ) {
@@ -5056,6 +5071,22 @@ gc_sweep_dequeue_page(rb_objspace_t *objspace, rb_heap_t *heap, bool free_in_use
50565071 rb_native_mutex_unlock (& heap -> swept_pages_lock );
50575072 if (page ) return page ;
50585073
5074+ #if PSWEEP_LOCK_STATS > 0
5075+ instrumented_lock_acquire (& heap -> sweeping_page_lock , & sweeping_page_lock_stats );
5076+ #else
5077+ rb_native_mutex_lock (& heap -> sweeping_page_lock );
5078+ #endif
5079+ {
5080+ if (heap -> sweeping_page ) {
5081+ page = heap -> sweeping_page ; // this could be the last page
5082+ heap -> sweeping_page = ccan_list_next (& heap -> pages , page , page_node );
5083+ psweep_debug (0 , "[gc] gc_sweep_dequeue_page: dequeued unswept page from heap(%p) (heap %ld)\n" , heap , heap - heaps );
5084+ * dequeued_unswept_page = true;
5085+ }
5086+ }
5087+ rb_native_mutex_unlock (& heap -> sweeping_page_lock );
5088+ if (page ) return page ;
5089+
50595090 sweep_lock_lock (& objspace -> sweep_lock );
50605091 {
50615092 GC_ASSERT (!objspace -> background_sweep_mode );
@@ -5074,14 +5105,11 @@ gc_sweep_dequeue_page(rb_objspace_t *objspace, rb_heap_t *heap, bool free_in_use
50745105 }
50755106 psweep_debug (0 , "[gc] gc_sweep_dequeue_page: got nil page from heap(%p) (heap %ld) end\n" , heap , heap - heaps );
50765107 }
5077- else {
5078- * dequeued_unswept_page = true;
5079- page = heap -> sweeping_page ; // this could be the last page
5080- heap -> sweeping_page = ccan_list_next (& heap -> pages , page , page_node );
5081- psweep_debug (0 , "[gc] gc_sweep_dequeue_page: dequeued unswept page from heap(%p) (heap %ld)\n" , heap , heap - heaps );
5082- }
50835108 GC_ASSERT (!objspace -> background_sweep_mode );
50845109 }
5110+ if (!heap -> sweeping_page && !heap -> pre_sweeping_page ) {
5111+ heap -> dequeued_last_page = true;
5112+ }
50855113 sweep_lock_unlock (& objspace -> sweep_lock );
50865114
50875115 return page ;
@@ -11044,6 +11072,7 @@ rb_gc_impl_objspace_free(void *objspace_ptr)
1104411072 for (int i = 0 ; i < HEAP_COUNT ; i ++ ) {
1104511073 rb_heap_t * heap = & heaps [i ];
1104611074 rb_native_mutex_destroy (& heap -> swept_pages_lock );
11075+ rb_native_mutex_destroy (& heap -> sweeping_page_lock );
1104711076 rb_native_cond_destroy (& heap -> sweep_page_cond );
1104811077 heap -> total_pages = 0 ;
1104911078 heap -> total_slots = 0 ;
@@ -11123,6 +11152,7 @@ rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
1112311152 rb_heap_t * heap = & heaps [i ];
1112411153
1112511154 rb_native_mutex_initialize (& heap -> swept_pages_lock );
11155+ rb_native_mutex_initialize (& heap -> sweeping_page_lock );
1112611156 rb_native_cond_initialize (& heap -> sweep_page_cond );
1112711157 heap -> pre_sweeping_page = NULL ;
1112811158 heap -> background_sweep_steps = heap -> foreground_sweep_steps ;
@@ -11235,6 +11265,7 @@ rb_gc_impl_objspace_init(void *objspace_ptr)
1123511265
1123611266 ccan_list_head_init (& heap -> pages );
1123711267 rb_native_mutex_initialize (& heap -> swept_pages_lock );
11268+ rb_native_mutex_initialize (& heap -> sweeping_page_lock );
1123811269 rb_native_cond_initialize (& heap -> sweep_page_cond );
1123911270 }
1124011271
0 commit comments