[threading] Split unwind state into sync and async.
authorRodrigo Kumpera <kumpera@gmail.com>
Mon, 2 Feb 2015 16:04:37 +0000 (11:04 -0500)
committerRodrigo Kumpera <kumpera@gmail.com>
Wed, 11 Mar 2015 16:26:37 +0000 (12:26 -0400)
Having a single unwind state means writes to it must be synchronized between sync and async suspend. We can't
have the state be broken as it could lead to bad unwinding or GC marking.

The original solution was to have an additional state in the self suspend path that signals it's writing to the
thread state and thus any async suspend must give up and let it finish. This ended up been overly complicated
as this requires two additional states instead.

By having a pair of unwind states both can write concurrently without the fear of clashing. This makes fetching the state
a little bit trickier but worth the trouble.

The simplified design has a much smaller state space, which is easier to reason about.

mono/metadata/sgen-stw.c
mono/metadata/threads.c
mono/mini/debugger-agent.c
mono/mini/exceptions-amd64.c
mono/utils/mono-threads-mach.c
mono/utils/mono-threads-posix.c
mono/utils/mono-threads-state-machine.c
mono/utils/mono-threads-windows.c
mono/utils/mono-threads.c
mono/utils/mono-threads.h

index 6b10caf7b23c3b4744b36c88445804c99fb8ab51..bc65136287da9043cbea143ba657b15ea6ae0447 100644 (file)
@@ -402,15 +402,15 @@ update_sgen_info (SgenThreadInfo *info)
 
        /* Once we remove the old suspend code, we should move sgen to directly access the state in MonoThread */
        info->stopped_domain = mono_thread_info_tls_get (info, TLS_KEY_DOMAIN);
-       info->stopped_ip = (gpointer) MONO_CONTEXT_GET_IP (&info->info.suspend_state.ctx);
-       stack_start = (char*)MONO_CONTEXT_GET_SP (&info->info.suspend_state.ctx) - REDZONE_SIZE;
+       info->stopped_ip = (gpointer) MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx);
+       stack_start = (char*)MONO_CONTEXT_GET_SP (&mono_thread_info_get_suspend_state (info)->ctx) - REDZONE_SIZE;
 
        /* altstack signal handler, sgen can't handle them, mono-threads should have handled this. */
        if (stack_start < (char*)info->stack_start_limit || stack_start >= (char*)info->stack_end)
                g_error ("BAD STACK");
 
        info->stack_start = stack_start;
-       info->ctx = info->info.suspend_state.ctx;
+       info->ctx = mono_thread_info_get_suspend_state (info)->ctx;
 }
 
 static int
index a1a1f6730dd224084cc0321be64dfa4506883a19..8cd8352adccd342d7b51919bcdeea29c057dc021 100644 (file)
@@ -3251,7 +3251,7 @@ print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
 #endif
 #endif
 
-       mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
+       mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, text);
        mono_thread_info_finish_suspend_and_resume (info);
 
        fprintf (stdout, "%s", text->str);
@@ -4564,7 +4564,7 @@ self_interrupt_thread (void *_unused)
        MonoThreadInfo *info = mono_thread_info_current ();
        MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ()); 
        if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
-               mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
+               mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
        g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
 }
 
@@ -4590,7 +4590,7 @@ mono_thread_info_get_last_managed (MonoThreadInfo *info)
        MonoJitInfo *ji = NULL;
        if (!info)
                return NULL;
-       mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
+       mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
        return ji;
 }
 
@@ -4625,7 +4625,7 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
                return;
        }
 
-       if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
+       if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info))) {
                mono_thread_info_finish_suspend_and_resume (info);
                return;
        }
@@ -4639,7 +4639,7 @@ abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception,
 
        ji = mono_thread_info_get_last_managed (info);
        protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
-       running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
+       running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
 
        if (!protected_wrapper && running_managed) {
                /*We are in managed code*/
@@ -4712,7 +4712,7 @@ suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
 
                ji = mono_thread_info_get_last_managed (info);
                protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
-               running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
+               running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
 
                if (running_managed && !protected_wrapper) {
                        transition_to_suspended (thread, info);
index 9541375054653209d13cac04ec29de4c6cff30cf..576d004ec91ef8e2e5ccf98c71a661d524d446c4 100644 (file)
@@ -2572,7 +2572,7 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, void *sigctx, Mono
        if (sigctx)
                ip = mono_arch_ip_from_context (sigctx);
        else if (info)
-               ip = MONO_CONTEXT_GET_IP (&info->suspend_state.ctx);
+               ip = MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx);
        else
                ip = NULL;
 
@@ -2629,7 +2629,7 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, void *sigctx, Mono
                                 */
                                mono_walk_stack_with_ctx (get_last_frame, &ctx, MONO_UNWIND_NONE, &data);
                        } else if (info) {
-                               mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &data);
+                               mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &data);
                        }
                        if (data.last_frame_set) {
                                memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo));
@@ -2758,7 +2758,7 @@ notify_thread (gpointer key, gpointer value, gpointer user_data)
                         */
                        tls->terminated = TRUE;
                } else {
-                       ji = mono_jit_info_table_find (info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN], MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
+                       ji = mono_jit_info_table_find (mono_thread_info_get_suspend_state (info)->unwind_data [MONO_UNWIND_DATA_DOMAIN], MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
 
                        thread_interrupt (tls, info, NULL, ji);
 
index 5df8f2f1805006be4409e4ffa652e744e8272200..9202255409b9669bd03e96177c09fcb1e506c34c 100644 (file)
@@ -1018,8 +1018,8 @@ mono_arch_notify_pending_exc (MonoThreadInfo *info)
        if (!info) {
                lmf = mono_get_lmf ();
        } else {
-               g_assert (info->suspend_state.valid);
-               lmf = info->suspend_state.unwind_data [MONO_UNWIND_DATA_LMF];
+               g_assert (info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].valid);
+               lmf = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].unwind_data [MONO_UNWIND_DATA_LMF];
        }
 
        if (!lmf)
index cfa20d7fae7267677777dba6d5f16f07835518de..7b20a9753a4986de57217828756e4de29a7acc5f 100644 (file)
@@ -73,7 +73,7 @@ mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_
                return TRUE;
        }
        res = mono_threads_get_runtime_callbacks ()->
-               thread_state_init_from_handle (&info->suspend_state, info);
+               thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info);
        THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)info->native_handle, res);
        if (res) {
                if (interrupt_kernel)
@@ -98,7 +98,7 @@ mono_threads_core_begin_async_resume (MonoThreadInfo *info)
        kern_return_t ret;
 
        if (info->async_target) {
-               MonoContext tmp = info->suspend_state.ctx;
+               MonoContext tmp = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx;
                mach_msg_type_number_t num_state;
                thread_state_t state;
                ucontext_t uctx;
index 8beb693a51cc2ba4ab6120fef1f7e2c379641dd3..dcb296fdbe9332c94a372808aa4e9e4a2c06e17f 100644 (file)
@@ -342,7 +342,6 @@ mono_thread_get_alt_suspend_signal (void)
 #endif /* SIGUSR1 */
 #else
        static int suspend_signum = -1;
-       int i;
        if (suspend_signum == -1)
                suspend_signum = mono_thread_search_alt_signal (-1);
        return suspend_signum;
@@ -362,7 +361,6 @@ mono_thread_get_alt_resume_signal (void)
 #endif /* SIGUSR1 */
 #else
        static int resume_signum = -1;
-       int i;
        if (resume_signum == -1)
                resume_signum = mono_thread_search_alt_signal (mono_thread_get_alt_suspend_signal ());
        return resume_signum;
@@ -406,7 +404,7 @@ suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
                goto done;
        }
 
-       ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->suspend_state, context);
+       ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&current->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], context);
 
        /* thread_state_init_from_sigctx return FALSE if the current thread is detaching and suspend can't continue. */
        current->suspend_can_continue = ret;
@@ -442,7 +440,7 @@ suspend_signal_handler (int _dummy, siginfo_t *info, void *context)
 
        if (current->async_target) {
 #if MONO_ARCH_HAS_MONO_CONTEXT
-               MonoContext tmp = current->suspend_state.ctx;
+               MonoContext tmp = current->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx;
                mono_threads_get_runtime_callbacks ()->setup_async_callback (&tmp, current->async_target, current->user_data);
                current->async_target = current->user_data = NULL;
                mono_monoctx_to_sigctx (&tmp, context);
index d63a7b7a3072ae7fbf1f2392ee8d76fada14f092..062c968608d3bc51d89aa11b26d36df9544f9f54 100644 (file)
@@ -41,8 +41,6 @@ state_name (int state)
                "SELF_SUSPENDED",
                "ASYNC_SUSPEND_REQUESTED",
                "SELF_SUSPEND_REQUESTED",
-               "SUSPEND_IN_PROGRESS",
-               "SUSPEND_PROMOTED_TO_ASYNC",
        };
        return state_names [get_thread_state (state)];
 }
@@ -68,8 +66,6 @@ check_thread_state (MonoThreadInfo* info)
        case STATE_SELF_SUSPENDED:
        case STATE_ASYNC_SUSPEND_REQUESTED:
        case STATE_SELF_SUSPEND_REQUESTED:
-       case STATE_SUSPEND_IN_PROGRESS:
-       case STATE_SUSPEND_PROMOTED_TO_ASYNC:
                g_assert (suspend_count > 0);
                break;
        default:
@@ -140,8 +136,6 @@ retry_state_change:
 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
 STATE_SELF_SUSPENDED: Code should not be running while suspended.
 STATE_SELF_SUSPEND_REQUESTED: This is a bug in the self suspend code that didn't execute the second part of it
-STATE_SUSPEND_IN_PROGRESS: This is an internal state of suspension
-STATE_SUSPEND_PROMOTED_TO_ASYNC: This is an internal state of suspension
 */
        default:
                g_error ("Cannot transition current thread %p from %s with DETACH", info, state_name (cur_state));
@@ -179,8 +173,6 @@ Other states:
 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
 STATE_SELF_SUSPENDED: Code should not be running while suspended.
 STATE_SELF_SUSPEND_REQUESTED: Self suspends should not nest as begin/end should be paired. [1]
-STATE_SUSPEND_IN_PROGRESS: This in an internal state of the self suspend finish protocol. A new self suspend request must not happen during it
-STATE_SUSPEND_PROMOTED_TO_ASYNC: This in an internal state of the self suspend finish protocol. A new self suspend request must not happen during it
 
 [1] This won't trap this sequence of requests: self suspend, async suspend and self suspend. 
 If this turns to be an issue we can introduce a new suspend request state for when both have been requested.
@@ -229,26 +221,13 @@ retry_state_change:
                if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, suspend_count + 1), raw_state) != raw_state)
                        goto retry_state_change;
                trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 1);
-               return AsyncSuspendInitSuspend; //This is the first async suspend request against the target [1]
-
-       case STATE_SUSPEND_IN_PROGRESS: //Self suspend has already initiated, we need to tell it to inform us in the end
-               g_assert (suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX);
-               g_assert (info != mono_thread_info_current ()); // if this is a self suspend request, which can't happen in this state, as this is the middle of the self suspend protocol.
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SUSPEND_PROMOTED_TO_ASYNC, suspend_count + 1), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_SUSPEND_PROMOTED_TO_ASYNC, 1);
-               return AsyncSuspendWait; //This is a self suspend in progress that now needs to notify the initiator
-               break;
+               return AsyncSuspendWait; //This is the first async suspend request, change the thread and let it notify us [1]
 /*
 
 [1] It's questionable on what to do if we hit the beginning of a self suspend.
 The expected behavior is that the target should poll its state very soon so the the suspend latency should be minimal.
-OTOH, an async suspend will speed this and could lead to this happening sooner. This is not set in stone, so we can back out from the current behavior if it shows
-to be a problem.
-
 
 STATE_ASYNC_SUSPEND_REQUESTED: Since there can only be one async suspend in progress and it must finish, it should not be possible to witness this.
-STATE_SUSPEND_PROMOTED_TO_ASYNC: This is a self suspend that was promoted to an async suspend, which should not be possible to witness due to async suspends happening one at a time.
 */
        default:
                g_error ("Cannot transition thread %p from %s with ASYNC_SUSPEND_REQUESTED", info, state_name (cur_state));
@@ -258,11 +237,17 @@ STATE_SUSPEND_PROMOTED_TO_ASYNC: This is a self suspend that was promoted to an
 
 /*
 Check the current state of the thread and try to init a self suspend.
+This must be called with self state saved.
+
+Returns one of the following values:
 
-Returns TRUE is self suspend should start.
+- Resumed: Async resume happened and current thread should keep running
+- Suspend: Caller should wait for a resume signal
+- SelfSuspendNotifyAndWait: Notify the suspend initiator and wait for a resume signals
+ suspend should start.
 
 */
-gboolean
+MonoSelfSupendResult
 mono_threads_transition_state_poll (MonoThreadInfo *info)
 {
        int raw_state, cur_state, suspend_count;
@@ -274,27 +259,22 @@ retry_state_change:
        case STATE_RUNNING:
                g_assert (suspend_count == 0);
                trace_state_change ("STATE_POLL", info, raw_state, cur_state, 0);
-               return FALSE; //We're fine, don't suspend
+               return SelfSuspendResumed; //We're fine, don't suspend
 
        case STATE_ASYNC_SUSPEND_REQUESTED: //Async suspend requested, service it with a self suspend
-               g_assert (suspend_count > 0);
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SUSPEND_PROMOTED_TO_ASYNC, suspend_count), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("STATE_POLL", info, raw_state, STATE_SUSPEND_PROMOTED_TO_ASYNC, 0);
-               return TRUE;
-
        case STATE_SELF_SUSPEND_REQUESTED: //Start the self suspend process
                g_assert (suspend_count > 0);
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SUSPEND_IN_PROGRESS, suspend_count), raw_state) != raw_state)
+               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPENDED, suspend_count), raw_state) != raw_state)
                        goto retry_state_change;
-               trace_state_change ("STATE_POLL", info, raw_state, STATE_SUSPEND_IN_PROGRESS, 0);
-               return TRUE;
+               trace_state_change ("STATE_POLL", info, raw_state, STATE_SELF_SUSPENDED, 0);
+               if (cur_state == STATE_SELF_SUSPEND_REQUESTED)
+                       return SelfSuspendWait; //Caller should wait for resume
+               else
+                       return SelfSuspendNotifyAndWait; //Caller should notify suspend initiator and wait for resume
 
 /*
 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
 STATE_SELF_SUSPENDED: Code should not be running while suspended.
-STATE_SUSPEND_IN_PROGRESS: State polling should not happen while self suspend is finishing
-STATE_SUSPEND_PROMOTED_TO_ASYNC: State polling should not happen while self suspend is finishing
 */
        default:
                g_error ("Cannot transition thread %p from %s with STATE_POLL", info, state_name (cur_state));
@@ -356,7 +336,7 @@ retry_state_change:
                }
 
        case STATE_SELF_SUSPEND_REQUESTED: //Self suspend was requested but another thread decided to resume it.
-       case STATE_SUSPEND_IN_PROGRESS: //Self suspend is in progress but another thread decided to resume it. [4]
+       // case STATE_SUSPEND_IN_PROGRESS: //Self suspend is in progress but another thread decided to resume it. [4]
                g_assert (suspend_count > 0);
                if (suspend_count > 1) {
                        if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
@@ -388,52 +368,6 @@ If this turns to be a problem we should either implement [2] or make this an inv
        }
 }
 
-/*
-Last part of the self suspend protocol.
-
-This must only happens in the context of a self suspend request. This means that the thread must be on one of the
-valid self suspend states.
-
-Returns one of the following values:
-
-- Resumed: Async resume happened and current thread should keep running
-- Suspend: Caller should wait for a resume signal
-- SelfSuspendNotifyAndWait: Notify the suspend initiator and wait for a resume signals
-*/
-MonoSelfSupendResult
-mono_threads_transition_finish_self_suspend (MonoThreadInfo* info)
-{
-       int raw_state, cur_state, suspend_count;
-       g_assert (info ==  mono_thread_info_current ());
-
-retry_state_change:
-       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
-       switch (cur_state) {
-       case STATE_RUNNING: //An async resume hit us and we should keep running
-               trace_state_change ("FINISH_SELF_SUSPEND", info, raw_state, cur_state, 0);
-               return SelfSuspendResumed; //Caller should not suspend
-
-       case STATE_SUSPEND_IN_PROGRESS: //Self suspend finished
-       case STATE_SUSPEND_PROMOTED_TO_ASYNC: //Async suspend happened during the second step of self suspend so the caller needs to notify the initiator.
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPENDED, suspend_count), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("FINISH_SELF_SUSPEND", info, raw_state, STATE_SELF_SUSPENDED, 0);
-               if (cur_state == STATE_SUSPEND_IN_PROGRESS)
-                       return SelfSuspendWait; //Caller should wait for resume
-               else
-                       return SelfSuspendNotifyAndWait; //Caller should notify suspend initiator and wait for resume
-/*
-STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
-STATE_SELF_SUSPENDED: Code should not be running while suspended.
-STATE_ASYNC_SUSPEND_REQUESTED: This state should one be witnessed by the state poll transition
-STATE_SELF_SUSPEND_REQUESTED: This state should one be witnessed by the state poll transition
-*/
-       default:
-               g_error ("Cannot transition thread %p from %s with FINISH_SELF_SUSPEND", info, state_name (cur_state));
-
-       }
-}
-
 /*
 This performs the last step of async suspend.
 
@@ -457,12 +391,12 @@ retry_state_change:
                        goto retry_state_change;
                trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, STATE_ASYNC_SUSPENDED, 0);
                return TRUE; //Async suspend worked, now wait for resume
-
-       case STATE_SUSPEND_IN_PROGRESS:
-               if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SUSPEND_PROMOTED_TO_ASYNC, suspend_count), raw_state) != raw_state)
-                       goto retry_state_change;
-               trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, STATE_SUSPEND_PROMOTED_TO_ASYNC, 0);
-               return FALSE; //async suspend race with self suspend and lost, let the other finish it
+       // 
+       // case STATE_SUSPEND_IN_PROGRESS:
+       //      if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SUSPEND_PROMOTED_TO_ASYNC, suspend_count), raw_state) != raw_state)
+       //              goto retry_state_change;
+       //      trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, STATE_SUSPEND_PROMOTED_TO_ASYNC, 0);
+       //      return FALSE; //async suspend race with self suspend and lost, let the other finish it
 /*
 STATE_RUNNING: A thread cannot escape suspension once requested.
 STATE_ASYNC_SUSPENDED: There can be only one suspend initiator at a given time, meaning this state should have been visible on the first stage of suspend.
@@ -520,6 +454,20 @@ STATE_SUSPEND_IN_PROGRESS: All those are invalid end states of a sucessfull fini
        }
 }
 
+MonoThreadUnwindState*
+mono_thread_info_get_suspend_state (MonoThreadInfo *info)
+{
+       int raw_state, cur_state, suspend_count;
+       UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
+       switch (cur_state) {
+       case STATE_ASYNC_SUSPENDED:
+               return &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX];
+       case STATE_SELF_SUSPENDED:
+               return &info->thread_saved_state [SELF_SUSPEND_STATE_INDEX];
+       default:
+               g_error ("Cannot read suspend state when the target is in the %s state", state_name (cur_state));
+       }
+}
 
 
 
index 8201fbcda68210e82f72e2bd81a8704edca72392..28e67394c721d103cc52b5dc50a5957829e88ff2 100755 (executable)
@@ -79,7 +79,7 @@ mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_
                //XXX interrupt_kernel doesn't make sense in this case as the target is not in a syscall
                return TRUE;
        }
-       res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->suspend_state, info);
+       res = mono_threads_get_runtime_callbacks ()->thread_state_init_from_handle (&info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX], info);
        THREADS_SUSPEND_DEBUG ("thread state %p -> %d\n", (void*)id, res);
        if (res) {
                //FIXME do we need to QueueUserAPC on this case?
@@ -116,7 +116,7 @@ mono_threads_core_begin_async_resume (MonoThreadInfo *info)
                CONTEXT context;
                gboolean res;
 
-               ctx = info->suspend_state.ctx;
+               ctx = info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx;
                mono_threads_get_runtime_callbacks ()->setup_async_callback (&ctx, info->async_target, info->user_data);
                info->async_target = info->user_data = NULL;
 
index 8dee08a9987b10b4bb74b636799f70bfc3f6210f..3e80e89613fc711a2a527d6b609cf6a752aa6279 100644 (file)
@@ -633,14 +633,10 @@ mono_thread_info_end_self_suspend (void)
                return;
        THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", info);
 
-       /* Begin stage two which allows us to save our state */
-       if (!mono_threads_transition_state_poll (info))
-               return;
-
-       g_assert (mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->suspend_state, NULL));
+       g_assert (mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX], NULL));
 
        /* commit the saved state and notify others if needed */
-       switch (mono_threads_transition_finish_self_suspend (info)) {
+       switch (mono_threads_transition_state_poll (info)) {
        case SelfSuspendResumed:
                return;
        case SelfSuspendWait:
@@ -770,6 +766,7 @@ is_thread_in_critical_region (MonoThreadInfo *info)
        MonoMethod *method;
        MonoJitInfo *ji;
        gpointer stack_start;
+       MonoThreadUnwindState *state;
 
        /* Are we inside a system critical region? */
        if (info->inside_critical_region)
@@ -785,17 +782,18 @@ is_thread_in_critical_region (MonoThreadInfo *info)
        }
 
        /* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
-       if (!info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN])
+       state = mono_thread_info_get_suspend_state (info);
+       if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
                return FALSE;
 
-       stack_start = MONO_CONTEXT_GET_SP (&info->suspend_state.ctx);
+       stack_start = MONO_CONTEXT_GET_SP (&state->ctx);
        /* altstack signal handler, sgen can't handle them, so we treat them as critical */
        if (stack_start < info->stack_start_limit || stack_start >= info->stack_end)
                return TRUE;
 
        ji = mono_jit_info_table_find (
-               info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN],
-               MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
+               state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
+               MONO_CONTEXT_GET_IP (&state->ctx));
 
        if (!ji)
                return FALSE;
index 8535646cc44817e0a5403da79f21564feae443bf..305da2f93ee3d3fc4bc3949d21194bf63cbeddb2 100644 (file)
@@ -137,14 +137,17 @@ enum {
        STATE_SELF_SUSPENDED                    = 0x04,
        STATE_ASYNC_SUSPEND_REQUESTED   = 0x05,
        STATE_SELF_SUSPEND_REQUESTED    = 0x06,
-       STATE_SUSPEND_IN_PROGRESS               = 0x07,
-       STATE_SUSPEND_PROMOTED_TO_ASYNC = 0x08,
-       STATE_MAX                                               = 0x08,
+       // STATE_SUSPEND_IN_PROGRESS            = 0x07,
+       // STATE_SUSPEND_PROMOTED_TO_ASYNC      = 0x08,
+       STATE_MAX                                               = 0x06,
 
        THREAD_STATE_MASK                       = 0x00FF,
        THREAD_SUSPEND_COUNT_MASK       = 0xFF00,
        THREAD_SUSPEND_COUNT_SHIFT      = 8,
-       THREAD_SUSPEND_COUNT_MAX        = 0xFF
+       THREAD_SUSPEND_COUNT_MAX        = 0xFF,
+
+       SELF_SUSPEND_STATE_INDEX = 0,
+       ASYNC_SUSPEND_STATE_INDEX = 1,
 };
 
 /*
@@ -186,7 +189,7 @@ typedef struct {
 #endif
 
        /*In theory, only the posix backend needs this, but having it on mach/win32 simplifies things a lot.*/
-       MonoThreadUnwindState suspend_state;
+       MonoThreadUnwindState thread_saved_state [2]; //0 is self suspend, 1 is async suspend.
 
        /*async call machinery, thread MUST be suspended before accessing those fields*/
        void (*async_target)(void*);
@@ -559,12 +562,12 @@ void mono_threads_transition_attach (THREAD_INFO_TYPE* info);
 gboolean mono_threads_transition_detach (THREAD_INFO_TYPE *info);
 void mono_threads_transition_request_self_suspension (THREAD_INFO_TYPE *info);
 MonoRequestAsyncSuspendResult mono_threads_transition_request_async_suspension (THREAD_INFO_TYPE *info);
-gboolean mono_threads_transition_state_poll (THREAD_INFO_TYPE *info);
+MonoSelfSupendResult mono_threads_transition_state_poll (THREAD_INFO_TYPE *info);
 MonoResumeResult mono_threads_transition_request_resume (THREAD_INFO_TYPE* info);
-MonoSelfSupendResult mono_threads_transition_finish_self_suspend (THREAD_INFO_TYPE* info);
 gboolean mono_threads_transition_finish_async_suspend (THREAD_INFO_TYPE* info);
-void mono_threads_transition_async_suspend_compensation (MonoThreadInfo* info);
+void mono_threads_transition_async_suspend_compensation (THREAD_INFO_TYPE* info);
 
+MonoThreadUnwindState* mono_thread_info_get_suspend_state (THREAD_INFO_TYPE *info);
 
 /* Advanced suspend API, used for suspending multiple threads as once. */
 gboolean mono_thread_info_is_running (THREAD_INFO_TYPE *info);