* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
#include <config.h>
}
mono_release_type_locks (thread);
- mono_profiler_thread_end (thread->tid);
+ /* Can happen when we attach the profiler helper thread in order to heapshot. */
+ if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
+ mono_profiler_thread_end (thread->tid);
if (thread == mono_thread_internal_current ()) {
/*
return thread;
}
-static void
-init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
+static gboolean
+init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate, MonoError *error)
{
- MonoError error;
MonoDomain *domain = mono_get_root_domain ();
+ mono_error_init (error);
if (!candidate || candidate->obj.vtable->domain != domain) {
- candidate = new_thread_with_internal (domain, thread, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ candidate = new_thread_with_internal (domain, thread, error);
+ return_val_if_nok (error, FALSE);
}
set_current_thread_for_domain (domain, thread, candidate);
g_assert (!thread->root_domain_thread);
MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
+ return TRUE;
}
static guint32 WINAPI start_wrapper_internal(void *data)
{
+ MonoError error;
MonoThreadInfo *info;
StartInfo *start_info = (StartInfo *)data;
guint32 (*start_func)(void *);
/* We have to do this here because mono_thread_new_init()
requires that root_domain_thread is set up. */
thread_adjust_static_data (internal);
- init_root_domain_thread (internal, start_info->obj);
+ init_root_domain_thread (internal, start_info->obj, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
/* This MUST be called before any managed code can be
* executed, as it calls the callback function that (for the
if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
mono_profiler_thread_name (internal->tid, tname);
+ mono_thread_info_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
g_free (tname);
}
/* start_func is set only for unmanaged start functions */
*/
static gboolean
create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
- gboolean throw_on_failure)
+ MonoError *error)
{
HANDLE thread_handle;
MonoNativeThreadId tid;
*/
mono_threads_join_threads ();
+ mono_error_init (error);
+
mono_threads_lock ();
if (shutting_down) {
g_free (start_info);
stack_size, create_flags, &tid);
if (thread_handle == NULL) {
- /* The thread couldn't be created, so throw an exception */
+ /* The thread couldn't be created, so set an exception */
mono_threads_lock ();
mono_g_hash_table_remove (threads_starting_up, thread);
mono_threads_unlock ();
g_free (start_info);
- if (throw_on_failure)
- mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
- else
- g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
+ mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
return FALSE;
}
THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
* ARG should not be a GC reference.
*/
MonoInternalThread*
-mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
+mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
{
- MonoError error;
MonoThread *thread;
MonoInternalThread *internal;
StartInfo *start_info;
gboolean res;
- thread = create_thread_object (domain, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_init (error);
- internal = create_internal_thread (&error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ thread = create_thread_object (domain, error);
+ return_val_if_nok (error, NULL);
+
+ internal = create_internal_thread (error);
+ return_val_if_nok (error, NULL);
MONO_OBJECT_SETREF (thread, internal_thread, internal);
start_info->obj = thread;
start_info->start_arg = arg;
- res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
- if (!res)
- return NULL;
+ res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, error);
+ return_val_if_nok (error, NULL);
/* Check that the managed and unmanaged layout of MonoInternalThread matches */
#ifndef MONO_CROSS_COMPILE
void
mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
{
- mono_thread_create_internal (domain, func, arg, FALSE, 0);
+ MonoError error;
+ if (!mono_thread_create_checked (domain, func, arg, &error))
+ mono_error_cleanup (&error);
+}
+
+gboolean
+mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
+{
+ return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
}
MonoThread *
thread_adjust_static_data (thread);
- init_root_domain_thread (thread, current_thread);
+ init_root_domain_thread (thread, current_thread, error);
+ return_val_if_nok (error, NULL);
+
if (domain != mono_get_root_domain ())
set_current_thread_for_domain (domain, thread, current_thread);
mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
}
- // FIXME: Need a separate callback
- mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
+ /* Can happen when we attach the profiler helper thread in order to heapshot. */
+ if (!info->tools_thread)
+ // FIXME: Need a separate callback
+ mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
return current_thread;
}
ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
MonoObject *start)
{
+ MonoError error;
StartInfo *start_info;
MonoInternalThread *internal;
gboolean res;
start_info->obj = this_obj;
g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
- res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
+ res = create_thread (this_obj, internal, start_info, FALSE, 0, &error);
if (!res) {
+ mono_error_cleanup (&error);
UNLOCK_THREAD (internal);
return NULL;
}
}
void
-mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
+mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed, MonoError *error)
{
LOCK_THREAD (this_obj);
+ mono_error_init (error);
+
if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
UNLOCK_THREAD (this_obj);
- mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
+ mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
return;
}
if (this_obj->name) {
void
ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
{
- mono_thread_set_name_internal (this_obj, name, TRUE);
+ MonoError error;
+ mono_thread_set_name_internal (this_obj, name, TRUE, &error);
+ mono_error_set_pending_exception (&error);
}
/*
/* If the array is already in the requested domain, we just return it,
otherwise we return a copy in that domain. */
static MonoArray*
-byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
+byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
{
MonoArray *copy;
+ mono_error_init (error);
if (!arr)
return NULL;
if (mono_object_domain (arr) == domain)
return arr;
- copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
+ copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
return copy;
}
MonoArray*
ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
{
- return byte_array_to_domain (arr, mono_get_root_domain ());
+ MonoError error;
+ MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
MonoArray*
ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
{
- return byte_array_to_domain (arr, mono_domain_get ());
+ MonoError error;
+ MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
+ mono_error_set_pending_exception (&error);
+ return result;
}
MonoThread *
return ret;
}
-/* FIXME: exitContext isnt documented */
-gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
+gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
{
HANDLE *handles;
guint32 numhandles;
g_free(handles);
- return ret;
+ /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
+ return ret == WAIT_FAILED ? 0x7fffffff : ret;
}
-/* FIXME: exitContext isnt documented */
-gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
+gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
{
HANDLE handles [MAXIMUM_WAIT_OBJECTS];
uintptr_t numhandles;
return ret - WAIT_ABANDONED_0;
}
else {
- return ret;
+ /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
+ return ret == WAIT_FAILED ? 0x7fffffff : ret;
}
}
-/* FIXME: exitContext isnt documented */
-gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms, gboolean exitContext)
+gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
{
guint32 ret;
MonoInternalThread *thread = mono_thread_internal_current ();
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
- return ret;
+ /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
+ return ret == WAIT_FAILED ? 0x7fffffff : ret;
}
gint32
-ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
+ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
{
guint32 ret;
MonoInternalThread *thread = mono_thread_internal_current ();
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
- return ret;
+ /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
+ return ret == WAIT_FAILED ? 0x7fffffff : ret;
}
HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
MonoObject*
ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
{
+ MonoError error;
MonoInternalThread *thread = this_obj->internal_thread;
- MonoObject *state, *deserialized = NULL, *exc;
+ MonoObject *state, *deserialized = NULL;
MonoDomain *domain;
if (!thread->abort_state_handle)
if (mono_object_domain (state) == domain)
return state;
- deserialized = mono_object_xdomain_representation (state, domain, &exc);
+ deserialized = mono_object_xdomain_representation (state, domain, &error);
if (!deserialized) {
MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
- if (exc)
+ if (!is_ok (&error)) {
+ MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
+ }
mono_set_pending_exception (invalid_op_exc);
return NULL;
}
ud.frames = g_new0 (MonoStackFrameInfo, 256);
ud.max_frames = 256;
- *out_threads = mono_array_new (domain, mono_defaults.thread_class, nthreads);
- *out_stack_frames = mono_array_new (domain, mono_defaults.array_class, nthreads);
+ *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, &error);
+ if (!is_ok (&error))
+ goto leave;
+ *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, &error);
+ if (!is_ok (&error))
+ goto leave;
for (tindex = 0; tindex < nthreads; ++tindex) {
MonoInternalThread *thread = thread_array [tindex];
mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
- thread_frames = mono_array_new (domain, mono_defaults.stack_frame_class, ud.nframes);
+ thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, &error);
+ if (!is_ok (&error))
+ goto leave;
mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
for (i = 0; i < ud.nframes; ++i) {