[threads] Rework MonoThreadInfoCallbacks.thread_{register,detach,unregister} callback...
[mono.git] / mono / metadata / threads.c
index 6831de896320d1b723061a9924f7cc78b3e242ec..60848191ddc3a64032d48c9d9f7dab5444f2411c 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * threads.c: Thread support internal calls
+/**
+ * \file
+ * Thread support internal calls
  *
  * Author:
  *     Dick Porter (dick@ximian.com)
@@ -134,7 +135,7 @@ 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 ().
+ * Added to from mono_threads_register_app_context ().
  */
 static GHashTable *contexts = NULL;
 
@@ -219,9 +220,18 @@ get_next_managed_thread_id (void)
        return InterlockedIncrement (&managed_thread_id_counter);
 }
 
+/*
+ * We separate interruptions/exceptions into either sync (they can be processed anytime,
+ * normally as soon as they are set, and are set by the same thread) and async (they can't
+ * be processed inside abort protected blocks and are normally set by other threads). We
+ * can have both a pending sync and async interruption. In this case, the sync exception is
+ * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
+ * also handle all sync type exceptions before the async type exceptions.
+ */
 enum {
-       INTERRUPT_REQUESTED_BIT = 0x1,
-       INTERRUPT_REQUEST_DEFERRED_BIT = 0x2,
+       INTERRUPT_SYNC_REQUESTED_BIT = 0x1,
+       INTERRUPT_ASYNC_REQUESTED_BIT = 0x2,
+       INTERRUPT_REQUESTED_MASK = 0x3,
        ABORT_PROT_BLOCK_SHIFT = 2,
        ABORT_PROT_BLOCK_BITS = 8,
        ABORT_PROT_BLOCK_MASK = (((1 << ABORT_PROT_BLOCK_BITS) - 1) << ABORT_PROT_BLOCK_SHIFT)
@@ -234,146 +244,141 @@ mono_thread_get_abort_prot_block_count (MonoInternalThread *thread)
        return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
 }
 
-static void
-verify_thread_state (gsize state)
-{
-       //can't have both INTERRUPT_REQUESTED_BIT and INTERRUPT_REQUEST_DEFERRED_BIT set at the same time
-       g_assert ((state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)) != (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT));
-
-       //XXX This would be nice to be true, but can happen due to self-aborts (and possibly set-pending-exception)
-       //if prot_count > 0, INTERRUPT_REQUESTED_BIT must never be set
-       // int prot_count = (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
-       // g_assert (!(prot_count > 0 && (state & INTERRUPT_REQUESTED_BIT)));
-}
-
 void
 mono_threads_begin_abort_protected_block (void)
 {
        MonoInternalThread *thread = mono_thread_internal_current ();
        gsize old_state, new_state;
+       int new_val;
        do {
                old_state = thread->thread_state;
-               verify_thread_state (old_state);
-
-               int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) + 1;
-
-               new_state = 0;
-               if (old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)) {
-                       new_state |= INTERRUPT_REQUEST_DEFERRED_BIT;
-               }
 
+               new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) + 1;
                //bounds check abort_prot_count
                g_assert (new_val > 0);
                g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
-               new_state |= new_val << ABORT_PROT_BLOCK_SHIFT;
 
+               new_state = old_state + (1 << ABORT_PROT_BLOCK_SHIFT);
        } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+
+       /* Defer async request since we won't be able to process until exiting the block */
+       if (new_val == 1 && (new_state & INTERRUPT_ASYNC_REQUESTED_BIT)) {
+               InterlockedDecrement (&thread_interruption_requested);
+               THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, defer tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
+               if (thread_interruption_requested < 0)
+                       g_warning ("bad thread_interruption_requested state");
+       } else {
+               THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
+       }
 }
 
-gboolean
-mono_threads_end_abort_protected_block (void)
+static gboolean
+mono_thread_state_has_interruption (gsize state)
 {
-       MonoInternalThread *thread = mono_thread_internal_current ();
-       gsize old_state, new_state;
-       do {
-               old_state = thread->thread_state;
-               verify_thread_state (old_state);
-
-               int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
-               new_state = 0;
-
-               if ((old_state & INTERRUPT_REQUEST_DEFERRED_BIT) && new_val == 0) {
-                       new_state |= INTERRUPT_REQUESTED_BIT;
-               }
+       /* pending exception, self abort */
+       if (state & INTERRUPT_SYNC_REQUESTED_BIT)
+               return TRUE;
 
-               //bounds check abort_prot_count
-               g_assert (new_val >= 0);
-               g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
-               new_state |= new_val << ABORT_PROT_BLOCK_SHIFT;
+       /* abort, interruption, suspend */
+       if ((state & INTERRUPT_ASYNC_REQUESTED_BIT) && !(state & ABORT_PROT_BLOCK_MASK))
+               return TRUE;
 
-       } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
-       return (new_state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
+       return FALSE;
 }
 
-
-//Don't use this function, use inc/dec below
-static void
-mono_thread_abort_prot_block_count_add (MonoInternalThread *thread, int val)
+gboolean
+mono_threads_end_abort_protected_block (void)
 {
+       MonoInternalThread *thread = mono_thread_internal_current ();
        gsize old_state, new_state;
+       int new_val;
        do {
                old_state = thread->thread_state;
-               verify_thread_state (old_state);
 
-               int new_val = val + ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT);
                //bounds check abort_prot_count
+               new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
                g_assert (new_val >= 0);
                g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
-               new_state = (old_state & ~ABORT_PROT_BLOCK_MASK) | (new_val << ABORT_PROT_BLOCK_SHIFT);
 
+               new_state = old_state - (1 << ABORT_PROT_BLOCK_SHIFT);
        } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
-}
 
-static void
-mono_thread_inc_abort_prot_block_count (MonoInternalThread *thread)
-{
-       mono_thread_abort_prot_block_count_add (thread, 1);
-}
+       if (new_val == 0 && (new_state & INTERRUPT_ASYNC_REQUESTED_BIT)) {
+               InterlockedIncrement (&thread_interruption_requested);
+               THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, restore tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
+       } else {
+               THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
+       }
 
-static void
-mono_thread_dec_abort_prot_block_count (MonoInternalThread *thread)
-{
-       mono_thread_abort_prot_block_count_add (thread, -1);
+       return mono_thread_state_has_interruption (new_state);
 }
 
 static gboolean
 mono_thread_get_interruption_requested (MonoInternalThread *thread)
 {
        gsize state = thread->thread_state;
-       return (state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
+
+       return mono_thread_state_has_interruption (state);
 }
 
-/* Returns TRUE is there was a state change */
+/*
+ * Returns TRUE is there was a state change
+ * We clear a single interruption request, sync has priority.
+ */
 static gboolean
 mono_thread_clear_interruption_requested (MonoInternalThread *thread)
 {
        gsize old_state, new_state;
        do {
                old_state = thread->thread_state;
-               verify_thread_state (old_state);
 
-               //Already cleared
-               if (!(old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)))
+               // no interruption to process
+               if (!(old_state & INTERRUPT_SYNC_REQUESTED_BIT) &&
+                               (!(old_state & INTERRUPT_ASYNC_REQUESTED_BIT) || (old_state & ABORT_PROT_BLOCK_MASK)))
                        return FALSE;
-               new_state = old_state & ~(INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT);
+
+               if (old_state & INTERRUPT_SYNC_REQUESTED_BIT)
+                       new_state = old_state & ~INTERRUPT_SYNC_REQUESTED_BIT;
+               else
+                       new_state = old_state & ~INTERRUPT_ASYNC_REQUESTED_BIT;
        } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+
+       InterlockedDecrement (&thread_interruption_requested);
+       THREADS_INTERRUPT_DEBUG ("[%d] clear interruption old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
+       if (thread_interruption_requested < 0)
+               g_warning ("bad thread_interruption_requested state");
        return TRUE;
 }
 
-/* Returns TRUE is there was a state change */
+/* Returns TRUE is there was a state change and the interruption can be processed */
 static gboolean
 mono_thread_set_interruption_requested (MonoInternalThread *thread)
 {
        //always force when the current thread is doing it to itself.
-       gboolean force_interrupt = thread == mono_thread_internal_current ();
+       gboolean sync = thread == mono_thread_internal_current ();
        gsize old_state, new_state;
        do {
                old_state = thread->thread_state;
-               verify_thread_state (old_state);
 
-               int prot_count = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT);
                //Already set
-               if (old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT))
+               if ((sync && (old_state & INTERRUPT_SYNC_REQUESTED_BIT)) ||
+                               (!sync && (old_state & INTERRUPT_ASYNC_REQUESTED_BIT)))
                        return FALSE;
 
-               //If there's an outstanding prot block, we queue it
-               if (prot_count && !force_interrupt) {
-                       new_state = old_state | INTERRUPT_REQUEST_DEFERRED_BIT;
-               } else
-                       new_state = old_state | INTERRUPT_REQUESTED_BIT;
+               if (sync)
+                       new_state = old_state | INTERRUPT_SYNC_REQUESTED_BIT;
+               else
+                       new_state = old_state | INTERRUPT_ASYNC_REQUESTED_BIT;
        } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
 
-       return (new_state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
+       if (sync || !(new_state & ABORT_PROT_BLOCK_MASK)) {
+               InterlockedIncrement (&thread_interruption_requested);
+               THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir %d\n", mono_thread_internal_current ()->small_id, thread->small_id, old_state, new_state, thread_interruption_requested);
+       } else {
+               THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir deferred %d\n", mono_thread_internal_current ()->small_id, thread->small_id, old_state, new_state, thread_interruption_requested);
+       }
+
+       return sync || !(new_state & ABORT_PROT_BLOCK_MASK);
 }
 
 static inline MonoNativeThreadId
@@ -879,11 +884,11 @@ start_wrapper (gpointer data)
        start_info = (StartInfo*) data;
        g_assert (start_info);
 
-       info = mono_thread_info_attach (&res);
+       info = mono_thread_info_attach ();
        info->runtime_thread = TRUE;
 
        /* Run the actual main function of the thread */
-       res = start_wrapper_internal (start_info, &res);
+       res = start_wrapper_internal (start_info, info->stack_end);
 
        mono_thread_info_exit (res);
 
@@ -998,19 +1003,31 @@ done:
        return ret;
 }
 
-void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
+/**
+ * mono_thread_new_init:
+ */
+void
+mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
 {
        if (mono_thread_start_cb) {
                mono_thread_start_cb (tid, stack_start, func);
        }
 }
 
-void mono_threads_set_default_stacksize (guint32 stacksize)
+/**
+ * mono_threads_set_default_stacksize:
+ */
+void
+mono_threads_set_default_stacksize (guint32 stacksize)
 {
        default_stacksize = stacksize;
 }
 
-guint32 mono_threads_get_default_stacksize (void)
+/**
+ * mono_threads_get_default_stacksize:
+ */
+guint32
+mono_threads_get_default_stacksize (void)
 {
        return default_stacksize;
 }
@@ -1043,6 +1060,9 @@ mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, Mo
        return internal;
 }
 
+/**
+ * mono_thread_create:
+ */
 void
 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
 {
@@ -1057,6 +1077,9 @@ mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, Mon
        return (NULL != mono_thread_create_internal (domain, func, arg, MONO_THREAD_CREATE_FLAGS_NONE, error));
 }
 
+/**
+ * mono_thread_attach:
+ */
 MonoThread *
 mono_thread_attach (MonoDomain *domain)
 {
@@ -1072,7 +1095,6 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
        MonoThread *thread;
        MonoThreadInfo *info;
        MonoNativeThreadId tid;
-       gsize stack_ptr;
 
        if (mono_thread_internal_current_is_attached ()) {
                if (domain != mono_domain_get ())
@@ -1081,7 +1103,7 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
                return mono_thread_current ();
        }
 
-       info = mono_thread_info_attach (&stack_ptr);
+       info = mono_thread_info_attach ();
        g_assert (info);
 
        tid=mono_native_thread_id_get ();
@@ -1098,17 +1120,8 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
 
        THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
 
-       if (mono_thread_attach_cb) {
-               guint8 *staddr;
-               size_t stsize;
-
-               mono_thread_info_get_stack_bounds (&staddr, &stsize);
-
-               if (staddr == NULL)
-                       mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
-               else
-                       mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
-       }
+       if (mono_thread_attach_cb)
+               mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), info->stack_end);
 
        /* Can happen when we attach the profiler helper thread in order to heapshot. */
        if (!mono_thread_info_current ()->tools_thread)
@@ -1164,8 +1177,7 @@ mono_thread_detach_internal (MonoInternalThread *thread)
        Leaving the counter unbalanced will cause a performance degradation since all threads
        will now keep checking their local flags all the time.
        */
-       if (mono_thread_clear_interruption_requested (thread))
-               InterlockedDecrement (&thread_interruption_requested);
+       mono_thread_clear_interruption_requested (thread);
 
        mono_threads_lock ();
 
@@ -1259,6 +1271,9 @@ done:
         */
 }
 
+/**
+ * mono_thread_detach:
+ */
 void
 mono_thread_detach (MonoThread *thread)
 {
@@ -1266,12 +1281,12 @@ mono_thread_detach (MonoThread *thread)
                mono_thread_detach_internal (thread->internal_thread);
 }
 
-/*
+/**
  * mono_thread_detach_if_exiting:
  *
- *   Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
+ * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
  * This should be used at the end of embedding code which calls into managed code, and which
- * can be called from pthread dtors, like dealloc: implementations in objective-c.
+ * can be called from pthread dtors, like <code>dealloc:</code> implementations in Objective-C.
  */
 mono_bool
 mono_thread_detach_if_exiting (void)
@@ -1301,6 +1316,9 @@ mono_thread_internal_current_is_attached (void)
        return TRUE;
 }
 
+/**
+ * mono_thread_exit:
+ */
 void
 mono_thread_exit (void)
 {
@@ -1493,10 +1511,9 @@ mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
        return res;
 }
 
-/*
+/**
  * mono_thread_get_name_utf8:
- *
- * Return the name of the thread in UTF-8.
+ * \returns the name of the thread in UTF-8.
  * Return NULL if the thread has no name.
  * The returned memory is owned by the caller.
  */
@@ -1519,11 +1536,10 @@ mono_thread_get_name_utf8 (MonoThread *thread)
        return tname;
 }
 
-/*
+/**
  * mono_thread_get_managed_id:
- *
- * Return the Thread.ManagedThreadId value of `thread`.
- * Returns -1 if `thread` is NULL.
+ * \returns the \c Thread.ManagedThreadId value of \p thread.
+ * Returns \c -1 if \p thread is NULL.
  */
 int32_t
 mono_thread_get_managed_id (MonoThread *thread)
@@ -1688,6 +1704,9 @@ ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
        return result;
 }
 
+/**
+ * mono_thread_current:
+ */
 MonoThread *
 mono_thread_current (void)
 {
@@ -2318,10 +2337,8 @@ void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
 
 /**
  * mono_thread_current_check_pending_interrupt:
- *
  * Checks if there's a interruption request and set the pending exception if so.
- *
- * @returns true if a pending exception was set
+ * \returns true if a pending exception was set
  */
 gboolean
 mono_thread_current_check_pending_interrupt (void)
@@ -2399,10 +2416,8 @@ ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject
 
 /**
  * mono_thread_internal_abort:
- *
- * Request thread @thread to be aborted.
- *
- * @thread MUST NOT be the current thread.
+ * Request thread \p thread to be aborted.
+ * \p thread MUST NOT be the current thread.
  */
 void
 mono_thread_internal_abort (MonoInternalThread *thread)
@@ -2620,6 +2635,9 @@ is_running_protected_wrapper (void)
        return found;
 }
 
+/**
+ * mono_thread_stop:
+ */
 void
 mono_thread_stop (MonoThread *thread)
 {
@@ -2936,8 +2954,9 @@ free_context (void *user_data)
 }
 
 void
-ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
+mono_threads_register_app_context (MonoAppContext *ctx, MonoError *error)
 {
+       error_init (error);
        mono_threads_lock ();
 
        //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
@@ -2969,7 +2988,14 @@ ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppConte
 }
 
 void
-ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
+ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContextHandle ctx, MonoError *error)
+{
+       error_init (error);
+       mono_threads_register_app_context (MONO_HANDLE_RAW (ctx), error); /* FIXME use handles in mono_threads_register_app_context */
+}
+
+void
+mono_threads_release_app_context (MonoAppContext* ctx, MonoError *error)
 {
        /*
         * NOTE: Since finalizers are unreliable for the purposes of ensuring
@@ -2982,6 +3008,13 @@ ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContex
        mono_profiler_context_unloaded (ctx);
 }
 
+void
+ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContextHandle ctx, MonoError *error)
+{
+       error_init (error);
+       mono_threads_release_app_context (MONO_HANDLE_RAW (ctx), error); /* FIXME use handles in mono_threads_release_app_context */
+}
+
 void mono_thread_init (MonoThreadStartCB start_cb,
                       MonoThreadAttachCB attach_cb)
 {
@@ -2999,7 +3032,11 @@ void mono_thread_init (MonoThreadStartCB start_cb,
        mono_thread_attach_cb = attach_cb;
 }
 
-void mono_thread_cleanup (void)
+/**
+ * mono_thread_cleanup:
+ */
+void
+mono_thread_cleanup (void)
 {
 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
        /* The main thread must abandon any held mutexes (particularly
@@ -3030,6 +3067,9 @@ mono_threads_install_cleanup (MonoThreadCleanupFunc func)
        mono_thread_cleanup_fn = func;
 }
 
+/**
+ * mono_thread_set_manage_callback:
+ */
 void
 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
 {
@@ -3223,7 +3263,11 @@ mono_threads_set_shutting_down (void)
        }
 }
 
-void mono_thread_manage (void)
+/**
+ * mono_thread_manage:
+ */
+void
+mono_thread_manage (void)
 {
        struct wait_data wait_data;
        struct wait_data *wait = &wait_data;
@@ -3673,7 +3717,10 @@ mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_fra
                                        sf->il_offset = location->il_offset;
 
                                        if (location && location->source_file) {
-                                               MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
+                                               MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
+                                               if (!is_ok (error))
+                                                       goto leave;
+                                               MONO_OBJECT_SETREF (sf, filename, filename);
                                                sf->line = location->row;
                                                sf->column = location->column;
                                        }
@@ -3859,10 +3906,6 @@ collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
 gboolean
 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
 {
-#ifdef __native_client__
-       return FALSE;
-#endif
-
        abort_appdomain_data user_data;
        gint64 start_time;
        int orig_timeout = timeout;
@@ -4378,16 +4421,17 @@ mono_thread_execute_interruption (void)
        LOCK_THREAD (thread);
 
        /* MonoThread::interruption_requested can only be changed with atomics */
-       if (mono_thread_clear_interruption_requested (thread)) {
-               /* this will consume pending APC calls */
+       if (!mono_thread_clear_interruption_requested (thread)) {
+               UNLOCK_THREAD (thread);
+               return NULL;
+       }
+
+       /* this will consume pending APC calls */
 #ifdef HOST_WIN32
-               WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
+       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_self_interrupt ();
-       }
+       /* Clear the interrupted flag of the thread so it can wait again */
+       mono_thread_info_clear_self_interrupt ();
 
        /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
        if (sys_thread->pending_exception) {
@@ -4445,7 +4489,6 @@ mono_thread_request_interruption (gboolean running_managed)
 
        if (!mono_thread_set_interruption_requested (thread))
                return NULL;
-       InterlockedIncrement (&thread_interruption_requested);
 
        if (!running_managed || is_running_protected_wrapper ()) {
                /* Can't stop while in unmanaged code. Increase the global interruption
@@ -4470,7 +4513,7 @@ mono_thread_request_interruption (gboolean running_managed)
 /*This function should be called by a thread after it has exited all of
  * its handle blocks at interruption time.*/
 MonoException*
-mono_thread_resume_interruption (void)
+mono_thread_resume_interruption (gboolean exec)
 {
        MonoInternalThread *thread = mono_thread_internal_current ();
        gboolean still_aborting;
@@ -4485,15 +4528,17 @@ mono_thread_resume_interruption (void)
 
        /*This can happen if the protected block called Thread::ResetAbort*/
        if (!still_aborting)
-               return FALSE;
+               return NULL;
 
        if (!mono_thread_set_interruption_requested (thread))
                return NULL;
-       InterlockedIncrement (&thread_interruption_requested);
 
        mono_thread_info_self_interrupt ();
 
-       return mono_thread_execute_interruption ();
+       if (exec)
+               return mono_thread_execute_interruption ();
+       else
+               return NULL;
 }
 
 gboolean mono_thread_interruption_requested ()
@@ -4620,10 +4665,8 @@ mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
 
 /**
  * mono_thread_test_and_set_state:
- *
- * Test if current state of @thread include @test. If it does not, OR @set into the state.
- *
- * Returns TRUE is @set was OR'd in.
+ * Test if current state of \p thread include \p test. If it does not, OR \p set into the state.
+ * \returns TRUE if \p set was OR'd in.
  */
 gboolean
 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
@@ -4746,8 +4789,6 @@ async_abort_critical (MonoThreadInfo *info, gpointer ud)
        if (!mono_thread_set_interruption_requested (thread))
                return MonoResumeThread;
 
-       InterlockedIncrement (&thread_interruption_requested);
-
        ji = mono_thread_info_get_last_managed (info);
        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));
@@ -4838,8 +4879,7 @@ async_suspend_critical (MonoThreadInfo *info, gpointer ud)
                        return KeepSuspended;
                }
        } else {
-               if (mono_thread_set_interruption_requested (thread))
-                       InterlockedIncrement (&thread_interruption_requested);
+               mono_thread_set_interruption_requested (thread);
                if (data->interrupt)
                        data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
 
@@ -4919,14 +4959,14 @@ mono_thread_internal_suspend_for_shutdown (MonoInternalThread *thread)
        mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, suspend_for_shutdown_critical, NULL);
 }
 
-/*
+/**
  * mono_thread_is_foreign:
- * @thread: the thread to query
+ * \param thread the thread to query
  *
  * This function allows one to determine if a thread was created by the mono runtime and has
- * a well defined lifecycle or it's a foreigh one, created by the native environment.
+ * a well defined lifecycle or it's a foreign one, created by the native environment.
  *
- * Returns: TRUE if @thread was not created by the runtime.
+ * \returns TRUE if \p thread was not created by the runtime.
  */
 mono_bool
 mono_thread_is_foreign (MonoThread *thread)
@@ -5163,20 +5203,6 @@ mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
        }
 }
 
-MonoException*
-mono_thread_try_resume_interruption (void)
-{
-       MonoInternalThread *thread;
-
-       thread = mono_thread_internal_current ();
-       if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
-               return NULL;
-       if (mono_thread_get_abort_prot_block_count (thread) > 0 || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
-               return NULL;
-
-       return mono_thread_resume_interruption ();
-}
-
 #if 0
 /* Returns TRUE if the current thread is ready to be interrupted. */
 gboolean