[corlib] Fixed StringBuilder construction bugs in marshalling caused by changes to...
[mono.git] / mono / utils / mono-threads.c
1 /*
2  * mono-threads.c: Low-level threading
3  *
4  * Author:
5  *      Rodrigo Kumpera (kumpera@gmail.com)
6  *
7  * Copyright 2011 Novell, Inc (http://www.novell.com)
8  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9  */
10
11 #include <config.h>
12
13 #include <mono/utils/mono-compiler.h>
14 #include <mono/utils/mono-semaphore.h>
15 #include <mono/utils/mono-threads.h>
16 #include <mono/utils/mono-tls.h>
17 #include <mono/utils/hazard-pointer.h>
18 #include <mono/utils/mono-memory-model.h>
19 #include <mono/utils/mono-mmap.h>
20 #include <mono/utils/atomic.h>
21 #include <mono/utils/mono-time.h>
22
23
24 #include <errno.h>
25
26 #if defined(__MACH__)
27 #include <mono/utils/mach-support.h>
28 #endif
29
30 /*
31 Mutex that makes sure only a single thread can be suspending others.
32 Suspend is a very racy operation since it requires restarting until
33 the target thread is not on an unsafe region.
34
35 We could implement this using critical regions, but would be much much
36 harder for an operation that is hardly performance critical.
37
38 The GC has to acquire this lock before starting a STW to make sure
39 a runtime suspend won't make it wronly see a thread in a safepoint
40 when it is in fact not.
41 */
42 static MonoSemType global_suspend_semaphore;
43
44 static size_t thread_info_size;
45 static MonoThreadInfoCallbacks threads_callbacks;
46 static MonoThreadInfoRuntimeCallbacks runtime_callbacks;
47 static MonoNativeTlsKey thread_info_key, thread_exited_key;
48 #ifdef HAVE_KW_THREAD
49 static __thread guint32 tls_small_id MONO_TLS_FAST;
50 #else
51 static MonoNativeTlsKey small_id_key;
52 #endif
53 static MonoLinkedListSet thread_list;
54 static gboolean disable_new_interrupt = FALSE;
55 static gboolean mono_threads_inited = FALSE;
56
57 static MonoSemType suspend_semaphore;
58 static size_t pending_suspends;
59 static gboolean unified_suspend_enabled;
60
61 #define mono_thread_info_run_state(info) (((MonoThreadInfo*)info)->thread_state & THREAD_STATE_MASK)
62
63 /*warn at 50 ms*/
64 #define SLEEP_DURATION_BEFORE_WARNING (50)
65 /*abort at 1 sec*/
66 #define SLEEP_DURATION_BEFORE_ABORT 1000
67
68 static void
69 wait_for_resume (MonoThreadInfo* info)
70 {
71         MONO_SEM_WAIT_UNITERRUPTIBLE (&info->resume_semaphore);
72 }
73
74 void
75 mono_threads_notify_initiator_of_suspend (MonoThreadInfo* info)
76 {
77         THREADS_SUSPEND_DEBUG ("[INITIATOR-NOTIFY-SUSPEND] %p\n", info);
78         MONO_SEM_POST (&suspend_semaphore);
79 }
80
81 void
82 mono_threads_notify_initiator_of_resume (MonoThreadInfo* info)
83 {
84         THREADS_SUSPEND_DEBUG ("[INITIATOR-NOTIFY-RESUME] %p\n", info);
85         MONO_SEM_POST (&suspend_semaphore);
86 }
87
88 static void
89 resume_self_suspended (MonoThreadInfo* info)
90 {
91         THREADS_SUSPEND_DEBUG ("begin self-resume %p\n", info);
92         MONO_SEM_POST (&info->resume_semaphore);
93 }
94
95 static void
96 resume_async_suspended (MonoThreadInfo *info)
97 {
98         g_assert (mono_threads_core_begin_async_resume (info));
99 }
100
101 void
102 mono_threads_add_to_pending_operation_set (MonoThreadInfo* info)
103 {
104         THREADS_SUSPEND_DEBUG ("added %p to pending suspend\n", info);
105         ++pending_suspends;
106 }
107
108 void
109 mono_threads_begin_global_suspend (void)
110 {
111         g_assert (pending_suspends == 0);
112         THREADS_SUSPEND_DEBUG ("------ BEGIN GLOBAL OP\n");
113 }
114
115 void
116 mono_threads_end_global_suspend (void) 
117 {
118         g_assert (pending_suspends == 0);
119         THREADS_SUSPEND_DEBUG ("------ END GLOBAL OP\n");
120 }
121
122 static void
123 dump_threads (void)
124 {
125         MonoThreadInfo *info;
126         FOREACH_THREAD_SAFE (info) {
127                 THREADS_SUSPEND_DEBUG ("--thread %p id %p state %x\n", info, mono_thread_info_get_tid (info), info->thread_state);
128         } END_FOREACH_THREAD_SAFE
129 }
130
131 gboolean
132 mono_threads_wait_pending_operations (void)
133 {
134         int i;
135         int c = pending_suspends;
136
137         /* Wait threads to park */
138         if (pending_suspends) {
139                 MonoStopwatch suspension_time;
140                 mono_stopwatch_start (&suspension_time);
141                 THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-COUNT] %d\n", c);
142                 for (i = 0; i < pending_suspends; ++i) {
143                         THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-WAITING]\n");
144                         if (!MONO_SEM_TIMEDWAIT (&suspend_semaphore, SLEEP_DURATION_BEFORE_ABORT))
145                                 continue;
146                         mono_stopwatch_stop (&suspension_time);
147
148                         dump_threads ();
149
150                         THREADS_SUSPEND_DEBUG ("WAITING for %d threads, got %d suspended\n", (int)pending_suspends, i);
151                         THREADS_SUSPEND_DEBUG ("cur thread is %p\n", pthread_self ());
152                         g_error ("suspend_thread suspend took %d ms, which is more than the allowed %d ms", (int)mono_stopwatch_elapsed_ms (&suspension_time), SLEEP_DURATION_BEFORE_ABORT);
153                 }
154                 mono_stopwatch_stop (&suspension_time);
155                 THREADS_SUSPEND_DEBUG ("Suspending %d threads took %d ms.\n", (int)pending_suspends, (int)mono_stopwatch_elapsed_ms (&suspension_time));
156
157         }
158
159         pending_suspends = 0;
160
161         return c > 0;
162 }
163
164
165 //Thread initialization code
166
167 static void mono_threads_unregister_current_thread (MonoThreadInfo *info);
168
169 static inline void
170 mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
171 {
172         if (retain != 0)
173                 mono_hazard_pointer_clear (hp, 0);
174         if (retain != 1)
175                 mono_hazard_pointer_clear (hp, 1);
176         if (retain != 2)
177                 mono_hazard_pointer_clear (hp, 2);
178 }
179
180 /*
181 If return non null Hazard Pointer 1 holds the return value.
182 */
183 MonoThreadInfo*
184 mono_thread_info_lookup (MonoNativeThreadId id)
185 {
186                 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
187
188         if (!mono_lls_find (&thread_list, hp, (uintptr_t)id)) {
189                 mono_hazard_pointer_clear_all (hp, -1);
190                 return NULL;
191         } 
192
193         mono_hazard_pointer_clear_all (hp, 1);
194         return mono_hazard_pointer_get_val (hp, 1);
195 }
196
197 static gboolean
198 mono_thread_info_insert (MonoThreadInfo *info)
199 {
200         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
201
202         if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info)) {
203                 mono_hazard_pointer_clear_all (hp, -1);
204                 return FALSE;
205         } 
206
207         mono_hazard_pointer_clear_all (hp, -1);
208         return TRUE;
209 }
210
211 static gboolean
212 mono_thread_info_remove (MonoThreadInfo *info)
213 {
214         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
215         gboolean res;
216
217         THREADS_DEBUG ("removing info %p\n", info);
218         res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info);
219         mono_hazard_pointer_clear_all (hp, -1);
220         return res;
221 }
222
223 static void
224 free_thread_info (gpointer mem)
225 {
226         MonoThreadInfo *info = mem;
227
228         MONO_SEM_DESTROY (&info->resume_semaphore);
229         mono_threads_platform_free (info);
230
231         g_free (info);
232 }
233
234 int
235 mono_thread_info_register_small_id (void)
236 {
237         int small_id = mono_thread_small_id_alloc ();
238 #ifdef HAVE_KW_THREAD
239         tls_small_id = small_id;
240 #else
241         mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (small_id + 1));
242 #endif
243         return small_id;
244 }
245
246 static void*
247 register_thread (MonoThreadInfo *info, gpointer baseptr)
248 {
249         size_t stsize = 0;
250         guint8 *staddr = NULL;
251         int small_id = mono_thread_info_register_small_id ();
252         gboolean result;
253         mono_thread_info_set_tid (info, mono_native_thread_id_get ());
254         info->small_id = small_id;
255
256         MONO_SEM_INIT (&info->resume_semaphore, 0);
257
258         /*set TLS early so SMR works */
259         mono_native_tls_set_value (thread_info_key, info);
260
261         THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);
262
263         if (threads_callbacks.thread_register) {
264                 if (threads_callbacks.thread_register (info, baseptr) == NULL) {
265                         // g_warning ("thread registation failed\n");
266                         g_free (info);
267                         return NULL;
268                 }
269         }
270
271         mono_thread_info_get_stack_bounds (&staddr, &stsize);
272         g_assert (staddr);
273         g_assert (stsize);
274         info->stack_start_limit = staddr;
275         info->stack_end = staddr + stsize;
276
277         mono_threads_platform_register (info);
278
279         /*
280         Transition it before taking any locks or publishing itself to reduce the chance
281         of others witnessing a detached thread.
282         We can reasonably expect that until this thread gets published, no other thread will
283         try to manipulate it.
284         */
285         mono_threads_transition_attach (info);
286         mono_thread_info_suspend_lock ();
287         /*If this fail it means a given thread has been registered twice, which doesn't make sense. */
288         result = mono_thread_info_insert (info);
289         g_assert (result);
290         mono_thread_info_suspend_unlock ();
291         return info;
292 }
293
294 static void
295 unregister_thread (void *arg)
296 {
297         MonoThreadInfo *info = arg;
298         int small_id = info->small_id;
299         g_assert (info);
300
301         THREADS_DEBUG ("unregistering info %p\n", info);
302
303         mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
304
305         mono_threads_core_unregister (info);
306
307         /*
308          * TLS destruction order is not reliable so small_id might be cleaned up
309          * before us.
310          */
311 #ifndef HAVE_KW_THREAD
312         mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
313 #endif
314
315         /*
316         First perform the callback that requires no locks.
317         This callback has the potential of taking other locks, so we do it before.
318         After it completes, the thread remains functional.
319         */
320         if (threads_callbacks.thread_detach)
321                 threads_callbacks.thread_detach (info);
322
323         mono_thread_info_suspend_lock ();
324
325         /*
326         Now perform the callback that must be done under locks.
327         This will render the thread useless and non-suspendable, so it must
328         be done while holding the suspend lock to give no other thread chance
329         to suspend it.
330         */
331         if (threads_callbacks.thread_unregister)
332                 threads_callbacks.thread_unregister (info);
333         mono_threads_unregister_current_thread (info);
334         mono_threads_transition_detach (info);
335
336         mono_thread_info_suspend_unlock ();
337
338         /*now it's safe to free the thread info.*/
339         mono_thread_hazardous_free_or_queue (info, free_thread_info, TRUE, FALSE);
340         mono_thread_small_id_free (small_id);
341 }
342
343 static void
344 thread_exited_dtor (void *arg)
345 {
346 #if defined(__MACH__)
347         /*
348          * Since we use pthread dtors to clean up thread data, if a thread
349          * is attached to the runtime by another pthread dtor after our dtor
350          * has ran, it will never be detached, leading to various problems
351          * since the thread ids etc. will be reused while they are still in
352          * the threads hashtables etc.
353          * Dtors are called in a loop until all user tls entries are 0,
354          * but the loop has a maximum count (4), so if we set the tls
355          * variable every time, it will remain set when system tls dtors
356          * are ran. This allows mono_thread_info_is_exiting () to detect
357          * whenever the thread is exiting, even if it is executed from a
358          * system tls dtor (i.e. obj-c dealloc methods).
359          */
360         mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
361 #endif
362 }
363
364 /**
365  * Removes the current thread from the thread list.
366  * This must be called from the thread unregister callback and nowhere else.
367  * The current thread must be passed as TLS might have already been cleaned up.
368 */
369 static void
370 mono_threads_unregister_current_thread (MonoThreadInfo *info)
371 {
372         gboolean result;
373         g_assert (mono_thread_info_get_tid (info) == mono_native_thread_id_get ());
374         result = mono_thread_info_remove (info);
375         g_assert (result);
376 }
377
378 static inline MonoThreadInfo*
379 mono_thread_info_current_unchecked (void)
380 {
381         return (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
382 }
383
384
385 MonoThreadInfo*
386 mono_thread_info_current (void)
387 {
388         MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
389         if (info)
390                 return info;
391
392         info = mono_thread_info_lookup (mono_native_thread_id_get ()); /*info on HP1*/
393
394         /*
395         We might be called during thread cleanup, but we cannot be called after cleanup as happened.
396         The way to distinguish between before, during and after cleanup is the following:
397
398         -If the TLS key is set, cleanup has not begun;
399         -If the TLS key is clean, but the thread remains registered, cleanup is in progress;
400         -If the thread is nowhere to be found, cleanup has finished.
401
402         We cannot function after cleanup since there's no way to ensure what will happen.
403         */
404         g_assert (info);
405
406         /*We're looking up the current thread which will not be freed until we finish running, so no need to keep it on a HP */
407         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
408
409         return info;
410 }
411
412 int
413 mono_thread_info_get_small_id (void)
414 {
415 #ifdef HAVE_KW_THREAD
416         return tls_small_id;
417 #else
418         gpointer val = mono_native_tls_get_value (small_id_key);
419         if (!val)
420                 return -1;
421         return GPOINTER_TO_INT (val) - 1;
422 #endif
423 }
424
425 MonoLinkedListSet*
426 mono_thread_info_list_head (void)
427 {
428         return &thread_list;
429 }
430
431 /**
432  * mono_threads_attach_tools_thread
433  *
434  * Attach the current thread as a tool thread. DON'T USE THIS FUNCTION WITHOUT READING ALL DISCLAIMERS.
435  *
436  * A tools thread is a very special kind of thread that needs access to core runtime facilities but should
437  * not be counted as a regular thread for high order facilities such as executing managed code or accessing
438  * the managed heap.
439  *
440  * This is intended only to tools such as a profiler than needs to be able to use our lock-free support when
441  * doing things like resolving backtraces in their background processing thread.
442  */
443 void
444 mono_threads_attach_tools_thread (void)
445 {
446         int dummy = 0;
447         MonoThreadInfo *info;
448
449         /* Must only be called once */
450         g_assert (!mono_native_tls_get_value (thread_info_key));
451
452         info = mono_thread_info_attach (&dummy);
453         info->tools_thread = TRUE;
454 }
455
456 MonoThreadInfo*
457 mono_thread_info_attach (void *baseptr)
458 {
459         MonoThreadInfo *info;
460         if (!mono_threads_inited)
461         {
462                 /* This can happen from DllMain(DLL_THREAD_ATTACH) on Windows, if a
463                  * thread is created before an embedding API user initialized Mono. */
464                 THREADS_DEBUG ("mono_thread_info_attach called before mono_threads_init\n");
465                 return NULL;
466         }
467         info = mono_native_tls_get_value (thread_info_key);
468         if (!info) {
469                 info = g_malloc0 (thread_info_size);
470                 THREADS_DEBUG ("attaching %p\n", info);
471                 if (!register_thread (info, baseptr))
472                         return NULL;
473         } else if (threads_callbacks.thread_attach) {
474                 threads_callbacks.thread_attach (info);
475         }
476         return info;
477 }
478
479 void
480 mono_thread_info_detach (void)
481 {
482         MonoThreadInfo *info;
483         if (!mono_threads_inited)
484         {
485                 /* This can happen from DllMain(THREAD_DETACH) on Windows, if a thread
486                  * is created before an embedding API user initialized Mono. */
487                 THREADS_DEBUG ("mono_thread_info_detach called before mono_threads_init\n");
488                 return;
489         }
490         info = mono_native_tls_get_value (thread_info_key);
491         if (info) {
492                 THREADS_DEBUG ("detaching %p\n", info);
493                 unregister_thread (info);
494                 mono_native_tls_set_value (thread_info_key, NULL);
495         }
496 }
497
498 /*
499  * mono_thread_info_is_exiting:
500  *
501  *   Return whenever the current thread is exiting, i.e. it is running pthread
502  * dtors.
503  */
504 gboolean
505 mono_thread_info_is_exiting (void)
506 {
507 #if defined(__MACH__)
508         if (mono_native_tls_get_value (thread_exited_key) == GUINT_TO_POINTER (1))
509                 return TRUE;
510 #endif
511         return FALSE;
512 }
513
514 void
515 mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
516 {
517         gboolean res;
518         threads_callbacks = *callbacks;
519         thread_info_size = info_size;
520 #ifdef HOST_WIN32
521         res = mono_native_tls_alloc (&thread_info_key, NULL);
522         res = mono_native_tls_alloc (&thread_exited_key, NULL);
523 #else
524         res = mono_native_tls_alloc (&thread_info_key, unregister_thread);
525         res = mono_native_tls_alloc (&thread_exited_key, thread_exited_dtor);
526 #endif
527         g_assert (res);
528
529 #ifndef HAVE_KW_THREAD
530         res = mono_native_tls_alloc (&small_id_key, NULL);
531 #endif
532         g_assert (res);
533
534         unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL;
535
536         MONO_SEM_INIT (&global_suspend_semaphore, 1);
537         MONO_SEM_INIT (&suspend_semaphore, 0);
538
539         mono_lls_init (&thread_list, NULL);
540         mono_thread_smr_init ();
541         mono_threads_init_platform ();
542
543 #if defined(__MACH__)
544         mono_mach_init (thread_info_key);
545 #endif
546
547         mono_threads_inited = TRUE;
548
549         g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
550 }
551
552 void
553 mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks)
554 {
555         runtime_callbacks = *callbacks;
556 }
557
558 MonoThreadInfoCallbacks *
559 mono_threads_get_callbacks (void)
560 {
561         return &threads_callbacks;
562 }
563
564 MonoThreadInfoRuntimeCallbacks *
565 mono_threads_get_runtime_callbacks (void)
566 {
567         return &runtime_callbacks;
568 }
569
570 /*
571 The return value is only valid until a matching mono_thread_info_resume is called
572 */
573 static MonoThreadInfo*
574 mono_thread_info_suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel, const char **error_condition)
575 {
576         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();      
577         MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
578         if (!info) {
579                 *error_condition = "Thread not found";
580                 return NULL;
581         }
582
583         switch (mono_threads_transition_request_async_suspension (info)) {
584         case AsyncSuspendAlreadySuspended:
585                 mono_hazard_pointer_clear (hp, 1); //XXX this is questionable we got to clean the suspend/resume nonsense of critical sections
586                 return info;
587         case AsyncSuspendWait:
588                 mono_threads_add_to_pending_operation_set (info);
589                 break;
590         case AsyncSuspendInitSuspend:
591                 if (!mono_threads_core_begin_async_suspend (info, interrupt_kernel)) {
592                         mono_hazard_pointer_clear (hp, 1);
593                         *error_condition = "Could not suspend thread";
594                         return NULL;
595                 }
596         }
597
598         //Wait for the pending suspend to finish
599         mono_threads_wait_pending_operations ();
600
601         if (!mono_threads_core_check_suspend_result (info)) {
602
603                 mono_hazard_pointer_clear (hp, 1);
604                 *error_condition = "Post suspend failed";
605                 return NULL;
606         }
607         return info;
608 }
609
610 /*
611 Signal that the current thread wants to be suspended.
612 This function can be called without holding the suspend lock held.
613 To finish suspending, call mono_suspend_check.
614 */
615 void
616 mono_thread_info_begin_self_suspend (void)
617 {
618         MonoThreadInfo *info = mono_thread_info_current_unchecked ();
619         if (!info)
620                 return;
621
622         THREADS_SUSPEND_DEBUG ("BEGIN SELF SUSPEND OF %p\n", info);
623         mono_threads_transition_request_self_suspension (info);
624 }
625
626 void
627 mono_thread_info_end_self_suspend (void)
628 {
629         MonoThreadInfo *info;
630
631         info = mono_thread_info_current ();
632         if (!info)
633                 return;
634         THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", info);
635
636         g_assert (mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX], NULL));
637
638         /* commit the saved state and notify others if needed */
639         switch (mono_threads_transition_state_poll (info)) {
640         case SelfSuspendResumed:
641                 return;
642         case SelfSuspendWait:
643                 wait_for_resume (info);
644                 break;
645         case SelfSuspendNotifyAndWait:
646                 mono_threads_notify_initiator_of_suspend (info);
647                 wait_for_resume (info);
648                 mono_threads_notify_initiator_of_resume (info);
649                 break;
650         }
651 }
652
653 static gboolean
654 mono_thread_info_core_resume (MonoThreadInfo *info)
655 {
656         gboolean res = FALSE;
657         if (info->create_suspended) {
658                 MonoNativeThreadId tid = mono_thread_info_get_tid (info);
659                 /* Have to special case this, as the normal suspend/resume pair are racy, they don't work if he resume is received before the suspend */
660                 info->create_suspended = FALSE;
661                 mono_threads_core_resume_created (info, tid);
662                 return TRUE;
663         }
664
665         switch (mono_threads_transition_request_resume (info)) {
666         case ResumeError:
667                 res = FALSE;
668                 break;
669         case ResumeOk:
670                 res = TRUE;
671                 break;
672         case ResumeInitSelfResume:
673                 resume_self_suspended (info);
674                 res = TRUE;
675                 break;
676         case ResumeInitAsyncResume:
677                 resume_async_suspended (info);
678                 res = TRUE;
679                 break;
680         }
681
682         return res;
683 }
684
685 gboolean
686 mono_thread_info_resume (MonoNativeThreadId tid)
687 {
688         gboolean result; /* don't initialize it so the compiler can catch unitilized paths. */
689         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
690         MonoThreadInfo *info;
691
692         THREADS_SUSPEND_DEBUG ("RESUMING tid %p\n", (void*)tid);
693
694         mono_thread_info_suspend_lock ();
695
696         info = mono_thread_info_lookup (tid); /*info on HP1*/
697         if (!info) {
698                 result = FALSE;
699                 goto cleanup;
700         }
701
702         result = mono_thread_info_core_resume (info);
703
704         //Wait for the pending resume to finish
705         mono_threads_wait_pending_operations ();
706
707 cleanup:
708         mono_thread_info_suspend_unlock ();
709         mono_hazard_pointer_clear (hp, 1);
710         return result;
711 }
712
713 gboolean
714 mono_thread_info_begin_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
715 {
716         switch (mono_threads_transition_request_async_suspension (info)) {
717         case AsyncSuspendAlreadySuspended:
718                 return TRUE;
719         case AsyncSuspendWait:
720                 mono_threads_add_to_pending_operation_set (info);
721                 return TRUE;
722         case AsyncSuspendInitSuspend:
723                 return mono_threads_core_begin_async_suspend (info, interrupt_kernel);
724         default:
725                 g_assert_not_reached ();
726         }
727 }
728
729 gboolean
730 mono_thread_info_begin_resume (MonoThreadInfo *info)
731 {
732         return mono_thread_info_core_resume (info);
733 }
734
735 /*
736 FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
737 WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
738 */
739 static gboolean
740 is_thread_in_critical_region (MonoThreadInfo *info)
741 {
742         MonoMethod *method;
743         MonoJitInfo *ji;
744         gpointer stack_start;
745         MonoThreadUnwindState *state;
746
747         /* Are we inside a system critical region? */
748         if (info->inside_critical_region)
749                 return TRUE;
750
751         if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
752                 return TRUE;
753         }
754
755         /* Are we inside a GC critical region? */
756         if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
757                 return TRUE;
758         }
759
760         /* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
761         state = mono_thread_info_get_suspend_state (info);
762         if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
763                 return FALSE;
764
765         stack_start = MONO_CONTEXT_GET_SP (&state->ctx);
766         /* altstack signal handler, sgen can't handle them, so we treat them as critical */
767         if (stack_start < info->stack_start_limit || stack_start >= info->stack_end)
768                 return TRUE;
769
770         ji = mono_jit_info_table_find (
771                 state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
772                 MONO_CONTEXT_GET_IP (&state->ctx));
773
774         if (!ji)
775                 return FALSE;
776
777         method = mono_jit_info_get_method (ji);
778
779         return threads_callbacks.mono_method_is_critical (method);
780 }
781
782 gboolean
783 mono_thread_info_in_critical_location (MonoThreadInfo *info)
784 {
785         return is_thread_in_critical_region (info);
786 }
787
788 static MonoThreadInfo*
789 suspend_sync_nolock (MonoNativeThreadId id, gboolean interrupt_kernel)
790 {
791         MonoThreadInfo *info = NULL;
792         int sleep_duration = 0;
793         for (;;) {
794                 const char *suspend_error = "Unknown error";
795                 if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel, &suspend_error))) {
796                         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
797                         return NULL;
798                 }
799
800                 /*WARNING: We now are in interrupt context until we resume the thread. */
801                 if (!is_thread_in_critical_region (info))
802                         break;
803
804                 if (!mono_thread_info_core_resume (info)) {
805                         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
806                         return NULL;
807                 }
808                 THREADS_SUSPEND_DEBUG ("RESTARTED thread tid %p\n", (void*)id);
809
810                 /* Wait for the pending resume to finish */
811                 mono_threads_wait_pending_operations ();
812
813                 if (!sleep_duration) {
814 #ifdef HOST_WIN32
815                         SwitchToThread ();
816 #else
817                         sched_yield ();
818 #endif
819                 }
820                 else {
821                         g_usleep (sleep_duration);
822                 }
823                 sleep_duration += 10;
824         }
825         return info;
826 }
827
828 void
829 mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data)
830 {
831         int result;
832         MonoThreadInfo *info = NULL;
833         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
834
835         THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id);
836         /*FIXME: unify this with self-suspend*/
837         g_assert (id != mono_native_thread_id_get ());
838
839         mono_thread_info_suspend_lock ();
840         mono_threads_begin_global_suspend ();
841
842         info = suspend_sync_nolock (id, interrupt_kernel);
843         if (!info)
844                 goto done;
845
846         switch (result = callback (info, user_data)) {
847         case MonoResumeThread:
848                 mono_hazard_pointer_set (hp, 1, info);
849                 mono_thread_info_core_resume (info);
850                 mono_threads_wait_pending_operations ();
851                 break;
852         case KeepSuspended:
853                 break;
854         default:
855                 g_error ("Invalid suspend_and_run callback return value %d", result);
856         }
857
858 done:
859         mono_hazard_pointer_clear (hp, 1);
860         mono_threads_end_global_suspend ();
861         mono_thread_info_suspend_unlock ();
862 }
863
864 /*
865 WARNING:
866 If we are trying to suspend a target that is on a critical region
867 and running a syscall we risk looping forever if @interrupt_kernel is FALSE.
868 So, be VERY carefull in calling this with @interrupt_kernel == FALSE.
869
870 Info is not put on a hazard pointer as a suspended thread cannot exit and be freed.
871
872 This function MUST be matched with mono_thread_info_finish_suspend or mono_thread_info_finish_suspend_and_resume
873 */
874 MonoThreadInfo*
875 mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel)
876 {
877         MonoThreadInfo *info = NULL;
878
879         THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id);
880         /*FIXME: unify this with self-suspend*/
881         g_assert (id != mono_native_thread_id_get ());
882
883         mono_thread_info_suspend_lock ();
884         mono_threads_begin_global_suspend ();
885
886         info = suspend_sync_nolock (id, interrupt_kernel);
887
888         /* XXX this clears HP 1, so we restated it again */
889         // mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, TRUE);
890         mono_threads_end_global_suspend ();
891         mono_thread_info_suspend_unlock ();
892
893         return info;
894 }
895
896 /**
897 Inject an assynchronous call into the target thread. The target thread must be suspended and
898 only a single async call can be setup for a given suspend cycle.
899 This async call must cause stack unwinding as the current implementation doesn't save enough state
900 to resume execution of the top-of-stack function. It's an acceptable limitation since this is
901 currently used only to deliver exceptions.
902 */
903 void
904 mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
905 {
906         /* An async call can only be setup on an async suspended thread */
907         g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED);
908         /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
909         g_assert (!info->async_target);
910         info->async_target = target_func;
911         /* This is not GC tracked */
912         info->user_data = user_data;
913 }
914
915 /*
916 The suspend lock is held during any suspend in progress.
917 A GC that has safepoints must take this lock as part of its
918 STW to make sure no unsafe pending suspend is in progress.   
919 */
920 void
921 mono_thread_info_suspend_lock (void)
922 {
923         MONO_SEM_WAIT_UNITERRUPTIBLE (&global_suspend_semaphore);
924 }
925
926 void
927 mono_thread_info_suspend_unlock (void)
928 {
929         MONO_SEM_POST (&global_suspend_semaphore);
930 }
931
932 void
933 mono_thread_info_disable_new_interrupt (gboolean disable)
934 {
935         disable_new_interrupt = disable;
936 }
937
938 /*
939  * This is a very specific function whose only purpose is to
940  * break a given thread from socket syscalls.
941  *
942  * This only exists because linux won't fail a call to connect
943  * if the underlying is closed.
944  *
945  * TODO We should cleanup and unify this with the other syscall abort
946  * facility.
947  */
948 void
949 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
950 {
951         MonoThreadHazardPointers *hp;
952         MonoThreadInfo *info;
953         
954         if (tid == mono_native_thread_id_get () || !mono_threads_core_needs_abort_syscall ())
955                 return;
956
957         hp = mono_hazard_pointer_get ();        
958         info = mono_thread_info_lookup (tid); /*info on HP1*/
959         if (!info)
960                 return;
961
962         if (mono_thread_info_run_state (info) > STATE_RUNNING) {
963                 mono_hazard_pointer_clear (hp, 1);
964                 return;
965         }
966
967         mono_thread_info_suspend_lock ();
968
969         mono_threads_core_abort_syscall (info);
970
971         mono_hazard_pointer_clear (hp, 1);
972         mono_thread_info_suspend_unlock ();
973 }
974
975 gboolean
976 mono_thread_info_unified_management_enabled (void)
977 {
978         return unified_suspend_enabled;
979 }
980
981 /*
982 Disabled by default for now.
983 To enable this we need mini to implement the callbacks by MonoThreadInfoRuntimeCallbacks
984 which means mono-context and setup_async_callback, and we need a mono-threads backend.
985 */
986 gboolean
987 mono_thread_info_new_interrupt_enabled (void)
988 {
989         /*We need STW gc events to work correctly*/
990 #if defined (HAVE_BOEHM_GC) && !defined (USE_INCLUDED_LIBGC)
991         return FALSE;
992 #endif
993 #if defined(HOST_WIN32)
994         return !disable_new_interrupt;
995 #endif
996 #if defined (__i386__) || defined(__x86_64__)
997         return !disable_new_interrupt;
998 #endif
999 #if defined(__arm__) || defined(__aarch64__)
1000         return !disable_new_interrupt;
1001 #endif
1002         return FALSE;
1003 }
1004
1005 /*
1006  * mono_thread_info_set_is_async_context:
1007  *
1008  *   Set whenever the current thread is in an async context. Some runtime functions might behave
1009  * differently while in an async context in order to be async safe.
1010  */
1011 void
1012 mono_thread_info_set_is_async_context (gboolean async_context)
1013 {
1014         MonoThreadInfo *info = mono_thread_info_current ();
1015
1016         if (info)
1017                 info->is_async_context = async_context;
1018 }
1019
1020 gboolean
1021 mono_thread_info_is_async_context (void)
1022 {
1023         MonoThreadInfo *info = mono_thread_info_current ();
1024
1025         if (info)
1026                 return info->is_async_context;
1027         else
1028                 return FALSE;
1029 }
1030
1031 /*
1032  * mono_threads_create_thread:
1033  *
1034  *   Create a new thread executing START with argument ARG. Store its id into OUT_TID.
1035  * Returns: a windows or io-layer handle for the thread.
1036  */
1037 HANDLE
1038 mono_threads_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
1039 {
1040         return mono_threads_core_create_thread (start, arg, stack_size, creation_flags, out_tid);
1041 }
1042
1043 /*
1044  * mono_thread_info_get_stack_bounds:
1045  *
1046  *   Return the address and size of the current threads stack. Return NULL as the 
1047  * stack address if the stack address cannot be determined.
1048  */
1049 void
1050 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize)
1051 {
1052         guint8 *current = (guint8 *)&stsize;
1053         mono_threads_core_get_stack_bounds (staddr, stsize);
1054         if (!*staddr)
1055                 return;
1056
1057         /* Sanity check the result */
1058         g_assert ((current > *staddr) && (current < *staddr + *stsize));
1059
1060         /* When running under emacs, sometimes staddr is not aligned to a page size */
1061         *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
1062 }
1063
1064 gboolean
1065 mono_thread_info_yield (void)
1066 {
1067         return mono_threads_core_yield ();
1068 }
1069
1070 gpointer
1071 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key)
1072 {
1073         return ((MonoThreadInfo*)info)->tls [key];
1074 }
1075
1076 /*
1077  * mono_threads_info_tls_set:
1078  *
1079  *   Set the TLS key to VALUE in the info structure. This can be used to obtain
1080  * values of TLS variables for threads other than the current thread.
1081  * This should only be used for infrequently changing TLS variables, and it should
1082  * be paired with setting the real TLS variable since this provides no GC tracking.
1083  */
1084 void
1085 mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value)
1086 {
1087         ((MonoThreadInfo*)info)->tls [key] = value;
1088 }
1089
1090 /*
1091  * mono_thread_info_exit:
1092  *
1093  *   Exit the current thread.
1094  * This function doesn't return.
1095  */
1096 void
1097 mono_thread_info_exit (void)
1098 {
1099         mono_threads_core_exit (0);
1100 }
1101
1102 /*
1103  * mono_thread_info_open_handle:
1104  *
1105  *   Return a io-layer/win32 handle for the current thread.
1106  * The handle need to be closed by calling CloseHandle () when it is no
1107  * longer needed.
1108  */
1109 HANDLE
1110 mono_thread_info_open_handle (void)
1111 {
1112         return mono_threads_core_open_handle ();
1113 }
1114
1115 /*
1116  * mono_threads_open_thread_handle:
1117  *
1118  *   Return a io-layer/win32 handle for the thread identified by HANDLE/TID.
1119  * The handle need to be closed by calling CloseHandle () when it is no
1120  * longer needed.
1121  */
1122 HANDLE
1123 mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
1124 {
1125         return mono_threads_core_open_thread_handle (handle, tid);
1126 }
1127
1128 void
1129 mono_thread_info_set_name (MonoNativeThreadId tid, const char *name)
1130 {
1131         mono_threads_core_set_name (tid, name);
1132 }
1133
1134 /*
1135  * mono_thread_info_prepare_interrupt:
1136  *
1137  *   See wapi_prepare_interrupt ().
1138  */
1139 gpointer
1140 mono_thread_info_prepare_interrupt (HANDLE thread_handle)
1141 {
1142         return mono_threads_core_prepare_interrupt (thread_handle);
1143 }
1144
1145 void
1146 mono_thread_info_finish_interrupt (gpointer wait_handle)
1147 {
1148         mono_threads_core_finish_interrupt (wait_handle);
1149 }
1150
1151 void
1152 mono_thread_info_interrupt (HANDLE thread_handle)
1153 {
1154         gpointer wait_handle;
1155
1156         wait_handle = mono_thread_info_prepare_interrupt (thread_handle);
1157         mono_thread_info_finish_interrupt (wait_handle);
1158 }
1159         
1160 void
1161 mono_thread_info_self_interrupt (void)
1162 {
1163         mono_threads_core_self_interrupt ();
1164 }
1165
1166 void
1167 mono_thread_info_clear_interruption (void)
1168 {
1169         mono_threads_core_clear_interruption ();
1170 }
1171
1172 /* info must be self or be held in a hazard pointer. */
1173 gboolean
1174 mono_threads_add_async_job (MonoThreadInfo *info, MonoAsyncJob job)
1175 {
1176         MonoAsyncJob old_job;
1177         do {
1178                 old_job = info->service_requests;
1179                 if (old_job & job)
1180                         return FALSE;
1181         } while (InterlockedCompareExchange (&info->service_requests, old_job | job, old_job) != old_job);
1182         return TRUE;
1183 }
1184
1185 MonoAsyncJob
1186 mono_threads_consume_async_jobs (void)
1187 {
1188         MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
1189
1190         if (!info)
1191                 return 0;
1192
1193         return InterlockedExchange (&info->service_requests, 0);
1194 }