X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fthreads.c;h=56a1ea2646be71194ebe78c192d034ce8c60dd2f;hb=4df4b7a47a07d924d7bfcfc53f43bd2319b54266;hp=e3b9e1a569dd3eccfe36042ab9c0aea4d3de9da0;hpb=52f83496133e03686f8a2ca04d258b2fa8f97b3c;p=mono.git diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index e3b9e1a569d..56a1ea2646b 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #ifndef HOST_WIN32 #include @@ -410,7 +411,11 @@ static void thread_cleanup (MonoInternalThread *thread) if (mono_thread_cleanup_fn) mono_thread_cleanup_fn (thread); - MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref); + if (mono_gc_is_moving ()) { + MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref); + thread->thread_pinning_ref = NULL; + } + } static gpointer @@ -695,13 +700,22 @@ register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg); } -MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size) +/* + * mono_thread_create_internal: + * + * If NO_DETACH is TRUE, then the thread is not detached using pthread_detach (). This is needed to fix the race condition where waiting for a thred to exit only waits for its exit event to be + * signalled, which can cause shutdown crashes if the thread shutdown code accesses data already freed by the runtime shutdown. + * Currently, this is only used for the finalizer thread. + */ +MonoInternalThread* +mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size) { MonoThread *thread; MonoInternalThread *internal; HANDLE thread_handle; struct StartInfo *start_info; gsize tid; + guint32 create_flags; thread = create_thread_object (domain); internal = create_internal_thread_object (); @@ -733,8 +747,13 @@ MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer fu /* Create suspended, so we can do some housekeeping before the thread * starts */ + create_flags = CREATE_SUSPENDED; +#ifndef HOST_WIN32 + if (no_detach) + create_flags |= CREATE_NO_DETACH; +#endif thread_handle = mono_create_thread (NULL, stack_size, (LPTHREAD_START_ROUTINE)start_wrapper, start_info, - CREATE_SUSPENDED, &tid); + create_flags, &tid); THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle)); if (thread_handle == NULL) { /* The thread couldn't be created, so throw an exception */ @@ -749,9 +768,11 @@ MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer fu internal->handle=thread_handle; internal->tid=tid; internal->apartment_state=ThreadApartmentState_Unknown; - internal->thread_pinning_ref = internal; internal->managed_id = get_next_managed_thread_id (); - MONO_GC_REGISTER_ROOT (internal->thread_pinning_ref); + if (mono_gc_is_moving ()) { + internal->thread_pinning_ref = internal; + MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref); + } internal->synch_cs = g_new0 (CRITICAL_SECTION, 1); InitializeCriticalSection (internal->synch_cs); @@ -763,13 +784,17 @@ MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer fu if (handle_store (thread)) ResumeThread (thread_handle); + /* Check that the managed and unmanaged layout of MonoInternalThread matches */ + if (mono_check_corlib_version () == NULL) + g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset); + return internal; } void mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg) { - mono_thread_create_internal (domain, func, arg, FALSE, 0); + mono_thread_create_internal (domain, func, arg, FALSE, FALSE, 0); } /* @@ -876,9 +901,11 @@ mono_thread_attach (MonoDomain *domain) thread->android_tid = (gpointer) gettid (); #endif thread->apartment_state=ThreadApartmentState_Unknown; - thread->thread_pinning_ref = thread; thread->managed_id = get_next_managed_thread_id (); - MONO_GC_REGISTER_ROOT (thread->thread_pinning_ref); + if (mono_gc_is_moving ()) { + thread->thread_pinning_ref = thread; + MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref); + } thread->stack_ptr = &tid; @@ -1045,8 +1072,10 @@ HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this, internal->handle=thread; internal->tid=tid; - internal->thread_pinning_ref = internal; - MONO_GC_REGISTER_ROOT (internal->thread_pinning_ref); + if (mono_gc_is_moving ()) { + internal->thread_pinning_ref = internal; + MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref); + } /* Don't call handle_store() here, delay it to Start. @@ -1359,6 +1388,44 @@ gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *thi return(FALSE); } +static gint32 +mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable) +{ + MonoException *exc; + guint32 ret; + gint64 start; + gint32 diff_ms; + gint32 wait = ms; + + start = (ms == -1) ? 0 : mono_100ns_ticks (); + do { + if (multiple) + ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable); + else + ret = WaitForSingleObjectEx (handles [0], ms, alertable); + + if (ret != WAIT_IO_COMPLETION) + break; + + exc = mono_thread_execute_interruption (thread); + if (exc) + mono_raise_exception (exc); + + if (ms == -1) + continue; + + /* Re-calculate ms according to the time passed */ + diff_ms = (mono_100ns_ticks () - start) / 10000; + if (diff_ms >= ms) { + ret = WAIT_TIMEOUT; + break; + } + wait = ms - diff_ms; + } while (TRUE); + + return ret; +} + /* FIXME: exitContext isnt documented */ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext) { @@ -1386,7 +1453,7 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - ret=WaitForMultipleObjectsEx(numhandles, handles, TRUE, ms, TRUE); + ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE); mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); @@ -1395,12 +1462,7 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_ if(ret==WAIT_FAILED) { THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ())); return(FALSE); - } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) { - /* Do we want to try again if we get - * WAIT_IO_COMPLETION? The documentation for - * WaitHandle doesn't give any clues. (We'd have to - * fiddle with the timeout if we retry.) - */ + } else if(ret==WAIT_TIMEOUT) { THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ())); return(FALSE); } @@ -1417,7 +1479,6 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha guint32 i; MonoObject *waitHandle; MonoInternalThread *thread = mono_thread_internal_current (); - guint32 start; /* Do this WaitSleepJoin check before creating objects */ mono_thread_current_check_pending_interrupt (); @@ -1437,20 +1498,7 @@ gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_ha mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - start = (ms == -1) ? 0 : mono_msec_ticks (); - do { - ret = WaitForMultipleObjectsEx (numhandles, handles, FALSE, ms, TRUE); - if (ret != WAIT_IO_COMPLETION) - break; - if (ms != -1) { - guint32 diff; - - diff = mono_msec_ticks () - start; - ms -= diff; - if (ms <= 0) - break; - } - } while (ms == -1 || ms > 0); + ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE); mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); @@ -1486,19 +1534,14 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this mono_thread_set_state (thread, ThreadState_WaitSleepJoin); - ret=WaitForSingleObjectEx (handle, ms, TRUE); + ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE); mono_thread_clr_state (thread, ThreadState_WaitSleepJoin); if(ret==WAIT_FAILED) { THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ())); return(FALSE); - } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) { - /* Do we want to try again if we get - * WAIT_IO_COMPLETION? The documentation for - * WaitHandle doesn't give any clues. (We'd have to - * fiddle with the timeout if we retry.) - */ + } else if(ret==WAIT_TIMEOUT) { THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ())); return(FALSE); } @@ -2054,13 +2097,14 @@ mono_thread_get_abort_signal (void) { #ifdef HOST_WIN32 return -1; -#else -#ifndef SIGRTMIN +#elif defined(PLATFORM_ANDROID) + return SIGUNUSED; +#elif !defined (SIGRTMIN) #ifdef SIGUSR1 return SIGUSR1; #else return -1; -#endif +#endif /* SIGUSR1 */ #else static int abort_signum = -1; int i; @@ -2077,7 +2121,6 @@ mono_thread_get_abort_signal (void) } /* fallback to the old way */ return SIGRTMIN; -#endif #endif /* HOST_WIN32 */ } @@ -2424,6 +2467,12 @@ ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr) return *((volatile float *) (ptr)); } +MonoObject* +ves_icall_System_Threading_Volatile_Read_T (void *ptr) +{ + return (MonoObject*)*((volatile MonoObject**)ptr); +} + void ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value) { @@ -2472,6 +2521,13 @@ ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value) *((volatile float *) ptr) = value; } +void +ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value) +{ + *((volatile MonoObject **) ptr) = value; + mono_gc_wbarrier_generic_nostore (ptr); +} + void mono_thread_init (MonoThreadStartCB start_cb, MonoThreadAttachCB attach_cb) { @@ -2851,6 +2907,10 @@ void mono_thread_manage (void) THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num)); } while(wait->num>0); +#ifndef MONO_CROSS_COMPILE + mono_runtime_shutdown (); +#endif + mono_threads_set_shutting_down (); /* No new threads will be created after this point */ @@ -3688,7 +3748,7 @@ search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 } static void -update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int max_set) +update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits) { int i; int idx = (offset >> 24) - 1; @@ -3699,7 +3759,7 @@ update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int max_set) offset &= 0xffffff; offset /= sizeof (gpointer); /* offset is now the bitmap offset */ - for (i = 0; i < max_set; ++i) { + for (i = 0; i < numbits; ++i) { if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1)))) rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1))); } @@ -3729,7 +3789,7 @@ clear_reference_bitmap (guint32 offset, guint32 size) */ guint32 -mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int max_set) +mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits) { guint32 offset; if (static_type == SPECIAL_STATIC_THREAD) { @@ -3743,7 +3803,7 @@ mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align } else { offset = mono_alloc_static_data_slot (&thread_static_info, size, align); } - update_tls_reference_bitmap (offset, bitmap, max_set); + update_tls_reference_bitmap (offset, bitmap, numbits); /* This can be called during startup */ if (threads != NULL) mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset)); @@ -3886,7 +3946,7 @@ mono_thread_alloc_tls (MonoReflectionType *type) /* TlsDatum is a struct, so we subtract the object header size offset */ bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE); size = mono_type_size (type->type, &align); - tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set); + tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1); if (bitmap != default_bitmap) g_free (bitmap); tlsrec = g_new0 (MonoTlsDataRecord, 1); @@ -4447,6 +4507,8 @@ static MonoJitInfo* mono_thread_info_get_last_managed (MonoThreadInfo *info) { MonoJitInfo *ji = NULL; + if (!info) + return NULL; mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji); return ji; } @@ -4553,10 +4615,20 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt) transition_to_suspended (thread); mono_thread_info_self_suspend (); } else { - MonoThreadInfo *info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt); - MonoJitInfo *ji = mono_thread_info_get_last_managed (info); - gboolean protected_wrapper = ji && mono_threads_is_critical_method (ji->method); - gboolean running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx)); + MonoThreadInfo *info; + MonoJitInfo *ji; + gboolean protected_wrapper; + gboolean running_managed; + + /*A null info usually means the thread is already dead. */ + if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) { + LeaveCriticalSection (thread->synch_cs); + return; + } + + ji = mono_thread_info_get_last_managed (info); + protected_wrapper = ji && mono_threads_is_critical_method (ji->method); + running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx)); if (running_managed && !protected_wrapper) { transition_to_suspended (thread);