X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mono%2Fmetadata%2Fthreads.c;h=eff73194349033fe43fc914dc0ec87141514b6a5;hb=81bd8db9cf9449aa500910c9fc9003cd77ed5244;hp=2f7fcabf081a4d25662147a77241d59472c17981;hpb=f9596050629ebf0d8d24fb256cc08f98d6d2c7e7;p=mono.git diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index 2f7fcabf081..eff73194349 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -204,7 +204,7 @@ 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 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort); -static void self_abort_internal (void); +static void self_abort_internal (MonoError *error); static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt); static void self_suspend_internal (void); @@ -257,8 +257,14 @@ mono_thread_get_tls_key (void) gint32 mono_thread_get_tls_offset (void) { - int offset; + int offset = -1; + +#ifdef HOST_WIN32 + if (current_object_key) + offset = current_object_key; +#else MONO_THREAD_VAR_OFFSET (tls_current_object,offset); +#endif return offset; } @@ -458,6 +464,8 @@ static void thread_cleanup (MonoInternalThread *thread) if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread) mono_profiler_thread_end (thread->tid); + mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); + if (thread == mono_thread_internal_current ()) { /* * This will signal async signal handlers that the thread has exited. @@ -727,12 +735,13 @@ static guint32 WINAPI start_wrapper_internal(void *data) mono_profiler_thread_start (tid); /* if the name was set before starting, we didn't invoke the profiler callback */ - if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) { + if (internal->name) { 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); + mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname); g_free (tname); } + /* start_func is set only for unmanaged start functions */ if (start_func) { start_func (start_arg); @@ -741,7 +750,8 @@ static guint32 WINAPI start_wrapper_internal(void *data) g_assert (start_delegate != NULL); args [0] = start_arg; /* we may want to handle the exception here. See comment below on unhandled exceptions */ - mono_runtime_delegate_invoke (start_delegate, args, NULL); + mono_runtime_delegate_invoke_checked (start_delegate, args, &error); + mono_error_raise_exception (&error); /* FIXME don't raise here */ } /* If the thread calls ExitThread at all, this remaining code @@ -879,9 +889,9 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *star */ THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid)); - MONO_PREPARE_BLOCKING; + MONO_ENTER_GC_SAFE; WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE); - MONO_FINISH_BLOCKING; + MONO_EXIT_GC_SAFE; CloseHandle (internal->start_notify); internal->start_notify = NULL; @@ -1129,7 +1139,8 @@ ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj) MonoInternalThread *internal; internal = create_internal_thread (&error); - mono_error_raise_exception (&error); + if (mono_error_set_pending_exception (&error)) + return; internal->state = ThreadState_Unstarted; @@ -1224,7 +1235,8 @@ ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms) THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms)); - mono_thread_current_check_pending_interrupt (); + if (mono_thread_current_check_pending_interrupt ()) + return; while (TRUE) { gboolean alerted = FALSE; @@ -1238,7 +1250,8 @@ ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms) if (alerted) { MonoException* exc = mono_thread_execute_interruption (); if (exc) { - mono_raise_exception (exc); + mono_set_pending_exception (exc); + return; } else { // FIXME: !INFINITE if (ms != INFINITE) @@ -1358,19 +1371,20 @@ ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj UNLOCK_THREAD (this_obj); - mono_error_raise_exception (&error); + if (mono_error_set_pending_exception (&error)) + return NULL; return str; } void -mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed, MonoError *error) +mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error) { LOCK_THREAD (this_obj); mono_error_init (error); - if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) { + if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) { UNLOCK_THREAD (this_obj); mono_error_set_invalid_operation (error, "Thread.Name can only be set once."); @@ -1384,19 +1398,20 @@ mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, g this_obj->name = g_new (gunichar2, mono_string_length (name)); memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2); this_obj->name_len = mono_string_length (name); + + if (permanent) + this_obj->flags |= MONO_THREAD_FLAG_NAME_SET; } else this_obj->name = NULL; - if (managed) - this_obj->flags |= MONO_THREAD_FLAG_NAME_SET; UNLOCK_THREAD (this_obj); if (this_obj->name && this_obj->tid) { char *tname = mono_string_to_utf8 (name); mono_profiler_thread_name (this_obj->tid, tname); - mono_thread_info_set_name (thread_get_tid (this_obj), tname); + mono_native_thread_set_name (thread_get_tid (this_obj), tname); mono_free (tname); } } @@ -1536,7 +1551,8 @@ ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms) MonoInternalThread *cur_thread = mono_thread_internal_current (); gboolean ret; - mono_thread_current_check_pending_interrupt (); + if (mono_thread_current_check_pending_interrupt ()) + return FALSE; LOCK_THREAD (thread); @@ -1556,9 +1572,9 @@ ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms) mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin); - MONO_PREPARE_BLOCKING; + MONO_ENTER_GC_SAFE; ret=WaitForSingleObjectEx (handle, ms, TRUE); - MONO_FINISH_BLOCKING; + MONO_EXIT_GC_SAFE; mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin); @@ -1573,8 +1589,17 @@ ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms) return(FALSE); } +#define MANAGED_WAIT_FAILED 0x7fffffff + +static gint32 +map_native_wait_result_to_managed (gint32 val) +{ + /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */ + return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val; +} + static gint32 -mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable) +mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error) { MonoException *exc; guint32 ret; @@ -1582,21 +1607,25 @@ mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 gint32 diff_ms; gint32 wait = ms; + mono_error_init (error); + start = (ms == -1) ? 0 : mono_100ns_ticks (); do { - MONO_PREPARE_BLOCKING; - if (multiple) - ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable); + MONO_ENTER_GC_SAFE; + if (numhandles != 1) + ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE); else - ret = WaitForSingleObjectEx (handles [0], ms, alertable); - MONO_FINISH_BLOCKING; + ret = WaitForSingleObjectEx (handles [0], ms, TRUE); + MONO_EXIT_GC_SAFE; if (ret != WAIT_IO_COMPLETION) break; exc = mono_thread_execute_interruption (); - if (exc) - mono_raise_exception (exc); + if (exc) { + mono_error_set_exception_instance (error, exc); + break; + } if (ms == -1) continue; @@ -1615,6 +1644,7 @@ mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms) { + MonoError error; HANDLE *handles; guint32 numhandles; guint32 ret; @@ -1623,7 +1653,8 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ha MonoInternalThread *thread = mono_thread_internal_current (); /* Do this WaitSleepJoin check before creating objects */ - mono_thread_current_check_pending_interrupt (); + if (mono_thread_current_check_pending_interrupt ()) + return map_native_wait_result_to_managed (WAIT_FAILED); /* We fail in managed if the array has more than 64 elements */ numhandles = (guint32)mono_array_length(mono_handles); @@ -1639,19 +1670,22 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ha } mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - - ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE); + + ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error); mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); g_free(handles); + mono_error_set_pending_exception (&error); + /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */ - return ret == WAIT_FAILED ? 0x7fffffff : ret; + return map_native_wait_result_to_managed (ret); } gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms) { + MonoError error; HANDLE handles [MAXIMUM_WAIT_OBJECTS]; uintptr_t numhandles; guint32 ret; @@ -1660,11 +1694,12 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha MonoInternalThread *thread = mono_thread_internal_current (); /* Do this WaitSleepJoin check before creating objects */ - mono_thread_current_check_pending_interrupt (); + if (mono_thread_current_check_pending_interrupt ()) + return map_native_wait_result_to_managed (WAIT_FAILED); numhandles = mono_array_length(mono_handles); if (numhandles > MAXIMUM_WAIT_OBJECTS) - return WAIT_FAILED; + return map_native_wait_result_to_managed (WAIT_FAILED); for(i = 0; i < numhandles; i++) { waitHandle = mono_array_get(mono_handles, MonoObject*, i); @@ -1677,29 +1712,31 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE); + ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error); mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret)); + mono_error_set_pending_exception (&error); /* * These need to be here. See MSDN dos on WaitForMultipleObjects. */ if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) { - return ret - WAIT_OBJECT_0; + return map_native_wait_result_to_managed (ret - WAIT_OBJECT_0); } else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) { - return ret - WAIT_ABANDONED_0; + return map_native_wait_result_to_managed (ret - WAIT_ABANDONED_0); } else { /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */ - return ret == WAIT_FAILED ? 0x7fffffff : ret; + return map_native_wait_result_to_managed (ret); } } gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms) { + MonoError error; guint32 ret; MonoInternalThread *thread = mono_thread_internal_current (); @@ -1709,16 +1746,17 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gin ms=INFINITE; } - mono_thread_current_check_pending_interrupt (); + if (mono_thread_current_check_pending_interrupt ()) + return map_native_wait_result_to_managed (WAIT_FAILED); mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE); + ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error); mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); - - /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */ - return ret == WAIT_FAILED ? 0x7fffffff : ret; + + mono_error_set_pending_exception (&error); + return map_native_wait_result_to_managed (ret == WAIT_FAILED); } gint32 @@ -1730,18 +1768,18 @@ ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, H if (ms == -1) ms = INFINITE; - mono_thread_current_check_pending_interrupt (); + if (mono_thread_current_check_pending_interrupt ()) + return map_native_wait_result_to_managed (WAIT_FAILED); mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - MONO_PREPARE_BLOCKING; + MONO_ENTER_GC_SAFE; ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE); - MONO_FINISH_BLOCKING; + MONO_EXIT_GC_SAFE; mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); - /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */ - return ret == WAIT_FAILED ? 0x7fffffff : ret; + return map_native_wait_result_to_managed (ret); } HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created) @@ -2172,7 +2210,15 @@ void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj) } } -void mono_thread_current_check_pending_interrupt () +/** + * mono_thread_current_check_pending_interrupt: + * + * Checks if there's a interruption request and set the pending exception if so. + * + * @returns true if a pending exception was set + */ +gboolean +mono_thread_current_check_pending_interrupt (void) { MonoInternalThread *thread = mono_thread_internal_current (); gboolean throw_ = FALSE; @@ -2186,13 +2232,13 @@ void mono_thread_current_check_pending_interrupt () UNLOCK_THREAD (thread); - if (throw_) { - mono_raise_exception (mono_get_exception_thread_interrupted ()); - } + if (throw_) + mono_set_pending_exception (mono_get_exception_thread_interrupted ()); + return throw_; } -void -ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state) +static gboolean +request_thread_abort (MonoInternalThread *thread, MonoObject *state) { LOCK_THREAD (thread); @@ -2201,13 +2247,13 @@ ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject (thread->state & ThreadState_Stopped) != 0) { UNLOCK_THREAD (thread); - return; + return FALSE; } if ((thread->state & ThreadState_Unstarted) != 0) { thread->state |= ThreadState_Aborted; UNLOCK_THREAD (thread); - return; + return FALSE; } thread->state |= ThreadState_AbortRequested; @@ -2229,11 +2275,39 @@ ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject mono_thread_resume (thread); UNLOCK_THREAD (thread); + return TRUE; +} - if (thread == mono_thread_internal_current ()) - self_abort_internal (); - else +void +ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state) +{ + if (!request_thread_abort (thread, state)) + return; + + if (thread == mono_thread_internal_current ()) { + MonoError error; + self_abort_internal (&error); + mono_error_set_pending_exception (&error); + } else { async_abort_internal (thread, TRUE); + } +} + +/** + * mono_thread_internal_abort: + * + * Request thread @thread to be aborted. + * + * @thread MUST NOT be the current thread. + */ +void +mono_thread_internal_abort (MonoInternalThread *thread) +{ + g_assert (thread != mono_thread_internal_current ()); + + if (!request_thread_abort (thread, NULL)) + return; + async_abort_internal (thread, TRUE); } void @@ -2433,7 +2507,8 @@ is_running_protected_wrapper (void) return found; } -void mono_thread_internal_stop (MonoInternalThread *thread) +static gboolean +request_thread_stop (MonoInternalThread *thread) { LOCK_THREAD (thread); @@ -2441,7 +2516,7 @@ void mono_thread_internal_stop (MonoInternalThread *thread) (thread->state & ThreadState_Stopped) != 0) { UNLOCK_THREAD (thread); - return; + return FALSE; } /* Make sure the thread is awake */ @@ -2451,16 +2526,45 @@ void mono_thread_internal_stop (MonoInternalThread *thread) thread->state &= ~ThreadState_AbortRequested; UNLOCK_THREAD (thread); + return TRUE; +} + +/** + * mono_thread_internal_stop: + * + * Request thread @thread to stop. + * + * @thread MUST NOT be the current thread. + */ +void +mono_thread_internal_stop (MonoInternalThread *thread) +{ + g_assert (thread != mono_thread_internal_current ()); + + if (!request_thread_stop (thread)) + return; - if (thread == mono_thread_internal_current ()) - self_abort_internal (); - else - async_abort_internal (thread, TRUE); + async_abort_internal (thread, TRUE); } void mono_thread_stop (MonoThread *thread) { - mono_thread_internal_stop (thread->internal_thread); + MonoInternalThread *internal = thread->internal_thread; + + if (!request_thread_stop (internal)) + return; + + if (internal == mono_thread_internal_current ()) { + MonoError error; + self_abort_internal (&error); + /* + This function is part of the embeding API and has no way to return the exception + to be thrown. So what we do is keep the old behavior and raise the exception. + */ + mono_error_raise_exception (&error); + } else { + async_abort_internal (internal, TRUE); + } } gint8 @@ -2905,9 +3009,9 @@ static void wait_for_tids (struct wait_data *wait, guint32 timeout) THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num)); - MONO_PREPARE_BLOCKING; + MONO_ENTER_GC_SAFE; ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE); - MONO_FINISH_BLOCKING; + MONO_EXIT_GC_SAFE; if(ret==WAIT_FAILED) { /* See the comment in build_wait_tids() */ @@ -2968,9 +3072,9 @@ static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeo count++; } - MONO_PREPARE_BLOCKING; + MONO_ENTER_GC_SAFE; ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE); - MONO_FINISH_BLOCKING; + MONO_EXIT_GC_SAFE; if(ret==WAIT_FAILED) { /* See the comment in build_wait_tids() */ @@ -3077,9 +3181,8 @@ remove_and_abort_threads (gpointer key, gpointer value, gpointer user) if (handle == NULL) return FALSE; - /* printf ("A: %d\n", wait->num); */ - wait->handles[wait->num]=thread->handle; - wait->threads[wait->num]=thread; + wait->handles[wait->num] = handle; + wait->threads[wait->num] = thread; wait->num++; THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid)); @@ -3790,7 +3893,7 @@ mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout) #endif abort_appdomain_data user_data; - guint32 start_time; + gint64 start_time; int orig_timeout = timeout; int i; @@ -3809,7 +3912,7 @@ mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout) if (user_data.wait.num > 0) { /* Abort the threads outside the threads lock */ for (i = 0; i < user_data.wait.num; ++i) - ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL); + mono_thread_internal_abort (user_data.wait.threads [i]); /* * We should wait for the threads either to abort, or to leave the @@ -4370,8 +4473,18 @@ mono_thread_execute_interruption (void) mono_thread_info_clear_self_interrupt (); } - if ((thread->state & ThreadState_AbortRequested) != 0) { + /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */ + if (sys_thread->pending_exception) { + MonoException *exc; + + exc = sys_thread->pending_exception; + sys_thread->pending_exception = NULL; + + UNLOCK_THREAD (thread); + return exc; + } else if ((thread->state & ThreadState_AbortRequested) != 0) { UNLOCK_THREAD (thread); + g_assert (sys_thread->pending_exception == NULL); if (thread->abort_exc == NULL) { /* * This might be racy, but it has to be called outside the lock @@ -4393,14 +4506,6 @@ mono_thread_execute_interruption (void) mono_thread_exit (); return NULL; - } else if (sys_thread->pending_exception) { - MonoException *exc; - - exc = sys_thread->pending_exception; - sys_thread->pending_exception = NULL; - - UNLOCK_THREAD (thread); - return exc; } else if (thread->thread_interrupt_requested) { thread->thread_interrupt_requested = FALSE; @@ -4764,18 +4869,20 @@ async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort) } static void -self_abort_internal (void) +self_abort_internal (MonoError *error) { MonoException *exc; + mono_error_init (error); + /* 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 (); + mono_error_set_exception_instance (error, exc); + else + mono_thread_info_self_interrupt (); } typedef struct {