コード例 #1
0
ファイル: sgen-workers.c プロジェクト: AlexanderBekrenev/mono
void
sgen_workers_enqueue_job (JobFunc func, void *data)
{
	int num_entries;
	JobQueueEntry *entry;

	if (!collection_needs_workers ()) {
		func (NULL, data);
		return;
	}

	g_assert (workers_state.data.gc_in_progress);

	entry = sgen_alloc_internal (INTERNAL_MEM_JOB_QUEUE_ENTRY);
	entry->func = func;
	entry->data = data;

	mono_mutex_lock (&workers_job_queue_mutex);
	entry->next = workers_job_queue;
	workers_job_queue = entry;
	num_entries = ++workers_job_queue_num_entries;
	++workers_num_jobs_enqueued;
	mono_mutex_unlock (&workers_job_queue_mutex);

	workers_wake_up (num_entries);
}
コード例 #2
0
ファイル: sgen-workers.c プロジェクト: phenixFire/mono
void
sgen_workers_start_all_workers (void)
{
	State old_state, new_state;
	int i;
	gboolean result;

	if (!collection_needs_workers ())
		return;

	if (sgen_get_major_collector ()->init_worker_thread)
		sgen_get_major_collector ()->init_worker_thread (workers_gc_thread_major_collector_data);

	old_state = new_state = workers_state;
	assert_not_working (old_state);

	g_assert (workers_job_queue_num_entries == 0);
	workers_num_jobs_enqueued = 0;
	workers_num_jobs_finished = 0;

	if (workers_started) {
		workers_signal_enqueue_work (workers_num, FALSE);
		return;
	}

	new_state.data.state = STATE_WORKING;
	new_state.data.num_awake = workers_num;
	result = set_state (old_state, new_state);
	SGEN_ASSERT (0, result, "Nobody else should have modified the state - workers have not been started yet");

	for (i = 0; i < workers_num; ++i)
		workers_start_worker (i);

	workers_started = TRUE;
}
コード例 #3
0
ファイル: sgen-workers.c プロジェクト: phenixFire/mono
void
sgen_workers_enqueue_job (const char *name, JobFunc func, void *data)
{
	int num_entries;
	JobQueueEntry *entry;

	if (!collection_needs_workers ()) {
		func (NULL, data);
		return;
	}

	entry = sgen_alloc_internal (INTERNAL_MEM_JOB_QUEUE_ENTRY);
	entry->name = name;
	entry->func = func;
	entry->data = data;

	mono_mutex_lock (&workers_job_queue_mutex);
	entry->next = workers_job_queue;
	workers_job_queue = entry;
	num_entries = ++workers_job_queue_num_entries;
	++workers_num_jobs_enqueued;
	mono_mutex_unlock (&workers_job_queue_mutex);

	if (workers_state.data.state != STATE_NURSERY_COLLECTION)
		workers_signal_enqueue_work_if_necessary (num_entries < workers_num ? num_entries : workers_num);
}
コード例 #4
0
ファイル: sgen-workers.c プロジェクト: AlexanderBekrenev/mono
void
sgen_workers_init_distribute_gray_queue (void)
{
	if (!collection_needs_workers ())
		return;

	init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent);
}
コード例 #5
0
ファイル: sgen-workers.c プロジェクト: phenixFire/mono
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));
}
コード例 #6
0
ファイル: sgen-workers.c プロジェクト: AlexanderBekrenev/mono
void
sgen_workers_start_marking (void)
{
	if (!collection_needs_workers ())
		return;

	g_assert (workers_started && workers_state.data.gc_in_progress);
	g_assert (!workers_marking);

	workers_marking = TRUE;

	workers_wake_up_all ();
}
コード例 #7
0
ファイル: sgen-workers.c プロジェクト: AlexanderBekrenev/mono
void
sgen_workers_start_all_workers (void)
{
	State old_state, new_state;
	int i;

	if (!collection_needs_workers ())
		return;

	if (sgen_get_major_collector ()->init_worker_thread)
		sgen_get_major_collector ()->init_worker_thread (workers_gc_thread_major_collector_data);

	old_state = new_state = workers_state;
	g_assert (!old_state.data.gc_in_progress);
	new_state.data.gc_in_progress = TRUE;

	workers_marking = FALSE;

	g_assert (workers_job_queue_num_entries == 0);
	workers_num_jobs_enqueued = 0;
	workers_num_jobs_finished = 0;

	if (workers_started) {
		g_assert (old_state.data.done_posted);
		if (old_state.data.num_waiting != workers_num) {
			g_error ("Expecting all %d sgen workers to be parked, but only %d are",
					workers_num, old_state.data.num_waiting);
		}

		/* Clear the done posted flag */
		new_state.data.done_posted = 0;
		if (!set_state (old_state, new_state))
			g_assert_not_reached ();

		workers_wake_up_all ();
		return;
	}

	g_assert (!old_state.data.done_posted);

	if (!set_state (old_state, new_state))
		g_assert_not_reached ();

	for (i = 0; i < workers_num; ++i)
		workers_start_worker (i);

	workers_started = TRUE;
}
コード例 #8
0
static gboolean
workers_dequeue_and_do_job (WorkerData *data)
{
	JobQueueEntry *entry;
	int num_finished;

	/*
	 * At this point the GC might not be running anymore.  We
	 * could have been woken up by a job that was then taken by
	 * another thread, after which the collection finished, so we
	 * first have to successfully dequeue a job before doing
	 * anything assuming that the collection is still ongoing.
	 */

	if (!workers_job_queue_num_entries)
		return FALSE;

	mono_mutex_lock (&workers_job_queue_mutex);
	entry = (JobQueueEntry*)workers_job_queue;
	if (entry) {
		workers_job_queue = entry->next;
		--workers_job_queue_num_entries;
	}
	mono_mutex_unlock (&workers_job_queue_mutex);

	if (!entry)
		return FALSE;

	g_assert (collection_needs_workers ());

	entry->func (data, entry->data);
	sgen_free_internal (entry, INTERNAL_MEM_JOB_QUEUE_ENTRY);

	SGEN_ATOMIC_ADD (workers_num_jobs_finished, 1);

	return TRUE;
}
コード例 #9
0
ファイル: sgen-workers.c プロジェクト: AlexanderBekrenev/mono
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));
	}
}