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>
8 #include <mono/utils/checked-build.h>
9 #include <mono/utils/mono-threads-debug.h>
13 /*thread state helpers*/
15 get_thread_state (int thread_state)
17 return thread_state & THREAD_STATE_MASK;
21 get_thread_suspend_count (int thread_state)
23 return (thread_state & THREAD_SUSPEND_COUNT_MASK) >> THREAD_SUSPEND_COUNT_SHIFT;
27 build_thread_state (int thread_state, int suspend_count)
29 g_assert (suspend_count >= 0 && suspend_count <= THREAD_SUSPEND_COUNT_MAX);
30 g_assert (thread_state >= 0 && thread_state <= STATE_MAX);
32 return thread_state | (suspend_count << THREAD_SUSPEND_COUNT_SHIFT);
36 state_name (int state)
38 static const char *state_names [] = {
44 "ASYNC_SUSPEND_REQUESTED",
45 "SELF_SUSPEND_REQUESTED",
47 "STATE_BLOCKING_AND_SUSPENDED",
49 return state_names [get_thread_state (state)];
52 #define UNWRAP_THREAD_STATE(RAW,CUR,COUNT,INFO) do { \
53 RAW = (INFO)->thread_state; \
54 CUR = get_thread_state (RAW); \
55 COUNT = get_thread_suspend_count (RAW); \
59 check_thread_state (MonoThreadInfo* info)
61 int raw_state, cur_state, suspend_count;
62 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
67 g_assert (suspend_count == 0);
69 case STATE_ASYNC_SUSPENDED:
70 case STATE_SELF_SUSPENDED:
71 case STATE_ASYNC_SUSPEND_REQUESTED:
72 case STATE_SELF_SUSPEND_REQUESTED:
73 case STATE_BLOCKING_AND_SUSPENDED:
74 g_assert (suspend_count > 0);
76 case STATE_BLOCKING: //this is a special state that can have zero or positive suspend count.
79 g_error ("Invalid state %d", cur_state);
84 trace_state_change (const char *transition, MonoThreadInfo *info, int cur_raw_state, int next_state, int suspend_count_delta)
86 check_thread_state (info);
87 THREADS_STATE_MACHINE_DEBUG ("[%s][%p] %s -> %s (%d -> %d)\n",
89 mono_thread_info_get_tid (info),
90 state_name (get_thread_state (cur_raw_state)),
91 state_name (next_state),
92 get_thread_suspend_count (cur_raw_state),
93 get_thread_suspend_count (cur_raw_state) + suspend_count_delta);
95 CHECKED_BUILD_THREAD_TRANSITION (transition, info, get_thread_state (cur_raw_state), get_thread_suspend_count (cur_raw_state), next_state, suspend_count_delta);
99 This is the transition that signals that a thread is functioning.
100 Its main goal is to catch threads been witnessed before been fully registered.
103 mono_threads_transition_attach (MonoThreadInfo* info)
105 int raw_state, cur_state, suspend_count;
108 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
111 if (!(suspend_count == 0))
112 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
113 if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
114 goto retry_state_change;
115 trace_state_change ("ATTACH", info, raw_state, STATE_RUNNING, 0);
118 mono_fatal_with_history ("Cannot transition current thread from %s with ATTACH", state_name (cur_state));
123 This is the transition that signals that a thread is no longer registered with the runtime.
124 Its main goal is to catch threads been witnessed after they detach.
126 This returns TRUE is the transition succeeded.
127 If it returns false it means that there's a pending suspend that should be acted upon.
130 mono_threads_transition_detach (MonoThreadInfo *info)
132 int raw_state, cur_state, suspend_count;
135 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
138 case STATE_BLOCKING: /* An OS thread on coop goes STARTING->BLOCKING->RUNNING->BLOCKING->DETACHED */
139 if (!(suspend_count == 0))
140 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
141 if (InterlockedCompareExchange (&info->thread_state, STATE_DETACHED, raw_state) != raw_state)
142 goto retry_state_change;
143 trace_state_change ("DETACH", info, raw_state, STATE_DETACHED, 0);
145 case STATE_ASYNC_SUSPEND_REQUESTED: //Can't detach until whoever asked us to suspend to be happy with us
149 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
150 STATE_SELF_SUSPENDED: Code should not be running while suspended.
151 STATE_SELF_SUSPEND_REQUESTED: This is a bug in the self suspend code that didn't execute the second part of it
152 STATE_BLOCKING_AND_SUSPENDED: This is a bug in coop x suspend that resulted the thread in an undetachable state.
155 mono_fatal_with_history ("Cannot transition current thread %p from %s with DETACH", info, state_name (cur_state));
160 This transition initiates the suspension of the current thread.
163 mono_threads_transition_request_self_suspension (MonoThreadInfo *info)
165 int raw_state, cur_state, suspend_count;
166 g_assert (info == mono_thread_info_current ());
169 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
172 case STATE_RUNNING: //Post a self suspend request
173 if (!(suspend_count == 0))
174 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
175 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPEND_REQUESTED, 1), raw_state) != raw_state)
176 goto retry_state_change;
177 trace_state_change ("SELF_SUSPEND_REQUEST", info, raw_state, STATE_SELF_SUSPEND_REQUESTED, 1);
180 case STATE_ASYNC_SUSPEND_REQUESTED: //Bump the suspend count but don't change the request type as async takes preference
181 if (!(suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX))
182 mono_fatal_with_history ("suspend_count = %d, but should be > 0 and < THREAD_SUSPEND_COUNT_MAX", suspend_count);
183 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
184 goto retry_state_change;
185 trace_state_change ("SUSPEND_REQUEST", info, raw_state, cur_state, 1);
189 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
190 STATE_SELF_SUSPENDED: Code should not be running while suspended.
191 STATE_SELF_SUSPEND_REQUESTED: Self suspends should not nest as begin/end should be paired. [1]
193 STATE_BLOCKING_AND_SUSPENDED: Self suspension cannot be started when the thread is in blocking state as it must finish first
195 [1] This won't trap this sequence of requests: self suspend, async suspend and self suspend.
196 If this turns to be an issue we can introduce a new suspend request state for when both have been requested.
199 mono_fatal_with_history ("Cannot transition thread %p from %s with SUSPEND_REQUEST", mono_thread_info_get_tid (info), state_name (cur_state));
204 This transition initiates the suspension of another thread.
206 Returns one of the following values:
208 - AsyncSuspendInitSuspend: Thread suspend requested, async suspend needs to be done.
209 - AsyncSuspendAlreadySuspended: Thread already suspended, nothing to do.
210 - AsyncSuspendWait: Self suspend in progress, asked it to notify us. Caller must add target to the notification set.
211 - AsyncSuspendBlocking: Thread in blocking state
213 MonoRequestAsyncSuspendResult
214 mono_threads_transition_request_async_suspension (MonoThreadInfo *info)
216 int raw_state, cur_state, suspend_count;
217 g_assert (info != mono_thread_info_current ());
220 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
223 case STATE_RUNNING: //Post an async suspend request
224 if (!(suspend_count == 0))
225 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
226 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, 1), raw_state) != raw_state)
227 goto retry_state_change;
228 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 1);
229 return AsyncSuspendInitSuspend; //This is the first async suspend request against the target
231 case STATE_ASYNC_SUSPENDED:
232 case STATE_SELF_SUSPENDED: //Async suspend can suspend the same thread multiple times as it starts from the outside
233 case STATE_BLOCKING_AND_SUSPENDED:
234 if (!(suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX))
235 mono_fatal_with_history ("suspend_count = %d, but should be > 0 and < THREAD_SUSPEND_COUNT_MAX", suspend_count);
236 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
237 goto retry_state_change;
238 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, cur_state, 1);
239 return AsyncSuspendAlreadySuspended; //Thread is already suspended so we don't need to wait it to suspend
241 case STATE_SELF_SUSPEND_REQUESTED: //This suspend needs to notify the initiator, so we need to promote the suspend to async
242 if (!(suspend_count > 0 && suspend_count < THREAD_SUSPEND_COUNT_MAX))
243 mono_fatal_with_history ("suspend_count = %d, but should be > 0 and < THREAD_SUSPEND_COUNT_MAX", suspend_count);
244 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPEND_REQUESTED, suspend_count + 1), raw_state) != raw_state)
245 goto retry_state_change;
246 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, STATE_ASYNC_SUSPEND_REQUESTED, 1);
247 return AsyncSuspendWait; //This is the first async suspend request, change the thread and let it notify us [1]
250 if (!(suspend_count < THREAD_SUSPEND_COUNT_MAX))
251 mono_fatal_with_history ("suspend_count = %d, but should be < THREAD_SUSPEND_COUNT_MAX", suspend_count);
252 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count + 1), raw_state) != raw_state)
253 goto retry_state_change;
254 trace_state_change ("ASYNC_SUSPEND_REQUESTED", info, raw_state, cur_state, 1);
255 return AsyncSuspendBlocking; //A thread in the blocking state has its state saved so we can treat it as suspended.
259 [1] It's questionable on what to do if we hit the beginning of a self suspend.
260 The expected behavior is that the target should poll its state very soon so the the suspend latency should be minimal.
262 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.
265 mono_fatal_with_history ("Cannot transition thread %p from %s with ASYNC_SUSPEND_REQUESTED", mono_thread_info_get_tid (info), state_name (cur_state));
267 return (MonoRequestAsyncSuspendResult) FALSE;
271 Check the current state of the thread and try to init a self suspend.
272 This must be called with self state saved.
274 Returns one of the following values:
276 - Resumed: Async resume happened and current thread should keep running
277 - Suspend: Caller should wait for a resume signal
278 - SelfSuspendNotifyAndWait: Notify the suspend initiator and wait for a resume signals
279 suspend should start.
283 mono_threads_transition_state_poll (MonoThreadInfo *info)
285 int raw_state, cur_state, suspend_count;
286 g_assert (mono_thread_info_is_current (info));
289 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
292 if (!(suspend_count == 0))
293 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
294 trace_state_change ("STATE_POLL", info, raw_state, cur_state, 0);
295 return SelfSuspendResumed; //We're fine, don't suspend
297 case STATE_ASYNC_SUSPEND_REQUESTED: //Async suspend requested, service it with a self suspend
298 case STATE_SELF_SUSPEND_REQUESTED: //Start the self suspend process
299 if (!(suspend_count > 0))
300 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
301 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_SELF_SUSPENDED, suspend_count), raw_state) != raw_state)
302 goto retry_state_change;
303 trace_state_change ("STATE_POLL", info, raw_state, STATE_SELF_SUSPENDED, 0);
304 if (cur_state == STATE_SELF_SUSPEND_REQUESTED)
305 return SelfSuspendWait; //Caller should wait for resume
307 return SelfSuspendNotifyAndWait; //Caller should notify suspend initiator and wait for resume
310 STATE_ASYNC_SUSPENDED: Code should not be running while suspended.
311 STATE_SELF_SUSPENDED: Code should not be running while suspended.
313 STATE_BLOCKING_AND_SUSPENDED: Pool is a local state transition. No VM activities are allowed while in blocking mode.
316 mono_fatal_with_history ("Cannot transition thread %p from %s with STATE_POLL", mono_thread_info_get_tid (info), state_name (cur_state));
321 Try to resume a suspended thread.
323 Returns one of the following values:
324 - Sucess: The thread was resumed.
325 - Error: The thread was not suspended in the first place. [2]
326 - InitSelfResume: The thread is blocked on self suspend and should be resumed
327 - InitAsycResume: The thread is blocked on async suspend and should be resumed
328 - ResumeInitBlockingResume: The thread was suspended on the exit path of blocking state and should be resumed
330 [2] This threading system uses an unsigned suspend count. Which means a resume cannot be
331 used as a suspend permit and cancel each other.
333 Suspend permits are really useful to implement managed synchronization structures that
334 don't consume native resources. The downside is that they further complicate the design of this
335 system as the RUNNING state now has a non zero suspend counter.
337 It can be implemented in the future if we find resume/suspend races that cannot be (efficiently) fixed by other means.
339 One major issue with suspend permits is runtime facilities (GC, debugger) that must have the target suspended when requested.
340 This would make permits really harder to add.
343 mono_threads_transition_request_resume (MonoThreadInfo* info)
345 int raw_state, cur_state, suspend_count;
346 g_assert (info != mono_thread_info_current ()); //One can't self resume [3]
349 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
351 case STATE_RUNNING: //Thread already running.
352 if (!(suspend_count == 0))
353 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
354 trace_state_change ("RESUME", info, raw_state, cur_state, 0);
355 return ResumeError; //Resume failed because thread was not blocked
357 case STATE_BLOCKING: //Blocking, might have a suspend count, we decrease if it's > 0
358 if (suspend_count == 0) {
359 trace_state_change ("RESUME", info, raw_state, cur_state, 0);
362 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
363 goto retry_state_change;
364 trace_state_change ("RESUME", info, raw_state, cur_state, -1);
365 return ResumeOk; //Resume worked and there's nothing for the caller to do.
368 case STATE_ASYNC_SUSPENDED:
369 case STATE_SELF_SUSPENDED:
370 case STATE_BLOCKING_AND_SUSPENDED: //Decrease the suspend_count and maybe resume
371 if (!(suspend_count > 0))
372 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
373 if (suspend_count > 1) {
374 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
375 goto retry_state_change;
376 trace_state_change ("RESUME", info, raw_state, cur_state, -1);
378 return ResumeOk; //Resume worked and there's nothing for the caller to do.
380 if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
381 goto retry_state_change;
382 trace_state_change ("RESUME", info, raw_state, STATE_RUNNING, -1);
384 if (cur_state == STATE_ASYNC_SUSPENDED)
385 return ResumeInitAsyncResume; //Resume worked and caller must do async resume
386 else if (cur_state == STATE_SELF_SUSPENDED)
387 return ResumeInitSelfResume; //Resume worked and caller must do self resume
389 return ResumeInitBlockingResume; //Resume worked and caller must do blocking resume
392 case STATE_SELF_SUSPEND_REQUESTED: //Self suspend was requested but another thread decided to resume it.
393 if (!(suspend_count > 0))
394 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
395 if (suspend_count > 1) {
396 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (cur_state, suspend_count - 1), raw_state) != raw_state)
397 goto retry_state_change;
398 trace_state_change ("RESUME", info, raw_state, cur_state, -1);
400 if (InterlockedCompareExchange (&info->thread_state, STATE_RUNNING, raw_state) != raw_state)
401 goto retry_state_change;
402 trace_state_change ("RESUME", info, raw_state, STATE_RUNNING, -1);
404 return ResumeOk; //Resume worked and there's nothing for the caller to do (the target never actually suspend).
407 STATE_ASYNC_SUSPEND_REQUESTED: Only one async suspend/resume operation can be in flight, so a resume cannot witness an internal state of suspend
409 [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
410 sense as a suspend permit, but as explained in [2] we don't support it so this is a bug.
412 [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
413 is similar to the one described in [2] when this is used for as a synchronization primitive.
415 If this turns to be a problem we should either implement [2] or make this an invalid transition.
419 mono_fatal_with_history ("Cannot transition thread %p from %s with REQUEST_RESUME", mono_thread_info_get_tid (info), state_name (cur_state));
424 This performs the last step of async suspend.
426 Returns TRUE if the caller should wait for resume.
429 mono_threads_transition_finish_async_suspend (MonoThreadInfo* info)
431 int raw_state, cur_state, suspend_count;
434 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
437 case STATE_SELF_SUSPENDED: //async suspend raced with self suspend and lost
438 case STATE_BLOCKING_AND_SUSPENDED: //async suspend raced with blocking and lost
439 trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, cur_state, 0);
440 return FALSE; //let self suspend wait
442 case STATE_ASYNC_SUSPEND_REQUESTED:
443 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_ASYNC_SUSPENDED, suspend_count), raw_state) != raw_state)
444 goto retry_state_change;
445 trace_state_change ("FINISH_ASYNC_SUSPEND", info, raw_state, STATE_ASYNC_SUSPENDED, 0);
446 return TRUE; //Async suspend worked, now wait for resume
449 STATE_RUNNING: A thread cannot escape suspension once requested.
450 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.
451 STATE_SELF_SUSPEND_REQUESTED: When self suspend and async suspend happen together, they converge to async suspend so this state should not be visible.
452 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.
455 mono_fatal_with_history ("Cannot transition thread %p from %s with FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
460 This transitions the thread into a cooperative state where it's assumed to be suspended but can continue.
462 Native runtime code might want to put itself into a state where the thread is considered suspended but can keep running.
463 That state only works as long as the only managed state touched is blitable and was pinned before the transition.
465 It returns the action the caller must perform:
467 - Continue: Entered blocking state sucessfully;
468 - PollAndRetry: Async suspend raced and won, try to suspend and then retry;
472 mono_threads_transition_do_blocking (MonoThreadInfo* info)
474 int raw_state, cur_state, suspend_count;
477 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
480 case STATE_RUNNING: //transition to blocked
481 if (!(suspend_count == 0))
482 mono_fatal_with_history ("suspend_count = %d, but should be == 0", suspend_count);
483 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_BLOCKING, suspend_count), raw_state) != raw_state)
484 goto retry_state_change;
485 trace_state_change ("DO_BLOCKING", info, raw_state, STATE_BLOCKING, 0);
486 return DoBlockingContinue;
488 case STATE_ASYNC_SUSPEND_REQUESTED:
489 if (!(suspend_count > 0))
490 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
491 trace_state_change ("DO_BLOCKING", info, raw_state, cur_state, 0);
492 return DoBlockingPollAndRetry;
494 STATE_ASYNC_SUSPENDED
495 STATE_SELF_SUSPENDED: Code should not be running while suspended.
496 STATE_SELF_SUSPEND_REQUESTED: A blocking operation must not be done while trying to self suspend
498 STATE_BLOCKING_AND_SUSPENDED: Blocking is not nestabled
501 mono_fatal_with_history ("Cannot transition thread %p from %s with DO_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
506 This is the exit transition from the blocking state. If this thread is logically async suspended it will have to wait
507 until its resumed before continuing.
510 -Aborted: The blocking operation was aborted and not properly restored. Aborts can happen due to lazy loading and some n2m transitions;
511 -Ok: Done with blocking, just move on;
512 -Wait: This thread was async suspended, wait for resume
515 MonoDoneBlockingResult
516 mono_threads_transition_done_blocking (MonoThreadInfo* info)
518 int raw_state, cur_state, suspend_count;
521 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
524 if (suspend_count == 0) {
525 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_RUNNING, suspend_count), raw_state) != raw_state)
526 goto retry_state_change;
527 trace_state_change ("DONE_BLOCKING", info, raw_state, STATE_RUNNING, 0);
528 return DoneBlockingOk;
530 if (!(suspend_count >= 0))
531 mono_fatal_with_history ("suspend_count = %d, but should be >= 0", suspend_count);
532 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_BLOCKING_AND_SUSPENDED, suspend_count), raw_state) != raw_state)
533 goto retry_state_change;
534 trace_state_change ("DONE_BLOCKING", info, raw_state, STATE_BLOCKING_AND_SUSPENDED, 0);
535 return DoneBlockingWait;
539 STATE_RUNNING: //Blocking was aborted and not properly restored
540 STATE_ASYNC_SUSPEND_REQUESTED: //Blocking was aborted, not properly restored and now there's a pending suspend
541 STATE_ASYNC_SUSPENDED
542 STATE_SELF_SUSPENDED: Code should not be running while suspended.
543 STATE_SELF_SUSPEND_REQUESTED: A blocking operation must not be done while trying to self suspend
544 STATE_BLOCKING_AND_SUSPENDED: This an exit state of done blocking
547 mono_fatal_with_history ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
552 Transition a thread in what should be a blocking state back to running state.
553 This is different that done blocking because the goal is to get back to blocking once we're done.
554 This is required to be able to bail out of blocking in case we're back to inside the runtime.
557 -Ignore: Thread was not in blocking, nothing to do;
558 -IgnoreAndPool: Thread was not blocking and there's a pending suspend that needs to be processed;
559 -Ok: Blocking state successfully aborted;
560 -Wait: Blocking state successfully aborted, there's a pending suspend to be processed though
562 MonoAbortBlockingResult
563 mono_threads_transition_abort_blocking (THREAD_INFO_TYPE* info)
565 int raw_state, cur_state, suspend_count;
568 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
570 case STATE_RUNNING: //thread already in runnable state
571 trace_state_change ("ABORT_BLOCKING", info, raw_state, cur_state, 0);
572 return AbortBlockingIgnore;
574 case STATE_ASYNC_SUSPEND_REQUESTED: //thread is runnable and have a pending suspend
575 trace_state_change ("ABORT_BLOCKING", info, raw_state, cur_state, 0);
576 return AbortBlockingIgnoreAndPoll;
579 if (suspend_count == 0) {
580 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_RUNNING, suspend_count), raw_state) != raw_state)
581 goto retry_state_change;
582 trace_state_change ("ABORT_BLOCKING", info, raw_state, STATE_RUNNING, 0);
583 return AbortBlockingOk;
585 if (!(suspend_count > 0))
586 mono_fatal_with_history ("suspend_count = %d, but should be > 0", suspend_count);
587 if (InterlockedCompareExchange (&info->thread_state, build_thread_state (STATE_BLOCKING_AND_SUSPENDED, suspend_count), raw_state) != raw_state)
588 goto retry_state_change;
589 trace_state_change ("ABORT_BLOCKING", info, raw_state, STATE_BLOCKING_AND_SUSPENDED, 0);
590 return AbortBlockingWait;
593 STATE_ASYNC_SUSPENDED:
594 STATE_SELF_SUSPENDED: Code should not be running while suspended.
595 STATE_SELF_SUSPEND_REQUESTED: A blocking operation must not be done while trying to self suspend.
596 STATE_BLOCKING_AND_SUSPENDED: This is an exit state of done blocking, can't happen here.
599 mono_fatal_with_history ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
603 MonoThreadUnwindState*
604 mono_thread_info_get_suspend_state (MonoThreadInfo *info)
606 int raw_state, cur_state, suspend_count;
607 UNWRAP_THREAD_STATE (raw_state, cur_state, suspend_count, info);
609 case STATE_ASYNC_SUSPENDED:
610 return &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX];
611 case STATE_SELF_SUSPENDED:
612 case STATE_BLOCKING_AND_SUSPENDED:
613 return &info->thread_saved_state [SELF_SUSPEND_STATE_INDEX];
615 if (suspend_count > 0)
616 return &info->thread_saved_state [SELF_SUSPEND_STATE_INDEX];
621 STATE_ASYNC_SUSPEND_REQUESTED
622 STATE_BLOCKING: All those are invalid suspend states.
624 g_error ("Cannot read suspend state when target %p is in the %s state", mono_thread_info_get_tid (info), state_name (cur_state));
628 // State checking code
630 * Return TRUE is the thread is in a runnable state.
633 mono_thread_info_is_running (MonoThreadInfo *info)
635 switch (get_thread_state (info->thread_state)) {
637 case STATE_ASYNC_SUSPEND_REQUESTED:
638 case STATE_SELF_SUSPEND_REQUESTED:
646 * Return TRUE is the thread is in an usable (suspendable) state
649 mono_thread_info_is_live (MonoThreadInfo *info)
651 switch (get_thread_state (info->thread_state)) {
660 mono_thread_info_suspend_count (MonoThreadInfo *info)
662 return get_thread_suspend_count (info->thread_state);
666 mono_thread_info_current_state (MonoThreadInfo *info)
668 return get_thread_state (info->thread_state);
672 mono_thread_state_name (int state)
674 return state_name (state);