#include <mono/utils/mono-memory-model.h>
#include <mono/metadata/gc-internals.h>
+#include <mono/metadata/reflection-internals.h>
#ifdef HAVE_SIGNAL_H
#include <signal.h>
/* function called at thread cleanup */
static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
-/* function called to notify the runtime about a pending exception on the current thread */
-static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
-
/* The default stack size for each thread */
static guint32 default_stacksize = 0;
#define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
static void mono_init_static_data_info (StaticDataInfo *static_data);
static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
static gboolean mono_thread_resume (MonoInternalThread* thread);
-static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
-static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
-static void self_suspend_internal (MonoInternalThread *thread);
+static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
+static void self_abort_internal (void);
+static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
+static void self_suspend_internal (void);
static MonoException* mono_thread_execute_interruption (void);
static void ref_stack_destroy (gpointer rs);
static gint32 managed_thread_id_counter = 0;
+/* Class lazy loading functions */
+static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
+
static void
mono_threads_lock (void)
{
MonoString*
ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
{
+ MonoError error;
MonoString* str;
+ mono_error_init (&error);
+
LOCK_THREAD (this_obj);
if (!this_obj->name)
str = NULL;
else
- str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
+ str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
UNLOCK_THREAD (this_obj);
+
+ mono_error_raise_exception (&error);
return str;
}
}
/* FIXME: exitContext isnt documented */
-gboolean 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, gboolean exitContext)
{
HANDLE *handles;
guint32 numhandles;
g_free(handles);
- if(ret==WAIT_FAILED) {
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
- return(FALSE);
- } else if(ret==WAIT_TIMEOUT) {
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
- return(FALSE);
- }
-
- return(TRUE);
+ return ret;
}
/* FIXME: exitContext isnt documented */
}
/* FIXME: exitContext isnt documented */
-gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
+gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms, gboolean exitContext)
{
guint32 ret;
MonoInternalThread *thread = mono_thread_internal_current ();
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
- if(ret==WAIT_FAILED) {
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
- return(FALSE);
- } else if(ret==WAIT_TIMEOUT) {
- THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
- return(FALSE);
- }
-
- return(TRUE);
+ return ret;
}
-gboolean
+gint32
ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
{
guint32 ret;
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
- return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
+ return ret;
}
HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
{
MonoObject *res;
+ MONO_CHECK_NULL (location, NULL);
res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
mono_gc_wbarrier_generic_nostore (location);
return res;
throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
UNLOCK_THREAD (thread);
-
+
if (throw_) {
- abort_thread_internal (thread, TRUE, FALSE);
+ async_abort_internal (thread, FALSE);
}
}
UNLOCK_THREAD (thread);
- abort_thread_internal (thread, TRUE, TRUE);
+ if (thread == mono_thread_internal_current ())
+ self_abort_internal ();
+ else
+ async_abort_internal (thread, TRUE);
}
void
thread->state |= ThreadState_SuspendRequested;
- UNLOCK_THREAD (thread);
+ if (thread == mono_thread_internal_current ()) {
+ /* calls UNLOCK_THREAD (thread) */
+ self_suspend_internal ();
+ } else {
+ /* calls UNLOCK_THREAD (thread) */
+ async_suspend_internal (thread, FALSE);
+ }
- suspend_thread_internal (thread, FALSE);
return TRUE;
}
UNLOCK_THREAD (thread);
- abort_thread_internal (thread, TRUE, TRUE);
+ if (thread == mono_thread_internal_current ())
+ self_abort_internal ();
+ else
+ async_abort_internal (thread, TRUE);
}
void mono_thread_stop (MonoThread *thread)
thread->internal_thread->manage_callback = func;
}
-void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
-{
- mono_thread_notify_pending_exc_fn = func;
-}
-
G_GNUC_UNUSED
static void print_tids (gpointer key, gpointer value, gpointer user)
{
thread->state |= ThreadState_SuspendRequested;
- UNLOCK_THREAD (thread);
-
- /* Signal the thread to suspend */
- suspend_thread_internal (thread, TRUE);
+ /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
+ async_suspend_internal (thread, TRUE);
}
if (eventidx <= 0) {
/*
mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames)
{
MonoError error;
+
ThreadDumpUserData ud;
MonoInternalThread *thread_array [128];
MonoDomain *domain = mono_domain_get ();
if (method) {
sf->method_address = (gsize) frame->ji->code_start;
- MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
+ MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MONO_OBJECT_SETREF (sf, method, rm);
location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
if (location) {
mono_thread_execute_interruption (void)
{
MonoInternalThread *thread = mono_thread_internal_current ();
+ MonoThread *sys_thread = mono_thread_current ();
LOCK_THREAD (thread);
return thread->abort_exc;
}
else if ((thread->state & ThreadState_SuspendRequested) != 0) {
- self_suspend_internal (thread);
+ /* calls UNLOCK_THREAD (thread) */
+ self_suspend_internal ();
return NULL;
}
else if ((thread->state & ThreadState_StopRequested) != 0) {
mono_thread_exit ();
return NULL;
- } else if (thread->pending_exception) {
+ } else if (sys_thread->pending_exception) {
MonoException *exc;
- exc = thread->pending_exception;
- thread->pending_exception = NULL;
+ exc = sys_thread->pending_exception;
+ sys_thread->pending_exception = NULL;
UNLOCK_THREAD (thread);
return exc;
request count. When exiting the unmanaged method the count will be
checked and the thread will be interrupted. */
- if (mono_thread_notify_pending_exc_fn && !running_managed)
- /* The JIT will notify the thread about the interruption */
- /* This shouldn't take any locks */
- mono_thread_notify_pending_exc_fn (NULL);
-
/* this will awake the thread if it is in WaitForSingleObject
or similar */
/* Our implementation of this function ignores the func argument */
mono_thread_get_and_clear_pending_exception (void)
{
MonoInternalThread *thread = mono_thread_internal_current ();
+ MonoThread *sys_thread = mono_thread_current ();
/* The thread may already be stopping */
if (thread == NULL)
return mono_thread_execute_interruption ();
}
- if (thread->pending_exception) {
- MonoException *exc = thread->pending_exception;
+ if (sys_thread->pending_exception) {
+ MonoException *exc = sys_thread->pending_exception;
- thread->pending_exception = NULL;
+ sys_thread->pending_exception = NULL;
return exc;
}
void
mono_set_pending_exception (MonoException *exc)
{
- MonoInternalThread *thread = mono_thread_internal_current ();
+ MonoThread *thread = mono_thread_current ();
/* The thread may already be stopping */
if (thread == NULL)
MonoJitInfo *ji = NULL;
if (!info)
return NULL;
+
+ /*
+ * The suspended thread might be holding runtime locks. Make sure we don't try taking
+ * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
+ * where we hold runtime locks.
+ */
+ if (!mono_threads_is_coop_enabled ())
+ mono_thread_info_set_is_async_context (TRUE);
mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
+ if (!mono_threads_is_coop_enabled ())
+ mono_thread_info_set_is_async_context (FALSE);
return ji;
}
} AbortThreadData;
static SuspendThreadResult
-abort_thread_critical (MonoThreadInfo *info, gpointer ud)
+async_abort_critical (MonoThreadInfo *info, gpointer ud)
{
AbortThreadData *data = (AbortThreadData *)ud;
MonoInternalThread *thread = data->thread;
mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
return MonoResumeThread;
} else {
- if (mono_thread_notify_pending_exc_fn)
- /* The JIT will notify the thread about the interruption */
- mono_thread_notify_pending_exc_fn (info);
-
/*
* This will cause waits to be broken.
* It will also prevent the thread from entering a wait, so if the thread returns
}
static void
-abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
+async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
{
- AbortThreadData data = { 0 };
- data.thread = thread;
- data.install_async_abort = install_async_abort;
+ AbortThreadData data;
- /*
- FIXME this is insanely broken, it doesn't cause interruption to happen
- synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
- */
- if (thread == mono_thread_internal_current ()) {
- /* Do it synchronously */
- MonoException *exc = mono_thread_request_interruption (can_raise_exception);
- if (exc)
- mono_raise_exception (exc);
-
- mono_thread_info_self_interrupt ();
+ g_assert (thread != mono_thread_internal_current ());
- return;
- }
+ data.thread = thread;
+ data.install_async_abort = install_async_abort;
+ data.interrupt_token = NULL;
- mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_critical, &data);
+ mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
if (data.interrupt_token)
mono_thread_info_finish_interrupt (data.interrupt_token);
/*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
}
-typedef struct{
+static void
+self_abort_internal (void)
+{
+ MonoException *exc;
+
+ /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
+ * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
+
+ exc = mono_thread_request_interruption (TRUE);
+ if (exc)
+ mono_raise_exception (exc);
+
+ mono_thread_info_self_interrupt ();
+}
+
+typedef struct {
MonoInternalThread *thread;
gboolean interrupt;
MonoThreadInfoInterruptToken *interrupt_token;
} SuspendThreadData;
static SuspendThreadResult
-suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
+async_suspend_critical (MonoThreadInfo *info, gpointer ud)
{
SuspendThreadData *data = (SuspendThreadData *)ud;
MonoInternalThread *thread = data->thread;
InterlockedIncrement (&thread_interruption_requested);
if (data->interrupt)
data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
-
- if (mono_thread_notify_pending_exc_fn && !running_managed)
- /* The JIT will notify the thread about the interruption */
- mono_thread_notify_pending_exc_fn (info);
+
return MonoResumeThread;
}
}
-
+
+/* LOCKING: called with @thread synch_cs held, and releases it */
static void
-suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
+async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
{
- LOCK_THREAD (thread);
- if (thread == mono_thread_internal_current ()) {
- mono_thread_info_begin_self_suspend ();
- //XXX replace this with better named functions
- thread->state &= ~ThreadState_SuspendRequested;
- thread->state |= ThreadState_Suspended;
- UNLOCK_THREAD (thread);
- mono_thread_info_end_self_suspend ();
- } else {
- SuspendThreadData data = { 0 };
- data.thread = thread;
- data.interrupt = interrupt;
+ SuspendThreadData data;
- mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, suspend_thread_critical, &data);
- if (data.interrupt_token)
- mono_thread_info_finish_interrupt (data.interrupt_token);
- UNLOCK_THREAD (thread);
- }
+ g_assert (thread != mono_thread_internal_current ());
+
+ data.thread = thread;
+ data.interrupt = interrupt;
+ data.interrupt_token = NULL;
+
+ mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
+ if (data.interrupt_token)
+ mono_thread_info_finish_interrupt (data.interrupt_token);
+
+ UNLOCK_THREAD (thread);
}
-/*This is called with @thread synch_cs held and it must release it*/
+/* LOCKING: called with @thread synch_cs held, and releases it */
static void
-self_suspend_internal (MonoInternalThread *thread)
+self_suspend_internal (void)
{
+ MonoInternalThread *thread;
+
+ thread = mono_thread_internal_current ();
+
mono_thread_info_begin_self_suspend ();
thread->state &= ~ThreadState_SuspendRequested;
thread->state |= ThreadState_Suspended;
+
UNLOCK_THREAD (thread);
+
mono_thread_info_end_self_suspend ();
}
-
/*
* mono_thread_is_foreign:
* @thread: the thread to query
* This function allows one to determine if a thread was created by the mono runtime and has
* a well defined lifecycle or it's a foreigh one, created by the native environment.
*
- * Returns: true if @thread was not created by the runtime.
+ * Returns: TRUE if @thread was not created by the runtime.
*/
mono_bool
mono_thread_is_foreign (MonoThread *thread)
static inline gboolean
is_appdomainunloaded_exception (MonoClass *klass)
{
- static MonoClass *app_domain_unloaded_exception_klass = NULL;
-
- if (!app_domain_unloaded_exception_klass)
- app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
- g_assert (app_domain_unloaded_exception_klass);
-
- return klass == app_domain_unloaded_exception_klass;
+ return klass == mono_class_get_appdomain_unloaded_exception_class ();
}
static inline gboolean