2 * mono-threads.c: Coop threading
5 * Rodrigo Kumpera (kumpera@gmail.com)
7 * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
10 #include <mono/utils/mono-compiler.h>
11 #include <mono/utils/mono-semaphore.h>
12 #include <mono/utils/mono-threads.h>
13 #include <mono/utils/mono-tls.h>
14 #include <mono/utils/hazard-pointer.h>
15 #include <mono/utils/mono-memory-model.h>
16 #include <mono/utils/mono-mmap.h>
17 #include <mono/utils/atomic.h>
18 #include <mono/utils/mono-time.h>
20 #ifdef USE_COOP_BACKEND
22 volatile size_t mono_polling_required
;
25 mono_threads_state_poll (void)
29 info
= mono_thread_info_current_unchecked ();
32 THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", mono_thread_info_get_tid (info
));
34 /* Fast check for pending suspend requests */
35 if (!(info
->thread_state
& (STATE_ASYNC_SUSPEND_REQUESTED
| STATE_SELF_SUSPEND_REQUESTED
)))
38 g_assert (mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info
->thread_saved_state
[SELF_SUSPEND_STATE_INDEX
], NULL
));
40 /* commit the saved state and notify others if needed */
41 switch (mono_threads_transition_state_poll (info
)) {
42 case SelfSuspendResumed
:
45 mono_thread_info_wait_for_resume (info
);
47 case SelfSuspendNotifyAndWait
:
48 mono_threads_notify_initiator_of_suspend (info
);
49 mono_thread_info_wait_for_resume (info
);
55 mono_threads_prepare_blocking (void)
59 info
= mono_thread_info_current_unchecked ();
60 /* If the thread is not attached, it doesn't make sense prepare for suspend. */
61 if (!info
|| !mono_thread_info_is_live (info
)) {
62 THREADS_SUSPEND_DEBUG ("PREPARE-BLOCKING failed %p\n", mono_thread_info_get_tid (info
));
67 /*The JIT might not be able to save*/
68 if (!mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info
->thread_saved_state
[SELF_SUSPEND_STATE_INDEX
], NULL
)) {
69 THREADS_SUSPEND_DEBUG ("PREPARE-BLOCKING failed %p to save thread state\n", mono_thread_info_get_tid (info
));
73 switch (mono_threads_transition_do_blocking (info
)) {
74 case DoBlockingContinue
:
76 case DoBlockingPollAndRetry
:
77 mono_threads_state_poll ();
85 mono_threads_finish_blocking (void *cookie
)
87 static gboolean warned_about_bad_transition
;
88 MonoThreadInfo
*info
= cookie
;
93 g_assert (info
== mono_thread_info_current_unchecked ());
95 switch (mono_threads_transition_done_blocking (info
)) {
96 case DoneBlockingAborted
:
97 if (!warned_about_bad_transition
) {
98 warned_about_bad_transition
= TRUE
;
99 g_warning ("[%p] Blocking call ended in running state for, this might lead to unbound GC pauses.", mono_thread_info_get_tid (info
));
101 mono_threads_state_poll ();
104 info
->thread_saved_state
[SELF_SUSPEND_STATE_INDEX
].valid
= FALSE
;
106 case DoneBlockingWait
:
107 THREADS_SUSPEND_DEBUG ("state polling done, notifying of resume\n");
108 mono_thread_info_wait_for_resume (info
);
111 g_error ("Unknown thread state");
117 mono_threads_reset_blocking_start (void)
119 MonoThreadInfo
*info
= mono_thread_info_current_unchecked ();
121 /* If the thread is not attached, it doesn't make sense prepare for suspend. */
122 if (!info
|| !mono_thread_info_is_live (info
))
125 switch (mono_threads_transition_abort_blocking (info
)) {
126 case AbortBlockingIgnore
:
127 info
->thread_saved_state
[SELF_SUSPEND_STATE_INDEX
].valid
= FALSE
;
129 case AbortBlockingIgnoreAndPoll
:
130 mono_threads_state_poll ();
132 case AbortBlockingOk
:
133 info
->thread_saved_state
[SELF_SUSPEND_STATE_INDEX
].valid
= FALSE
;
135 case AbortBlockingOkAndPool
:
136 mono_threads_state_poll ();
139 g_error ("Unknown thread state");
144 mono_threads_reset_blocking_end (void *cookie
)
146 MonoThreadInfo
*info
= cookie
;
151 g_assert (info
== mono_thread_info_current_unchecked ());
152 mono_threads_prepare_blocking ();
156 mono_threads_try_prepare_blocking (void)
158 MonoThreadInfo
*info
;
160 info
= mono_thread_info_current_unchecked ();
161 /* If the thread is not attached, it doesn't make sense prepare for suspend. */
162 if (!info
|| !mono_thread_info_is_live (info
) || mono_thread_info_current_state (info
) == STATE_BLOCKING
) {
163 THREADS_SUSPEND_DEBUG ("PREPARE-TRY-BLOCKING failed %p\n", mono_thread_info_get_tid (info
));
168 /*The JIT might not be able to save*/
169 if (!mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info
->thread_saved_state
[SELF_SUSPEND_STATE_INDEX
], NULL
)) {
170 THREADS_SUSPEND_DEBUG ("PREPARE-TRY-BLOCKING failed %p to save thread state\n", mono_thread_info_get_tid (info
));
174 switch (mono_threads_transition_do_blocking (info
)) {
175 case DoBlockingContinue
:
177 case DoBlockingPollAndRetry
:
178 mono_threads_state_poll ();
186 mono_threads_finish_try_blocking (void* cookie
)
188 mono_threads_finish_blocking (cookie
);
192 mono_threads_core_abort_syscall (MonoThreadInfo
*info
)
198 mono_threads_core_begin_async_resume (MonoThreadInfo
*info
)
205 mono_threads_core_begin_async_suspend (MonoThreadInfo
*info
, gboolean interrupt_kernel
)
207 mono_threads_add_to_pending_operation_set (info
);
208 /* There's nothing else to do after we async request the thread to suspend */
213 mono_threads_core_check_suspend_result (MonoThreadInfo
*info
)
215 /* Async suspend can't async fail on coop */
220 mono_threads_core_needs_abort_syscall (void)
224 Syscall abort can't be handled by the suspend machinery even though it's kind of implemented
225 in a similar way (with, like, signals).
227 So, having it here is wrong, it should be on mono-threads-(mach|posix|windows).
228 Ideally we would slice this in (coop|preemp) and target. Then have this file set:
229 mono-threads-mach, mono-threads-mach-preempt and mono-threads-mach-coop.
230 More files, less ifdef hell.
236 mono_threads_init_platform (void)
238 //See the above for what's wrong here.
242 mono_threads_platform_free (MonoThreadInfo
*info
)
244 //See the above for what's wrong here.
248 mono_threads_platform_register (MonoThreadInfo
*info
)
250 //See the above for what's wrong here.
254 mono_threads_core_begin_global_suspend (void)
256 mono_polling_required
= 1;
260 mono_threads_core_end_global_suspend (void)
262 mono_polling_required
= 0;