Beispiel #1
0
void
sgen_workers_join (void)
{
	State old_state;
	int i;

	if (!collection_needs_workers ())
		return;

	for (;;) {
		old_state = workers_state;
		SGEN_ASSERT (0, old_state.data.state != STATE_NURSERY_COLLECTION, "Can't be in nursery collection when joining");

		if (old_state.data.state == STATE_WORKING) {
			State new_state = old_state;

			SGEN_ASSERT (0, !old_state.data.post_done, "Why is post_done already set?");
			new_state.data.post_done = 1;
			if (!set_state (old_state, new_state))
				continue;

			MONO_SEM_WAIT (&workers_done_sem);

			old_state = workers_state;
		}

		assert_not_working (old_state);

		/*
		 * Checking whether there is still work left and, if not, going to sleep,
		 * are two separate actions that are not performed atomically by the
		 * workers.  Therefore there's a race condition where work can be added
		 * after they've checked for work, and before they've gone to sleep.
		 */
		if (!workers_job_queue_num_entries && sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue))
			break;

		workers_signal_enqueue_work (workers_num, FALSE);
	}

	/* At this point all the workers have stopped. */

	if (sgen_get_major_collector ()->reset_worker_data) {
		for (i = 0; i < workers_num; ++i)
			sgen_get_major_collector ()->reset_worker_data (workers_data [i].major_collector_data);
	}

	g_assert (workers_job_queue_num_entries == 0);
	g_assert (sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue));
	for (i = 0; i < workers_num; ++i)
		g_assert (sgen_gray_object_queue_is_empty (&workers_data [i].private_gray_queue));
}
Beispiel #2
0
static void
init_distribute_gray_queue (void)
{
    if (workers_distribute_gray_queue_inited) {
        g_assert (sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue));
        g_assert (workers_distribute_gray_queue.locked);
        return;
    }

    sgen_section_gray_queue_init (&workers_distribute_gray_queue, TRUE,
                                  sgen_get_major_collector ()->is_concurrent ? concurrent_enqueue_check : NULL);
    workers_distribute_gray_queue_inited = TRUE;
}
Beispiel #3
0
void
sgen_section_gray_queue_init (SgenSectionGrayQueue *queue, gboolean locked, GrayQueueEnqueueCheckFunc enqueue_check_func)
{
	g_assert (sgen_section_gray_queue_is_empty (queue));

	queue->locked = locked;
	if (locked) {
		mono_os_mutex_init_recursive (&queue->lock);
	}

#ifdef SGEN_CHECK_GRAY_OBJECT_ENQUEUE
	queue->enqueue_check_func = enqueue_check_func;
#endif
}
Beispiel #4
0
void
sgen_workers_join (void)
{
    int i;

    sgen_thread_pool_wait_for_all_jobs ();
    sgen_thread_pool_idle_wait ();
    SGEN_ASSERT (0, workers_state == STATE_NOT_WORKING, "Can only signal enqueue work when in no work state");

    /* At this point all the workers have stopped. */

    SGEN_ASSERT (0, sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue), "Why is there still work left to do?");
    for (i = 0; i < workers_num; ++i)
        SGEN_ASSERT (0, sgen_gray_object_queue_is_empty (&workers_data [i].private_gray_queue), "Why is there still work left to do?");
}
Beispiel #5
0
/*
 * Can only be called if the workers are stopped.
 * If we're stopped, there are also no pending jobs.
 */
gboolean
sgen_workers_have_idle_work (void)
{
	int i;

	SGEN_ASSERT (0, forced_stop && sgen_workers_all_done (), "Checking for idle work should only happen if the workers are stopped.");

	if (!sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue))
		return TRUE;

	for (i = 0; i < workers_num; ++i) {
		if (!sgen_gray_object_queue_is_empty (&workers_data [i].private_gray_queue))
			return TRUE;
	}

	return FALSE;
}
Beispiel #6
0
void
sgen_workers_join (void)
{
	State old_state, new_state;
	int i;

	if (!collection_needs_workers ())
		return;

	do {
		old_state = new_state = workers_state;
		g_assert (old_state.data.gc_in_progress);
		g_assert (!old_state.data.done_posted);

		new_state.data.gc_in_progress = 0;
	} while (!set_state (old_state, new_state));

	if (new_state.data.num_waiting == workers_num) {
		/*
		 * All the workers have shut down but haven't posted
		 * the done semaphore yet, or, if we come from below,
		 * haven't done all their work yet.
		 *
		 * It's not a big deal to wake them up again - they'll
		 * just do one iteration of their loop trying to find
		 * something to do and then go back to waiting again.
		 */
	reawaken:
		workers_wake_up_all ();
	}
	MONO_SEM_WAIT (&workers_done_sem);

	old_state = new_state = workers_state;
	g_assert (old_state.data.num_waiting == workers_num);
	g_assert (old_state.data.done_posted);

	if (workers_job_queue_num_entries || !sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue)) {
		/*
		 * There's a small race condition that we avoid here.
		 * It's possible that a worker thread runs out of
		 * things to do, so it goes to sleep.  Right at that
		 * moment a new job is enqueued, but the thread is
		 * still registered as running.  Now the threads are
		 * joined, and we wait for the semaphore.  Only at
		 * this point does the worker go to sleep, and posts
		 * the semaphore, because workers_gc_in_progress is
		 * already FALSE.  The job is still in the queue,
		 * though.
		 *
		 * Clear the done posted flag.
		 */
		new_state.data.done_posted = 0;
		if (!set_state (old_state, new_state))
			g_assert_not_reached ();
		goto reawaken;
	}

	/* At this point all the workers have stopped. */

	workers_marking = FALSE;

	if (sgen_get_major_collector ()->reset_worker_data) {
		for (i = 0; i < workers_num; ++i)
			sgen_get_major_collector ()->reset_worker_data (workers_data [i].major_collector_data);
	}

	g_assert (workers_job_queue_num_entries == 0);
	g_assert (sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue));
	for (i = 0; i < workers_num; ++i) {
		g_assert (!workers_data [i].stealable_stack_fill);
		g_assert (sgen_gray_object_queue_is_empty (&workers_data [i].private_gray_queue));
	}
}