[runtime] Collapse interruption_requested and abort_protected_block_count into a...
authorRodrigo Kumpera <kumpera@gmail.com>
Fri, 16 Dec 2016 01:58:32 +0000 (23:58 -0200)
committerRodrigo Kumpera <kumpera@gmail.com>
Thu, 19 Jan 2017 21:34:51 +0000 (13:34 -0800)
This change doesn't change behavior.

mono/metadata/object-internals.h
mono/metadata/threads.c

index 8cd694f24f845c4d8019bbb0254c490517ed150a..2d175ae3a0636efddf89afb88330c2c4587c1c0a 100644 (file)
@@ -375,7 +375,7 @@ struct _MonoInternalThread {
        int _serialized_principal_version;
        gpointer appdomain_refs;
        /* This is modified using atomic ops, so keep it a gint32 */
-       gint32 interruption_requested;
+       gint32 __interruption_requested;
        MonoCoopMutex *synch_cs;
        MonoBoolean threadpool_thread;
        MonoBoolean thread_interrupt_requested;
@@ -388,18 +388,19 @@ struct _MonoInternalThread {
        gpointer interrupt_on_stop;
        gsize    flags;
        gpointer thread_pinning_ref;
-       gsize abort_protected_block_count;
+       gsize __abort_protected_block_count;
        gint32 priority;
        GPtrArray *owned_mutexes;
        MonoOSEvent *suspended;
        gint32 self_suspended; // TRUE | FALSE
+
+       gsize thread_state;
        /* 
         * These fields are used to avoid having to increment corlib versions
         * when a new field is added to this structure.
         * Please synchronize any changes with InternalThread in Thread.cs, i.e. add the
         * same field there.
         */
-       gsize unused1;
        gsize unused2;
 
        /* This is used only to check that we are in sync between the representation
index b5ffc0202314853e9c36d478c6eab0df86575253..b2fec90ae7219b602c2e766bfc9b3b8ce06347df 100644 (file)
@@ -228,6 +228,85 @@ get_next_managed_thread_id (void)
        return InterlockedIncrement (&managed_thread_id_counter);
 }
 
+enum {
+       INTERRUPT_REQUESTED_BIT = 0x1,
+       ABORT_PROT_BLOCK_SHIFT = 1,
+       ABORT_PROT_BLOCK_BITS = 8,
+       ABORT_PROT_BLOCK_MASK = (((1 << ABORT_PROT_BLOCK_BITS) - 1) << ABORT_PROT_BLOCK_SHIFT)
+};
+
+static int
+mono_thread_get_abort_prot_block_count (MonoInternalThread *thread)
+{
+       gsize state = thread->thread_state;
+       return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
+}
+
+//Don't use this function, use inc/dec below
+static void
+mono_thread_abort_prot_block_count_add (MonoInternalThread *thread, int val)
+{
+       gsize old_state, new_state;
+       do {
+               old_state = thread->thread_state;
+               int new_val = val + ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT);
+               //bounds check abort_prot_count
+               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);
+
+       } 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);
+}
+
+static void
+mono_thread_dec_abort_prot_block_count (MonoInternalThread *thread)
+{
+       mono_thread_abort_prot_block_count_add (thread, -1);
+}
+
+static gboolean
+mono_thread_get_interruption_requested (MonoInternalThread *thread)
+{
+       gsize state = thread->thread_state;
+       return (state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
+}
+
+/* Returns TRUE is there was a state change */
+static gboolean
+mono_thread_clear_interruption_requested (MonoInternalThread *thread)
+{
+       gsize old_state, new_state;
+       do {
+               old_state = thread->thread_state;
+               //Already cleared
+               if (!(old_state & INTERRUPT_REQUESTED_BIT))
+                       return FALSE;
+               new_state = old_state & ~INTERRUPT_REQUESTED_BIT;
+       } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+       return TRUE;
+}
+
+/* Returns TRUE is there was a state change */
+static gboolean
+mono_thread_set_interruption_requested (MonoInternalThread *thread)
+{
+       gsize old_state, new_state;
+       do {
+               old_state = thread->thread_state;
+               //Already set
+               if (old_state & INTERRUPT_REQUESTED_BIT)
+                       return FALSE;
+               new_state = old_state | INTERRUPT_REQUESTED_BIT;
+       } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
+       return TRUE;
+}
+
 static inline MonoNativeThreadId
 thread_get_tid (MonoInternalThread *thread)
 {
@@ -1007,7 +1086,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 (InterlockedExchange (&thread->interruption_requested, 0) != 0)
+       if (mono_thread_clear_interruption_requested (thread))
                InterlockedDecrement (&thread_interruption_requested);
 
        mono_threads_lock ();
@@ -4306,7 +4385,7 @@ mono_thread_execute_interruption (void)
        LOCK_THREAD (thread);
 
        /* MonoThread::interruption_requested can only be changed with atomics */
-       if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
+       if (mono_thread_clear_interruption_requested (thread)) {
                /* this will consume pending APC calls */
 #ifdef HOST_WIN32
                WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
@@ -4386,7 +4465,7 @@ mono_thread_request_interruption (gboolean running_managed)
                thread->state & ThreadState_Background)
                ExitThread (1);
 #endif
-       if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
+       if (!mono_thread_set_interruption_requested (thread))
                return NULL;
        InterlockedIncrement (&thread_interruption_requested);
 
@@ -4430,7 +4509,7 @@ mono_thread_resume_interruption (void)
        if (!still_aborting)
                return FALSE;
 
-       if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
+       if (!mono_thread_set_interruption_requested (thread))
                return NULL;
        InterlockedIncrement (&thread_interruption_requested);
 
@@ -4445,7 +4524,7 @@ gboolean mono_thread_interruption_requested ()
                MonoInternalThread *thread = mono_thread_internal_current ();
                /* The thread may already be stopping */
                if (thread != NULL) 
-                       return (thread->interruption_requested);
+                       return mono_thread_get_interruption_requested (thread);
        }
        return FALSE;
 }
@@ -4458,7 +4537,7 @@ mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
        /* The thread may already be stopping */
        if (!thread)
                return NULL;
-       if (!thread->interruption_requested)
+       if (!mono_thread_get_interruption_requested (thread))
                return NULL;
        if (!bypass_abort_protection && is_running_protected_wrapper ())
                return NULL;
@@ -4689,11 +4768,11 @@ async_abort_critical (MonoThreadInfo *info, gpointer ud)
        The target thread is running at least one protected block, which must not be interrupted, so we give up.
        The protected block code will give them a chance when appropriate.
        */
-       if (thread->abort_protected_block_count)
+       if (mono_thread_get_abort_prot_block_count (thread) > 0)
                return MonoResumeThread;
 
        /*someone is already interrupting it*/
-       if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
+       if (!mono_thread_set_interruption_requested (thread))
                return MonoResumeThread;
 
        InterlockedIncrement (&thread_interruption_requested);
@@ -4788,7 +4867,7 @@ async_suspend_critical (MonoThreadInfo *info, gpointer ud)
                        return KeepSuspended;
                }
        } else {
-               if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
+               if (mono_thread_set_interruption_requested (thread))
                        InterlockedIncrement (&thread_interruption_requested);
                if (data->interrupt)
                        data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
@@ -5102,7 +5181,7 @@ mono_threads_begin_abort_protected_block (void)
        MonoInternalThread *thread;
 
        thread = mono_thread_internal_current ();
-       ++thread->abort_protected_block_count;
+       mono_thread_inc_abort_prot_block_count (thread);
        mono_memory_barrier ();
 }
 
@@ -5114,7 +5193,7 @@ mono_threads_end_abort_protected_block (void)
        thread = mono_thread_internal_current ();
 
        mono_memory_barrier ();
-       --thread->abort_protected_block_count;
+       mono_thread_dec_abort_prot_block_count (thread);
 }
 
 MonoException*
@@ -5123,7 +5202,7 @@ mono_thread_try_resume_interruption (void)
        MonoInternalThread *thread;
 
        thread = mono_thread_internal_current ();
-       if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
+       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 ();
@@ -5143,7 +5222,7 @@ mono_threads_is_ready_to_be_interrupted (void)
                return FALSE;
        }
 
-       if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
+       if (mono_thread_get_abort_prot_block_count (thread) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
                UNLOCK_THREAD (thread);
                return FALSE;
        }