Example #1
0
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");
}
Example #2
0
/* 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;
}
Example #3
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);
    }
}
Example #4
0
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;
    }
}
Example #5
0
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);
        }
    }
}
Example #6
0
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);
        }
    }
}