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>
19 #include <mono/utils/mono-counters.h>
21 #ifdef USE_COOP_BACKEND
23 volatile size_t mono_polling_required;
25 static int coop_reset_blocking_count, coop_try_blocking_count, coop_do_blocking_count, coop_do_polling_count, coop_save_count;
28 mono_threads_state_poll (void)
31 ++coop_do_polling_count;
33 info = mono_thread_info_current_unchecked ();
36 THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", mono_thread_info_get_tid (info));
38 /* Fast check for pending suspend requests */
39 if (!(info->thread_state & (STATE_ASYNC_SUSPEND_REQUESTED | STATE_SELF_SUSPEND_REQUESTED)))
43 mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
45 /* commit the saved state and notify others if needed */
46 switch (mono_threads_transition_state_poll (info)) {
47 case SelfSuspendResumed:
50 mono_thread_info_wait_for_resume (info);
52 case SelfSuspendNotifyAndWait:
53 mono_threads_notify_initiator_of_suspend (info);
54 mono_thread_info_wait_for_resume (info);
60 mono_threads_prepare_blocking (void)
63 ++coop_do_blocking_count;
65 info = mono_thread_info_current_unchecked ();
66 /* If the thread is not attached, it doesn't make sense prepare for suspend. */
67 if (!info || !mono_thread_info_is_live (info)) {
68 THREADS_SUSPEND_DEBUG ("PREPARE-BLOCKING failed %p\n", mono_thread_info_get_tid (info));
74 mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
76 switch (mono_threads_transition_do_blocking (info)) {
77 case DoBlockingContinue:
79 case DoBlockingPollAndRetry:
80 mono_threads_state_poll ();
88 mono_threads_finish_blocking (void *cookie)
90 static gboolean warned_about_bad_transition;
91 MonoThreadInfo *info = cookie;
96 g_assert (info == mono_thread_info_current_unchecked ());
98 switch (mono_threads_transition_done_blocking (info)) {
99 case DoneBlockingAborted:
100 if (!warned_about_bad_transition) {
101 warned_about_bad_transition = TRUE;
102 g_warning ("[%p] Blocking call ended in running state for, this might lead to unbound GC pauses.", mono_thread_info_get_tid (info));
104 mono_threads_state_poll ();
107 info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
109 case DoneBlockingWait:
110 THREADS_SUSPEND_DEBUG ("state polling done, notifying of resume\n");
111 mono_thread_info_wait_for_resume (info);
114 g_error ("Unknown thread state");
120 mono_threads_reset_blocking_start (void)
122 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
123 ++coop_reset_blocking_count;
125 /* If the thread is not attached, it doesn't make sense prepare for suspend. */
126 if (!info || !mono_thread_info_is_live (info))
129 switch (mono_threads_transition_abort_blocking (info)) {
130 case AbortBlockingIgnore:
131 info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
133 case AbortBlockingIgnoreAndPoll:
134 mono_threads_state_poll ();
136 case AbortBlockingOk:
137 info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
139 case AbortBlockingOkAndPool:
140 mono_threads_state_poll ();
143 g_error ("Unknown thread state");
148 mono_threads_reset_blocking_end (void *cookie)
150 MonoThreadInfo *info = cookie;
155 g_assert (info == mono_thread_info_current_unchecked ());
156 mono_threads_prepare_blocking ();
160 mono_threads_try_prepare_blocking (void)
162 MonoThreadInfo *info;
163 ++coop_try_blocking_count;
165 info = mono_thread_info_current_unchecked ();
166 /* If the thread is not attached, it doesn't make sense prepare for suspend. */
167 if (!info || !mono_thread_info_is_live (info) || mono_thread_info_current_state (info) == STATE_BLOCKING) {
168 THREADS_SUSPEND_DEBUG ("PREPARE-TRY-BLOCKING failed %p\n", mono_thread_info_get_tid (info));
174 mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
176 switch (mono_threads_transition_do_blocking (info)) {
177 case DoBlockingContinue:
179 case DoBlockingPollAndRetry:
180 mono_threads_state_poll ();
188 mono_threads_finish_try_blocking (void* cookie)
190 mono_threads_finish_blocking (cookie);
194 mono_threads_core_abort_syscall (MonoThreadInfo *info)
200 mono_threads_core_begin_async_resume (MonoThreadInfo *info)
207 mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
209 mono_threads_add_to_pending_operation_set (info);
210 /* There's nothing else to do after we async request the thread to suspend */
215 mono_threads_core_check_suspend_result (MonoThreadInfo *info)
217 /* Async suspend can't async fail on coop */
222 mono_threads_core_needs_abort_syscall (void)
226 Syscall abort can't be handled by the suspend machinery even though it's kind of implemented
227 in a similar way (with, like, signals).
229 So, having it here is wrong, it should be on mono-threads-(mach|posix|windows).
230 Ideally we would slice this in (coop|preemp) and target. Then have this file set:
231 mono-threads-mach, mono-threads-mach-preempt and mono-threads-mach-coop.
232 More files, less ifdef hell.
238 mono_threads_init_platform (void)
240 mono_counters_register ("Coop Reset Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_reset_blocking_count);
241 mono_counters_register ("Coop Try Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_try_blocking_count);
242 mono_counters_register ("Coop Do Blocking", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_do_blocking_count);
243 mono_counters_register ("Coop Do Polling", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_do_polling_count);
244 mono_counters_register ("Coop Save Count", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_save_count);
245 //See the above for what's wrong here.
249 mono_threads_platform_free (MonoThreadInfo *info)
251 //See the above for what's wrong here.
255 mono_threads_platform_register (MonoThreadInfo *info)
257 //See the above for what's wrong here.
261 mono_threads_core_begin_global_suspend (void)
263 mono_polling_required = 1;
267 mono_threads_core_end_global_suspend (void)
269 mono_polling_required = 0;