[threads] Fix async call in coop (#4423)
[mono.git] / mono / utils / mono-threads-coop.c
index 78ff1c45d7075b7e8ae584af1230c422702d889a..ed6b1807a3a22a97bcba35b62862c27e3a09e670 100644 (file)
@@ -27,6 +27,7 @@
 #include <mono/utils/mono-threads-coop.h>
 #include <mono/utils/mono-threads-api.h>
 #include <mono/utils/checked-build.h>
+#include <mono/utils/mono-threads-debug.h>
 
 #ifdef TARGET_OSX
 #include <mono/utils/mach-support.h>
@@ -70,7 +71,7 @@ coop_tls_pop (gpointer received_cookie)
 
        stack = mono_native_tls_get_value (coop_reset_count_stack_key);
        if (!stack || 0 == stack->len)
-               mono_fatal_with_history ("Received cookie %p but found no stack at all, %x\n", received_cookie);
+               mono_fatal_with_history ("Received cookie %p but found no stack at all\n", received_cookie);
 
        expected_cookie = g_array_index (stack, gpointer, stack->len - 1);
        stack->len --;
@@ -103,18 +104,25 @@ static int coop_do_blocking_count;
 static int coop_do_polling_count;
 static int coop_save_count;
 
+static void
+mono_threads_state_poll_with_info (MonoThreadInfo *info);
+
 void
 mono_threads_state_poll (void)
 {
-       MonoThreadInfo *info;
+       mono_threads_state_poll_with_info (mono_thread_info_current_unchecked ());
+}
 
+static void
+mono_threads_state_poll_with_info (MonoThreadInfo *info)
+{
        g_assert (mono_threads_is_coop_enabled ());
 
        ++coop_do_polling_count;
 
-       info = mono_thread_info_current_unchecked ();
        if (!info)
                return;
+
        THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", mono_thread_info_get_tid (info));
 
        /* Fast check for pending suspend requests */
@@ -127,7 +135,7 @@ mono_threads_state_poll (void)
        /* commit the saved state and notify others if needed */
        switch (mono_threads_transition_state_poll (info)) {
        case SelfSuspendResumed:
-               return;
+               break;
        case SelfSuspendWait:
                mono_thread_info_wait_for_resume (info);
                break;
@@ -136,13 +144,22 @@ mono_threads_state_poll (void)
                mono_thread_info_wait_for_resume (info);
                break;
        }
+
+       if (info->async_target) {
+               info->async_target (info->user_data);
+               info->async_target = NULL;
+               info->user_data = NULL;
+       }
 }
 
-static void *
-return_stack_ptr ()
+static volatile gpointer* dummy_global;
+
+static MONO_NEVER_INLINE
+void*
+return_stack_ptr (gpointer *i)
 {
-       gpointer i;
-       return &i;
+       dummy_global = i;
+       return i;
 }
 
 static void
@@ -150,7 +167,8 @@ copy_stack_data (MonoThreadInfo *info, gpointer *stackdata_begin)
 {
        MonoThreadUnwindState *state;
        int stackdata_size;
-       void* stackdata_end = return_stack_ptr ();
+       gpointer dummy;
+       void* stackdata_end = return_stack_ptr (&dummy);
 
        SAVE_REGS_ON_STACK;
 
@@ -226,7 +244,7 @@ retry:
        case DoBlockingContinue:
                break;
        case DoBlockingPollAndRetry:
-               mono_threads_state_poll ();
+               mono_threads_state_poll_with_info (info);
                goto retry;
        }
 
@@ -270,6 +288,12 @@ mono_threads_exit_gc_safe_region_unbalanced (gpointer cookie, gpointer *stackdat
        default:
                g_error ("Unknown thread state");
        }
+
+       if (info->async_target) {
+               info->async_target (info->user_data);
+               info->async_target = NULL;
+               info->user_data = NULL;
+       }
 }
 
 void
@@ -325,7 +349,7 @@ mono_threads_enter_gc_unsafe_region_unbalanced_with_info (MonoThreadInfo *info,
                info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
                return NULL;
        case AbortBlockingIgnoreAndPoll:
-               mono_threads_state_poll ();
+               mono_threads_state_poll_with_info (info);
                return NULL;
        case AbortBlockingOk:
                info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
@@ -337,6 +361,12 @@ mono_threads_enter_gc_unsafe_region_unbalanced_with_info (MonoThreadInfo *info,
                g_error ("Unknown thread state");
        }
 
+       if (info->async_target) {
+               info->async_target (info->user_data);
+               info->async_target = NULL;
+               info->user_data = NULL;
+       }
+
        return info;
 }
 
@@ -382,13 +412,6 @@ mono_threads_exit_gc_unsafe_region_unbalanced (gpointer cookie, gpointer *stackd
        if (!cookie)
                return;
 
-#ifdef ENABLE_CHECKED_BUILD_GC
-       if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
-#endif
-       {
-               g_assert (((MonoThreadInfo *)cookie) == mono_thread_info_current_unchecked ());
-       }
-
        mono_threads_enter_gc_safe_region_unbalanced (stackdata);
 }
 
@@ -413,7 +436,7 @@ mono_threads_is_coop_enabled (void)
 
 
 void
-mono_threads_init_coop (void)
+mono_threads_coop_init (void)
 {
        if (!mono_threads_is_coop_enabled ())
                return;