[eglib] Prefer <langinfo.h> to <localcharset.h>
[mono.git] / mono / utils / mono-threads-coop.c
1 /*
2  * mono-threads.c: Coop threading
3  *
4  * Author:
5  *      Rodrigo Kumpera (kumpera@gmail.com)
6  *
7  * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
8  */
9
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
20 #ifdef USE_COOP_BACKEND
21
22 volatile size_t mono_polling_required;
23
24 void
25 mono_threads_state_poll (void)
26 {
27         MonoThreadInfo *info;
28
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));
33
34         /* Fast check for pending suspend requests */
35         if (!(info->thread_state & (STATE_ASYNC_SUSPEND_REQUESTED | STATE_SELF_SUSPEND_REQUESTED)))
36                 return;
37
38         g_assert (mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX], NULL));
39
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;
51         }
52 }
53
54 void*
55 mono_threads_prepare_blocking (void)
56 {
57         MonoThreadInfo *info;
58
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;
64         }
65
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;
71         }
72
73         switch (mono_threads_transition_do_blocking (info)) {
74         case DoBlockingContinue:
75                 break;
76         case DoBlockingPollAndRetry:
77                 mono_threads_state_poll ();
78                 goto retry;
79         }
80
81         return info;
82 }
83
84 void
85 mono_threads_finish_blocking (void *cookie)
86 {
87         static gboolean warned_about_bad_transition;
88         MonoThreadInfo *info = cookie;
89
90         if (!info)
91                 return;
92
93         g_assert (info == mono_thread_info_current_unchecked ());
94
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));
100                 }
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");
112         }
113 }
114
115
116 void*
117 mono_threads_reset_blocking_start (void)
118 {
119         MonoThreadInfo *info = mono_thread_info_current_unchecked ();
120
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;
124
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");
140         }
141 }
142
143 void
144 mono_threads_reset_blocking_end (void *cookie)
145 {
146         MonoThreadInfo *info = cookie;
147
148         if (!info)
149                 return;
150
151         g_assert (info == mono_thread_info_current_unchecked ());
152         mono_threads_prepare_blocking ();
153 }
154
155 void*
156 mono_threads_try_prepare_blocking (void)
157 {
158         MonoThreadInfo *info;
159
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;
165         }
166
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;
172         }
173
174         switch (mono_threads_transition_do_blocking (info)) {
175         case DoBlockingContinue:
176                 break;
177         case DoBlockingPollAndRetry:
178                 mono_threads_state_poll ();
179                 goto retry;
180         }
181
182         return info;
183 }
184
185 void
186 mono_threads_finish_try_blocking (void* cookie)
187 {
188         mono_threads_finish_blocking (cookie);
189 }
190
191 void
192 mono_threads_core_abort_syscall (MonoThreadInfo *info)
193 {
194         g_error ("FIXME");
195 }
196
197 gboolean
198 mono_threads_core_begin_async_resume (MonoThreadInfo *info)
199 {
200         g_error ("FIXME");
201         return FALSE;
202 }
203
204 gboolean
205 mono_threads_core_begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
206 {
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;
210 }
211
212 gboolean
213 mono_threads_core_check_suspend_result (MonoThreadInfo *info)
214 {
215         /* Async suspend can't async fail on coop */
216         return TRUE;
217 }
218
219 gboolean
220 mono_threads_core_needs_abort_syscall (void)
221 {
222         /*
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).
226
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.
231         */
232         return FALSE;
233 }
234
235 void
236 mono_threads_init_platform (void)
237 {
238         //See the above for what's wrong here.
239 }
240
241 void
242 mono_threads_platform_free (MonoThreadInfo *info)
243 {
244         //See the above for what's wrong here.
245 }
246
247 void
248 mono_threads_platform_register (MonoThreadInfo *info)
249 {
250         //See the above for what's wrong here.
251 }
252
253 void
254 mono_threads_core_begin_global_suspend (void)
255 {
256         mono_polling_required = 1;
257 }
258
259 void
260 mono_threads_core_end_global_suspend (void)
261 {
262         mono_polling_required = 0;
263 }
264
265
266 #endif