[threading] Add a global variable that is set while a global suspend is hapening.
[mono-project.git] / mono / utils / mono-threads-coop.c
blobb44719109ffc277ad377942a4b219b21a92d8408
1 /*
2 * mono-threads.c: Coop threading
4 * Author:
5 * Rodrigo Kumpera (kumpera@gmail.com)
7 * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
8 */
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;
24 void
25 mono_threads_state_poll (void)
27 MonoThreadInfo *info;
29 info = mono_thread_info_current_unchecked ();
30 if (!info)
31 return;
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)))
36 return;
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:
43 return;
44 case SelfSuspendWait:
45 mono_thread_info_wait_for_resume (info);
46 break;
47 case SelfSuspendNotifyAndWait:
48 mono_threads_notify_initiator_of_suspend (info);
49 mono_thread_info_wait_for_resume (info);
50 break;
54 void*
55 mono_threads_prepare_blocking (void)
57 MonoThreadInfo *info;
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));
63 return NULL;
66 retry:
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));
70 return NULL;
73 switch (mono_threads_transition_do_blocking (info)) {
74 case DoBlockingContinue:
75 break;
76 case DoBlockingPollAndRetry:
77 mono_threads_state_poll ();
78 goto retry;
81 return info;
84 void
85 mono_threads_finish_blocking (void *cookie)
87 static gboolean warned_about_bad_transition;
88 MonoThreadInfo *info = cookie;
90 if (!info)
91 return;
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 ();
102 break;
103 case DoneBlockingOk:
104 info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
105 break;
106 case DoneBlockingWait:
107 THREADS_SUSPEND_DEBUG ("state polling done, notifying of resume\n");
108 mono_thread_info_wait_for_resume (info);
109 break;
110 default:
111 g_error ("Unknown thread state");
116 void*
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))
123 return NULL;
125 switch (mono_threads_transition_abort_blocking (info)) {
126 case AbortBlockingIgnore:
127 info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
128 return NULL;
129 case AbortBlockingIgnoreAndPoll:
130 mono_threads_state_poll ();
131 return NULL;
132 case AbortBlockingOk:
133 info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
134 return info;
135 case AbortBlockingOkAndPool:
136 mono_threads_state_poll ();
137 return info;
138 default:
139 g_error ("Unknown thread state");
143 void
144 mono_threads_reset_blocking_end (void *cookie)
146 MonoThreadInfo *info = cookie;
148 if (!info)
149 return;
151 g_assert (info == mono_thread_info_current_unchecked ());
152 mono_threads_prepare_blocking ();
155 void*
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));
164 return NULL;
167 retry:
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));
171 return NULL;
174 switch (mono_threads_transition_do_blocking (info)) {
175 case DoBlockingContinue:
176 break;
177 case DoBlockingPollAndRetry:
178 mono_threads_state_poll ();
179 goto retry;
182 return info;
185 void
186 mono_threads_finish_try_blocking (void* cookie)
188 mono_threads_finish_blocking (cookie);
191 void
192 mono_threads_core_abort_syscall (MonoThreadInfo *info)
194 g_error ("FIXME");
197 gboolean
198 mono_threads_core_begin_async_resume (MonoThreadInfo *info)
200 g_error ("FIXME");
201 return FALSE;
204 gboolean
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 */
209 return TRUE;
212 gboolean
213 mono_threads_core_check_suspend_result (MonoThreadInfo *info)
215 /* Async suspend can't async fail on coop */
216 return TRUE;
219 gboolean
220 mono_threads_core_needs_abort_syscall (void)
223 Small digression.
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.
232 return FALSE;
235 void
236 mono_threads_init_platform (void)
238 //See the above for what's wrong here.
241 void
242 mono_threads_platform_free (MonoThreadInfo *info)
244 //See the above for what's wrong here.
247 void
248 mono_threads_platform_register (MonoThreadInfo *info)
250 //See the above for what's wrong here.
253 void
254 mono_threads_core_begin_global_suspend (void)
256 mono_polling_required = 1;
259 void
260 mono_threads_core_end_global_suspend (void)
262 mono_polling_required = 0;
266 #endif