Esempio n. 1
0
/* This is called when a thread hits an interrupt at a GC safe point. This means
 * that another thread is already trying to start a GC run, so we don't need to
 * try and do that, just enlist in the run. */
void MVM_gc_enter_from_interrupt(MVMThreadContext *tc) {
    MVMuint8 decr = 0;
    AO_t curr;

    tc->gc_work_count = 0;

    add_work(tc, tc);

    /* grab our child */
    signal_child(tc);

    /* Count us in to the GC run. Wait for a vote to steal. */
    GCORCH_LOG(tc, "Thread %d run %d : Entered from interrupt\n");

    while ((curr = tc->instance->gc_start) < 2
            || !MVM_trycas(&tc->instance->gc_start, curr, curr - 1)) {
    /*    apr_sleep(1);
        apr_thread_yield();*/
    }

    /* Wait for all threads to indicate readiness to collect. */
    while (tc->instance->gc_start) {
    /*    apr_sleep(1);
        apr_thread_yield();*/
    }
    run_gc(tc, MVMGCWhatToDo_NoInstance);
}
Esempio n. 2
0
static void _sig_child()
{
	pid_t pid;
	int status, errno_save = errno;

	while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)
	{
		// just ignore stop/continue signal
		if (WIFSTOPPED(status) || WIFCONTINUED(status))
			continue;
		// called only when child process exit() normal, -2 : signal
		status = WIFEXITED(status) ? (char) WEXITSTATUS(status) : -2;
		signal_child(pid, status);
	}
	errno = errno_save;
}
Esempio n. 3
0
/* This is called when the allocator finds it has run out of memory and wants
 * to trigger a GC run. In this case, it's possible (probable, really) that it
 * will need to do that triggering, notifying other running threads that the
 * time has come to GC. */
void MVM_gc_enter_from_allocator(MVMThreadContext *tc) {

    GCORCH_LOG(tc, "Thread %d run %d : Entered from allocate\n");

    /* Try to start the GC run. */
    if (MVM_trycas(&tc->instance->gc_start, 0, 1)) {
        MVMThread *last_starter = NULL;
        MVMuint32 num_threads = 0;

        /* We are the winner of the GC starting race. This gives us some
         * extra responsibilities as well as doing the usual things.
         * First, increment GC sequence number. */
        tc->instance->gc_seq_number++;
        GCORCH_LOG(tc, "Thread %d run %d : GC thread elected coordinator: starting gc seq %d\n", tc->instance->gc_seq_number);

        /* Ensure our stolen list is empty. */
        tc->gc_work_count = 0;

        /* need to wait for other threads to reset their gc_status. */
        while (tc->instance->gc_ack)
            apr_thread_yield();

        add_work(tc, tc);

        /* grab our child */
        signal_child(tc);

        do {
            if (tc->instance->threads && tc->instance->threads != last_starter) {
                MVMThread *head;
                MVMuint32 add;
                while (!MVM_trycas(&tc->instance->threads, (head = tc->instance->threads), NULL));

                add = signal_all_but(tc, head, last_starter);
                last_starter = head;
                if (add) {
                    GCORCH_LOG(tc, "Thread %d run %d : Found %d other threads\n", add);
                    MVM_atomic_add(&tc->instance->gc_start, add);
                    num_threads += add;
                }
            }
        } while (tc->instance->gc_start > 1);

        if (!MVM_trycas(&tc->instance->threads, NULL, last_starter))
            MVM_panic(MVM_exitcode_gcorch, "threads list corrupted\n");

        if (tc->instance->gc_finish != 0)
            MVM_panic(MVM_exitcode_gcorch, "finish votes was %d\n", tc->instance->gc_finish);

        tc->instance->gc_ack = tc->instance->gc_finish = num_threads + 1;
        GCORCH_LOG(tc, "Thread %d run %d : finish votes is %d\n", (int)tc->instance->gc_finish);

        /* signal to the rest to start */
        if (MVM_atomic_decr(&tc->instance->gc_start) != 1)
            MVM_panic(MVM_exitcode_gcorch, "start votes was %d\n", tc->instance->gc_finish);

        run_gc(tc, MVMGCWhatToDo_All);
    }
    else {
        /* Another thread beat us to starting the GC sync process. Thus, act as
         * if we were interrupted to GC. */
        GCORCH_LOG(tc, "Thread %d run %d : Lost coordinator election\n");
        MVM_gc_enter_from_interrupt(tc);
    }
}