3 #include <mono/utils/mono-compiler.h>
4 #include <mono/utils/mono-threads.h>
5 #include <mono/utils/mono-tls.h>
6 #include <mono/utils/mono-memory-model.h>
7 #include <mono/utils/atomic.h>
11 /*thread state helpers*/
13 get_thread_state (int thread_state)
15 return thread_state & THREAD_STATE_MASK;
19 get_thread_suspend_count (int thread_state)
21 return (thread_state & THREAD_SUSPEND_COUNT_MASK) >> THREAD_SUSPEND_COUNT_SHIFT;
25 build_thread_state (int thread_state, int suspend_count)
27 g_assert (suspend_count >= 0 && suspend_count <= THREAD_SUSPEND_COUNT_MAX);
28 g_assert (thread_state >= 0 && thread_state <= STATE_MAX);
30 return thread_state | (suspend_count << THREAD_SUSPEND_COUNT_SHIFT);
34 state_name (int state)
36 static const char *state_names [] = {
42 "ASYNC_SUSPEND_REQUESTED",
43 "SELF_SUSPEND_REQUESTED",
45 "STATE_BLOCKING_AND_SUSPENDED",
47 return state_names [get_thread_state (state)];
50 #define UNWRAP_THREAD_STATE(RAW,CUR,COUNT,INFO) do { \
51 RAW = (INFO)->thread_state; \
52 CUR = get_thread_state (RAW); \
53 COUNT = get_thread_suspend_count (RAW); \
57 check_thread_state (MonoThreadInfo* info)
59 int raw_state, cur_state, suspend_count;
60 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
65 g_assert (suspend_count == 0);
67 case STATE_ASYNC_SUSPENDED:
68 case STATE_SELF_SUSPENDED:
69 case STATE_ASYNC_SUSPEND_REQUESTED:
70 case STATE_SELF_SUSPEND_REQUESTED:
71 case STATE_BLOCKING_AND_SUSPENDED:
72 g_assert (suspend_count > 0);
74 case STATE_BLOCKING: //this is a special state that can have zero or positive suspend count.
77 g_error ("Invalid state %d", cur_state);
82 trace_state_change (const char *transition, MonoThreadInfo *info, int cur_raw_state, int next_state, int suspend_count_delta)
84 check_thread_state (info);
85 THREADS_STATE_MACHINE_DEBUG ("[%s][%p] %s -> %s (%d -> %d)\n",
87 mono_thread_info_get_tid (info),
88 state_name (get_thread_state (cur_raw_state)),
89 state_name (next_state),
90 get_thread_suspend_count (cur_raw_state),
91 get_thread_suspend_count (cur_raw_state) + suspend_count_delta);
95 This is the transition that signals that a thread is functioning.
96 Its main goal is to catch threads been witnessed before been fully registered.
99 mono_threads_transition_attach (MonoThreadInfo* info)
101 int raw_state, cur_state, suspend_count;
104 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
107 g_assert (suspend_count == 0);
108 if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
109 goto retry_state_change;
110 trace_state_change ("ATTACH", info, raw_state, STATE_RUNNING, 0);
113 g_error ("Cannot transition current thread from %s with ATTACH", state_name (cur_state));
118 This is the transition that signals that a thread is no longer registered with the runtime.
119 Its main goal is to catch threads been witnessed after they detach.
121 This returns TRUE is the transition succeeded.
122 If it returns false it means that there's a pending suspend that should be acted upon.
125 mono_threads_transition_detach (MonoThreadInfo *info)
127 int raw_state, cur_state, suspend_count;
130 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
133 g_assert (suspend_count == 0);
134 if (InterlockedCompareExchange (&info->thread_state, STATE_DETACHED, raw_state) != raw_state)
135 goto retry_state_change;
136 trace_state_change ("DETACH", info, raw_state, STATE_DETACHED, 0);
138 case STATE_ASYNC_SUSPEND_REQUESTED: //Can't detach until whoever asked us to suspend to be happy with us
141 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
142 STATE_SELF_SUSPENDED: Code should not be running while suspended.
143 STATE_SELF_SUSPEND_REQUESTED: This is a bug in the self suspend code that didn't execute the second part of it
144 STATE_BLOCKING: This is a bug in the coop code that forgot to do a finish blocking before exiting.
145 STATE_BLOCKING_AND_SUSPENDED: This is a bug in coop x suspend that resulted the thread in an undetachable state.
148 g_error ("Cannot transition current thread %p from %s with DETACH", info, state_name (cur_state));
153 This transition initiates the suspension of the current thread.
156 mono_threads_transition_request_self_suspension (MonoThreadInfo *info)
158 int raw_state, cur_state, suspend_count;
159 g_assert (info == mono_thread_info_current ());
162 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
165 case STATE_RUNNING: //Post a self suspend request
166 g_assert (suspend_count == 0);
167 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPEND_REQUESTED, 1), raw_state) != raw_state)
168 goto retry_state_change;
169 trace_state_change ("SELF_SUSPEND_REQUEST", info, raw_state, STATE_SELF_SUSPEND_REQUESTED, 1);
172 case STATE_ASYNC_SUSPEND_REQUESTED: //Bump the suspend count but don't change the request type as async takes preference
173 g_assert (suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX);
174 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
175 goto retry_state_change;
176 trace_state_change ("SUSPEND_REQUEST", info, raw_state, cur_state, 1);
180 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
181 STATE_SELF_SUSPENDED: Code should not be running while suspended.
182 STATE_SELF_SUSPEND_REQUESTED: Self suspends should not nest as begin/end should be paired. [1]
184 STATE_BLOCKING_AND_SUSPENDED: Self suspension cannot be started when the thread is in blocking state as it must finish first
186 [1] This won't trap this sequence of requests: self suspend, async suspend and self suspend.
187 If this turns to be an issue we can introduce a new suspend request state for when both have been requested.
190 g_error ("Cannot transition thread %p from %s with SUSPEND_REQUEST", info, state_name (cur_state));
195 This transition initiates the suspension of another thread.
197 Returns one of the following values:
199 - AsyncSuspendInitSuspend: Thread suspend requested, async suspend needs to be done.
200 - AsyncSuspendAlreadySuspended: Thread already suspended, nothing to do.
201 - AsyncSuspendWait: Self suspend in progress, asked it to notify us. Caller must add target to the notification set.
203 MonoRequestAsyncSuspendResult
204 mono_threads_transition_request_async_suspension (MonoThreadInfo *info)
206 int raw_state, cur_state, suspend_count;
207 g_assert (info != mono_thread_info_current ());
210 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
213 case STATE_RUNNING: //Post an async suspend request
214 g_assert (suspend_count == 0);
215 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, 1), raw_state) != raw_state)
216 goto retry_state_change;
217 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 1);
218 return AsyncSuspendInitSuspend; //This is the first async suspend request against the target
220 case STATE_ASYNC_SUSPENDED:
221 case STATE_SELF_SUSPENDED: //Async suspend can suspend the same thread multiple times as it starts from the outside
222 case STATE_BLOCKING_AND_SUSPENDED:
223 g_assert (suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX);
224 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
225 goto retry_state_change;
226 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, cur_state, 1);
227 return AsyncSuspendAlreadySuspended; //Thread is already suspended so we don't need to wait it to suspend
229 case STATE_SELF_SUSPEND_REQUESTED: //This suspend needs to notify the initiator, so we need to promote the suspend to async
230 g_assert (suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX);
231 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, suspend_count + 1), raw_state) != raw_state)
232 goto retry_state_change;
233 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 1);
234 return AsyncSuspendWait; //This is the first async suspend request, change the thread and let it notify us [1]
237 g_assert (suspend_count < THREAD_SUSPEND_COUNT_MAX);
238 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
239 goto retry_state_change;
240 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, cur_state, 1);
241 return AsyncSuspendAlreadySuspended; //A thread in the blocking state has its state saved so we can treat it as suspended.
245 [1] It's questionable on what to do if we hit the beginning of a self suspend.
246 The expected behavior is that the target should poll its state very soon so the the suspend latency should be minimal.
248 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.
251 g_error ("Cannot transition thread %p from %s with ASYNC_SUSPEND_REQUESTED", info, state_name (cur_state));
257 Check the current state of the thread and try to init a self suspend.
258 This must be called with self state saved.
260 Returns one of the following values:
262 - Resumed: Async resume happened and current thread should keep running
263 - Suspend: Caller should wait for a resume signal
264 - SelfSuspendNotifyAndWait: Notify the suspend initiator and wait for a resume signals
265 suspend should start.
269 mono_threads_transition_state_poll (MonoThreadInfo *info)
271 int raw_state, cur_state, suspend_count;
272 g_assert (info == mono_thread_info_current ());
275 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
278 g_assert (suspend_count == 0);
279 trace_state_change ("STATE_POLL", info, raw_state, cur_state, 0);
280 return SelfSuspendResumed; //We're fine, don't suspend
282 case STATE_ASYNC_SUSPEND_REQUESTED: //Async suspend requested, service it with a self suspend
283 case STATE_SELF_SUSPEND_REQUESTED: //Start the self suspend process
284 g_assert (suspend_count > 0);
285 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPENDED, suspend_count), raw_state) != raw_state)
286 goto retry_state_change;
287 trace_state_change ("STATE_POLL", info, raw_state, STATE_SELF_SUSPENDED, 0);
288 if (cur_state == STATE_SELF_SUSPEND_REQUESTED)
289 return SelfSuspendWait; //Caller should wait for resume
291 return SelfSuspendNotifyAndWait; //Caller should notify suspend initiator and wait for resume
294 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
295 STATE_SELF_SUSPENDED: Code should not be running while suspended.
297 STATE_BLOCKING_AND_SUSPENDED: Pool is a local state transition. No VM activities are allowed while in blocking mode.
300 g_error ("Cannot transition thread %p from %s with STATE_POLL", info, state_name (cur_state));
305 Try to resume a suspended thread.
307 Returns one of the following values:
308 - Sucess: The thread was resumed.
309 - Error: The thread was not suspended in the first place. [2]
310 - InitSelfResume: The thread is blocked on self suspend and should be resumed
311 - InitAsycResume: The thread is blocked on async suspend and should be resumed
312 - ResumeInitBlockingResume: The thread was suspended on the exit path of blocking state and should be resumed
314 [2] This threading system uses an unsigned suspend count. Which means a resume cannot be
315 used as a suspend permit and cancel each other.
317 Suspend permits are really useful to implement managed synchronization structures that
318 don't consume native resources. The downside is that they further complicate the design of this
319 system as the RUNNING state now has a non zero suspend counter.
321 It can be implemented in the future if we find resume/suspend races that cannot be (efficiently) fixed by other means.
323 One major issue with suspend permits is runtime facilities (GC, debugger) that must have the target suspended when requested.
324 This would make permits really harder to add.
327 mono_threads_transition_request_resume (MonoThreadInfo* info)
329 int raw_state, cur_state, suspend_count;
330 g_assert (info != mono_thread_info_current ()); //One can't self resume [3]
333 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
335 case STATE_RUNNING: //Thread already running.
336 g_assert (suspend_count == 0);
337 trace_state_change ("RESUME", info, raw_state, cur_state, 0);
338 return ResumeError; //Resume failed because thread was not blocked
340 case STATE_BLOCKING: //Blocking, might have a suspend count, we decrease if it's > 0
341 if (suspend_count == 0) {
342 trace_state_change ("RESUME", info, raw_state, cur_state, 0);
345 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
346 goto retry_state_change;
347 trace_state_change ("RESUME", info, raw_state, cur_state, -1);
348 return ResumeOk; //Resume worked and there's nothing for the caller to do.
351 case STATE_ASYNC_SUSPENDED:
352 case STATE_SELF_SUSPENDED:
353 case STATE_BLOCKING_AND_SUSPENDED: //Decrease the suspend_count and maybe resume
354 g_assert (suspend_count > 0);
355 if (suspend_count > 1) {
356 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
357 goto retry_state_change;
358 trace_state_change ("RESUME", info, raw_state, cur_state, -1);
360 return ResumeOk; //Resume worked and there's nothing for the caller to do.
362 if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
363 goto retry_state_change;
364 trace_state_change ("RESUME", info, raw_state, STATE_RUNNING, -1);
366 if (cur_state == STATE_ASYNC_SUSPENDED)
367 return ResumeInitAsyncResume; //Resume worked and caller must do async resume
368 else if (cur_state == STATE_SELF_SUSPENDED)
369 return ResumeInitSelfResume; //Resume worked and caller must do self resume
371 return ResumeInitBlockingResume; //Resume worked and caller must do blocking resume
374 case STATE_SELF_SUSPEND_REQUESTED: //Self suspend was requested but another thread decided to resume it.
375 g_assert (suspend_count > 0);
376 if (suspend_count > 1) {
377 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
378 goto retry_state_change;
379 trace_state_change ("RESUME", info, raw_state, cur_state, -1);
381 if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
382 goto retry_state_change;
383 trace_state_change ("RESUME", info, raw_state, STATE_RUNNING, -1);
385 return ResumeOk; //Resume worked and there's nothing for the caller to do (the target never actually suspend).
388 STATE_ASYNC_SUSPEND_REQUESTED: Only one async suspend/resume operation can be in flight, so a resume cannot witness an internal state of suspend
390 [3] A self-resume makes no sense given it requires the thread to be running, which means its suspend count must be zero. A self resume would make
391 sense as a suspend permit, but as explained in [2] we don't support it so this is a bug.
393 [4] It's questionable on whether a resume (an async operation) should be able to cancel a self suspend. The scenario where this would happen
394 is similar to the one described in [2] when this is used for as a synchronization primitive.
396 If this turns to be a problem we should either implement [2] or make this an invalid transition.
400 g_error ("Cannot transition thread %p from %s with REQUEST_RESUME", info, state_name (cur_state));
405 This performs the last step of async suspend.
407 Returns TRUE if the caller should wait for resume.
410 mono_threads_transition_finish_async_suspend (MonoThreadInfo* info)
412 int raw_state, cur_state, suspend_count;
415 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
418 case STATE_SELF_SUSPENDED: //async suspend raced with self suspend and lost
419 case STATE_BLOCKING_AND_SUSPENDED: //async suspend raced with blocking and lost
420 trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, cur_state, 0);
421 return FALSE; //let self suspend wait
423 case STATE_ASYNC_SUSPEND_REQUESTED:
424 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPENDED, suspend_count), raw_state) != raw_state)
425 goto retry_state_change;
426 trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, STATE_ASYNC_SUSPENDED, 0);
427 return TRUE; //Async suspend worked, now wait for resume
430 STATE_RUNNING: A thread cannot escape suspension once requested.
431 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.
432 STATE_SELF_SUSPEND_REQUESTED: When self suspend and async suspend happen together, they converge to async suspend so this state should not be visible.
433 STATE_BLOCKING: Async suspend only begins if a transition to async suspend requested happened. Blocking would have put us into blocking with positive suspend count if it raced with async finish.
436 g_error ("Cannot transition thread %p from %s with FINISH_ASYNC_SUSPEND", info, state_name (cur_state));
441 This the compensatory transition for failed async suspend.
443 Async suspend can land on a thread as it began cleaning up and is no longer
444 functional. This happens as cleanup is a racy process from the async suspend
445 perspective. The thread could have cleaned up its domain or jit_tls, for example.
447 It can only transition the state as left by a sucessfull finish async suspend transition.
451 mono_threads_transition_async_suspend_compensation (MonoThreadInfo* info)
453 int raw_state, cur_state, suspend_count;
456 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
459 case STATE_ASYNC_SUSPENDED:
461 Must be one since if a self suspend is in progress the thread should still be async suspendable.
462 If count > 1 and no self suspend is in progress then it means one of the following two.
463 - the thread was previously suspended, which means we should never reach end suspend in the first place.
464 - another suspend happened concurrently, which means the global suspend lock didn't happen.
466 g_assert (suspend_count == 1);
467 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_RUNNING, suspend_count - 1), raw_state) != raw_state)
468 goto retry_state_change;
469 trace_state_change ("COMPENSATE_FINISH_ASYNC_SUSPEND", info, raw_state, STATE_RUNNING, -1);
474 STATE_ASYNC_SUSPEND_REQUESTED
476 STATE_BLOCKING_AND_SUSPENDED
477 STATE_SELF_SUSPEND_REQUESTED: All those are invalid end states of a sucessfull finish async suspend
480 g_error ("Cannot transition thread %p from %s with COMPENSATE_FINISH_ASYNC_SUSPEND", info, state_name (cur_state));
486 This transitions the thread into a cooperative state where it's assumed to be suspended but can continue.
488 Native runtime code might want to put itself into a state where the thread is considered suspended but can keep running.
489 That state only works as long as the only managed state touched is blitable and was pinned before the transition.
491 It returns the action the caller must perform:
493 - Continue: Entered blocking state sucessfully;
494 - PollAndRetry: Async suspend raced and won, try to suspend and then retry;
498 mono_threads_transition_do_blocking (MonoThreadInfo* info)
500 int raw_state, cur_state, suspend_count;
503 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
506 case STATE_RUNNING: //transition to blocked
507 g_assert (suspend_count == 0);
508 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_BLOCKING, suspend_count), raw_state) != raw_state)
509 goto retry_state_change;
510 trace_state_change ("DO_BLOCKING", info, raw_state, STATE_BLOCKING, 0);
511 return DoBlockingContinue;
513 case STATE_ASYNC_SUSPEND_REQUESTED:
514 g_assert (suspend_count > 0);
515 trace_state_change ("DO_BLOCKING", info, raw_state, cur_state, 0);
516 return DoBlockingPollAndRetry;
518 STATE_ASYNC_SUSPENDED
519 STATE_SELF_SUSPENDED: Code should not be running while suspended.
520 STATE_SELF_SUSPEND_REQUESTED: A blocking operation must not be done while trying to self suspend
522 STATE_BLOCKING_AND_SUSPENDED: Blocking is not nestabled
525 g_error ("Cannot transition thread %p from %s with DO_BLOCKING", info, state_name (cur_state));
530 This is the exit transition from the blocking state. If this thread is logically async suspended it will have to wait
531 until its resumed before continuing.
534 -Aborted: The blocking operation was aborted and not properly restored. Aborts can happen due to lazy loading and some n2m transitions;
535 -Ok: Done with blocking, just move on;
536 -Wait: This thread was async suspended, wait for resume
539 MonoDoneBlockingResult
540 mono_threads_transition_done_blocking (MonoThreadInfo* info)
542 int raw_state, cur_state, suspend_count;
545 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
547 case STATE_RUNNING: //Blocking was aborted and not properly restored
548 case STATE_ASYNC_SUSPEND_REQUESTED: //Blocking was aborted, not properly restored and now there's a pending suspend
549 trace_state_change ("DONE_BLOCKING", info, raw_state, cur_state, 0);
550 return DoneBlockingAborted;
553 if (suspend_count == 0) {
554 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_RUNNING, suspend_count), raw_state) != raw_state)
555 goto retry_state_change;
556 trace_state_change ("DONE_BLOCKING", info, raw_state, STATE_RUNNING, 0);
557 return DoneBlockingOk;
559 g_assert (suspend_count >= 0);
560 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_BLOCKING_AND_SUSPENDED, suspend_count), raw_state) != raw_state)
561 goto retry_state_change;
562 trace_state_change ("DONE_BLOCKING", info, raw_state, STATE_BLOCKING_AND_SUSPENDED, 0);
563 return DoneBlockingWait;
567 STATE_ASYNC_SUSPENDED
568 STATE_SELF_SUSPENDED: Code should not be running while suspended.
569 STATE_SELF_SUSPEND_REQUESTED: A blocking operation must not be done while trying to self suspend
570 STATE_BLOCKING_AND_SUSPENDED: This an exit state of done blocking
573 g_error ("Cannot transition thread %p from %s with DONE_BLOCKING", info, state_name (cur_state));
578 Transition a thread in what should be a blocking state back to running state.
579 This is different that done blocking because the goal is to get back to blocking once we're done.
580 This is required to be able to bail out of blocking in case we're back to inside the runtime.
583 -Ignore: Thread was not in blocking, nothing to do;
584 -IgnoreAndPool: Thread was not blocking and there's a pending suspend that needs to be processed;
585 -Ok: Blocking state successfully aborted;
586 -OkAndPool: Blocking state successfully aborted, there's a pending suspend to be processed though
588 MonoAbortBlockingResult
589 mono_threads_transition_abort_blocking (THREAD_INFO_TYPE* info)
591 int raw_state, cur_state, suspend_count;
594 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
596 case STATE_RUNNING: //thread already in runnable state
597 trace_state_change ("ABORT_BLOCKING", info, raw_state, cur_state, 0);
598 return AbortBlockingIgnore;
600 case STATE_ASYNC_SUSPEND_REQUESTED: //thread is runnable and have a pending suspend
601 trace_state_change ("ABORT_BLOCKING", info, raw_state, cur_state, 0);
602 return AbortBlockingIgnoreAndPoll;
605 if (suspend_count == 0) {
606 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_RUNNING, suspend_count), raw_state) != raw_state)
607 goto retry_state_change;
608 trace_state_change ("ABORT_BLOCKING", info, raw_state, STATE_RUNNING, 0);
609 return AbortBlockingOk;
611 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, suspend_count), raw_state) != raw_state)
612 goto retry_state_change;
613 trace_state_change ("ABORT_BLOCKING", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 0);
614 return AbortBlockingOkAndPool;
617 STATE_ASYNC_SUSPENDED:
618 STATE_SELF_SUSPENDED: Code should not be running while suspended.
619 STATE_SELF_SUSPEND_REQUESTED: A blocking operation must not be done while trying to self suspend.
620 STATE_BLOCKING_AND_SUSPENDED: This is an exit state of done blocking, can't happen here.
623 g_error ("Cannot transition thread %p from %s with DONE_BLOCKING", info, state_name (cur_state));
627 MonoThreadUnwindState*
628 mono_thread_info_get_suspend_state (MonoThreadInfo *info)
630 int raw_state, cur_state, suspend_count;
631 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
633 case STATE_ASYNC_SUSPENDED:
634 return &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX];
635 case STATE_SELF_SUSPENDED:
636 case STATE_BLOCKING_AND_SUSPENDED:
637 return &info->thread_saved_state [SELF_SUSPEND_STATE_INDEX];
639 if (suspend_count > 0)
640 return &info->thread_saved_state [SELF_SUSPEND_STATE_INDEX];
645 STATE_ASYNC_SUSPEND_REQUESTED
646 STATE_BLOCKING: All those are invalid suspend states.
648 g_error ("Cannot read suspend state when target %p is in the %s state", mono_thread_info_get_tid (info), state_name (cur_state));
652 // State checking code
654 * Return TRUE is the thread is in a runnable state.
657 mono_thread_info_is_running (MonoThreadInfo *info)
659 switch (get_thread_state (info->thread_state)) {
661 case STATE_ASYNC_SUSPEND_REQUESTED:
662 case STATE_SELF_SUSPEND_REQUESTED:
670 * Return TRUE is the thread is in an usable (suspendable) state
673 mono_thread_info_is_live (MonoThreadInfo *info)
675 switch (get_thread_state (info->thread_state)) {
684 mono_thread_info_suspend_count (MonoThreadInfo *info)
686 return get_thread_suspend_count (info->thread_state);