static void*
worker (void *arg)
{
	thread_data_t *thread_data = (thread_data_t *)arg;
	MonoThreadHazardPointers *hp;
	int skip = thread_data->skip;
	int i, j;
	gboolean result;

	mono_thread_info_register_small_id ();

	hp = mono_hazard_pointer_get ();

	i = 0;
	for (j = 0; j < NUM_ITERS; ++j) {
		switch (nodes [i].state) {
		case STATE_BUSY:
			mono_thread_hazardous_try_free_some ();
			break;
		case STATE_OUT:
			if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_OUT) == STATE_OUT) {
				result = mono_lls_find (&lls, hp, i, HAZARD_FREE_SAFE_CTX);
				assert (!result);
				mono_hazard_pointer_clear_all (hp, -1);

				result = mono_lls_insert (&lls, hp, &nodes [i].node, HAZARD_FREE_SAFE_CTX);
				mono_hazard_pointer_clear_all (hp, -1);

				assert (nodes [i].state == STATE_BUSY);
				nodes [i].state = STATE_IN;

				++thread_data->num_adds;
			}
			break;
		case STATE_IN:
			if (InterlockedCompareExchange (&nodes [i].state, STATE_BUSY, STATE_IN) == STATE_IN) {
				result = mono_lls_find (&lls, hp, i, HAZARD_FREE_SAFE_CTX);
				assert (result);
				assert (mono_hazard_pointer_get_val (hp, 1) == &nodes [i].node);
				mono_hazard_pointer_clear_all (hp, -1);

				result = mono_lls_remove (&lls, hp, &nodes [i].node, HAZARD_FREE_SAFE_CTX);
				mono_hazard_pointer_clear_all (hp, -1);

				++thread_data->num_removes;
			}
			break;
		default:
			assert (FALSE);
		}

		i += skip;
		if (i >= N)
			i -= N;
	}

	return NULL;
}
Example #2
0
/* LOCKING: assumes the GC lock is held */
int
sgen_restart_world (int generation, GGTimingInfo *timing)
{
	int count;
	SgenThreadInfo *info;
	TV_DECLARE (end_sw);
	TV_DECLARE (end_bridge);
	unsigned long usec, bridge_usec;

	/* notify the profiler of the leftovers */
	/* FIXME this is the wrong spot at we can STW for non collection reasons. */
	if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_GC_MOVES))
		sgen_gc_event_moves ();
	mono_profiler_gc_event (MONO_GC_EVENT_PRE_START_WORLD, generation);
	MONO_GC_WORLD_RESTART_BEGIN (generation);
	FOREACH_THREAD (info) {
		info->stack_start = NULL;
#ifdef USE_MONO_CTX
		memset (&info->ctx, 0, sizeof (MonoContext));
#else
		memset (&info->regs, 0, sizeof (info->regs));
#endif
	} END_FOREACH_THREAD

	release_gc_locks ();

	count = sgen_thread_handshake (FALSE);
	TV_GETTIME (end_sw);
	usec = TV_ELAPSED (stop_world_time, end_sw);
	max_pause_usec = MAX (usec, max_pause_usec);
	SGEN_LOG (2, "restarted %d thread(s) (pause time: %d usec, max: %d)", count, (int)usec, (int)max_pause_usec);
	mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD, generation);
	MONO_GC_WORLD_RESTART_END (generation);

	mono_thread_hazardous_try_free_some ();

	sgen_bridge_processing_finish (generation);

	TV_GETTIME (end_bridge);
	bridge_usec = TV_ELAPSED (end_sw, end_bridge);

	if (timing) {
		timing [0].stw_time = usec;
		timing [0].bridge_time = bridge_usec;
	}
	
	sgen_memgov_collection_end (generation, timing, timing ? 2 : 0);

	return count;
}
Example #3
0
static void
unregister_thread (void *arg)
{
	gpointer gc_unsafe_stackdata;
	MonoThreadInfo *info;
	int small_id;

	info = (MonoThreadInfo *) arg;
	g_assert (info);
	g_assert (mono_thread_info_is_current (info));
	g_assert (mono_thread_info_is_live (info));

	small_id = info->small_id;

	/* We only enter the GC unsafe region, as when exiting this function, the thread
	 * will be detached, and the current MonoThreadInfo* will be destroyed. */
	mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, &gc_unsafe_stackdata);

	THREADS_DEBUG ("unregistering info %p\n", info);

	mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));

	mono_threads_platform_unregister (info);

	/*
	 * TLS destruction order is not reliable so small_id might be cleaned up
	 * before us.
	 */
#ifndef HAVE_KW_THREAD
	mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
#endif

	/*
	First perform the callback that requires no locks.
	This callback has the potential of taking other locks, so we do it before.
	After it completes, the thread remains functional.
	*/
	if (threads_callbacks.thread_detach)
		threads_callbacks.thread_detach (info);

	mono_thread_info_suspend_lock_with_info (info);

	/*
	Now perform the callback that must be done under locks.
	This will render the thread useless and non-suspendable, so it must
	be done while holding the suspend lock to give no other thread chance
	to suspend it.
	*/
	if (threads_callbacks.thread_unregister)
		threads_callbacks.thread_unregister (info);
	mono_threads_unregister_current_thread (info);
	mono_threads_transition_detach (info);

	mono_thread_info_suspend_unlock ();

	g_byte_array_free (info->stackdata, /*free_segment=*/TRUE);

	/*now it's safe to free the thread info.*/
	mono_thread_hazardous_try_free (info, free_thread_info);
	/* Pump the HP queue */
	mono_thread_hazardous_try_free_some ();

	mono_thread_small_id_free (small_id);
}