Merge pull request #1949 from lewurm/fixtype
[mono.git] / mono / metadata / threads.c
index cfd6f9e2e8a9dd098fda9bc773e76fba6047e375..fd83f30929e108812f54c1f0106c4e16f4b3e401 100644 (file)
@@ -20,7 +20,6 @@
 #include <mono/metadata/domain-internals.h>
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/threads.h>
-#include <mono/metadata/threadpool.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/exception.h>
 #include <mono/metadata/environment.h>
@@ -156,10 +155,6 @@ static GHashTable *contexts = NULL;
  * Protected by mono_threads_lock ().
  */
 static MonoGHashTable *threads_starting_up = NULL;
-/* Maps a MonoThread to its start argument */
-/* Protected by mono_threads_lock () */
-static MonoGHashTable *thread_start_args = NULL;
 
 /* The TLS key that holds the MonoObject assigned to each thread */
 static MonoNativeTlsKey current_object_key;
@@ -211,7 +206,7 @@ static void suspend_thread_internal (MonoInternalThread *thread, gboolean interr
 static void self_suspend_internal (MonoInternalThread *thread);
 static gboolean resume_thread_internal (MonoInternalThread *thread);
 
-static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
+static MonoException* mono_thread_execute_interruption ();
 static void ref_stack_destroy (gpointer rs);
 
 /* Spin lock for InterlockedXXX 64 bit functions */
@@ -229,13 +224,12 @@ static gboolean shutting_down = FALSE;
 
 static gint32 managed_thread_id_counter = 0;
 
-
 static void
 mono_threads_lock (void)
 {
-       MONO_TRY_BLOCKING
+       MONO_TRY_BLOCKING;
        mono_locks_acquire (&threads_mutex, ThreadsLock);
-       MONO_FINISH_TRY_BLOCKING
+       MONO_FINISH_TRY_BLOCKING;
 }
 
 static void
@@ -293,8 +287,8 @@ static gboolean handle_store(MonoThread *thread, gboolean force_attach)
        }
 
        if(threads==NULL) {
-               MONO_GC_REGISTER_ROOT_FIXED (threads);
-               threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
+               MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
+               threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
        }
 
        /* We don't need to duplicate thread->handle, because it is
@@ -380,9 +374,9 @@ lock_thread (MonoInternalThread *thread)
 
        g_assert (thread->synch_cs);
 
-       MONO_TRY_BLOCKING
+       MONO_TRY_BLOCKING;
        mono_mutex_lock (thread->synch_cs);
-       MONO_FINISH_TRY_BLOCKING
+       MONO_FINISH_TRY_BLOCKING;
 }
 
 static inline void
@@ -454,7 +448,7 @@ static void thread_cleanup (MonoInternalThread *thread)
                }
                /* This needs to be called even if handle_remove () fails */
                if (mono_thread_cleanup_fn)
-                       mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
+                       mono_thread_cleanup_fn (thread_get_tid (thread));
                return;
        }
        mono_release_type_locks (thread);
@@ -481,7 +475,7 @@ static void thread_cleanup (MonoInternalThread *thread)
        thread->appdomain_refs = NULL;
 
        if (mono_thread_cleanup_fn)
-               mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
+               mono_thread_cleanup_fn (thread_get_tid (thread));
 
        if (mono_gc_is_moving ()) {
                MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
@@ -499,9 +493,15 @@ static void thread_cleanup (MonoInternalThread *thread)
 
 typedef union {
        struct {
+#if G_BYTE_ORDER != G_LITTLE_ENDIAN
+               guint32 type : 1;
+               guint32 offset : 25;
+               guint32 index : 6;
+#else
                guint32 index : 6;
                guint32 offset : 25;
                guint32 type : 1;
+#endif
        } fields;
        guint32 raw;
 } SpecialStaticOffset;
@@ -599,7 +599,7 @@ create_internal_thread (void)
        thread->managed_id = get_next_managed_thread_id ();
        if (mono_gc_is_moving ()) {
                thread->thread_pinning_ref = thread;
-               MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
+               MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
        }
 
        return thread;
@@ -645,7 +645,7 @@ static guint32 WINAPI start_wrapper_internal(void *data)
        internal->thread_info = info;
        internal->small_id = info->small_id;
 
-       tid=internal->tid;
+       tid = internal->tid;
 
        SET_CURRENT_OBJECT (internal);
 
@@ -660,7 +660,9 @@ static guint32 WINAPI start_wrapper_internal(void *data)
        }
 
        start_func = start_info->func;
-       start_arg = start_info->start_arg;
+       start_arg = start_info->obj->start_obj;
+       if (!start_arg)
+               start_arg = start_info->start_arg;
 
        /* We have to do this here because mono_thread_new_init()
           requires that root_domain_thread is set up. */
@@ -692,13 +694,6 @@ static guint32 WINAPI start_wrapper_internal(void *data)
                ReleaseSemaphore (internal->start_notify, 1, NULL);
        }
 
-       mono_threads_lock ();
-       mono_g_hash_table_remove (thread_start_args, start_info->obj);
-       mono_threads_unlock ();
-
-       mono_thread_set_execution_context (start_info->obj->ec_to_set);
-       start_info->obj->ec_to_set = NULL;
-
        g_free (start_info);
        THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
                                                         internal->tid));
@@ -794,20 +789,9 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *star
                mono_threads_unlock ();
                return FALSE;
        }
-       /*
-        * The thread start argument may be an object reference, and there is
-        * no ref to keep it alive when the new thread is started but not yet
-        * registered with the collector. So we store it in a GC tracked hash
-        * table.
-        */
-       if (thread_start_args == NULL) {
-               MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
-               thread_start_args = mono_g_hash_table_new (NULL, NULL);
-       }
-       mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
        if (threads_starting_up == NULL) {
-               MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
-               threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
+               MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
+               threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
        }
        mono_g_hash_table_insert (threads_starting_up, thread, thread);
        mono_threads_unlock ();
@@ -830,10 +814,10 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *star
         */
        create_flags = CREATE_SUSPENDED;
 
-       MONO_PREPARE_BLOCKING
+       MONO_PREPARE_BLOCKING;
        thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
                                                                                                stack_size, create_flags, &tid);
-       MONO_FINISH_BLOCKING
+       MONO_FINISH_BLOCKING;
 
        if (thread_handle == NULL) {
                /* The thread couldn't be created, so throw an exception */
@@ -865,9 +849,9 @@ create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *star
        if (!handle_store (thread, FALSE))
                return FALSE;
 
-       MONO_PREPARE_BLOCKING
+       MONO_PREPARE_BLOCKING;
        mono_thread_info_resume (tid);
-       MONO_FINISH_BLOCKING
+       MONO_FINISH_BLOCKING;
 
        if (internal->start_notify) {
                /*
@@ -878,9 +862,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__, GetCurrentThreadId (), internal, (gsize)internal->tid));
 
-               MONO_PREPARE_BLOCKING
+               MONO_PREPARE_BLOCKING;
                WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
-               MONO_FINISH_BLOCKING
+               MONO_FINISH_BLOCKING;
 
                CloseHandle (internal->start_notify);
                internal->start_notify = NULL;
@@ -910,7 +894,8 @@ guint32 mono_threads_get_default_stacksize (void)
 
 /*
  * mono_thread_create_internal:
- * 
+ *
+ *   ARG should not be a GC reference.
  */
 MonoInternalThread*
 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
@@ -979,8 +964,8 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
 
        tid=GetCurrentThreadId ();
 
-       thread->handle=thread_handle;
-       thread->tid=tid;
+       thread->handle = thread_handle;
+       thread->tid = tid;
        thread->stack_ptr = &tid;
 
        THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
@@ -1092,28 +1077,28 @@ mono_thread_exit ()
 }
 
 void
-ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
+ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
 {
        MonoInternalThread *internal = create_internal_thread ();
 
        internal->state = ThreadState_Unstarted;
 
-       InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
+       InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
 }
 
 HANDLE
-ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
+ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
                                                                                                   MonoObject *start)
 {
        StartInfo *start_info;
        MonoInternalThread *internal;
        gboolean res;
 
-       THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
+       THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
 
-       if (!this->internal_thread)
-               ves_icall_System_Threading_Thread_ConstructInternalThread (this);
-       internal = this->internal_thread;
+       if (!this_obj->internal_thread)
+               ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
+       internal = this_obj->internal_thread;
 
        LOCK_THREAD (internal);
 
@@ -1125,17 +1110,17 @@ ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
 
        if ((internal->state & ThreadState_Aborted) != 0) {
                UNLOCK_THREAD (internal);
-               return this;
+               return this_obj;
        }
        /* This is freed in start_wrapper */
        start_info = g_new0 (StartInfo, 1);
        start_info->func = NULL;
-       start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
+       start_info->start_arg = NULL;
        start_info->delegate = start;
-       start_info->obj = this;
-       g_assert (this->obj.vtable->domain == mono_domain_get ());
+       start_info->obj = this_obj;
+       g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
 
-       res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
+       res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
        if (!res) {
                UNLOCK_THREAD (internal);
                return NULL;
@@ -1153,7 +1138,7 @@ ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
  * This is called from the finalizer of the internal thread object.
  */
 void
-ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
+ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
 {
        THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
 
@@ -1165,16 +1150,16 @@ ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThre
        if (thread)
                CloseHandle (thread);
 
-       if (this->synch_cs) {
-               mono_mutex_t *synch_cs = this->synch_cs;
-               this->synch_cs = NULL;
+       if (this_obj->synch_cs) {
+               mono_mutex_t *synch_cs = this_obj->synch_cs;
+               this_obj->synch_cs = NULL;
                mono_mutex_destroy (synch_cs);
                g_free (synch_cs);
        }
 
-       if (this->name) {
-               void *name = this->name;
-               this->name = NULL;
+       if (this_obj->name) {
+               void *name = this_obj->name;
+               this_obj->name = NULL;
                g_free (name);
        }
 }
@@ -1192,14 +1177,14 @@ ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
        while (TRUE) {
                mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
        
-               MONO_PREPARE_BLOCKING
+               MONO_PREPARE_BLOCKING;
                res = SleepEx(ms,TRUE);
-               MONO_FINISH_BLOCKING
+               MONO_FINISH_BLOCKING;
        
                mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
 
                if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
-                       MonoException* exc = mono_thread_execute_interruption (thread);
+                       MonoException* exc = mono_thread_execute_interruption ();
                        if (exc) {
                                mono_raise_exception (exc);
                        } else {
@@ -1317,13 +1302,13 @@ ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj
 }
 
 int
-ves_icall_System_Threading_Thread_GetPriority (MonoInternalThread *thread)
+ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
 {
        return ThreadPriority_Lowest;
 }
 
 void
-ves_icall_System_Threading_Thread_SetPriority (MonoInternalThread *thread, int priority)
+ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
 {
 }
 
@@ -1383,35 +1368,36 @@ mono_thread_internal_current (void)
 }
 
 gboolean
-ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
-                                                                                               int ms, HANDLE thread)
+ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
 {
+       MonoInternalThread *thread = this_obj->internal_thread;
+       HANDLE handle = thread->handle;
        MonoInternalThread *cur_thread = mono_thread_internal_current ();
        gboolean ret;
 
        mono_thread_current_check_pending_interrupt ();
 
-       LOCK_THREAD (this);
+       LOCK_THREAD (thread);
        
-       if ((this->state & ThreadState_Unstarted) != 0) {
-               UNLOCK_THREAD (this);
+       if ((thread->state & ThreadState_Unstarted) != 0) {
+               UNLOCK_THREAD (thread);
                
                mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
                return FALSE;
        }
 
-       UNLOCK_THREAD (this);
+       UNLOCK_THREAD (thread);
 
        if(ms== -1) {
                ms=INFINITE;
        }
-       THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
+       THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
        
        mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
 
-       MONO_PREPARE_BLOCKING
-       ret=WaitForSingleObjectEx (thread, ms, TRUE);
-       MONO_FINISH_BLOCKING
+       MONO_PREPARE_BLOCKING;
+       ret=WaitForSingleObjectEx (handle, ms, TRUE);
+       MONO_FINISH_BLOCKING;
 
        mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
        
@@ -1437,17 +1423,17 @@ mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32
 
        start = (ms == -1) ? 0 : mono_100ns_ticks ();
        do {
-               MONO_PREPARE_BLOCKING
+               MONO_PREPARE_BLOCKING;
                        if (multiple)
                        ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
                else
                        ret = WaitForSingleObjectEx (handles [0], ms, alertable);
-               MONO_FINISH_BLOCKING
+               MONO_FINISH_BLOCKING;
 
                if (ret != WAIT_IO_COMPLETION)
                        break;
 
-               exc = mono_thread_execute_interruption (thread);
+               exc = mono_thread_execute_interruption ();
                if (exc)
                        mono_raise_exception (exc);
 
@@ -1560,7 +1546,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, HANDLE handle, gint32 ms, gboolean exitContext)
+gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
 {
        guint32 ret;
        MonoInternalThread *thread = mono_thread_internal_current ();
@@ -1603,9 +1589,9 @@ ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, H
 
        mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
        
-       MONO_PREPARE_BLOCKING
+       MONO_PREPARE_BLOCKING;
        ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
-       MONO_FINISH_BLOCKING
+       MONO_FINISH_BLOCKING;
        
        mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
 
@@ -2019,22 +2005,23 @@ ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
        return state;
 }
 
-void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
+void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
 {
        MonoInternalThread *current;
        gboolean throw;
+       MonoInternalThread *thread = this_obj->internal_thread;
 
-       LOCK_THREAD (this);
+       LOCK_THREAD (thread);
 
        current = mono_thread_internal_current ();
 
-       this->thread_interrupt_requested = TRUE;        
-       throw = current != this && (this->state & ThreadState_WaitSleepJoin);   
+       thread->thread_interrupt_requested = TRUE;
+       throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
 
-       UNLOCK_THREAD (this);
+       UNLOCK_THREAD (thread);
        
        if (throw) {
-               abort_thread_internal (this, TRUE, FALSE);
+               abort_thread_internal (thread, TRUE, FALSE);
        }
 }
 
@@ -2100,7 +2087,7 @@ ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject
 }
 
 void
-ves_icall_System_Threading_Thread_ResetAbort (void)
+ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
 {
        MonoInternalThread *thread = mono_thread_internal_current ();
        gboolean was_aborting;
@@ -2145,9 +2132,9 @@ mono_thread_internal_reset_abort (MonoInternalThread *thread)
 }
 
 MonoObject*
-ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
+ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
 {
-       MonoInternalThread *thread = this->internal_thread;
+       MonoInternalThread *thread = this_obj->internal_thread;
        MonoObject *state, *deserialized = NULL, *exc;
        MonoDomain *domain;
 
@@ -2204,9 +2191,9 @@ mono_thread_suspend (MonoInternalThread *thread)
 }
 
 void
-ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
+ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
 {
-       if (!mono_thread_suspend (thread)) {
+       if (!mono_thread_suspend (this_obj->internal_thread)) {
                mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
                return;
        }
@@ -2580,6 +2567,24 @@ ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppConte
        g_hash_table_insert (contexts, gch, gch);
 
        mono_threads_unlock ();
+
+       mono_profiler_context_loaded (ctx);
+}
+
+void
+ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
+{
+       /*
+        * NOTE: Since finalizers are unreliable for the purposes of ensuring
+        * cleanup in exceptional circumstances, we don't actually do any
+        * cleanup work here. We instead do this when we iterate the `contexts`
+        * hash table. The only purpose of this finalizer, at the moment, is to
+        * notify the profiler.
+        */
+
+       //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
+
+       mono_profiler_context_unloaded (ctx);
 }
 
 void
@@ -2687,9 +2692,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_PREPARE_BLOCKING;
        ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
-       MONO_FINISH_BLOCKING
+       MONO_FINISH_BLOCKING;
 
        if(ret==WAIT_FAILED) {
                /* See the comment in build_wait_tids() */
@@ -2750,9 +2755,9 @@ static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeo
                count++;
        }
 
-       MONO_PREPARE_BLOCKING
+       MONO_PREPARE_BLOCKING;
        ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
-       MONO_FINISH_BLOCKING
+       MONO_FINISH_BLOCKING;
 
        if(ret==WAIT_FAILED) {
                /* See the comment in build_wait_tids() */
@@ -2814,7 +2819,7 @@ static void build_wait_tids (gpointer key, gpointer value, gpointer user)
                        return;
                }
 
-               handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
+               handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
                if (handle == NULL) {
                        THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
                        return;
@@ -2854,7 +2859,7 @@ remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
        if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
                !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
        
-               handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
+               handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
                if (handle == NULL)
                        return FALSE;
 
@@ -2896,7 +2901,7 @@ mono_threads_set_shutting_down (void)
                    (current_thread->state & ThreadState_AbortRequested) ||
                    (current_thread->state & ThreadState_StopRequested)) {
                        UNLOCK_THREAD (current_thread);
-                       mono_thread_execute_interruption (current_thread);
+                       mono_thread_execute_interruption ();
                } else {
                        current_thread->state |= ThreadState_Stopped;
                        UNLOCK_THREAD (current_thread);
@@ -2964,7 +2969,7 @@ void mono_thread_manage (void)
        if (!mono_runtime_try_shutdown ()) {
                /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
                mono_thread_suspend (mono_thread_internal_current ());
-               mono_thread_execute_interruption (mono_thread_internal_current ());
+               mono_thread_execute_interruption ();
        }
 
        /* 
@@ -3036,7 +3041,7 @@ collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
                return;
 
        if (wait->num<MAXIMUM_WAIT_OBJECTS) {
-               handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
+               handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
                if (handle == NULL)
                        return;
 
@@ -3158,7 +3163,7 @@ print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpoint
 {
        GString *p = (GString*)data;
        MonoMethod *method = NULL;
-       if (frame->ji)
+       if (frame->type == FRAME_TYPE_MANAGED)
                method = mono_jit_info_get_method (frame->ji);
 
        if (method) {
@@ -3227,7 +3232,7 @@ dump_thread (gpointer key, gpointer value, gpointer user)
        We probably should loop a bit around trying to get it to either managed code
        or WSJ state.
        */
-       mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
+       mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, print_thread_dump, thread);
 }
 
 void
@@ -3403,7 +3408,7 @@ collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
                /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
 
                if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
-                       HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
+                       HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
                        if (handle == NULL)
                                return;
                        data->wait.handles [data->wait.num] = handle;
@@ -3559,7 +3564,7 @@ mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc
                        void **p = ptr + idx;
 
                        if (*p)
-                               mark_func (p, gc_data);
+                               mark_func ((MonoObject**)p, gc_data);
                });
        }
 }
@@ -3589,18 +3594,20 @@ mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean thr
 
        gpointer* static_data = *static_data_ptr;
        if (!static_data) {
-               static void *tls_desc = NULL;
-               static void *ctx_desc = NULL;
+               static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
+               static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
 
                if (mono_gc_user_markers_supported ()) {
-                       if (!tls_desc)
+                       if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
                                tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
 
-                       if (!ctx_desc)
+                       if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
                                ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
                }
 
-               static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc);
+               static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
+                       threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
+                       threadlocal ? "managed thread-static variables" : "managed context-static variables");
                *static_data_ptr = static_data;
                static_data [0] = static_data;
        }
@@ -3612,7 +3619,9 @@ mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean thr
                if (mono_gc_user_markers_supported ())
                        static_data [i] = g_malloc0 (static_data_size [i]);
                else
-                       static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
+                       static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
+                               threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
+                               threadlocal ? "managed thread-static variables" : "managed context-static variables");
        }
 }
 
@@ -3698,17 +3707,16 @@ thread_adjust_static_data (MonoInternalThread *thread)
        mono_threads_unlock ();
 }
 
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
 static void
 context_adjust_static_data (MonoAppContext *ctx)
 {
-       mono_threads_lock ();
-
        if (context_static_info.offset || context_static_info.idx > 0) {
                guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
                mono_alloc_static_data (&ctx->static_data, offset, FALSE);
        }
-
-       mono_threads_unlock ();
 }
 
 /*
@@ -3726,20 +3734,21 @@ alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
 /*
  * LOCKING: requires that threads_mutex is held
  */
-static void
+static gboolean
 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
 {
        uint32_t gch = GPOINTER_TO_INT (key);
        MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
 
        if (!ctx) {
-               g_hash_table_remove (contexts, key);
                mono_gchandle_free (gch);
-               return;
+               return TRUE; // Remove this key/value pair
        }
 
        guint32 offset = GPOINTER_TO_UINT (user);
        mono_alloc_static_data (&ctx->static_data, offset, FALSE);
+
+       return FALSE; // Don't remove it
 }
 
 static StaticDataFreeList*
@@ -3831,7 +3840,7 @@ mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align
                        mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
        } else {
                if (contexts != NULL)
-                       g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
+                       g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
 
                ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
        }
@@ -3885,16 +3894,15 @@ free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
 /*
  * LOCKING: requires that threads_mutex is held
  */
-static void
+static gboolean
 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
 {
        uint32_t gch = GPOINTER_TO_INT (key);
        MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
 
        if (!ctx) {
-               g_hash_table_remove (contexts, key);
                mono_gchandle_free (gch);
-               return;
+               return TRUE; // Remove this key/value pair
        }
 
        OffsetSize *data = user;
@@ -3903,10 +3911,12 @@ free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
        char *ptr;
 
        if (!ctx->static_data || !ctx->static_data [idx])
-               return;
+               return FALSE; // Don't remove this key/value pair
 
        ptr = ((char*) ctx->static_data [idx]) + off;
        mono_gc_bzero_atomic (ptr, data->size);
+
+       return FALSE; // Don't remove this key/value pair
 }
 
 static void
@@ -3935,7 +3945,7 @@ do_free_special_slot (guint32 offset, guint32 size)
                        mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
        } else {
                if (contexts != NULL)
-                       g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
+                       g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
        }
 
        if (!mono_runtime_is_shutting_down ()) {
@@ -3981,147 +3991,6 @@ mono_special_static_data_free_slot (guint32 offset, guint32 size)
        mono_threads_unlock ();
 }
 
-/*
- * allocates room in the thread local area for storing an instance of the struct type
- * the allocation is kept track of in domain->tlsrec_list.
- */
-uint32_t
-mono_thread_alloc_tls (MonoReflectionType *type)
-{
-       MonoDomain *domain = mono_domain_get ();
-       MonoClass *klass;
-       MonoTlsDataRecord *tlsrec;
-       int max_set = 0;
-       gsize *bitmap;
-       gsize default_bitmap [4] = {0};
-       uint32_t tls_offset;
-       guint32 size;
-       gint32 align;
-
-       klass = mono_class_from_mono_type (type->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 + 1);
-       if (bitmap != default_bitmap)
-               g_free (bitmap);
-       tlsrec = g_new0 (MonoTlsDataRecord, 1);
-       tlsrec->tls_offset = tls_offset;
-       tlsrec->size = size;
-       mono_domain_lock (domain);
-       tlsrec->next = domain->tlsrec_list;
-       domain->tlsrec_list = tlsrec;
-       mono_domain_unlock (domain);
-       return tls_offset;
-}
-
-static void
-destroy_tls (MonoDomain *domain, uint32_t tls_offset)
-{
-       MonoTlsDataRecord *prev = NULL;
-       MonoTlsDataRecord *cur;
-       guint32 size = 0;
-
-       mono_domain_lock (domain);
-       cur = domain->tlsrec_list;
-       while (cur) {
-               if (cur->tls_offset == tls_offset) {
-                       if (prev)
-                               prev->next = cur->next;
-                       else
-                               domain->tlsrec_list = cur->next;
-                       size = cur->size;
-                       g_free (cur);
-                       break;
-               }
-               prev = cur;
-               cur = cur->next;
-       }
-       mono_domain_unlock (domain);
-       if (size)
-               mono_special_static_data_free_slot (tls_offset, size);
-}
-
-void
-mono_thread_destroy_tls (uint32_t tls_offset)
-{
-       destroy_tls (mono_domain_get (), tls_offset);
-}
-
-/*
- * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
- */
-void
-mono_thread_destroy_domain_tls (MonoDomain *domain)
-{
-       while (domain->tlsrec_list)
-               destroy_tls (domain, domain->tlsrec_list->tls_offset);
-}
-
-static MonoClassField *local_slots = NULL;
-
-typedef struct {
-       /* local tls data to get locals_slot from a thread */
-       guint32 offset;
-       int idx;
-       /* index in the locals_slot array */
-       int slot;
-} LocalSlotID;
-
-static void
-clear_local_slot (gpointer key, gpointer value, gpointer user_data)
-{
-       LocalSlotID *sid = user_data;
-       MonoInternalThread *thread = (MonoInternalThread*)value;
-       MonoArray *slots_array;
-       /*
-        * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
-        * it is for the right domain, so we need to check if it is allocated an initialized
-        * for the current thread.
-        */
-       /*g_print ("handling thread %p\n", thread);*/
-       if (!thread->static_data || !thread->static_data [sid->idx])
-               return;
-       slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
-       if (!slots_array || sid->slot >= mono_array_length (slots_array))
-               return;
-       mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
-}
-
-void
-mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
-{
-       MonoDomain *domain;
-       LocalSlotID sid;
-       sid.slot = slot;
-       if (thread_local) {
-               void *addr = NULL;
-               if (!local_slots) {
-                       local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
-                       if (!local_slots) {
-                               g_warning ("local_slots field not found in Thread class");
-                               return;
-                       }
-               }
-               domain = mono_domain_get ();
-               mono_domain_lock (domain);
-               if (domain->special_static_fields)
-                       addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
-               mono_domain_unlock (domain);
-               if (!addr)
-                       return;
-               /*g_print ("freeing slot %d at %p\n", slot, addr);*/
-               sid.offset = GPOINTER_TO_UINT (addr);
-               sid.offset &= 0x7fffffff;
-               sid.idx = (sid.offset >> 24) - 1;
-               mono_threads_lock ();
-               mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
-               mono_threads_unlock ();
-       } else {
-               /* FIXME: clear the slot for MonoAppContexts, too */
-       }
-}
-
 #ifdef HOST_WIN32
 static void CALLBACK dummy_apc (ULONG_PTR param)
 {
@@ -4135,8 +4004,10 @@ static void CALLBACK dummy_apc (ULONG_PTR param)
  * suspend or stop)
  */
 static MonoException*
-mono_thread_execute_interruption (MonoInternalThread *thread)
+mono_thread_execute_interruption (void)
 {
+       MonoInternalThread *thread = mono_thread_internal_current ();
+
        LOCK_THREAD (thread);
 
        /* MonoThread::interruption_requested can only be changed with atomics */
@@ -4146,8 +4017,9 @@ mono_thread_execute_interruption (MonoInternalThread *thread)
                WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
 #endif
                InterlockedDecrement (&thread_interruption_requested);
+
                /* Clear the interrupted flag of the thread so it can wait again */
-               mono_thread_info_clear_interruption ();
+               mono_thread_info_clear_self_interrupt ();
        }
 
        if ((thread->state & ThreadState_AbortRequested) != 0) {
@@ -4242,7 +4114,7 @@ mono_thread_request_interruption (gboolean running_managed)
                return NULL;
        }
        else {
-               return mono_thread_execute_interruption (thread);
+               return mono_thread_execute_interruption ();
        }
 }
 
@@ -4272,7 +4144,7 @@ mono_thread_resume_interruption (void)
 
        mono_thread_info_self_interrupt ();
 
-       return mono_thread_execute_interruption (thread);
+       return mono_thread_execute_interruption ();
 }
 
 gboolean mono_thread_interruption_requested ()
@@ -4296,7 +4168,7 @@ mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
                return NULL;
 
        if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
-               MonoException* exc = mono_thread_execute_interruption (thread);
+               MonoException* exc = mono_thread_execute_interruption ();
                if (exc)
                        return exc;
        }
@@ -4353,7 +4225,7 @@ mono_thread_get_and_clear_pending_exception (void)
                return NULL;
 
        if (thread->interruption_requested && !is_running_protected_wrapper ()) {
-               return mono_thread_execute_interruption (thread);
+               return mono_thread_execute_interruption ();
        }
        
        if (thread->pending_exception) {
@@ -4464,43 +4336,6 @@ mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
        return ret;
 }
 
-//static MonoClassField *execution_context_field;
-
-static MonoObject**
-get_execution_context_addr (void)
-{
-       MonoDomain *domain = mono_domain_get ();
-       guint32 offset = domain->execution_context_field_offset;
-
-       if (!offset) {
-               MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
-               g_assert (field);
-
-               g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
-
-               mono_domain_lock (domain);
-               offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
-               mono_domain_unlock (domain);
-               g_assert (offset);
-
-               domain->execution_context_field_offset = offset;
-       }
-
-       return (MonoObject**) mono_get_special_static_data (offset);
-}
-
-MonoObject*
-mono_thread_get_execution_context (void)
-{
-       return *get_execution_context_addr ();
-}
-
-void
-mono_thread_set_execution_context (MonoObject *ec)
-{
-       *get_execution_context_addr () = ec;
-}
-
 static gboolean has_tls_get = FALSE;
 
 void
@@ -4519,7 +4354,7 @@ static void
 self_interrupt_thread (void *_unused)
 {
        MonoThreadInfo *info = mono_thread_info_current ();
-       MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ()); 
+       MonoException *exc = mono_thread_execute_interruption ();
        if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
                mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
        g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
@@ -4554,7 +4389,7 @@ mono_thread_info_get_last_managed (MonoThreadInfo *info)
 typedef struct {
        MonoInternalThread *thread;
        gboolean install_async_abort;
-       gpointer interrupt_handle;
+       MonoThreadInfoInterruptToken *interrupt_token;
 } AbortThreadData;
 
 static SuspendThreadResult
@@ -4576,7 +4411,7 @@ abort_thread_critical (MonoThreadInfo *info, gpointer ud)
        InterlockedIncrement (&thread_interruption_requested);
 
        ji = mono_thread_info_get_last_managed (info);
-       protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
+       protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
        running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
 
        if (!protected_wrapper && running_managed) {
@@ -4597,7 +4432,8 @@ abort_thread_critical (MonoThreadInfo *info, gpointer ud)
                 * functions in the io-layer until the signal handler calls QueueUserAPC which will
                 * make it return.
                 */
-               data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+               data->interrupt_token = mono_thread_info_prepare_interrupt (info);
+
                return MonoResumeThread;
        }
 }
@@ -4618,20 +4454,22 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
                MonoException *exc = mono_thread_request_interruption (can_raise_exception); 
                if (exc)
                        mono_raise_exception (exc);
-               mono_thread_info_interrupt (thread->handle);
+
+               mono_thread_info_self_interrupt ();
+
                return;
        }
 
-       mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
-       if (data.interrupt_handle)
-               mono_thread_info_finish_interrupt (data.interrupt_handle);
+       mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_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{
        MonoInternalThread *thread;
        gboolean interrupt;
-       gpointer interrupt_handle;
+       MonoThreadInfoInterruptToken *interrupt_token;
 } SuspendThreadData;
 
 static SuspendThreadResult
@@ -4644,7 +4482,7 @@ suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
        gboolean running_managed;
 
        ji = mono_thread_info_get_last_managed (info);
-       protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
+       protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
        running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
 
        if (running_managed && !protected_wrapper) {
@@ -4655,7 +4493,7 @@ suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
                if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
                        InterlockedIncrement (&thread_interruption_requested);
                if (data->interrupt)
-                       data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
+                       data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
                
                if (mono_thread_notify_pending_exc_fn && !running_managed)
                        /* The JIT will notify the thread about the interruption */
@@ -4680,9 +4518,9 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
                data.thread = thread;
                data.interrupt = interrupt;
 
-               mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
-               if (data.interrupt_handle)
-                       mono_thread_info_finish_interrupt (data.interrupt_handle);
+               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);
        }
 }
@@ -4704,7 +4542,7 @@ resume_thread_internal (MonoInternalThread *thread)
 {
        UNLOCK_THREAD (thread);
        /* Awake the thread */
-       if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
+       if (!mono_thread_info_resume (thread_get_tid (thread)))
                return FALSE;
        LOCK_THREAD (thread);
        thread->state &= ~ThreadState_Suspended;
@@ -4826,3 +4664,43 @@ mono_thread_join (gpointer tid)
        pthread_join (thread, NULL);
 #endif
 }
+
+void
+mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
+{
+       if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
+               mono_thread_interruption_checkpoint ();
+}
+
+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;
+}
+
+static inline gboolean
+is_threadabort_exception (MonoClass *klass)
+{
+       return klass == mono_defaults.threadabortexception_class;
+}
+
+void
+mono_thread_internal_unhandled_exception (MonoObject* exc)
+{
+       if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
+               MonoClass *klass = exc->vtable->klass;
+               if (is_threadabort_exception (klass)) {
+                       mono_thread_internal_reset_abort (mono_thread_internal_current ());
+               } else if (!is_appdomainunloaded_exception (klass)) {
+                       mono_unhandled_exception (exc);
+                       if (mono_environment_exitcode_get () == 1)
+                               exit (255);
+               }
+       }
+}