[runtime] Defer async requests during abort protected blocks
[mono.git] / mono / metadata / threads.c
index c41e8d6a832b13b1ecf9d35e5508e8f619ba4435..86c6b8173ea3d49e8b709c557cc835f613784a68 100644 (file)
@@ -259,6 +259,10 @@ mono_threads_begin_abort_protected_block (void)
 
                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);
 }
 
 static gboolean
@@ -280,17 +284,21 @@ 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;
 
                //bounds check abort_prot_count
-               int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
+               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 - (1 << ABORT_PROT_BLOCK_SHIFT);
        } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
 
+       if (new_val == 0 && (new_state & INTERRUPT_ASYNC_REQUESTED_BIT))
+               InterlockedIncrement (&thread_interruption_requested);
+
        return mono_thread_state_has_interruption (new_state);
 }
 
@@ -350,7 +358,8 @@ mono_thread_set_interruption_requested (MonoInternalThread *thread)
                        new_state = old_state | INTERRUPT_ASYNC_REQUESTED_BIT;
        } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
 
-       InterlockedIncrement (&thread_interruption_requested);
+       if (sync || !(new_state & ABORT_PROT_BLOCK_MASK))
+               InterlockedIncrement (&thread_interruption_requested);
 
        return sync || !(new_state & ABORT_PROT_BLOCK_MASK);
 }
@@ -4445,7 +4454,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;
@@ -4460,14 +4469,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;
 
        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 ()
@@ -5134,20 +5146,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