7 #include <mono/utils/mono-compiler.h>
8 #include <mono/utils/mono-threads.h>
9 #include <mono/utils/mono-tls.h>
10 #include <mono/utils/mono-memory-model.h>
11 #include <mono/utils/atomic.h>
12 #include <mono/utils/checked-build.h>
13 #include <mono/utils/mono-threads-debug.h>
17 /*thread state helpers*/
19 get_thread_state (int thread_state)
21 return thread_state & THREAD_STATE_MASK;
25 get_thread_suspend_count (int thread_state)
27 return (thread_state & THREAD_SUSPEND_COUNT_MASK) >> THREAD_SUSPEND_COUNT_SHIFT;
31 build_thread_state (int thread_state, int suspend_count)
33 g_assert (suspend_count >= 0 && suspend_count <= THREAD_SUSPEND_COUNT_MAX);
34 g_assert (thread_state >= 0 && thread_state <= STATE_MAX);
36 return thread_state | (suspend_count << THREAD_SUSPEND_COUNT_SHIFT);
40 state_name (int state)
42 static const char *state_names [] = {
48 "ASYNC_SUSPEND_REQUESTED",
49 "SELF_SUSPEND_REQUESTED",
51 "STATE_BLOCKING_AND_SUSPENDED",
53 return state_names [get_thread_state (state)];
56 #define UNWRAP_THREAD_STATE(RAW,CUR,COUNT,INFO) do { \
57 RAW = (INFO)->thread_state; \
58 CUR = get_thread_state (RAW); \
59 COUNT = get_thread_suspend_count (RAW); \
63 check_thread_state (MonoThreadInfo* info)
65 int raw_state, cur_state, suspend_count;
66 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
71 g_assert (suspend_count == 0);
73 case STATE_ASYNC_SUSPENDED:
74 case STATE_SELF_SUSPENDED:
75 case STATE_ASYNC_SUSPEND_REQUESTED:
76 case STATE_SELF_SUSPEND_REQUESTED:
77 case STATE_BLOCKING_AND_SUSPENDED:
78 g_assert (suspend_count > 0);
80 case STATE_BLOCKING: //this is a special state that can have zero or positive suspend count.
83 g_error ("Invalid state %d", cur_state);
88 trace_state_change (const char *transition, MonoThreadInfo *info, int cur_raw_state, int next_state, int suspend_count_delta)
90 check_thread_state (info);
91 THREADS_STATE_MACHINE_DEBUG ("[%s][%p] %s -> %s (%d -> %d)\n",
93 mono_thread_info_get_tid (info),
94 state_name (get_thread_state (cur_raw_state)),
95 state_name (next_state),
96 get_thread_suspend_count (cur_raw_state),
97 get_thread_suspend_count (cur_raw_state) + suspend_count_delta);
99 CHECKED_BUILD_THREAD_TRANSITION (transition, info, get_thread_state (cur_raw_state), get_thread_suspend_count (cur_raw_state), next_state, suspend_count_delta);
103 This is the transition that signals that a thread is functioning.
104 Its main goal is to catch threads been witnessed before been fully registered.
107 mono_threads_transition_attach (MonoThreadInfo* info)
109 int raw_state, cur_state, suspend_count;
112 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
115 if (!(suspend_count == 0))
116 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
117 if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
118 goto retry_state_change;
119 trace_state_change ("ATTACH", info, raw_state, STATE_RUNNING, 0);
122 mono_fatal_with_history ("Cannot transition current thread from %s with ATTACH", state_name (cur_state));
127 This is the transition that signals that a thread is no longer registered with the runtime.
128 Its main goal is to catch threads been witnessed after they detach.
130 This returns TRUE is the transition succeeded.
131 If it returns false it means that there's a pending suspend that should be acted upon.
134 mono_threads_transition_detach (MonoThreadInfo *info)
136 int raw_state, cur_state, suspend_count;
139 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
142 case STATE_BLOCKING: /* An OS thread on coop goes STARTING->BLOCKING->RUNNING->BLOCKING->DETACHED */
143 if (!(suspend_count == 0))
144 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
145 if (InterlockedCompareExchange (&info->thread_state, STATE_DETACHED, raw_state) != raw_state)
146 goto retry_state_change;
147 trace_state_change ("DETACH", info, raw_state, STATE_DETACHED, 0);
149 case STATE_ASYNC_SUSPEND_REQUESTED: //Can't detach until whoever asked us to suspend to be happy with us
153 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
154 STATE_SELF_SUSPENDED: Code should not be running while suspended.
155 STATE_SELF_SUSPEND_REQUESTED: This is a bug in the self suspend code that didn't execute the second part of it
156 STATE_BLOCKING_AND_SUSPENDED: This is a bug in coop x suspend that resulted the thread in an undetachable state.
159 mono_fatal_with_history ("Cannot transition current thread %p from %s with DETACH", info, state_name (cur_state));
164 This transition initiates the suspension of another thread.
166 Returns one of the following values:
168 - AsyncSuspendInitSuspend: Thread suspend requested, async suspend needs to be done.
169 - AsyncSuspendAlreadySuspended: Thread already suspended, nothing to do.
170 - AsyncSuspendWait: Self suspend in progress, asked it to notify us. Caller must add target to the notification set.
171 - AsyncSuspendBlocking: Thread in blocking state
173 MonoRequestAsyncSuspendResult
174 mono_threads_transition_request_async_suspension (MonoThreadInfo *info)
176 int raw_state, cur_state, suspend_count;
177 g_assert (info != mono_thread_info_current ());
180 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
183 case STATE_RUNNING: //Post an async suspend request
184 if (!(suspend_count == 0))
185 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
186 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, 1), raw_state) != raw_state)
187 goto retry_state_change;
188 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 1);
189 return AsyncSuspendInitSuspend; //This is the first async suspend request against the target
191 case STATE_ASYNC_SUSPENDED:
192 case STATE_SELF_SUSPENDED: //Async suspend can suspend the same thread multiple times as it starts from the outside
193 case STATE_BLOCKING_AND_SUSPENDED:
194 if (!(suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX))
195 mono_fatal_with_history ("suspend_count = %d, but should be > 0 and < THREAD_SUSPEND_COUNT_MAX", suspend_count);
196 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
197 goto retry_state_change;
198 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, cur_state, 1);
199 return AsyncSuspendAlreadySuspended; //Thread is already suspended so we don't need to wait it to suspend
201 case STATE_SELF_SUSPEND_REQUESTED: //This suspend needs to notify the initiator, so we need to promote the suspend to async
202 if (!(suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX))
203 mono_fatal_with_history ("suspend_count = %d, but should be > 0 and < THREAD_SUSPEND_COUNT_MAX", suspend_count);
204 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, suspend_count + 1), raw_state) != raw_state)
205 goto retry_state_change;
206 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 1);
207 return AsyncSuspendWait; //This is the first async suspend request, change the thread and let it notify us [1]
210 if (!(suspend_count < THREAD_SUSPEND_COUNT_MAX))
211 mono_fatal_with_history ("suspend_count = %d, but should be < THREAD_SUSPEND_COUNT_MAX", suspend_count);
212 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
213 goto retry_state_change;
214 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, cur_state, 1);
215 return AsyncSuspendBlocking; //A thread in the blocking state has its state saved so we can treat it as suspended.
219 [1] It's questionable on what to do if we hit the beginning of a self suspend.
220 The expected behavior is that the target should poll its state very soon so the the suspend latency should be minimal.
222 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.
225 mono_fatal_with_history ("Cannot transition thread %p from %s with ASYNC_SUSPEND_REQUESTED", mono_thread_info_get_tid (info), state_name (cur_state));
227 return (MonoRequestAsyncSuspendResult) FALSE;
231 Check the current state of the thread and try to init a self suspend.
232 This must be called with self state saved.
234 Returns one of the following values:
236 - Resumed: Async resume happened and current thread should keep running
237 - Suspend: Caller should wait for a resume signal
238 - SelfSuspendNotifyAndWait: Notify the suspend initiator and wait for a resume signals
239 suspend should start.
243 mono_threads_transition_state_poll (MonoThreadInfo *info)
245 int raw_state, cur_state, suspend_count;
246 g_assert (mono_thread_info_is_current (info));
249 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
252 if (!(suspend_count == 0))
253 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
254 trace_state_change ("STATE_POLL", info, raw_state, cur_state, 0);
255 return SelfSuspendResumed; //We're fine, don't suspend
257 case STATE_ASYNC_SUSPEND_REQUESTED: //Async suspend requested, service it with a self suspend
258 case STATE_SELF_SUSPEND_REQUESTED: //Start the self suspend process
259 if (!(suspend_count > 0))
260 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
261 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPENDED, suspend_count), raw_state) != raw_state)
262 goto retry_state_change;
263 trace_state_change ("STATE_POLL", info, raw_state, STATE_SELF_SUSPENDED, 0);
264 if (cur_state == STATE_SELF_SUSPEND_REQUESTED)
265 return SelfSuspendWait; //Caller should wait for resume
267 return SelfSuspendNotifyAndWait; //Caller should notify suspend initiator and wait for resume
270 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
271 STATE_SELF_SUSPENDED: Code should not be running while suspended.
273 STATE_BLOCKING_AND_SUSPENDED: Pool is a local state transition. No VM activities are allowed while in blocking mode.
276 mono_fatal_with_history ("Cannot transition thread %p from %s with STATE_POLL", mono_thread_info_get_tid (info), state_name (cur_state));
281 Try to resume a suspended thread.
283 Returns one of the following values:
284 - Sucess: The thread was resumed.
285 - Error: The thread was not suspended in the first place. [2]
286 - InitSelfResume: The thread is blocked on self suspend and should be resumed
287 - InitAsycResume: The thread is blocked on async suspend and should be resumed
288 - ResumeInitBlockingResume: The thread was suspended on the exit path of blocking state and should be resumed
290 [2] This threading system uses an unsigned suspend count. Which means a resume cannot be
291 used as a suspend permit and cancel each other.
293 Suspend permits are really useful to implement managed synchronization structures that
294 don't consume native resources. The downside is that they further complicate the design of this
295 system as the RUNNING state now has a non zero suspend counter.
297 It can be implemented in the future if we find resume/suspend races that cannot be (efficiently) fixed by other means.
299 One major issue with suspend permits is runtime facilities (GC, debugger) that must have the target suspended when requested.
300 This would make permits really harder to add.
303 mono_threads_transition_request_resume (MonoThreadInfo* info)
305 int raw_state, cur_state, suspend_count;
306 g_assert (info != mono_thread_info_current ()); //One can't self resume [3]
309 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
311 case STATE_RUNNING: //Thread already running.
312 if (!(suspend_count == 0))
313 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
314 trace_state_change ("RESUME", info, raw_state, cur_state, 0);
315 return ResumeError; //Resume failed because thread was not blocked
317 case STATE_BLOCKING: //Blocking, might have a suspend count, we decrease if it's > 0
318 if (suspend_count == 0) {
319 trace_state_change ("RESUME", info, raw_state, cur_state, 0);
322 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
323 goto retry_state_change;
324 trace_state_change ("RESUME", info, raw_state, cur_state, -1);
325 return ResumeOk; //Resume worked and there's nothing for the caller to do.
328 case STATE_ASYNC_SUSPENDED:
329 case STATE_SELF_SUSPENDED:
330 case STATE_BLOCKING_AND_SUSPENDED: //Decrease the suspend_count and maybe resume
331 if (!(suspend_count > 0))
332 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
333 if (suspend_count > 1) {
334 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
335 goto retry_state_change;
336 trace_state_change ("RESUME", info, raw_state, cur_state, -1);
338 return ResumeOk; //Resume worked and there's nothing for the caller to do.
340 if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
341 goto retry_state_change;
342 trace_state_change ("RESUME", info, raw_state, STATE_RUNNING, -1);
344 if (cur_state == STATE_ASYNC_SUSPENDED)
345 return ResumeInitAsyncResume; //Resume worked and caller must do async resume
346 else if (cur_state == STATE_SELF_SUSPENDED)
347 return ResumeInitSelfResume; //Resume worked and caller must do self resume
349 return ResumeInitBlockingResume; //Resume worked and caller must do blocking resume
352 case STATE_SELF_SUSPEND_REQUESTED: //Self suspend was requested but another thread decided to resume it.
353 if (!(suspend_count > 0))
354 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
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 if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
361 goto retry_state_change;
362 trace_state_change ("RESUME", info, raw_state, STATE_RUNNING, -1);
364 return ResumeOk; //Resume worked and there's nothing for the caller to do (the target never actually suspend).
367 STATE_ASYNC_SUSPEND_REQUESTED: Only one async suspend/resume operation can be in flight, so a resume cannot witness an internal state of suspend
369 [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
370 sense as a suspend permit, but as explained in [2] we don't support it so this is a bug.
372 [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
373 is similar to the one described in [2] when this is used for as a synchronization primitive.
375 If this turns to be a problem we should either implement [2] or make this an invalid transition.
379 mono_fatal_with_history ("Cannot transition thread %p from %s with REQUEST_RESUME", mono_thread_info_get_tid (info), state_name (cur_state));
384 This performs the last step of async suspend.
386 Returns TRUE if the caller should wait for resume.
389 mono_threads_transition_finish_async_suspend (MonoThreadInfo* info)
391 int raw_state, cur_state, suspend_count;
394 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
397 case STATE_SELF_SUSPENDED: //async suspend raced with self suspend and lost
398 case STATE_BLOCKING_AND_SUSPENDED: //async suspend raced with blocking and lost
399 trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, cur_state, 0);
400 return FALSE; //let self suspend wait
402 case STATE_ASYNC_SUSPEND_REQUESTED:
403 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPENDED, suspend_count), raw_state) != raw_state)
404 goto retry_state_change;
405 trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, STATE_ASYNC_SUSPENDED, 0);
406 return TRUE; //Async suspend worked, now wait for resume
409 STATE_RUNNING: A thread cannot escape suspension once requested.
410 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.
411 STATE_SELF_SUSPEND_REQUESTED: When self suspend and async suspend happen together, they converge to async suspend so this state should not be visible.
412 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.
415 mono_fatal_with_history ("Cannot transition thread %p from %s with FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
420 This transitions the thread into a cooperative state where it's assumed to be suspended but can continue.
422 Native runtime code might want to put itself into a state where the thread is considered suspended but can keep running.
423 That state only works as long as the only managed state touched is blitable and was pinned before the transition.
425 It returns the action the caller must perform:
427 - Continue: Entered blocking state sucessfully;
428 - PollAndRetry: Async suspend raced and won, try to suspend and then retry;
432 mono_threads_transition_do_blocking (MonoThreadInfo* info)
434 int raw_state, cur_state, suspend_count;
437 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
440 case STATE_RUNNING: //transition to blocked
441 if (!(suspend_count == 0))
442 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
443 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_BLOCKING, suspend_count), raw_state) != raw_state)
444 goto retry_state_change;
445 trace_state_change ("DO_BLOCKING", info, raw_state, STATE_BLOCKING, 0);
446 return DoBlockingContinue;
448 case STATE_ASYNC_SUSPEND_REQUESTED:
449 if (!(suspend_count > 0))
450 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
451 trace_state_change ("DO_BLOCKING", info, raw_state, cur_state, 0);
452 return DoBlockingPollAndRetry;
454 STATE_ASYNC_SUSPENDED
455 STATE_SELF_SUSPENDED: Code should not be running while suspended.
456 STATE_SELF_SUSPEND_REQUESTED: A blocking operation must not be done while trying to self suspend
458 STATE_BLOCKING_AND_SUSPENDED: Blocking is not nestabled
461 mono_fatal_with_history ("Cannot transition thread %p from %s with DO_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
466 This is the exit transition from the blocking state. If this thread is logically async suspended it will have to wait
467 until its resumed before continuing.
470 -Aborted: The blocking operation was aborted and not properly restored. Aborts can happen due to lazy loading and some n2m transitions;
471 -Ok: Done with blocking, just move on;
472 -Wait: This thread was async suspended, wait for resume
475 MonoDoneBlockingResult
476 mono_threads_transition_done_blocking (MonoThreadInfo* info)
478 int raw_state, cur_state, suspend_count;
481 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
484 if (suspend_count == 0) {
485 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_RUNNING, suspend_count), raw_state) != raw_state)
486 goto retry_state_change;
487 trace_state_change ("DONE_BLOCKING", info, raw_state, STATE_RUNNING, 0);
488 return DoneBlockingOk;
490 if (!(suspend_count >= 0))
491 mono_fatal_with_history ("suspend_count = %d, but should be >= 0", suspend_count);
492 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_BLOCKING_AND_SUSPENDED, suspend_count), raw_state) != raw_state)
493 goto retry_state_change;
494 trace_state_change ("DONE_BLOCKING", info, raw_state, STATE_BLOCKING_AND_SUSPENDED, 0);
495 return DoneBlockingWait;
499 STATE_RUNNING: //Blocking was aborted and not properly restored
500 STATE_ASYNC_SUSPEND_REQUESTED: //Blocking was aborted, not properly restored and now there's a pending suspend
501 STATE_ASYNC_SUSPENDED
502 STATE_SELF_SUSPENDED: Code should not be running while suspended.
503 STATE_SELF_SUSPEND_REQUESTED: A blocking operation must not be done while trying to self suspend
504 STATE_BLOCKING_AND_SUSPENDED: This an exit state of done blocking
507 mono_fatal_with_history ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
512 Transition a thread in what should be a blocking state back to running state.
513 This is different that done blocking because the goal is to get back to blocking once we're done.
514 This is required to be able to bail out of blocking in case we're back to inside the runtime.
517 -Ignore: Thread was not in blocking, nothing to do;
518 -IgnoreAndPool: Thread was not blocking and there's a pending suspend that needs to be processed;
519 -Ok: Blocking state successfully aborted;
520 -Wait: Blocking state successfully aborted, there's a pending suspend to be processed though
522 MonoAbortBlockingResult
523 mono_threads_transition_abort_blocking (THREAD_INFO_TYPE* info)
525 int raw_state, cur_state, suspend_count;
528 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
530 case STATE_RUNNING: //thread already in runnable state
531 trace_state_change ("ABORT_BLOCKING", info, raw_state, cur_state, 0);
532 return AbortBlockingIgnore;
534 case STATE_ASYNC_SUSPEND_REQUESTED: //thread is runnable and have a pending suspend
535 trace_state_change ("ABORT_BLOCKING", info, raw_state, cur_state, 0);
536 return AbortBlockingIgnoreAndPoll;
539 if (suspend_count == 0) {
540 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_RUNNING, suspend_count), raw_state) != raw_state)
541 goto retry_state_change;
542 trace_state_change ("ABORT_BLOCKING", info, raw_state, STATE_RUNNING, 0);
543 return AbortBlockingOk;
545 if (!(suspend_count > 0))
546 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
547 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_BLOCKING_AND_SUSPENDED, suspend_count), raw_state) != raw_state)
548 goto retry_state_change;
549 trace_state_change ("ABORT_BLOCKING", info, raw_state, STATE_BLOCKING_AND_SUSPENDED, 0);
550 return AbortBlockingWait;
553 STATE_ASYNC_SUSPENDED:
554 STATE_SELF_SUSPENDED: Code should not be running while suspended.
555 STATE_SELF_SUSPEND_REQUESTED: A blocking operation must not be done while trying to self suspend.
556 STATE_BLOCKING_AND_SUSPENDED: This is an exit state of done blocking, can't happen here.
559 mono_fatal_with_history ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
563 MonoThreadUnwindState*
564 mono_thread_info_get_suspend_state (MonoThreadInfo *info)
566 int raw_state, cur_state, suspend_count;
567 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
569 case STATE_ASYNC_SUSPENDED:
570 return &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX];
571 case STATE_SELF_SUSPENDED:
572 case STATE_BLOCKING_AND_SUSPENDED:
573 return &info->thread_saved_state [SELF_SUSPEND_STATE_INDEX];
575 if (suspend_count > 0)
576 return &info->thread_saved_state [SELF_SUSPEND_STATE_INDEX];
581 STATE_ASYNC_SUSPEND_REQUESTED
582 STATE_BLOCKING: All those are invalid suspend states.
584 g_error ("Cannot read suspend state when target %p is in the %s state", mono_thread_info_get_tid (info), state_name (cur_state));
588 // State checking code
590 * Return TRUE is the thread is in a runnable state.
593 mono_thread_info_is_running (MonoThreadInfo *info)
595 switch (get_thread_state (info->thread_state)) {
597 case STATE_ASYNC_SUSPEND_REQUESTED:
598 case STATE_SELF_SUSPEND_REQUESTED:
606 * Return TRUE is the thread is in an usable (suspendable) state
609 mono_thread_info_is_live (MonoThreadInfo *info)
611 switch (get_thread_state (info->thread_state)) {
620 mono_thread_info_suspend_count (MonoThreadInfo *info)
622 return get_thread_suspend_count (info->thread_state);
626 mono_thread_info_current_state (MonoThreadInfo *info)
628 return get_thread_state (info->thread_state);
632 mono_thread_state_name (int state)
634 return state_name (state);
638 mono_thread_is_gc_unsafe_mode (void)
640 MonoThreadInfo *cur = mono_thread_info_current ();
645 switch (mono_thread_info_current_state (cur)) {
647 case STATE_ASYNC_SUSPEND_REQUESTED:
648 case STATE_SELF_SUSPEND_REQUESTED: