Merge pull request #1840 from ludovic-henry/iolayer-thread-interrupt
[mono.git] / mono / metadata / threads.c
index 668a9c74b9fa416e39a74f9c1245f16e30ae1f6e..17246184a8c573982ac41504c16d66e5919b57f8 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>
@@ -31,6 +30,7 @@
 #include <mono/io-layer/io-layer.h>
 #include <mono/metadata/object-internals.h>
 #include <mono/metadata/mono-debug-debugger.h>
+#include <mono/utils/monobitset.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/mono-membar.h>
@@ -104,9 +104,9 @@ typedef union {
        gdouble fval;
 } LongDoubleUnion;
  
-typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
-struct _MonoThreadDomainTls {
-       MonoThreadDomainTls *next;
+typedef struct _StaticDataFreeList StaticDataFreeList;
+struct _StaticDataFreeList {
+       StaticDataFreeList *next;
        guint32 offset;
        guint32 size;
 };
@@ -114,7 +114,7 @@ struct _MonoThreadDomainTls {
 typedef struct {
        int idx;
        int offset;
-       MonoThreadDomainTls *freelist;
+       StaticDataFreeList *freelist;
 } StaticDataInfo;
 
 /* Number of cached culture objects in the MonoThread->cached_culture_info array
@@ -130,11 +130,6 @@ static void mono_threads_lock (void);
 static void mono_threads_unlock (void);
 static mono_mutex_t threads_mutex;
 
-/* Controls access to context static data */
-#define mono_contexts_lock() mono_mutex_lock (&contexts_mutex)
-#define mono_contexts_unlock() mono_mutex_unlock (&contexts_mutex)
-static mono_mutex_t contexts_mutex;
-
 /* Controls access to the 'joinable_threads' hash table */
 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
@@ -149,6 +144,11 @@ static StaticDataInfo context_static_info;
  */
 static MonoGHashTable *threads=NULL;
 
+/* List of app context GC handles.
+ * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
+ */
+static GHashTable *contexts = NULL;
+
 /*
  * Threads which are starting up and they are not in the 'threads' hash yet.
  * When handle_store is called for a thread, it will be removed from this hash table.
@@ -200,7 +200,8 @@ static guint32 default_stacksize = 0;
 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
 
 static void thread_adjust_static_data (MonoInternalThread *thread);
-static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
+static void context_adjust_static_data (MonoAppContext *ctx);
+static void mono_free_static_data (gpointer* static_data);
 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);
@@ -473,7 +474,7 @@ static void thread_cleanup (MonoInternalThread *thread)
 
        thread->cached_culture_info = NULL;
 
-       mono_free_static_data (thread->static_data, TRUE);
+       mono_free_static_data (thread->static_data);
        thread->static_data = NULL;
        ref_stack_destroy (thread->appdomain_refs);
        thread->appdomain_refs = NULL;
@@ -487,14 +488,57 @@ static void thread_cleanup (MonoInternalThread *thread)
        }
 }
 
+/*
+ * A special static data offset (guint32) consists of 3 parts:
+ *
+ * [0]   6-bit index into the array of chunks.
+ * [6]   25-bit offset into the array.
+ * [31]  Bit indicating thread or context static.
+ */
+
+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;
+
+#define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
+#define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
+
+#define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
+       ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
+#define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
+       (((SpecialStaticOffset *) &(x))->fields.f)
+
 static gpointer
 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
 {
-       int idx;
-       g_assert ((offset & 0x80000000) == 0);
-       offset &= 0x7fffffff;
-       idx = (offset >> 24) - 1;
-       return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
+       g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
+
+       int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
+       int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
+
+       return ((char *) thread->static_data [idx]) + off;
+}
+
+static gpointer
+get_context_static_data (MonoAppContext *ctx, guint32 offset)
+{
+       g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
+
+       int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
+       int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
+
+       return ((char *) ctx->static_data [idx]) + off;
 }
 
 static MonoThread**
@@ -657,9 +701,6 @@ static guint32 WINAPI start_wrapper_internal(void *data)
        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));
@@ -1053,28 +1094,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);
 
@@ -1086,17 +1127,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 = this_obj->start_obj; /* FIXME: GC object stored in unmanaged memory */
        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;
@@ -1114,7 +1155,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));
 
@@ -1126,16 +1167,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);
        }
 }
@@ -1278,13 +1319,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)
 {
 }
 
@@ -1344,34 +1385,35 @@ 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);
+       ret=WaitForSingleObjectEx (handle, ms, TRUE);
        MONO_FINISH_BLOCKING
 
        mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
@@ -1521,7 +1563,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 ();
@@ -1980,22 +2022,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);
        }
 }
 
@@ -2018,46 +2061,6 @@ void mono_thread_current_check_pending_interrupt ()
        }
 }
 
-int  
-mono_thread_get_abort_signal (void)
-{
-#if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
-       return -1;
-#elif defined(PLATFORM_ANDROID)
-       return SIGUNUSED;
-#elif !defined (SIGRTMIN)
-#ifdef SIGUSR1
-       return SIGUSR1;
-#else
-       return -1;
-#endif /* SIGUSR1 */
-#else
-       static int abort_signum = -1;
-       int i;
-       if (abort_signum != -1)
-               return abort_signum;
-       /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
-       for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
-               struct sigaction sinfo;
-               sigaction (i, NULL, &sinfo);
-               if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
-                       abort_signum = i;
-                       return i;
-               }
-       }
-       /* fallback to the old way */
-       return SIGRTMIN;
-#endif /* HOST_WIN32 */
-}
-
-#ifdef HOST_WIN32
-static void CALLBACK interruption_request_apc (ULONG_PTR param)
-{
-       MonoException* exc = mono_thread_request_interruption (FALSE);
-       if (exc) mono_raise_exception (exc);
-}
-#endif /* HOST_WIN32 */
-
 void
 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
 {
@@ -2101,7 +2104,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;
@@ -2146,9 +2149,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;
 
@@ -2205,9 +2208,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;
        }
@@ -2566,6 +2569,41 @@ ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
        mono_gc_wbarrier_generic_store_atomic (ptr, value);
 }
 
+void
+ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
+{
+       mono_threads_lock ();
+
+       //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
+
+       if (!contexts)
+               contexts = g_hash_table_new (NULL, NULL);
+
+       context_adjust_static_data (ctx);
+       gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
+       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
 mono_thread_init_tls (void)
 {
@@ -2578,7 +2616,6 @@ void mono_thread_init (MonoThreadStartCB start_cb,
 {
        mono_mutex_init_recursive(&threads_mutex);
        mono_mutex_init_recursive(&interlocked_mutex);
-       mono_mutex_init_recursive(&contexts_mutex);
        mono_mutex_init_recursive(&joinable_threads_mutex);
        
        background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
@@ -2622,7 +2659,6 @@ void mono_thread_cleanup (void)
         */
        mono_mutex_destroy (&threads_mutex);
        mono_mutex_destroy (&interlocked_mutex);
-       mono_mutex_destroy (&contexts_mutex);
        mono_mutex_destroy (&delayed_free_table_mutex);
        mono_mutex_destroy (&small_id_mutex);
        CloseHandle (background_change_event);
@@ -3137,24 +3173,6 @@ void mono_thread_suspend_all_other_threads (void)
        }
 }
 
-static void
-collect_threads (gpointer key, gpointer value, gpointer user_data)
-{
-       MonoInternalThread *thread = (MonoInternalThread*)value;
-       struct wait_data *wait = (struct wait_data*)user_data;
-       HANDLE handle;
-
-       if (wait->num<MAXIMUM_WAIT_OBJECTS) {
-               handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
-               if (handle == NULL)
-                       return;
-
-               wait->handles [wait->num] = handle;
-               wait->threads [wait->num] = thread;
-               wait->num++;
-       }
-}
-
 static gboolean thread_dump_requested;
 
 static G_GNUC_UNUSED gboolean
@@ -3162,7 +3180,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) {
@@ -3545,34 +3563,41 @@ static const int static_data_size [NUM_STATIC_DATA_IDX] = {
 };
 #endif
 
-static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
+static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
+static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
 
 static void
-mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
+mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
 {
-       int i;
        gpointer *static_data = addr;
-       for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
-               int j, numwords;
-               void **ptr;
-               if (!static_data [i])
+
+       for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
+               void **ptr = static_data [i];
+
+               if (!ptr)
                        continue;
-               numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
-               ptr = static_data [i];
-               for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
-                       uintptr_t bmap = static_reference_bitmaps [i][j];
-                       void ** p = ptr;
-                       while (bmap) {
-                               if ((bmap & 1) && *p) {
-                                       mark_func (p, gc_data);
-                               }
-                               p++;
-                               bmap >>= 1;
-                       }
-               }
+
+               MONO_BITSET_FOREACH (bitmaps [i], idx, {
+                       void **p = ptr + idx;
+
+                       if (*p)
+                               mark_func ((MonoObject**)p, gc_data);
+               });
        }
 }
 
+static void
+mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
+{
+       mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
+}
+
+static void
+mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
+{
+       mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
+}
+
 /*
  *  mono_alloc_static_data
  *
@@ -3581,15 +3606,23 @@ mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
 static void 
 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
 {
-       guint idx = (offset >> 24) - 1;
+       guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
        int i;
 
        gpointer* static_data = *static_data_ptr;
        if (!static_data) {
-               static void* tls_desc = NULL;
-               if (mono_gc_user_markers_supported () && !tls_desc)
-                       tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
-               static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_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 == MONO_GC_DESCRIPTOR_NULL)
+                               tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
+
+                       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_ptr = static_data;
                static_data [0] = static_data;
        }
@@ -3597,15 +3630,16 @@ mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean thr
        for (i = 1; i <= idx; ++i) {
                if (static_data [i])
                        continue;
-               if (mono_gc_user_markers_supported () && threadlocal)
+
+               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);
        }
 }
 
 static void 
-mono_free_static_data (gpointer* static_data, gboolean threadlocal)
+mono_free_static_data (gpointer* static_data)
 {
        int i;
        for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
@@ -3616,12 +3650,12 @@ mono_free_static_data (gpointer* static_data, gboolean threadlocal)
                 * At this point, the static data pointer array is still registered with the
                 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
                 * data.  Freeing the individual arrays without first nulling their slots
-                * would make it possible for mark_tls_slots() to encounter a pointer to
+                * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
                 * such an already freed array.  See bug #13813.
                 */
                static_data [i] = NULL;
                mono_memory_write_barrier ();
-               if (mono_gc_user_markers_supported () && threadlocal)
+               if (mono_gc_user_markers_supported ())
                        g_free (p);
                else
                        mono_gc_free_fixed (p);
@@ -3650,8 +3684,6 @@ static void mono_init_static_data_info (StaticDataInfo *static_data)
 static guint32
 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
 {
-       guint32 offset;
-
        if (!static_data->idx && !static_data->offset) {
                /* 
                 * we use the first chunk of the first allocation also as
@@ -3667,7 +3699,7 @@ mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32
                g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
                static_data->offset = 0;
        }
-       offset = static_data->offset | ((static_data->idx + 1) << 24);
+       guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
        static_data->offset += size;
        return offset;
 }
@@ -3679,17 +3711,30 @@ mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32
 static void
 thread_adjust_static_data (MonoInternalThread *thread)
 {
-       guint32 offset;
-
        mono_threads_lock ();
        if (thread_static_info.offset || thread_static_info.idx > 0) {
                /* get the current allocated size */
-               offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
-               mono_alloc_static_data (&(thread->static_data), offset, TRUE);
+               guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
+               mono_alloc_static_data (&thread->static_data, offset, TRUE);
        }
        mono_threads_unlock ();
 }
 
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
+static void
+context_adjust_static_data (MonoAppContext *ctx)
+{
+       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);
+       }
+}
+
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
 static void 
 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
 {
@@ -3699,11 +3744,31 @@ alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
        mono_alloc_static_data (&(thread->static_data), offset, TRUE);
 }
 
-static MonoThreadDomainTls*
-search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
+static gboolean
+alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
 {
-       MonoThreadDomainTls* prev = NULL;
-       MonoThreadDomainTls* tmp = static_data->freelist;
+       uint32_t gch = GPOINTER_TO_INT (key);
+       MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
+
+       if (!ctx) {
+               mono_gchandle_free (gch);
+               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*
+search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
+{
+       StaticDataFreeList* prev = NULL;
+       StaticDataFreeList* tmp = static_data->freelist;
        while (tmp) {
                if (tmp->size == size) {
                        if (prev)
@@ -3725,100 +3790,88 @@ search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32
 #endif
 
 static void
-update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
-{
-       int i;
-       int idx = (offset >> 24) - 1;
-       uintptr_t *rb;
-       if (!static_reference_bitmaps [idx])
-               static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
-       rb = static_reference_bitmaps [idx];
-       offset &= 0xffffff;
-       offset /= sizeof (gpointer);
+update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
+{
+       int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
+       if (!sets [idx])
+               sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
+       MonoBitSet *rb = sets [idx];
+       offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
+       offset /= sizeof (uintptr_t);
        /* offset is now the bitmap offset */
-       for (i = 0; i < numbits; ++i) {
+       for (int i = 0; i < numbits; ++i) {
                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)));
+                       mono_bitset_set_fast (rb, offset + i);
        }
 }
 
 static void
-clear_reference_bitmap (guint32 offset, guint32 size)
-{
-       int idx = (offset >> 24) - 1;
-       uintptr_t *rb;
-       rb = static_reference_bitmaps [idx];
-       offset &= 0xffffff;
-       offset /= sizeof (gpointer);
-       size /= sizeof (gpointer);
-       size += offset;
+clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
+{
+       int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
+       MonoBitSet *rb = sets [idx];
+       offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
+       offset /= sizeof (uintptr_t);
        /* offset is now the bitmap offset */
-       for (; offset < size; ++offset)
-               rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
+       for (int i = 0; i < size / sizeof (uintptr_t); i++)
+               mono_bitset_clear_fast (rb, offset + i);
 }
 
-/*
- * The offset for a special static variable is composed of three parts:
- * a bit that indicates the type of static data (0:thread, 1:context),
- * an index in the array of chunks of memory for the thread (thread->static_data)
- * and an offset in that chunk of mem. This allows allocating less memory in the 
- * common case.
- */
-
 guint32
 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
 {
+       g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
+
+       StaticDataInfo *info;
+       MonoBitSet **sets;
+
+       if (static_type == SPECIAL_STATIC_THREAD) {
+               info = &thread_static_info;
+               sets = thread_reference_bitmaps;
+       } else {
+               info = &context_static_info;
+               sets = context_reference_bitmaps;
+       }
+
+       mono_threads_lock ();
+
+       StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
        guint32 offset;
+
+       if (item) {
+               offset = item->offset;
+               g_free (item);
+       } else {
+               offset = mono_alloc_static_data_slot (info, size, align);
+       }
+
+       update_reference_bitmap (sets, offset, bitmap, numbits);
+
        if (static_type == SPECIAL_STATIC_THREAD) {
-               MonoThreadDomainTls *item;
-               mono_threads_lock ();
-               item = search_tls_slot_in_freelist (&thread_static_info, size, align);
-               /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
-               if (item) {
-                       offset = item->offset;
-                       g_free (item);
-               } else {
-                       offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
-               }
-               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));
-               mono_threads_unlock ();
        } else {
-               g_assert (static_type == SPECIAL_STATIC_CONTEXT);
-               mono_contexts_lock ();
-               offset = mono_alloc_static_data_slot (&context_static_info, size, align);
-               mono_contexts_unlock ();
-               offset |= 0x80000000;   /* Set the high bit to indicate context static data */
+               if (contexts != NULL)
+                       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;
        }
+
+       mono_threads_unlock ();
+
        return offset;
 }
 
 gpointer
 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
 {
-       /* The high bit means either thread (0) or static (1) data. */
-
-       guint32 static_type = (offset & 0x80000000);
-       int idx;
+       guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
 
-       offset &= 0x7fffffff;
-       idx = (offset >> 24) - 1;
-
-       if (static_type == 0) {
+       if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
                return get_thread_static_data (thread, offset);
        } else {
-               /* Allocate static data block under demand, since we don't have a list
-               // of contexts
-               */
-               MonoAppContext *context = mono_context_get ();
-               if (!context->static_data || !context->static_data [idx]) {
-                       mono_contexts_lock ();
-                       mono_alloc_static_data (&(context->static_data), offset, FALSE);
-                       mono_contexts_unlock ();
-               }
-               return ((char*) context->static_data [idx]) + (offset & 0xffffff);      
+               return get_context_static_data (thread->current_appcontext, offset);
        }
 }
 
@@ -3831,47 +3884,91 @@ mono_get_special_static_data (guint32 offset)
 typedef struct {
        guint32 offset;
        guint32 size;
-} TlsOffsetSize;
+} OffsetSize;
 
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
 static void 
 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
 {
        MonoInternalThread *thread = value;
-       TlsOffsetSize *data = user;
-       int idx = (data->offset >> 24) - 1;
+       OffsetSize *data = user;
+       int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
+       int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
        char *ptr;
 
        if (!thread->static_data || !thread->static_data [idx])
                return;
-       ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
+       ptr = ((char*) thread->static_data [idx]) + off;
        mono_gc_bzero_atomic (ptr, data->size);
 }
 
+/*
+ * LOCKING: requires that threads_mutex is held
+ */
+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) {
+               mono_gchandle_free (gch);
+               return TRUE; // Remove this key/value pair
+       }
+
+       OffsetSize *data = user;
+       int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
+       int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
+       char *ptr;
+
+       if (!ctx->static_data || !ctx->static_data [idx])
+               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
 do_free_special_slot (guint32 offset, guint32 size)
 {
-       guint32 static_type = (offset & 0x80000000);
-       /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
-       if (static_type == 0) {
-               TlsOffsetSize data;
-               MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
-               data.offset = offset & 0x7fffffff;
-               data.size = size;
-               clear_reference_bitmap (data.offset, data.size);
+       guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
+       MonoBitSet **sets;
+       StaticDataInfo *info;
+
+       if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
+               info = &thread_static_info;
+               sets = thread_reference_bitmaps;
+       } else {
+               info = &context_static_info;
+               sets = context_reference_bitmaps;
+       }
+
+       guint32 data_offset = offset;
+       ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
+       OffsetSize data = { data_offset, size };
+
+       clear_reference_bitmap (sets, data.offset, data.size);
+
+       if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
                if (threads != NULL)
                        mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
+       } else {
+               if (contexts != NULL)
+                       g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
+       }
+
+       if (!mono_runtime_is_shutting_down ()) {
+               StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
+
                item->offset = offset;
                item->size = size;
 
-               if (!mono_runtime_is_shutting_down ()) {
-                       item->next = thread_static_info.freelist;
-                       thread_static_info.freelist = item;
-               } else {
-                       /* We could be called during shutdown after mono_thread_cleanup () is called */
-                       g_free (item);
-               }
-       } else {
-               /* FIXME: free context static data as well */
+               item->next = info->freelist;
+               info->freelist = item;
        }
 }
 
@@ -3890,159 +3987,23 @@ void
 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
 {
        mono_threads_lock ();
+
        g_hash_table_foreach (special_static_fields, do_free_special, NULL);
+
        mono_threads_unlock ();
 }
 
-void
+static void
 mono_special_static_data_free_slot (guint32 offset, guint32 size)
 {
+       /* Only ever called for ThreadLocal instances */
+       g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
+
        mono_threads_lock ();
        do_free_special_slot (offset, 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)
 {
@@ -4067,8 +4028,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) {
@@ -4385,43 +4347,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
@@ -4475,7 +4400,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
@@ -4497,7 +4422,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) {
@@ -4518,7 +4443,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;
        }
 }
@@ -4539,20 +4465,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);
+       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
@@ -4565,7 +4493,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) {
@@ -4576,7 +4504,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 */
@@ -4602,8 +4530,8 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
                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);
+               if (data.interrupt_token)
+                       mono_thread_info_finish_interrupt (data.interrupt_token);
                UNLOCK_THREAD (thread);
        }
 }
@@ -4747,3 +4675,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);
+               }
+       }
+}