diff options
Diffstat (limited to 'gc.c')
-rw-r--r-- | gc.c | 19 |
1 files changed, 13 insertions, 6 deletions
@@ -377,6 +377,7 @@ typedef struct rb_objspace { int dont_gc; int dont_lazy_sweep; int during_gc; + rb_atomic_t finalizing; } flags; struct { st_table *table; @@ -415,6 +416,7 @@ int *ruby_initial_gc_stress_ptr = &rb_objspace.gc_stress; #define heaps_freed objspace->heap.freed #define dont_gc objspace->flags.dont_gc #define during_gc objspace->flags.during_gc +#define finalizing objspace->flags.finalizing #define finalizer_table objspace->final.table #define deferred_final_list objspace->final.deferred #define global_List objspace->global_list @@ -2175,7 +2177,7 @@ slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot) } objspace->heap.final_num += final_num; - if (deferred_final_list) { + if (deferred_final_list && !finalizing) { rb_thread_t *th = GET_THREAD(); if (th) { RUBY_VM_SET_FINALIZER_INTERRUPT(th); @@ -3042,10 +3044,9 @@ run_final(rb_objspace_t *objspace, VALUE obj) static void finalize_deferred(rb_objspace_t *objspace) { - RVALUE *p = deferred_final_list; - deferred_final_list = 0; + RVALUE *p; - if (p) { + while ((p = ATOMIC_PTR_EXCHANGE(deferred_final_list, 0)) != 0) { finalize_list(objspace, p); } } @@ -3053,7 +3054,10 @@ finalize_deferred(rb_objspace_t *objspace) void rb_gc_finalize_deferred(void) { - finalize_deferred(&rb_objspace); + rb_objspace_t *objspace = &rb_objspace; + if (ATOMIC_EXCHANGE(finalizing, 1)) return; + finalize_deferred(objspace); + ATOMIC_SET(finalizing, 0); } struct force_finalize_list { @@ -3093,6 +3097,8 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace) finalize_deferred(objspace); assert(deferred_final_list == 0); + if (ATOMIC_EXCHANGE(finalizing, 1)) return; + /* force to run finalizer */ while (finalizer_table->num_entries) { struct force_finalize_list *list = 0; @@ -3147,6 +3153,7 @@ rb_objspace_call_finalizer(rb_objspace_t *objspace) st_free_table(finalizer_table); finalizer_table = 0; + ATOMIC_SET(finalizing, 0); } void @@ -3154,7 +3161,7 @@ rb_gc(void) { rb_objspace_t *objspace = &rb_objspace; garbage_collect(objspace); - finalize_deferred(objspace); + if (!finalizing) finalize_deferred(objspace); free_unused_heaps(objspace); } |