Esempio n. 1
0
static void*
register_thread (MonoThreadInfo *info, gpointer baseptr)
{
	int small_id = mono_thread_info_register_small_id ();
	gboolean result;
	mono_thread_info_set_tid (info, mono_native_thread_id_get ());
	info->small_id = small_id;

	MONO_SEM_INIT (&info->suspend_semaphore, 1);
	MONO_SEM_INIT (&info->resume_semaphore, 0);
	MONO_SEM_INIT (&info->finish_resume_semaphore, 0);

	/*set TLS early so SMR works */
	mono_native_tls_set_value (thread_info_key, info);

	THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);

	if (threads_callbacks.thread_register) {
		if (threads_callbacks.thread_register (info, baseptr) == NULL) {
			g_warning ("thread registation failed\n");
			g_free (info);
			return NULL;
		}
	}

	mono_threads_platform_register (info);
	info->thread_state = STATE_RUNNING;
	mono_thread_info_suspend_lock ();
	/*If this fail it means a given thread has been registered twice, which doesn't make sense. */
	result = mono_thread_info_insert (info);
	g_assert (result);
	mono_thread_info_suspend_unlock ();
	return info;
}
Esempio n. 2
0
void
mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
{
	gboolean res;
	threads_callbacks = *callbacks;
	thread_info_size = info_size;
#ifdef HOST_WIN32
	res = mono_native_tls_alloc (&thread_info_key, NULL);
#else
	res = mono_native_tls_alloc (&thread_info_key, unregister_thread);
#endif
	g_assert (res);

	res = mono_native_tls_alloc (&small_id_key, NULL);
	g_assert (res);

	MONO_SEM_INIT (&global_suspend_semaphore, 1);

	mono_lls_init (&thread_list, NULL);
	mono_thread_smr_init ();
	mono_threads_init_platform ();

#if defined(__MACH__)
	mono_mach_init (thread_info_key);
#endif

	mono_threads_inited = TRUE;

	g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
}
Esempio n. 3
0
void
sgen_os_init (void)
{
	struct sigaction sinfo;

	suspend_ack_semaphore_ptr = &suspend_ack_semaphore;
	MONO_SEM_INIT (&suspend_ack_semaphore, 0);

	sigfillset (&sinfo.sa_mask);
	sinfo.sa_flags = SA_RESTART | SA_SIGINFO;
	sinfo.sa_sigaction = suspend_handler;
	if (sigaction (suspend_signal_num, &sinfo, NULL) != 0) {
		g_error ("failed sigaction");
	}

	sinfo.sa_handler = restart_handler;
	if (sigaction (restart_signal_num, &sinfo, NULL) != 0) {
		g_error ("failed sigaction");
	}

	sigfillset (&suspend_signal_mask);
	sigdelset (&suspend_signal_mask, restart_signal_num);

	sigemptyset (&suspend_ack_signal_mask);
	sigaddset (&suspend_ack_signal_mask, restart_signal_num);
	
}
Esempio n. 4
0
HANDLE
mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
{
    pthread_attr_t attr;
    int res;
    pthread_t thread;
    StartInfo start_info;

    res = pthread_attr_init (&attr);
    g_assert (!res);

    if (stack_size == 0) {
#if HAVE_VALGRIND_MEMCHECK_H
        if (RUNNING_ON_VALGRIND)
            stack_size = 1 << 20;
        else
            stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
#else
        stack_size = (SIZEOF_VOID_P / 4) * 1024 * 1024;
#endif
    }

#ifdef PTHREAD_STACK_MIN
    if (stack_size < PTHREAD_STACK_MIN)
        stack_size = PTHREAD_STACK_MIN;
#endif

#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
    res = pthread_attr_setstacksize (&attr, stack_size);
    g_assert (!res);
#endif

    memset (&start_info, 0, sizeof (StartInfo));
    start_info.start_routine = (void *(*)(void *)) start_routine;
    start_info.arg = arg;
    start_info.flags = creation_flags;
    MONO_SEM_INIT (&(start_info.registered), 0);

    /* Actually start the thread */
    res = mono_gc_pthread_create (&thread, &attr, inner_start_thread, &start_info);
    if (res) {
        MONO_SEM_DESTROY (&(start_info.registered));
        return NULL;
    }

    MONO_TRY_BLOCKING;
    /* Wait until the thread register itself in various places */
    while (MONO_SEM_WAIT (&(start_info.registered)) != 0) {
        /*if (EINTR != errno) ABORT("sem_wait failed"); */
    }
    MONO_FINISH_TRY_BLOCKING;

    MONO_SEM_DESTROY (&(start_info.registered));

    if (out_tid)
        *out_tid = thread;

    return start_info.handle;
}
Esempio n. 5
0
void
mono_threads_platform_register (MonoThreadInfo *info)
{
	MONO_SEM_INIT (&info->begin_suspend_semaphore, 0);

#if defined (PLATFORM_ANDROID)
	info->native_handle = (gpointer) gettid ();
#endif
}
Esempio n. 6
0
void
sgen_workers_init (int num_workers)
{
	int i;

	if (!sgen_get_major_collector ()->is_parallel)
		return;

	//g_print ("initing %d workers\n", num_workers);

	workers_num = num_workers;

	workers_data = sgen_alloc_internal_dynamic (sizeof (WorkerData) * num_workers, INTERNAL_MEM_WORKER_DATA, TRUE);
	memset (workers_data, 0, sizeof (WorkerData) * num_workers);

	MONO_SEM_INIT (&workers_waiting_sem, 0);
	MONO_SEM_INIT (&workers_done_sem, 0);

	sgen_gray_object_queue_init_with_alloc_prepare (&workers_distribute_gray_queue,
			workers_gray_queue_share_redirect, &workers_gc_thread_data);
	mono_mutex_init (&workers_gc_thread_data.stealable_stack_mutex, NULL);
	workers_gc_thread_data.stealable_stack_fill = 0;

	if (sgen_get_major_collector ()->alloc_worker_data)
		workers_gc_thread_data.major_collector_data = sgen_get_major_collector ()->alloc_worker_data ();

	for (i = 0; i < workers_num; ++i) {
		/* private gray queue is inited by the thread itself */
		mono_mutex_init (&workers_data [i].stealable_stack_mutex, NULL);
		workers_data [i].stealable_stack_fill = 0;

		if (sgen_get_major_collector ()->alloc_worker_data)
			workers_data [i].major_collector_data = sgen_get_major_collector ()->alloc_worker_data ();
	}

	LOCK_INIT (workers_job_queue_mutex);

	sgen_register_fixed_internal_mem_type (INTERNAL_MEM_JOB_QUEUE_ENTRY, sizeof (JobQueueEntry));

	mono_counters_register ("Stolen from self lock", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_workers_stolen_from_self_lock);
	mono_counters_register ("Stolen from self no lock", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_workers_stolen_from_self_no_lock);
	mono_counters_register ("Stolen from others", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_workers_stolen_from_others);
	mono_counters_register ("# workers waited", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_workers_num_waited);
}
Esempio n. 7
0
static void
threadpool_init (ThreadPool *tp, int min_threads, int max_threads, void (*async_invoke) (gpointer))
{
	memset (tp, 0, sizeof (ThreadPool));
	tp->min_threads = min_threads;
	tp->max_threads = max_threads;
	tp->async_invoke = async_invoke;
	tp->queue = mono_cq_create ();
	MONO_SEM_INIT (&tp->new_job, 0);
}
Esempio n. 8
0
void
mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
{
    gboolean res;
    threads_callbacks = *callbacks;
    thread_info_size = info_size;
#ifdef HOST_WIN32
    res = mono_native_tls_alloc (&thread_info_key, NULL);
    res = mono_native_tls_alloc (&thread_exited_key, NULL);
#else
    res = mono_native_tls_alloc (&thread_info_key, (void *) unregister_thread);
    res = mono_native_tls_alloc (&thread_exited_key, (void *) thread_exited_dtor);
#endif

    g_assert (res);

#ifndef HAVE_KW_THREAD
    res = mono_native_tls_alloc (&small_id_key, NULL);
#endif
    g_assert (res);

    unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || MONO_THREADS_PLATFORM_REQUIRES_UNIFIED_SUSPEND;

    MONO_SEM_INIT (&global_suspend_semaphore, 1);
    MONO_SEM_INIT (&suspend_semaphore, 0);

    mono_lls_init (&thread_list, NULL);
    mono_thread_smr_init ();
    mono_threads_init_platform ();
    mono_threads_init_abort_syscall ();

#if defined(__MACH__)
    mono_mach_init (thread_info_key);
#endif

    mono_threads_inited = TRUE;

    g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
}
Esempio n. 9
0
void
sgen_workers_init (int num_workers)
{
	int i;

	if (!sgen_get_major_collector ()->is_concurrent)
		return;

	//g_print ("initing %d workers\n", num_workers);

	workers_num = num_workers;

	workers_data = sgen_alloc_internal_dynamic (sizeof (WorkerData) * num_workers, INTERNAL_MEM_WORKER_DATA, TRUE);
	memset (workers_data, 0, sizeof (WorkerData) * num_workers);

	MONO_SEM_INIT (&workers_waiting_sem, 0);
	MONO_SEM_INIT (&workers_done_sem, 0);

	init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent);

	if (sgen_get_major_collector ()->alloc_worker_data)
		workers_gc_thread_major_collector_data = sgen_get_major_collector ()->alloc_worker_data ();

	for (i = 0; i < workers_num; ++i) {
		workers_data [i].index = i;

		if (sgen_get_major_collector ()->alloc_worker_data)
			workers_data [i].major_collector_data = sgen_get_major_collector ()->alloc_worker_data ();
	}

	LOCK_INIT (workers_job_queue_mutex);

	sgen_register_fixed_internal_mem_type (INTERNAL_MEM_JOB_QUEUE_ENTRY, sizeof (JobQueueEntry));

	mono_counters_register ("Stolen from self lock", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_workers_stolen_from_self_lock);
	mono_counters_register ("Stolen from self no lock", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_workers_stolen_from_self_no_lock);
	mono_counters_register ("Stolen from others", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_workers_stolen_from_others);
	mono_counters_register ("# workers waited", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_workers_num_waited);
}
Esempio n. 10
0
static gpointer
tp_poll_init (SocketIOData *data)
{
	tp_poll_data *result;
#ifdef HOST_WIN32
	struct sockaddr_in client;
	struct sockaddr_in server;
	SOCKET srv;
	int len;
#endif

	result = g_new0 (tp_poll_data, 1);
#ifndef HOST_WIN32
	if (pipe (result->pipe) != 0) {
		int err = errno;
		perror ("mono");
		g_assert (err);
	}
#else
	srv = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
	g_assert (srv != INVALID_SOCKET);
	result->pipe [1] = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
	g_assert (result->pipe [1] != INVALID_SOCKET);

	server.sin_family = AF_INET;
	server.sin_addr.s_addr = inet_addr ("127.0.0.1");
	server.sin_port = 0;
	if (bind (srv, (SOCKADDR *) &server, sizeof (struct sockaddr_in))) {
		g_print ("%d\n", WSAGetLastError ());
		g_assert (1 != 0);
	}

	len = sizeof (server);
	getsockname (srv, (SOCKADDR *) &server, &len);
	listen (srv, 1);
	if (connect ((SOCKET) result->pipe [1], (SOCKADDR *) &server, sizeof (server)) == SOCKET_ERROR) {
		g_print ("%d\n", WSAGetLastError ());
		g_assert (1 != 0);
	}
	len = sizeof (client);
	result->pipe [0] = accept (srv, (SOCKADDR *) &client, &len);
	g_assert (result->pipe [0] != INVALID_SOCKET);
	closesocket (srv);
#endif
	MONO_SEM_INIT (&result->new_sem, 1);
	data->shutdown = tp_poll_shutdown;
	data->modify = tp_poll_modify;
	data->wait = tp_poll_wait;
	return result;
}
Esempio n. 11
0
static void*
inner_start_thread (void *arg)
{
	StartInfo *start_info = (StartInfo *) arg;
	void *t_arg = start_info->arg;
	int res;
	void *(*start_func)(void*) = start_info->start_routine;
	guint32 flags = start_info->flags;
	void *result;
	HANDLE handle;
	MonoThreadInfo *info;

	/* Register the thread with the io-layer */
	handle = wapi_create_thread_handle ();
	if (!handle) {
		res = MONO_SEM_POST (&(start_info->registered));
		g_assert (!res);
		return NULL;
	}
	start_info->handle = handle;

	info = mono_thread_info_attach (&result);
	MONO_PREPARE_BLOCKING

	info->runtime_thread = TRUE;
	info->handle = handle;

	if (flags & CREATE_SUSPENDED) {
		info->create_suspended = TRUE;
		MONO_SEM_INIT (&info->create_suspended_sem, 0);
	}

	/* start_info is not valid after this */
	res = MONO_SEM_POST (&(start_info->registered));
	g_assert (!res);
	start_info = NULL;

	if (flags & CREATE_SUSPENDED) {
		while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 &&
			   errno == EINTR);
		MONO_SEM_DESTROY (&info->create_suspended_sem);
	}

	MONO_FINISH_BLOCKING
	/* Run the actual main function of the thread */
	result = start_func (t_arg);

	mono_threads_core_exit (GPOINTER_TO_UINT (result));
	g_assert_not_reached ();
}
Esempio n. 12
0
static void*
register_thread (MonoThreadInfo *info, gpointer baseptr)
{
	size_t stsize = 0;
	guint8 *staddr = NULL;
	int small_id = mono_thread_info_register_small_id ();
	gboolean result;
	mono_thread_info_set_tid (info, mono_native_thread_id_get ());
	info->small_id = small_id;

	MONO_SEM_INIT (&info->resume_semaphore, 0);

	/*set TLS early so SMR works */
	mono_native_tls_set_value (thread_info_key, info);

	THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);

	if (threads_callbacks.thread_register) {
		if (threads_callbacks.thread_register (info, baseptr) == NULL) {
			// g_warning ("thread registation failed\n");
			g_free (info);
			return NULL;
		}
	}

	mono_thread_info_get_stack_bounds (&staddr, &stsize);
	g_assert (staddr);
	g_assert (stsize);
	info->stack_start_limit = staddr;
	info->stack_end = staddr + stsize;

	mono_threads_platform_register (info);

	/*
	Transition it before taking any locks or publishing itself to reduce the chance
	of others witnessing a detached thread.
	We can reasonably expect that until this thread gets published, no other thread will
	try to manipulate it.
	*/
	mono_threads_transition_attach (info);
	mono_thread_info_suspend_lock ();
	/*If this fail it means a given thread has been registered twice, which doesn't make sense. */
	result = mono_thread_info_insert (info);
	g_assert (result);
	mono_thread_info_suspend_unlock ();
	return info;
}
Esempio n. 13
0
HANDLE
mono_threads_core_create_thread (LPTHREAD_START_ROUTINE start_routine, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
{
	ThreadStartInfo *start_info;
	HANDLE result;
	DWORD thread_id;

	start_info = g_malloc0 (sizeof (ThreadStartInfo));
	if (!start_info)
		return NULL;
	MONO_SEM_INIT (&(start_info->registered), 0);
	start_info->arg = arg;
	start_info->start_routine = start_routine;
	start_info->suspend = creation_flags & CREATE_SUSPENDED;
	creation_flags &= ~CREATE_SUSPENDED;
	if (start_info->suspend) {
		start_info->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
		if (!start_info->suspend_event)
			return NULL;
	}

	result = CreateThread (NULL, stack_size, inner_start_thread, start_info, creation_flags, &thread_id);
	if (result) {
		while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
			/*if (EINTR != errno) ABORT("sem_wait failed"); */
		}
		if (start_info->suspend) {
			g_assert (SuspendThread (result) != (DWORD)-1);
			SetEvent (start_info->suspend_event);
		}
	} else if (start_info->suspend) {
		CloseHandle (start_info->suspend_event);
	}
	if (out_tid)
		*out_tid = thread_id;
	MONO_SEM_DESTROY (&(start_info->registered));
	g_free (start_info);
	return result;
}
Esempio n. 14
0
int
mono_threads_pthread_create (pthread_t *new_thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
{
	ThreadStartInfo *start_info;
	int result;

	start_info = g_malloc0 (sizeof (ThreadStartInfo));
	if (!start_info)
		return ENOMEM;
	MONO_SEM_INIT (&(start_info->registered), 0);
	start_info->arg = arg;
	start_info->start_routine = start_routine;

	result = mono_threads_get_callbacks ()->mono_gc_pthread_create (new_thread, attr, inner_start_thread, start_info);
	if (result == 0) {
		while (MONO_SEM_WAIT (&(start_info->registered)) != 0) {
			/*if (EINTR != errno) ABORT("sem_wait failed"); */
		}
	}
	MONO_SEM_DESTROY (&(start_info->registered));
	g_free (start_info);
	return result;
}
Esempio n. 15
0
static void*
inner_start_thread (void *arg)
{
	StartInfo *start_info = arg;
	void *t_arg = start_info->arg;
	int res;
	void *(*start_func)(void*) = start_info->start_routine;
	guint32 flags = start_info->flags;
	void *result;
	HANDLE handle;
	MonoThreadInfo *info;

	/* Register the thread with the io-layer */
	handle = wapi_create_thread_handle ();
	if (!handle) {
		res = MONO_SEM_POST (&(start_info->registered));
		g_assert (!res);
		return NULL;
	}
	start_info->handle = handle;

	info = mono_thread_info_attach (&result);
	info->runtime_thread = TRUE;
	info->handle = handle;

	if (flags & CREATE_SUSPENDED) {
		info->create_suspended = TRUE;
		MONO_SEM_INIT (&info->create_suspended_sem, 0);
	}

	/* start_info is not valid after this */
	res = MONO_SEM_POST (&(start_info->registered));
	g_assert (!res);
	start_info = NULL;

	if (flags & CREATE_SUSPENDED) {
		while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 &&
			   errno == EINTR);
		MONO_SEM_DESTROY (&info->create_suspended_sem);
	}

	/* Run the actual main function of the thread */
	result = start_func (t_arg);

	/*
	mono_thread_info_detach ();
	*/

#if defined(__native_client__)
	nacl_shutdown_gc_thread();
#endif

	wapi_thread_handle_set_exited (handle, GPOINTER_TO_UINT (result));
	/* This is needed by mono_threads_core_unregister () which is called later */
	info->handle = NULL;

	g_assert (mono_threads_get_callbacks ()->thread_exit);
	mono_threads_get_callbacks ()->thread_exit (NULL);
	g_assert_not_reached ();
	return result;
}
Esempio n. 16
0
void
mono_thread_pool_init (void)
{
	gint threads_per_cpu = 1;
	gint thread_count;
	gint cpu_count = mono_cpu_count ();
	int result;

	if (tp_inited == 2)
		return;

	result = InterlockedCompareExchange (&tp_inited, 1, 0);
	if (result == 1) {
		while (1) {
			SleepEx (1, FALSE);
			if (tp_inited == 2)
				return;
		}
	}

	MONO_GC_REGISTER_ROOT_FIXED (socket_io_data.sock_to_state);
	mono_mutex_init_recursive (&socket_io_data.io_lock);
	if (g_getenv ("MONO_THREADS_PER_CPU") != NULL) {
		threads_per_cpu = atoi (g_getenv ("MONO_THREADS_PER_CPU"));
		if (threads_per_cpu < 1)
			threads_per_cpu = 1;
	}

	thread_count = MIN (cpu_count * threads_per_cpu, 100 * cpu_count);
	threadpool_init (&async_tp, thread_count, MAX (100 * cpu_count, thread_count), async_invoke_thread);
	threadpool_init (&async_io_tp, cpu_count * 2, cpu_count * 4, async_invoke_thread);
	async_io_tp.is_io = TRUE;

	async_call_klass = mono_class_from_name (mono_defaults.corlib, "System", "MonoAsyncCall");
	g_assert (async_call_klass);

	mono_mutex_init (&threads_lock);
	threads = g_ptr_array_sized_new (thread_count);
	g_assert (threads);

	mono_mutex_init_recursive (&wsqs_lock);
	wsqs = g_ptr_array_sized_new (MAX (100 * cpu_count, thread_count));

#ifndef DISABLE_PERFCOUNTERS
	async_tp.pc_nitems = init_perf_counter ("Mono Threadpool", "Work Items Added");
	g_assert (async_tp.pc_nitems);

	async_io_tp.pc_nitems = init_perf_counter ("Mono Threadpool", "IO Work Items Added");
	g_assert (async_io_tp.pc_nitems);

	async_tp.pc_nthreads = init_perf_counter ("Mono Threadpool", "# of Threads");
	g_assert (async_tp.pc_nthreads);

	async_io_tp.pc_nthreads = init_perf_counter ("Mono Threadpool", "# of IO Threads");
	g_assert (async_io_tp.pc_nthreads);
#endif
	tp_inited = 2;
#ifdef DEBUG
	signal (SIGALRM, signal_handler);
	alarm (2);
#endif

	MONO_SEM_INIT (&monitor_sem, 0);
	monitor_state = MONITOR_STATE_AWAKE;
	monitor_njobs = 0;
}