Merge branch 'BigIntegerParse'
[mono.git] / mono / utils / mono-threads.c
index e3160eff1f4d486a60fe4bf33b33b88ee9dfdc90..d56564f86a7f419bce39ac4434d85351fa301435 100644 (file)
@@ -14,8 +14,6 @@
 #include <mono/utils/mono-tls.h>
 #include <mono/utils/hazard-pointer.h>
 #include <mono/utils/mono-memory-model.h>
-#include <mono/metadata/appdomain.h>
-#include <mono/metadata/domain-internals.h>
 
 #include <errno.h>
 
@@ -170,6 +168,8 @@ unregister_thread (void *arg)
 
        THREADS_DEBUG ("unregistering info %p\n", info);
 
+       mono_threads_core_unregister (info);
+
        /*
         * TLS destruction order is not reliable so small_id might be cleaned up
         * before us.
@@ -177,7 +177,23 @@ unregister_thread (void *arg)
        mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
 
        info->thread_state = STATE_SHUTTING_DOWN;
+
+       /*
+       First perform the callback that requires no locks.
+       This callback has the potential of taking other locks, so we do it before.
+       After it completes, the thread remains functional.
+       */
+       if (threads_callbacks.thread_detach)
+               threads_callbacks.thread_detach (info);
+
        mono_thread_info_suspend_lock ();
+
+       /*
+       Now perform the callback that must be done under locks.
+       This will render the thread useless and non-suspendable, so it must
+       be done while holding the suspend lock to give no other thread chance
+       to suspend it.
+       */
        if (threads_callbacks.thread_unregister)
                threads_callbacks.thread_unregister (info);
        mono_threads_unregister_current_thread (info);
@@ -270,14 +286,14 @@ mono_thread_info_attach (void *baseptr)
 }
 
 void
-mono_thread_info_dettach (void)
+mono_thread_info_detach (void)
 {
        MonoThreadInfo *info;
        if (!mono_threads_inited)
        {
                /* This can happen from DllMain(THREAD_DETACH) on Windows, if a thread
                 * is created before an embedding API user initialized Mono. */
-               THREADS_DEBUG ("mono_thread_info_dettach called before mono_threads_init\n");
+               THREADS_DEBUG ("mono_thread_info_detach called before mono_threads_init\n");
                return;
        }
        info = mono_native_tls_get_value (thread_info_key);
@@ -431,9 +447,17 @@ mono_thread_info_resume (MonoNativeThreadId tid)
        gboolean result = TRUE;
        MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();      
        MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
+
        if (!info)
                return FALSE;
 
+       if (info->create_suspended) {
+               /* Have to special case this, as the normal suspend/resume pair are racy, they don't work if he resume is received before the suspend */
+               info->create_suspended = FALSE;
+               mono_threads_core_resume_created (info, tid);
+               return TRUE;
+       }
+
        MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
 
        THREADS_DEBUG ("resume %x IN COUNT %d\n",tid, info->suspend_count);
@@ -479,6 +503,10 @@ is_thread_in_critical_region (MonoThreadInfo *info)
        if (info->inside_critical_region)
                return TRUE;
 
+       /* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
+       if (!info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN])
+               return FALSE;
+
        ji = mono_jit_info_table_find (
                info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN],
                MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
@@ -670,3 +698,77 @@ mono_thread_info_is_async_context (void)
                return FALSE;
 }
 
+/*
+ * mono_threads_create_thread:
+ *
+ *   Create a new thread executing START with argument ARG. Store its id into OUT_TID.
+ * Returns: a windows or io-layer handle for the thread.
+ */
+HANDLE
+mono_threads_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
+{
+       return mono_threads_core_create_thread (start, arg, stack_size, creation_flags, out_tid);
+}
+
+/*
+ * mono_thread_info_get_stack_bounds:
+ *
+ *   Return the address and size of the current threads stack. Return NULL as the 
+ * stack address if the stack address cannot be determined.
+ */
+void
+mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize)
+{
+       return mono_threads_core_get_stack_bounds (staddr, stsize);
+}
+
+gboolean
+mono_thread_info_yield (void)
+{
+       return mono_threads_core_yield ();
+}
+
+gpointer
+mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key)
+{
+       return ((MonoThreadInfo*)info)->tls [key];
+}
+
+/*
+ * mono_threads_info_tls_set:
+ *
+ *   Set the TLS key to VALUE in the info structure. This can be used to obtain
+ * values of TLS variables for threads other than the current thread.
+ * This should only be used for infrequently changing TLS variables, and it should
+ * be paired with setting the real TLS variable since this provides no GC tracking.
+ */
+void
+mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value)
+{
+       ((MonoThreadInfo*)info)->tls [key] = value;
+}
+
+/*
+ * mono_thread_info_exit:
+ *
+ *   Exit the current thread.
+ * This function doesn't return.
+ */
+void
+mono_thread_info_exit (void)
+{
+       mono_threads_core_exit (0);
+}
+
+/*
+ * mono_thread_info_open_handle:
+ *
+ *   Return a io-layer/win32 handle for the current thread.
+ * The handle need to be closed by calling CloseHandle () when it is no
+ * longer needed.
+ */
+HANDLE
+mono_thread_info_open_handle (void)
+{
+       return mono_threads_core_open_handle ();
+}