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