Merge pull request #1122 from PoppermostProductions/master
[mono.git] / mono / metadata / threads.c
index 43e57280ee1f22ce9510fca0d439f5a36fc6c4bd..0867b3dee8509793a824eb9bc44ed098c762db7e 100755 (executable)
@@ -242,6 +242,13 @@ mono_thread_get_tls_offset (void)
        return offset;
 }
 
+static inline MonoNativeThreadId
+thread_get_tid (MonoInternalThread *thread)
+{
+       /* We store the tid as a guint64 to keep the object layout constant between platforms */
+       return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
+}
+
 /* handle_store() and handle_remove() manage the array of threads that
  * still need to be waited for when the main thread exits.
  *
@@ -642,6 +649,12 @@ 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)) {
+               char *tname = g_utf16_to_utf8 (internal->name, -1, NULL, NULL, NULL);
+               mono_profiler_thread_name (internal->tid, tname);
+               g_free (tname);
+       }
        /* start_func is set only for unmanaged start functions */
        if (start_func) {
                start_func (start_arg);
@@ -708,6 +721,12 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *star
        MonoNativeThreadId tid;
        guint32 create_flags;
 
+       /*
+        * Join joinable threads to prevent running out of threads since the finalizer
+        * thread might be blocked/backlogged.
+        */
+       mono_threads_join_threads ();
+
        mono_threads_lock ();
        if (shutting_down) {
                g_free (start_info);
@@ -944,13 +963,13 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
 }
 
 void
-mono_thread_detach (MonoThread *thread)
+mono_thread_detach_internal (MonoInternalThread *thread)
 {
        g_return_if_fail (thread != NULL);
 
-       THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
+       THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
 
-       thread_cleanup (thread->internal_thread);
+       thread_cleanup (thread);
 
        SET_CURRENT_OBJECT (NULL);
        mono_domain_unset ();
@@ -961,6 +980,13 @@ mono_thread_detach (MonoThread *thread)
         */
 }
 
+void
+mono_thread_detach (MonoThread *thread)
+{
+       if (thread)
+               mono_thread_detach_internal (thread->internal_thread);
+}
+
 void
 mono_thread_exit ()
 {
@@ -1182,13 +1208,10 @@ mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, g
        
        UNLOCK_THREAD (this_obj);
 
-       if (this_obj->name) {
+       if (this_obj->name && this_obj->tid) {
                char *tname = mono_string_to_utf8 (name);
-
-               if (this_obj->tid) {
-                       mono_profiler_thread_name (this_obj->tid, tname);
-                       mono_thread_info_set_name (this_obj->tid, tname);
-               }
+               mono_profiler_thread_name (this_obj->tid, tname);
+               mono_thread_info_set_name (thread_get_tid (this_obj), tname);
                mono_free (tname);
        }
 }
@@ -1322,7 +1345,7 @@ mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32
                        continue;
 
                /* Re-calculate ms according to the time passed */
-               diff_ms = (mono_100ns_ticks () - start) / 10000;
+               diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
                if (diff_ms >= ms) {
                        ret = WAIT_TIMEOUT;
                        break;
@@ -1346,7 +1369,8 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_
        /* Do this WaitSleepJoin check before creating objects */
        mono_thread_current_check_pending_interrupt ();
 
-       numhandles = mono_array_length(mono_handles);
+       /* We fail in managed if the array has more than 64 elements */
+       numhandles = (guint32)mono_array_length(mono_handles);
        handles = g_new0(HANDLE, numhandles);
 
        for(i = 0; i < numhandles; i++) {       
@@ -1381,7 +1405,7 @@ gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_
 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
 {
        HANDLE handles [MAXIMUM_WAIT_OBJECTS];
-       guint32 numhandles;
+       uintptr_t numhandles;
        guint32 ret;
        guint32 i;
        MonoObject *waitHandle;
@@ -1962,6 +1986,10 @@ static void CALLBACK interruption_request_apc (ULONG_PTR param)
  */
 static void signal_thread_state_change (MonoInternalThread *thread)
 {
+#ifndef HOST_WIN32
+       gpointer wait_handle;
+#endif
+
        if (thread == mono_thread_internal_current ()) {
                /* Do it synchronously */
                MonoException *exc = mono_thread_request_interruption (FALSE); 
@@ -1970,11 +1998,8 @@ static void signal_thread_state_change (MonoInternalThread *thread)
        }
 
 #ifdef HOST_WIN32
-       QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
+       QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, (ULONG_PTR)NULL);
 #else
-       /* fixme: store the state somewhere */
-       mono_thread_kill (thread, mono_thread_get_abort_signal ());
-
        /* 
         * This will cause waits to be broken.
         * It will also prevent the thread from entering a wait, so if the thread returns
@@ -1982,7 +2007,12 @@ static void signal_thread_state_change (MonoInternalThread *thread)
         * functions in the io-layer until the signal handler calls QueueUserAPC which will
         * make it return.
         */
-       wapi_interrupt_thread (thread->handle);
+       wait_handle = wapi_prepare_interrupt_thread (thread->handle);
+
+       /* fixme: store the state somewhere */
+       mono_thread_kill (thread, mono_thread_get_abort_signal ());
+
+       wapi_finish_interrupt_thread (wait_handle);
 #endif /* HOST_WIN32 */
 }
 
@@ -3170,7 +3200,7 @@ print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
 #endif
 
        mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
-       mono_thread_info_resume (mono_thread_info_get_tid (info));
+       mono_thread_info_finish_suspend_and_resume (info);
 
        fprintf (stdout, "%s", text->str);
 
@@ -3547,7 +3577,7 @@ static const int static_data_size [NUM_STATIC_DATA_IDX] = {
 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
 
 static void
-mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
+mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
 {
        int i;
        gpointer *static_data = addr;
@@ -3563,7 +3593,7 @@ mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
                        void ** p = ptr;
                        while (bmap) {
                                if ((bmap & 1) && *p) {
-                                       mark_func (p);
+                                       mark_func (p, gc_data);
                                }
                                p++;
                                bmap >>= 1;
@@ -3717,6 +3747,12 @@ search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32
        return NULL;
 }
 
+#if SIZEOF_VOID_P == 4
+#define ONE_P 1
+#else
+#define ONE_P 1ll
+#endif
+
 static void
 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
 {
@@ -3730,8 +3766,8 @@ update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
        offset /= sizeof (gpointer);
        /* offset is now the bitmap offset */
        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)));
+               if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
+                       rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (ONE_P << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
        }
 }
 
@@ -4144,7 +4180,9 @@ mono_thread_request_interruption (gboolean running_managed)
                   or similar */
                /* Our implementation of this function ignores the func argument */
 #ifdef HOST_WIN32
-               QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
+               QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
+#else
+               wapi_self_interrupt ();
 #endif
                return NULL;
        }
@@ -4508,13 +4546,13 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
        }
 
        if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
-               mono_thread_info_resume (mono_thread_info_get_tid (info));
+               mono_thread_info_finish_suspend_and_resume (info);
                return;
        }
 
        /*someone is already interrupting it*/
        if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
-               mono_thread_info_resume (mono_thread_info_get_tid (info));
+               mono_thread_info_finish_suspend_and_resume (info);
                return;
        }
        InterlockedIncrement (&thread_interruption_requested);
@@ -4528,9 +4566,8 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
                /*Set the thread to call */
                if (install_async_abort)
                        mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
-               mono_thread_info_resume (mono_thread_info_get_tid (info));
+               mono_thread_info_finish_suspend_and_resume (info);
        } else {
-               gpointer interrupt_handle;
                /* 
                 * This will cause waits to be broken.
                 * It will also prevent the thread from entering a wait, so if the thread returns
@@ -4539,9 +4576,10 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
                 * make it return.
                 */
 #ifndef HOST_WIN32
+               gpointer interrupt_handle;
                interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
 #endif
-               mono_thread_info_resume (mono_thread_info_get_tid (info));
+               mono_thread_info_finish_suspend_and_resume (info);
 #ifndef HOST_WIN32
                wapi_finish_interrupt_thread (interrupt_handle);
 #endif
@@ -4550,16 +4588,18 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
 }
 
 static void
-transition_to_suspended (MonoInternalThread *thread)
+transition_to_suspended (MonoInternalThread *thread, MonoThreadInfo *info)
 {
        if ((thread->state & ThreadState_SuspendRequested) == 0) {
                g_assert (0); /*FIXME we should not reach this */
                /*Make sure we balance the suspend count.*/
-               mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
+               if (info)
+                       mono_thread_info_finish_suspend_and_resume (info);
        } else {
                thread->state &= ~ThreadState_SuspendRequested;
                thread->state |= ThreadState_Suspended;
-               mono_thread_info_finish_suspend ();
+               if (info)
+                       mono_thread_info_finish_suspend (info);
        }
        UNLOCK_THREAD (thread);
 }
@@ -4574,7 +4614,7 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
 
        LOCK_THREAD (thread);
        if (thread == mono_thread_internal_current ()) {
-               transition_to_suspended (thread);
+               transition_to_suspended (thread, NULL);
                mono_thread_info_self_suspend ();
        } else {
                MonoThreadInfo *info;
@@ -4593,9 +4633,11 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
                running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
 
                if (running_managed && !protected_wrapper) {
-                       transition_to_suspended (thread);
+                       transition_to_suspended (thread, info);
                } else {
+#ifndef HOST_WIN32
                        gpointer interrupt_handle;
+#endif
 
                        if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
                                InterlockedIncrement (&thread_interruption_requested);
@@ -4603,7 +4645,7 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
                        if (interrupt)
                                interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
 #endif
-                       mono_thread_info_resume (mono_thread_info_get_tid (info));
+                       mono_thread_info_finish_suspend_and_resume (info);
 #ifndef HOST_WIN32
                        if (interrupt)
                                wapi_finish_interrupt_thread (interrupt_handle);
@@ -4653,7 +4695,7 @@ self_suspend_internal (MonoInternalThread *thread)
                return;
        }
 
-       transition_to_suspended (thread);
+       transition_to_suspended (thread, NULL);
        mono_thread_info_self_suspend ();
 }