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