[runtime] Ignore ResetAbort when the current appdomain is unloading
authorVlad Brezae <brezaevlad@gmail.com>
Mon, 11 Sep 2017 19:26:28 +0000 (22:26 +0300)
committerVlad Brezae <brezaevlad@gmail.com>
Fri, 22 Sep 2017 08:08:49 +0000 (11:08 +0300)
Fixes #5804

mono/metadata/gc.c
mono/metadata/object-internals.h
mono/metadata/threads-types.h
mono/metadata/threads.c
mono/mini/debugger-agent.c

index 3e0fcb0953e83f67c14eaf27afae8c3a4ddaf978..80605dba2d0d7f4aff7090ebf2e60aefb53704a0 100644 (file)
@@ -1009,7 +1009,7 @@ mono_gc_cleanup (void)
                                        mono_gc_suspend_finalizers ();
 
                                        /* Try to abort the thread, in the hope that it is running managed code */
-                                       mono_thread_internal_abort (gc_thread);
+                                       mono_thread_internal_abort (gc_thread, FALSE);
 
                                        /* Wait for it to stop */
                                        ret = guarded_wait (gc_thread->handle, 100, FALSE);
index 07aaee6830005ba3f2df4103838289d2820a772a..3b4db614bba06297be0e6e70e2a96e35f4e9a21a 100644 (file)
@@ -376,6 +376,7 @@ typedef struct {
 typedef enum {
        MONO_THREAD_FLAG_DONT_MANAGE = 1, // Don't wait for or abort this thread
        MONO_THREAD_FLAG_NAME_SET = 2, // Thread name set from managed code
+       MONO_THREAD_FLAG_APPDOMAIN_ABORT = 4, // Current requested abort originates from appdomain unload
 } MonoThreadFlags;
 
 struct _MonoInternalThread {
index ced0ac516efbf9a8e91c47df9fbef6ceec645bc6..013046d0ee808d6cd1bfcd4cd0894d628faeed1e 100644 (file)
@@ -189,7 +189,7 @@ void ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppC
 
 MonoInternalThread *mono_thread_internal_current (void);
 
-void mono_thread_internal_abort (MonoInternalThread *thread);
+void mono_thread_internal_abort (MonoInternalThread *thread, gboolean appdomain_unload);
 void mono_thread_internal_suspend_for_shutdown (MonoInternalThread *thread);
 
 gboolean mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain);
index 3b5b518666b77822bd077816ca58cc7668b029c8..f804fce27933f6565bdb532785e2ba2be895cf3e 100644 (file)
@@ -2292,7 +2292,7 @@ mono_thread_current_check_pending_interrupt (void)
 }
 
 static gboolean
-request_thread_abort (MonoInternalThread *thread, MonoObject *state)
+request_thread_abort (MonoInternalThread *thread, MonoObject *state, gboolean appdomain_unload)
 {
        LOCK_THREAD (thread);
        
@@ -2309,6 +2309,11 @@ request_thread_abort (MonoInternalThread *thread, MonoObject *state)
        }
 
        thread->state |= ThreadState_AbortRequested;
+       if (appdomain_unload)
+               thread->flags |= MONO_THREAD_FLAG_APPDOMAIN_ABORT;
+       else
+               thread->flags &= ~MONO_THREAD_FLAG_APPDOMAIN_ABORT;
+
        if (thread->abort_state_handle)
                mono_gchandle_free (thread->abort_state_handle);
        if (state) {
@@ -2333,7 +2338,7 @@ request_thread_abort (MonoInternalThread *thread, MonoObject *state)
 void
 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
 {
-       if (!request_thread_abort (thread, state))
+       if (!request_thread_abort (thread, state, FALSE))
                return;
 
        if (thread == mono_thread_internal_current ()) {
@@ -2351,11 +2356,11 @@ ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject
  * \p thread MUST NOT be the current thread.
  */
 void
-mono_thread_internal_abort (MonoInternalThread *thread)
+mono_thread_internal_abort (MonoInternalThread *thread, gboolean appdomain_unload)
 {
        g_assert (thread != mono_thread_internal_current ());
 
-       if (!request_thread_abort (thread, NULL))
+       if (!request_thread_abort (thread, NULL, appdomain_unload))
                return;
        async_abort_internal (thread, TRUE);
 }
@@ -2364,17 +2369,23 @@ void
 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
 {
        MonoInternalThread *thread = mono_thread_internal_current ();
-       gboolean was_aborting;
+       gboolean was_aborting, is_domain_abort;
 
        LOCK_THREAD (thread);
        was_aborting = thread->state & ThreadState_AbortRequested;
-       thread->state &= ~ThreadState_AbortRequested;
+       is_domain_abort = thread->flags & MONO_THREAD_FLAG_APPDOMAIN_ABORT; 
+
+       if (was_aborting && !is_domain_abort)
+               thread->state &= ~ThreadState_AbortRequested;
        UNLOCK_THREAD (thread);
 
        if (!was_aborting) {
                const char *msg = "Unable to reset abort because no abort was requested";
                mono_set_pending_exception (mono_get_exception_thread_state (msg));
                return;
+       } else if (is_domain_abort) {
+               /* Silently ignore abort resets in unloading appdomains */
+               return;
        }
 
        mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
@@ -2574,7 +2585,7 @@ mono_thread_stop (MonoThread *thread)
 {
        MonoInternalThread *internal = thread->internal_thread;
 
-       if (!request_thread_abort (internal, NULL))
+       if (!request_thread_abort (internal, NULL, FALSE))
                return;
 
        if (internal == mono_thread_internal_current ()) {
@@ -3222,7 +3233,7 @@ remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
                wait->num++;
 
                THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
-               mono_thread_internal_abort (thread);
+               mono_thread_internal_abort (thread, FALSE);
        }
 
        return TRUE;
@@ -3937,7 +3948,7 @@ mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
                if (user_data.wait.num > 0) {
                        /* Abort the threads outside the threads lock */
                        for (i = 0; i < user_data.wait.num; ++i)
-                               mono_thread_internal_abort (user_data.wait.threads [i]);
+                               mono_thread_internal_abort (user_data.wait.threads [i], TRUE);
 
                        /*
                         * We should wait for the threads either to abort, or to leave the
index cb0600828e9c4116eccd38a44843358bd263666c..29f94ba1e06e0b4870e9d4bda438e4ab39a9718d 100644 (file)
@@ -7691,7 +7691,7 @@ vm_commands (int command, int id, guint8 *p, guint8 *end, Buffer *buf)
 
                tls->abort_requested = TRUE;
 
-               mono_thread_internal_abort (THREAD_TO_INTERNAL (thread));
+               mono_thread_internal_abort (THREAD_TO_INTERNAL (thread), FALSE);
                mono_loader_unlock ();
                break;
        }