static void run_gc(MVMThreadContext *tc, MVMuint8 what_to_do) { MVMuint8 gen; MVMuint32 i, n; unsigned int interval_id; #if MVM_GC_DEBUG if (tc->in_spesh) MVM_panic(1, "Must not GC when in the specializer/JIT\n"); #endif /* Decide nursery or full collection. */ gen = tc->instance->gc_full_collect ? MVMGCGenerations_Both : MVMGCGenerations_Nursery; if (tc->instance->gc_full_collect) { interval_id = MVM_telemetry_interval_start(tc, "start full collection"); } else { interval_id = MVM_telemetry_interval_start(tc, "start minor collection"); } /* Do GC work for ourselves and any work threads. */ for (i = 0, n = tc->gc_work_count ; i < n; i++) { MVMThreadContext *other = tc->gc_work[i].tc; tc->gc_work[i].limit = other->nursery_alloc; GCDEBUG_LOG(tc, MVM_GC_DEBUG_ORCHESTRATE, "Thread %d run %d : starting collection for thread %d\n", other->thread_id); other->gc_promoted_bytes = 0; MVM_gc_collect(other, (other == tc ? what_to_do : MVMGCWhatToDo_NoInstance), gen); } /* Wait for everybody to agree we're done. */ finish_gc(tc, gen, what_to_do == MVMGCWhatToDo_All); MVM_telemetry_interval_stop(tc, interval_id, "finished run_gc"); }
/* Does work in a thread's in-tray, if any. Returns a non-zero value if work * was found and done, and zero otherwise. */ static int process_in_tray(MVMThreadContext *tc, MVMuint8 gen) { GCDEBUG_LOG(tc, MVM_GC_DEBUG_ORCHESTRATE, "Thread %d run %d : Considering extra work\n"); if (MVM_load(&tc->gc_in_tray)) { GCDEBUG_LOG(tc, MVM_GC_DEBUG_ORCHESTRATE, "Thread %d run %d : Was given extra work by another thread; doing it\n"); MVM_gc_collect(tc, MVMGCWhatToDo_InTray, gen); return 1; } return 0; }
/* Does work in a thread's in-tray, if any. */ static void process_in_tray(MVMThreadContext *tc, MVMuint8 gen, MVMuint32 *put_vote) { /* Do we have any more work given by another thread? If so, re-enter * GC loop to process it. Note that since we're now doing GC stuff * again, we take back our vote to finish. */ if (tc->gc_in_tray) { GCORCH_LOG(tc, "Thread %d run %d : Was given extra work by another thread; doing it\n"); if (!*put_vote) { MVM_atomic_incr(&tc->instance->gc_finish); *put_vote = 1; } MVM_gc_collect(tc, MVMGCWhatToDo_InTray, gen); } }
void MVM_finalize_walk_queues(MVMThreadContext *tc, MVMuint8 gen) { MVMThread *cur_thread = (MVMThread *)MVM_load(&tc->instance->threads); while (cur_thread) { if (cur_thread->body.tc) { walk_thread_finalize_queue(cur_thread->body.tc, gen); if (cur_thread->body.tc->num_finalizing > 0) { MVM_gc_collect(cur_thread->body.tc, MVMGCWhatToDo_Finalizing, gen); setup_finalize_handler_call(cur_thread->body.tc); } } cur_thread = cur_thread->body.next; } }
static void run_gc(MVMThreadContext *tc, MVMuint8 what_to_do) { MVMuint8 gen; MVMuint32 i, n; /* Decide nursery or full collection. */ gen = is_full_collection(tc) ? MVMGCGenerations_Both : MVMGCGenerations_Nursery; /* Do GC work for ourselves and any work threads. */ for (i = 0, n = tc->gc_work_count ; i < n; i++) { MVMThreadContext *other = tc->gc_work[i].tc; tc->gc_work[i].limit = other->nursery_alloc; GCDEBUG_LOG(tc, MVM_GC_DEBUG_ORCHESTRATE, "Thread %d run %d : starting collection for thread %d\n", other->thread_id); other->gc_promoted_bytes = 0; MVM_gc_collect(other, (other == tc ? what_to_do : MVMGCWhatToDo_NoInstance), gen); } /* Wait for everybody to agree we're done. */ finish_gc(tc, gen, what_to_do == MVMGCWhatToDo_All); /* Now we're all done, it's safe to finalize any objects that need it. */ /* XXX TODO explore the feasability of doing this in a background * finalizer/destructor thread and letting the main thread(s) continue * on their merry way(s). */ for (i = 0, n = tc->gc_work_count ; i < n; i++) { MVMThreadContext *other = tc->gc_work[i].tc; /* The thread might've been destroyed */ if (!other) continue; /* Contribute this thread's promoted bytes. */ MVM_add(&tc->instance->gc_promoted_bytes_since_last_full, other->gc_promoted_bytes); /* Collect nursery and gen2 as needed. */ GCDEBUG_LOG(tc, MVM_GC_DEBUG_ORCHESTRATE, "Thread %d run %d : collecting nursery uncopied of thread %d\n", other->thread_id); MVM_gc_collect_free_nursery_uncopied(other, tc->gc_work[i].limit); if (gen == MVMGCGenerations_Both) { GCDEBUG_LOG(tc, MVM_GC_DEBUG_ORCHESTRATE, "Thread %d run %d : freeing gen2 of thread %d\n", other->thread_id); MVM_gc_collect_free_gen2_unmarked(other); } } }
static void run_gc(MVMThreadContext *tc, MVMuint8 what_to_do) { MVMuint8 gen; MVMThread *child; MVMuint32 i, n; /* Do GC work for this thread, or at least all we know about. */ gen = tc->instance->gc_seq_number % MVM_GC_GEN2_RATIO == 0 ? MVMGCGenerations_Both : MVMGCGenerations_Nursery; /* Do GC work for any work threads. */ for (i = 0, n = tc->gc_work_count ; i < n; i++) { MVMThreadContext *other = tc->gc_work[i].tc; tc->gc_work[i].limit = other->nursery_alloc; GCORCH_LOG(tc, "Thread %d run %d : starting collection for thread %d\n", other->thread_id); MVM_gc_collect(other, (other == tc ? what_to_do : MVMGCWhatToDo_NoInstance), gen); } /* Wait for everybody to agree we're done. */ finish_gc(tc, gen); /* Now we're all done, it's safe to finalize any objects that need it. */ for (i = 0, n = tc->gc_work_count ; i < n; i++) { MVMThreadContext *other = tc->gc_work[i].tc; MVMThread *thread_obj; /* the thread might've been destroyed */ if (!other) continue; thread_obj = other->thread_obj; MVM_gc_collect_free_nursery_uncopied(other, tc->gc_work[i].limit); if (gen == MVMGCGenerations_Both) { GCORCH_LOG(tc, "Thread %d run %d : freeing gen2 of thread %d\n", other->thread_id); MVM_gc_collect_cleanup_gen2roots(other); MVM_gc_collect_free_gen2_unmarked(other); } } }