X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fthreads.c;h=68c4b9025c0a8812e183ceb1ee2611e8f41c3bb3;hb=8e7561bc87ec87bf3d802cdbb94cc1355e9a05a6;hp=041e86866102bb75b1f9b4a8af0b50db918c3a8f;hpb=a87f458b483087b645ef4353b9393e79934ed257;p=mono.git diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index 041e8686610..68c4b9025c0 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -42,6 +42,7 @@ #include #include +#include #ifdef HAVE_SIGNAL_H #include @@ -191,9 +192,6 @@ static MonoThreadAttachCB mono_thread_attach_cb = NULL; /* 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) @@ -204,9 +202,10 @@ static void mono_free_static_data (gpointer* static_data); 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); @@ -226,6 +225,9 @@ static gboolean shutting_down = FALSE; 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) { @@ -1322,16 +1324,21 @@ mono_thread_get_managed_id (MonoThread *thread) 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; } @@ -1576,7 +1583,7 @@ mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 } /* 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; @@ -1609,15 +1616,7 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ 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 */ @@ -1669,7 +1668,7 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha } /* 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 (); @@ -1688,18 +1687,10 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this 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; @@ -1718,7 +1709,7 @@ ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, H 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) @@ -2038,6 +2029,7 @@ MonoObject* 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; @@ -2142,9 +2134,9 @@ void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj) throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin); UNLOCK_THREAD (thread); - + if (throw_) { - abort_thread_internal (thread, TRUE, FALSE); + async_abort_internal (thread, FALSE); } } @@ -2206,7 +2198,10 @@ ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject 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 @@ -2307,9 +2302,14 @@ mono_thread_suspend (MonoInternalThread *thread) 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; } @@ -2417,7 +2417,10 @@ void mono_thread_internal_stop (MonoInternalThread *thread) 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) @@ -2842,11 +2845,6 @@ mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback fu 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) { @@ -3291,10 +3289,8 @@ void mono_thread_suspend_all_other_threads (void) 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) { /* @@ -3492,12 +3488,16 @@ mono_threads_perform_thread_dump (void) static void 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 (); MonoDebugSourceLocation *location; int tindex, nthreads; + mono_error_init (&error); + *out_threads = NULL; *out_stack_frames = NULL; @@ -3534,7 +3534,9 @@ mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_fra for (i = 0; i < ud.nframes; ++i) { MonoStackFrameInfo *frame = &ud.frames [i]; MonoMethod *method = NULL; - MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class); + MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error); + if (!mono_error_ok (&error)) + goto leave; sf->native_offset = frame->native_offset; @@ -3544,7 +3546,9 @@ mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_fra 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) { @@ -3564,7 +3568,9 @@ mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_fra } } +leave: g_free (ud.frames); + mono_error_raise_exception (&error); /* FIXME don't raise here */ } /** @@ -4307,6 +4313,7 @@ static MonoException* mono_thread_execute_interruption (void) { MonoInternalThread *thread = mono_thread_internal_current (); + MonoThread *sys_thread = mono_thread_current (); LOCK_THREAD (thread); @@ -4334,7 +4341,8 @@ mono_thread_execute_interruption (void) 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) { @@ -4344,11 +4352,11 @@ mono_thread_execute_interruption (void) 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; @@ -4398,11 +4406,6 @@ mono_thread_request_interruption (gboolean running_managed) 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 */ @@ -4496,20 +4499,6 @@ mono_thread_force_interruption_checkpoint_noraise (void) return mono_thread_interruption_checkpoint_request (TRUE); } -/* - * Performs the interruption of the current thread, if one has been requested. - * Throw the exception which needs to be thrown, if any. - */ -void -mono_thread_force_interruption_checkpoint (void) -{ - MonoException *ex; - - ex = mono_thread_interruption_checkpoint_request (TRUE); - if (ex) - mono_raise_exception (ex); -} - /* * mono_thread_get_and_clear_pending_exception: * @@ -4519,6 +4508,7 @@ MonoException* 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) @@ -4528,10 +4518,10 @@ mono_thread_get_and_clear_pending_exception (void) 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; } @@ -4547,7 +4537,7 @@ mono_thread_get_and_clear_pending_exception (void) 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) @@ -4682,7 +4672,17 @@ mono_thread_info_get_last_managed (MonoThreadInfo *info) 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; } @@ -4693,7 +4693,7 @@ typedef struct { } 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; @@ -4721,10 +4721,6 @@ abort_thread_critical (MonoThreadInfo *info, gpointer ud) 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 @@ -4739,41 +4735,45 @@ abort_thread_critical (MonoThreadInfo *info, gpointer ud) } 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); + g_assert (thread != mono_thread_internal_current ()); - mono_thread_info_self_interrupt (); - - 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; @@ -4794,49 +4794,47 @@ suspend_thread_critical (MonoThreadInfo *info, gpointer ud) 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 @@ -4844,7 +4842,7 @@ self_suspend_internal (MonoInternalThread *thread) * 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) @@ -4961,13 +4959,7 @@ mono_thread_internal_check_for_interruption_critical (MonoInternalThread *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