Merge pull request #3550 from alexrp/revert-tp-monitor
[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  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
10  */
11
12 #include <config.h>
13
14 /* enable pthread extensions */
15 #ifdef TARGET_MACH
16 #define _DARWIN_C_SOURCE
17 #endif
18
19 #include <mono/utils/mono-compiler.h>
20 #include <mono/utils/mono-os-semaphore.h>
21 #include <mono/utils/mono-threads.h>
22 #include <mono/utils/mono-tls.h>
23 #include <mono/utils/hazard-pointer.h>
24 #include <mono/utils/mono-memory-model.h>
25 #include <mono/utils/mono-mmap.h>
26 #include <mono/utils/atomic.h>
27 #include <mono/utils/mono-time.h>
28 #include <mono/utils/mono-lazy-init.h>
29 #include <mono/utils/mono-coop-mutex.h>
30 #include <mono/utils/mono-coop-semaphore.h>
31 #include <mono/utils/mono-threads-coop.h>
32
33 #include <errno.h>
34
35 #if defined(__MACH__)
36 #include <mono/utils/mach-support.h>
37 #endif
38
39 /*
40 Mutex that makes sure only a single thread can be suspending others.
41 Suspend is a very racy operation since it requires restarting until
42 the target thread is not on an unsafe region.
43
44 We could implement this using critical regions, but would be much much
45 harder for an operation that is hardly performance critical.
46
47 The GC has to acquire this lock before starting a STW to make sure
48 a runtime suspend won't make it wronly see a thread in a safepoint
49 when it is in fact not.
50
51 This has to be a naked locking primitive, and not a coop aware one, as
52 it needs to be usable when destroying thread_info_key, the TLS key for
53 the current MonoThreadInfo. In this case, mono_thread_info_current_unchecked,
54 (which is used inside MONO_ENTER_GC_SAFE), would return NULL, leading
55 to an assertion error. We then simply switch state manually in
56 mono_thread_info_suspend_lock_with_info.
57 */
58 static MonoSemType global_suspend_semaphore;
59
60 static size_t thread_info_size;
61 static MonoThreadInfoCallbacks threads_callbacks;
62 static MonoThreadInfoRuntimeCallbacks runtime_callbacks;
63 static MonoNativeTlsKey thread_info_key, thread_exited_key;
64 #ifdef HAVE_KW_THREAD
65 static __thread guint32 tls_small_id MONO_TLS_FAST;
66 #else
67 static MonoNativeTlsKey small_id_key;
68 #endif
69 static MonoLinkedListSet thread_list;
70 static gboolean mono_threads_inited = FALSE;
71
72 static MonoSemType suspend_semaphore;
73 static size_t pending_suspends;
74 static gboolean unified_suspend_enabled;
75
76 #define mono_thread_info_run_state(info) (((MonoThreadInfo*)info)->thread_state & THREAD_STATE_MASK)
77
78 /*warn at 50 ms*/
79 #define SLEEP_DURATION_BEFORE_WARNING (50)
80 /*never aborts */
81 #define SLEEP_DURATION_BEFORE_ABORT MONO_INFINITE_WAIT
82
83 static guint32 sleepWarnDuration = SLEEP_DURATION_BEFORE_WARNING,
84             sleepAbortDuration = SLEEP_DURATION_BEFORE_ABORT;
85
86 static int suspend_posts, resume_posts, abort_posts, waits_done, pending_ops;
87
88 void
89 mono_threads_notify_initiator_of_abort (MonoThreadInfo* info)
90 {
91         THREADS_SUSPEND_DEBUG ("[INITIATOR-NOTIFY-ABORT] %p\n", mono_thread_info_get_tid (info));
92         InterlockedIncrement (&abort_posts);
93         mono_os_sem_post (&suspend_semaphore);
94 }
95
96 void
97 mono_threads_notify_initiator_of_suspend (MonoThreadInfo* info)
98 {
99         THREADS_SUSPEND_DEBUG ("[INITIATOR-NOTIFY-SUSPEND] %p\n", mono_thread_info_get_tid (info));
100         InterlockedIncrement (&suspend_posts);
101         mono_os_sem_post (&suspend_semaphore);
102 }
103
104 void
105 mono_threads_notify_initiator_of_resume (MonoThreadInfo* info)
106 {
107         THREADS_SUSPEND_DEBUG ("[INITIATOR-NOTIFY-RESUME] %p\n", mono_thread_info_get_tid (info));
108         InterlockedIncrement (&resume_posts);
109         mono_os_sem_post (&suspend_semaphore);
110 }
111
112 static gboolean
113 begin_async_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
114 {
115         if (mono_threads_is_coop_enabled ()) {
116                 /* There's nothing else to do after we async request the thread to suspend */
117                 mono_threads_add_to_pending_operation_set (info);
118                 return TRUE;
119         }
120
121         return mono_threads_suspend_begin_async_suspend (info, interrupt_kernel);
122 }
123
124 static gboolean
125 check_async_suspend (MonoThreadInfo *info)
126 {
127         if (mono_threads_is_coop_enabled ()) {
128                 /* Async suspend can't async fail on coop */
129                 return TRUE;
130         }
131
132         return mono_threads_suspend_check_suspend_result (info);
133 }
134
135 static void
136 resume_async_suspended (MonoThreadInfo *info)
137 {
138         if (mono_threads_is_coop_enabled ())
139                 g_assert_not_reached ();
140
141         g_assert (mono_threads_suspend_begin_async_resume (info));
142 }
143
144 static void
145 resume_self_suspended (MonoThreadInfo* info)
146 {
147         THREADS_SUSPEND_DEBUG ("**BEGIN self-resume %p\n", mono_thread_info_get_tid (info));
148         mono_os_sem_post (&info->resume_semaphore);
149 }
150
151 void
152 mono_thread_info_wait_for_resume (MonoThreadInfo* info)
153 {
154         int res;
155         THREADS_SUSPEND_DEBUG ("**WAIT self-resume %p\n", mono_thread_info_get_tid (info));
156         res = mono_os_sem_wait (&info->resume_semaphore, MONO_SEM_FLAGS_NONE);
157         g_assert (res != -1);
158 }
159
160 static void
161 resume_blocking_suspended (MonoThreadInfo* info)
162 {
163         THREADS_SUSPEND_DEBUG ("**BEGIN blocking-resume %p\n", mono_thread_info_get_tid (info));
164         mono_os_sem_post (&info->resume_semaphore);
165 }
166
167 void
168 mono_threads_add_to_pending_operation_set (MonoThreadInfo* info)
169 {
170         THREADS_SUSPEND_DEBUG ("added %p to pending suspend\n", mono_thread_info_get_tid (info));
171         ++pending_suspends;
172         InterlockedIncrement (&pending_ops);
173 }
174
175 void
176 mono_threads_begin_global_suspend (void)
177 {
178         size_t ps = pending_suspends;
179         if (G_UNLIKELY (ps != 0))
180                 g_error ("pending_suspends = %d, but must be 0", ps);
181         THREADS_SUSPEND_DEBUG ("------ BEGIN GLOBAL OP sp %d rp %d ap %d wd %d po %d (sp + rp + ap == wd) (wd == po)\n", suspend_posts, resume_posts,
182                 abort_posts, waits_done, pending_ops);
183         g_assert ((suspend_posts + resume_posts + abort_posts) == waits_done);
184         mono_threads_coop_begin_global_suspend ();
185 }
186
187 void
188 mono_threads_end_global_suspend (void) 
189 {
190         size_t ps = pending_suspends;
191         if (G_UNLIKELY (ps != 0))
192                 g_error ("pending_suspends = %d, but must be 0", ps);
193         THREADS_SUSPEND_DEBUG ("------ END GLOBAL OP sp %d rp %d ap %d wd %d po %d\n", suspend_posts, resume_posts,
194                 abort_posts, waits_done, pending_ops);
195         g_assert ((suspend_posts + resume_posts + abort_posts) == waits_done);
196         mono_threads_coop_end_global_suspend ();
197 }
198
199 static void
200 dump_threads (void)
201 {
202         MonoThreadInfo *cur = mono_thread_info_current ();
203
204         MOSTLY_ASYNC_SAFE_PRINTF ("STATE CUE CARD: (? means a positive number, usually 1 or 2, * means any number)\n");
205         MOSTLY_ASYNC_SAFE_PRINTF ("\t0x0\t- starting (GOOD, unless the thread is running managed code)\n");
206         MOSTLY_ASYNC_SAFE_PRINTF ("\t0x1\t- running (BAD, unless it's the gc thread)\n");
207         MOSTLY_ASYNC_SAFE_PRINTF ("\t0x2\t- detached (GOOD, unless the thread is running managed code)\n");
208         MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?03\t- async suspended (GOOD)\n");
209         MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?04\t- self suspended (GOOD)\n");
210         MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?05\t- async suspend requested (BAD)\n");
211         MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?06\t- self suspend requested (BAD)\n");
212         MOSTLY_ASYNC_SAFE_PRINTF ("\t0x*07\t- blocking (GOOD)\n");
213         MOSTLY_ASYNC_SAFE_PRINTF ("\t0x?08\t- blocking with pending suspend (GOOD)\n");
214
215         FOREACH_THREAD_SAFE (info) {
216 #ifdef TARGET_MACH
217                 char thread_name [256] = { 0 };
218                 pthread_getname_np (mono_thread_info_get_tid (info), thread_name, 255);
219
220                 MOSTLY_ASYNC_SAFE_PRINTF ("--thread %p id %p [%p] (%s) state %x  %s\n", info, (void *) mono_thread_info_get_tid (info), (void*)(size_t)info->native_handle, thread_name, info->thread_state, info == cur ? "GC INITIATOR" : "" );
221 #else
222                 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" : "" );
223 #endif
224         } FOREACH_THREAD_SAFE_END
225 }
226
227 gboolean
228 mono_threads_wait_pending_operations (void)
229 {
230         int i;
231         int c = pending_suspends;
232
233         /* Wait threads to park */
234         THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-COUNT] %d\n", c);
235         if (pending_suspends) {
236                 MonoStopwatch suspension_time;
237                 mono_stopwatch_start (&suspension_time);
238                 for (i = 0; i < pending_suspends; ++i) {
239                         THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-WAITING]\n");
240                         InterlockedIncrement (&waits_done);
241                         if (mono_os_sem_timedwait (&suspend_semaphore, sleepAbortDuration, MONO_SEM_FLAGS_NONE) == MONO_SEM_TIMEDWAIT_RET_SUCCESS)
242                                 continue;
243                         mono_stopwatch_stop (&suspension_time);
244
245                         dump_threads ();
246
247                         MOSTLY_ASYNC_SAFE_PRINTF ("WAITING for %d threads, got %d suspended\n", (int)pending_suspends, i);
248                         g_error ("suspend_thread suspend took %d ms, which is more than the allowed %d ms", (int)mono_stopwatch_elapsed_ms (&suspension_time), sleepAbortDuration);
249                 }
250                 mono_stopwatch_stop (&suspension_time);
251                 THREADS_SUSPEND_DEBUG ("Suspending %d threads took %d ms.\n", (int)pending_suspends, (int)mono_stopwatch_elapsed_ms (&suspension_time));
252
253         }
254
255         pending_suspends = 0;
256
257         return c > 0;
258 }
259
260
261 //Thread initialization code
262
263 static void mono_threads_unregister_current_thread (MonoThreadInfo *info);
264
265 static inline void
266 mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
267 {
268         if (retain != 0)
269                 mono_hazard_pointer_clear (hp, 0);
270         if (retain != 1)
271                 mono_hazard_pointer_clear (hp, 1);
272         if (retain != 2)
273                 mono_hazard_pointer_clear (hp, 2);
274 }
275
276 /*
277 If return non null Hazard Pointer 1 holds the return value.
278 */
279 MonoThreadInfo*
280 mono_thread_info_lookup (MonoNativeThreadId id)
281 {
282         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
283
284         if (!mono_lls_find (&thread_list, hp, (uintptr_t)id)) {
285                 mono_hazard_pointer_clear_all (hp, -1);
286                 return NULL;
287         } 
288
289         mono_hazard_pointer_clear_all (hp, 1);
290         return (MonoThreadInfo *) mono_hazard_pointer_get_val (hp, 1);
291 }
292
293 static gboolean
294 mono_thread_info_insert (MonoThreadInfo *info)
295 {
296         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
297
298         if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info)) {
299                 mono_hazard_pointer_clear_all (hp, -1);
300                 return FALSE;
301         } 
302
303         mono_hazard_pointer_clear_all (hp, -1);
304         return TRUE;
305 }
306
307 static gboolean
308 mono_thread_info_remove (MonoThreadInfo *info)
309 {
310         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
311         gboolean res;
312
313         THREADS_DEBUG ("removing info %p\n", info);
314         res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info);
315         mono_hazard_pointer_clear_all (hp, -1);
316         return res;
317 }
318
319 static void
320 free_thread_info (gpointer mem)
321 {
322         MonoThreadInfo *info = (MonoThreadInfo *) mem;
323
324         mono_os_sem_destroy (&info->resume_semaphore);
325         mono_threads_suspend_free (info);
326
327         g_free (info);
328 }
329
330 int
331 mono_thread_info_register_small_id (void)
332 {
333         int small_id = mono_thread_small_id_alloc ();
334 #ifdef HAVE_KW_THREAD
335         tls_small_id = small_id;
336 #else
337         mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (small_id + 1));
338 #endif
339         return small_id;
340 }
341
342 static void*
343 register_thread (MonoThreadInfo *info, gpointer baseptr)
344 {
345         size_t stsize = 0;
346         guint8 *staddr = NULL;
347         int small_id = mono_thread_info_register_small_id ();
348         gboolean result;
349         mono_thread_info_set_tid (info, mono_native_thread_id_get ());
350         info->small_id = small_id;
351
352         mono_os_sem_init (&info->resume_semaphore, 0);
353
354         /*set TLS early so SMR works */
355         mono_native_tls_set_value (thread_info_key, info);
356
357         THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);
358
359         if (threads_callbacks.thread_register) {
360                 if (threads_callbacks.thread_register (info, baseptr) == NULL) {
361                         // g_warning ("thread registation failed\n");
362                         mono_native_tls_set_value (thread_info_key, NULL);
363                         g_free (info);
364                         return NULL;
365                 }
366         }
367
368         mono_thread_info_get_stack_bounds (&staddr, &stsize);
369         g_assert (staddr);
370         g_assert (stsize);
371         info->stack_start_limit = staddr;
372         info->stack_end = staddr + stsize;
373
374         info->stackdata = g_byte_array_new ();
375
376         mono_threads_platform_register (info);
377         mono_threads_suspend_register (info);
378
379         /*
380         Transition it before taking any locks or publishing itself to reduce the chance
381         of others witnessing a detached thread.
382         We can reasonably expect that until this thread gets published, no other thread will
383         try to manipulate it.
384         */
385         mono_threads_transition_attach (info);
386         mono_thread_info_suspend_lock ();
387         /*If this fail it means a given thread has been registered twice, which doesn't make sense. */
388         result = mono_thread_info_insert (info);
389         g_assert (result);
390         mono_thread_info_suspend_unlock ();
391         return info;
392 }
393
394 static void
395 mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info);
396
397 static void
398 unregister_thread (void *arg)
399 {
400         gpointer gc_unsafe_stackdata;
401         MonoThreadInfo *info;
402         int small_id;
403
404         info = (MonoThreadInfo *) arg;
405         g_assert (info);
406         g_assert (mono_thread_info_is_current (info));
407         g_assert (mono_thread_info_is_live (info));
408
409         small_id = info->small_id;
410
411         /* We only enter the GC unsafe region, as when exiting this function, the thread
412          * will be detached, and the current MonoThreadInfo* will be destroyed. */
413         mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, &gc_unsafe_stackdata);
414
415         THREADS_DEBUG ("unregistering info %p\n", info);
416
417         mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
418
419         mono_threads_platform_unregister (info);
420
421         /*
422          * TLS destruction order is not reliable so small_id might be cleaned up
423          * before us.
424          */
425 #ifndef HAVE_KW_THREAD
426         mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
427 #endif
428
429         /*
430         First perform the callback that requires no locks.
431         This callback has the potential of taking other locks, so we do it before.
432         After it completes, the thread remains functional.
433         */
434         if (threads_callbacks.thread_detach)
435                 threads_callbacks.thread_detach (info);
436
437         mono_thread_info_suspend_lock_with_info (info);
438
439         /*
440         Now perform the callback that must be done under locks.
441         This will render the thread useless and non-suspendable, so it must
442         be done while holding the suspend lock to give no other thread chance
443         to suspend it.
444         */
445         if (threads_callbacks.thread_unregister)
446                 threads_callbacks.thread_unregister (info);
447         mono_threads_unregister_current_thread (info);
448         mono_threads_transition_detach (info);
449
450         mono_thread_info_suspend_unlock ();
451
452         g_byte_array_free (info->stackdata, /*free_segment=*/TRUE);
453
454         /*now it's safe to free the thread info.*/
455         mono_thread_hazardous_try_free (info, free_thread_info);
456         /* Pump the HP queue */
457         mono_thread_hazardous_try_free_some ();
458
459         mono_thread_small_id_free (small_id);
460 }
461
462 static void
463 thread_exited_dtor (void *arg)
464 {
465 #if defined(__MACH__)
466         /*
467          * Since we use pthread dtors to clean up thread data, if a thread
468          * is attached to the runtime by another pthread dtor after our dtor
469          * has ran, it will never be detached, leading to various problems
470          * since the thread ids etc. will be reused while they are still in
471          * the threads hashtables etc.
472          * Dtors are called in a loop until all user tls entries are 0,
473          * but the loop has a maximum count (4), so if we set the tls
474          * variable every time, it will remain set when system tls dtors
475          * are ran. This allows mono_thread_info_is_exiting () to detect
476          * whenever the thread is exiting, even if it is executed from a
477          * system tls dtor (i.e. obj-c dealloc methods).
478          */
479         mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
480 #endif
481 }
482
483 /**
484  * Removes the current thread from the thread list.
485  * This must be called from the thread unregister callback and nowhere else.
486  * The current thread must be passed as TLS might have already been cleaned up.
487 */
488 static void
489 mono_threads_unregister_current_thread (MonoThreadInfo *info)
490 {
491         gboolean result;
492         g_assert (mono_thread_info_get_tid (info) == mono_native_thread_id_get ());
493         result = mono_thread_info_remove (info);
494         g_assert (result);
495 }
496
497 MonoThreadInfo*
498 mono_thread_info_current_unchecked (void)
499 {
500         return mono_threads_inited ? (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key) : NULL;
501 }
502
503
504 MonoThreadInfo*
505 mono_thread_info_current (void)
506 {
507         MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
508         if (info)
509                 return info;
510
511         info = mono_thread_info_lookup (mono_native_thread_id_get ()); /*info on HP1*/
512
513         /*
514         We might be called during thread cleanup, but we cannot be called after cleanup as happened.
515         The way to distinguish between before, during and after cleanup is the following:
516
517         -If the TLS key is set, cleanup has not begun;
518         -If the TLS key is clean, but the thread remains registered, cleanup is in progress;
519         -If the thread is nowhere to be found, cleanup has finished.
520
521         We cannot function after cleanup since there's no way to ensure what will happen.
522         */
523         g_assert (info);
524
525         /*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 */
526         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
527
528         return info;
529 }
530
531 int
532 mono_thread_info_get_small_id (void)
533 {
534 #ifdef HAVE_KW_THREAD
535         return tls_small_id;
536 #else
537         gpointer val = mono_native_tls_get_value (small_id_key);
538         if (!val)
539                 return -1;
540         return GPOINTER_TO_INT (val) - 1;
541 #endif
542 }
543
544 MonoLinkedListSet*
545 mono_thread_info_list_head (void)
546 {
547         return &thread_list;
548 }
549
550 /**
551  * mono_threads_attach_tools_thread
552  *
553  * Attach the current thread as a tool thread. DON'T USE THIS FUNCTION WITHOUT READING ALL DISCLAIMERS.
554  *
555  * A tools thread is a very special kind of thread that needs access to core runtime facilities but should
556  * not be counted as a regular thread for high order facilities such as executing managed code or accessing
557  * the managed heap.
558  *
559  * This is intended only to tools such as a profiler than needs to be able to use our lock-free support when
560  * doing things like resolving backtraces in their background processing thread.
561  */
562 void
563 mono_threads_attach_tools_thread (void)
564 {
565         int dummy = 0;
566         MonoThreadInfo *info;
567
568         /* Must only be called once */
569         g_assert (!mono_native_tls_get_value (thread_info_key));
570         
571         while (!mono_threads_inited) { 
572                 mono_thread_info_usleep (10);
573         }
574
575         info = mono_thread_info_attach (&dummy);
576         g_assert (info);
577
578         info->tools_thread = TRUE;
579 }
580
581 MonoThreadInfo*
582 mono_thread_info_attach (void *baseptr)
583 {
584         MonoThreadInfo *info;
585         if (!mono_threads_inited)
586         {
587 #ifdef HOST_WIN32
588                 /* This can happen from DllMain(DLL_THREAD_ATTACH) on Windows, if a
589                  * thread is created before an embedding API user initialized Mono. */
590                 THREADS_DEBUG ("mono_thread_info_attach called before mono_threads_init\n");
591                 return NULL;
592 #else
593                 g_assert (mono_threads_inited);
594 #endif
595         }
596         info = (MonoThreadInfo *) mono_native_tls_get_value (thread_info_key);
597         if (!info) {
598                 info = (MonoThreadInfo *) g_malloc0 (thread_info_size);
599                 THREADS_DEBUG ("attaching %p\n", info);
600                 if (!register_thread (info, baseptr))
601                         return NULL;
602         } else if (threads_callbacks.thread_attach) {
603                 threads_callbacks.thread_attach (info);
604         }
605         return info;
606 }
607
608 void
609 mono_thread_info_detach (void)
610 {
611         MonoThreadInfo *info;
612         if (!mono_threads_inited)
613         {
614                 /* This can happen from DllMain(THREAD_DETACH) on Windows, if a thread
615                  * is created before an embedding API user initialized Mono. */
616                 THREADS_DEBUG ("mono_thread_info_detach called before mono_threads_init\n");
617                 return;
618         }
619         info = (MonoThreadInfo *) mono_native_tls_get_value (thread_info_key);
620         if (info) {
621                 THREADS_DEBUG ("detaching %p\n", info);
622                 unregister_thread (info);
623                 mono_native_tls_set_value (thread_info_key, NULL);
624         }
625 }
626
627 /*
628  * mono_thread_info_is_exiting:
629  *
630  *   Return whenever the current thread is exiting, i.e. it is running pthread
631  * dtors.
632  */
633 gboolean
634 mono_thread_info_is_exiting (void)
635 {
636 #if defined(__MACH__)
637         if (mono_native_tls_get_value (thread_exited_key) == GUINT_TO_POINTER (1))
638                 return TRUE;
639 #endif
640         return FALSE;
641 }
642
643 #ifndef HOST_WIN32
644 static void
645 thread_info_key_dtor (void *arg)
646 {
647         /* Put the MonoThreadInfo back for the duration of the
648          * unregister code.  In some circumstances the thread needs to
649          * take the GC lock which may block which requires a coop
650          * state transition. */
651         mono_native_tls_set_value (thread_info_key, arg);
652         unregister_thread (arg);
653         mono_native_tls_set_value (thread_info_key, NULL);
654 }
655 #endif
656
657 void
658 mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
659 {
660         gboolean res;
661         threads_callbacks = *callbacks;
662         thread_info_size = info_size;
663         const char *sleepLimit;
664 #ifdef HOST_WIN32
665         res = mono_native_tls_alloc (&thread_info_key, NULL);
666         res = mono_native_tls_alloc (&thread_exited_key, NULL);
667 #else
668         res = mono_native_tls_alloc (&thread_info_key, (void *) thread_info_key_dtor);
669         res = mono_native_tls_alloc (&thread_exited_key, (void *) thread_exited_dtor);
670 #endif
671
672         g_assert (res);
673
674 #ifndef HAVE_KW_THREAD
675         res = mono_native_tls_alloc (&small_id_key, NULL);
676 #endif
677         g_assert (res);
678
679         unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || mono_threads_is_coop_enabled ();
680         
681         if ((sleepLimit = g_getenv ("MONO_SLEEP_ABORT_LIMIT")) != NULL) {
682                 errno = 0;
683                 long threshold = strtol(sleepLimit, NULL, 10);
684                 if ((errno == 0) && (threshold >= 40))  {
685                         sleepAbortDuration = threshold;
686                         sleepWarnDuration = threshold / 20;
687                 } else
688                         g_warning("MONO_SLEEP_ABORT_LIMIT must be a number >= 40");
689         }
690
691         mono_os_sem_init (&global_suspend_semaphore, 1);
692         mono_os_sem_init (&suspend_semaphore, 0);
693
694         mono_lls_init (&thread_list, NULL);
695         mono_thread_smr_init ();
696         mono_threads_platform_init ();
697         mono_threads_suspend_init ();
698         mono_threads_coop_init ();
699         mono_threads_abort_syscall_init ();
700
701 #if defined(__MACH__)
702         mono_mach_init (thread_info_key);
703 #endif
704
705         mono_threads_inited = TRUE;
706
707         g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
708 }
709
710 void
711 mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks)
712 {
713         runtime_callbacks = *callbacks;
714 }
715
716 MonoThreadInfoRuntimeCallbacks *
717 mono_threads_get_runtime_callbacks (void)
718 {
719         return &runtime_callbacks;
720 }
721
722 /*
723 Signal that the current thread wants to be suspended.
724 This function can be called without holding the suspend lock held.
725 To finish suspending, call mono_suspend_check.
726 */
727 void
728 mono_thread_info_begin_self_suspend (void)
729 {
730         MonoThreadInfo *info = mono_thread_info_current_unchecked ();
731         if (!info)
732                 return;
733
734         THREADS_SUSPEND_DEBUG ("BEGIN SELF SUSPEND OF %p\n", info);
735         mono_threads_transition_request_self_suspension (info);
736 }
737
738 void
739 mono_thread_info_end_self_suspend (void)
740 {
741         MonoThreadInfo *info;
742
743         info = mono_thread_info_current ();
744         if (!info)
745                 return;
746         THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", info);
747
748         mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
749
750         /* commit the saved state and notify others if needed */
751         switch (mono_threads_transition_state_poll (info)) {
752         case SelfSuspendResumed:
753                 return;
754         case SelfSuspendWait:
755                 mono_thread_info_wait_for_resume (info);
756                 break;
757         case SelfSuspendNotifyAndWait:
758                 mono_threads_notify_initiator_of_suspend (info);
759                 mono_thread_info_wait_for_resume (info);
760                 mono_threads_notify_initiator_of_resume (info);
761                 break;
762         }
763 }
764
765 static gboolean
766 mono_thread_info_core_resume (MonoThreadInfo *info)
767 {
768         gboolean res = FALSE;
769
770         switch (mono_threads_transition_request_resume (info)) {
771         case ResumeError:
772                 res = FALSE;
773                 break;
774         case ResumeOk:
775                 res = TRUE;
776                 break;
777         case ResumeInitSelfResume:
778                 resume_self_suspended (info);
779                 res = TRUE;
780                 break;
781         case ResumeInitAsyncResume:
782                 resume_async_suspended (info);
783                 res = TRUE;
784                 break;
785         case ResumeInitBlockingResume:
786                 resume_blocking_suspended (info);
787                 res = TRUE;
788                 break;
789         }
790
791         return res;
792 }
793
794 gboolean
795 mono_thread_info_resume (MonoNativeThreadId tid)
796 {
797         gboolean result; /* don't initialize it so the compiler can catch unitilized paths. */
798         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
799         MonoThreadInfo *info;
800
801         THREADS_SUSPEND_DEBUG ("RESUMING tid %p\n", (void*)tid);
802
803         mono_thread_info_suspend_lock ();
804
805         info = mono_thread_info_lookup (tid); /*info on HP1*/
806         if (!info) {
807                 result = FALSE;
808                 goto cleanup;
809         }
810
811         result = mono_thread_info_core_resume (info);
812
813         //Wait for the pending resume to finish
814         mono_threads_wait_pending_operations ();
815
816 cleanup:
817         mono_thread_info_suspend_unlock ();
818         mono_hazard_pointer_clear (hp, 1);
819         return result;
820 }
821
822 gboolean
823 mono_thread_info_begin_suspend (MonoThreadInfo *info)
824 {
825         switch (mono_threads_transition_request_async_suspension (info)) {
826         case AsyncSuspendAlreadySuspended:
827         case AsyncSuspendBlocking:
828                 return TRUE;
829         case AsyncSuspendWait:
830                 mono_threads_add_to_pending_operation_set (info);
831                 return TRUE;
832         case AsyncSuspendInitSuspend:
833                 return begin_async_suspend (info, FALSE);
834         default:
835                 g_assert_not_reached ();
836         }
837 }
838
839 gboolean
840 mono_thread_info_begin_resume (MonoThreadInfo *info)
841 {
842         return mono_thread_info_core_resume (info);
843 }
844
845 /*
846 FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
847 WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
848 */
849 static gboolean
850 is_thread_in_critical_region (MonoThreadInfo *info)
851 {
852         MonoMethod *method;
853         MonoJitInfo *ji;
854         gpointer stack_start;
855         MonoThreadUnwindState *state;
856
857         /* Are we inside a system critical region? */
858         if (info->inside_critical_region)
859                 return TRUE;
860
861         /* Are we inside a GC critical region? */
862         if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
863                 return TRUE;
864         }
865
866         /* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
867         state = mono_thread_info_get_suspend_state (info);
868         if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
869                 return FALSE;
870
871         stack_start = MONO_CONTEXT_GET_SP (&state->ctx);
872         /* altstack signal handler, sgen can't handle them, so we treat them as critical */
873         if (stack_start < info->stack_start_limit || stack_start >= info->stack_end)
874                 return TRUE;
875
876         ji = mono_jit_info_table_find (
877                 (MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
878                 (char *) MONO_CONTEXT_GET_IP (&state->ctx));
879
880         if (!ji)
881                 return FALSE;
882
883         method = mono_jit_info_get_method (ji);
884
885         return threads_callbacks.mono_method_is_critical (method);
886 }
887
888 gboolean
889 mono_thread_info_in_critical_location (MonoThreadInfo *info)
890 {
891         return is_thread_in_critical_region (info);
892 }
893
894 /*
895 The return value is only valid until a matching mono_thread_info_resume is called
896 */
897 static MonoThreadInfo*
898 suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel)
899 {
900         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
901         MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
902         if (!info)
903                 return NULL;
904
905         switch (mono_threads_transition_request_async_suspension (info)) {
906         case AsyncSuspendAlreadySuspended:
907                 mono_hazard_pointer_clear (hp, 1); //XXX this is questionable we got to clean the suspend/resume nonsense of critical sections
908                 return info;
909         case AsyncSuspendWait:
910                 mono_threads_add_to_pending_operation_set (info);
911                 break;
912         case AsyncSuspendInitSuspend:
913                 if (!begin_async_suspend (info, interrupt_kernel)) {
914                         mono_hazard_pointer_clear (hp, 1);
915                         return NULL;
916                 }
917                 break;
918         case AsyncSuspendBlocking:
919                 if (interrupt_kernel)
920                         mono_threads_suspend_abort_syscall (info);
921
922                 break;
923         default:
924                 g_assert_not_reached ();
925         }
926
927         //Wait for the pending suspend to finish
928         mono_threads_wait_pending_operations ();
929
930         if (!check_async_suspend (info)) {
931                 mono_thread_info_core_resume (info);
932                 mono_threads_wait_pending_operations ();
933                 mono_hazard_pointer_clear (hp, 1);
934                 return NULL;
935         }
936         return info;
937 }
938
939 static MonoThreadInfo*
940 suspend_sync_nolock (MonoNativeThreadId id, gboolean interrupt_kernel)
941 {
942         MonoThreadInfo *info = NULL;
943         int sleep_duration = 0;
944         for (;;) {
945                 if (!(info = suspend_sync (id, interrupt_kernel))) {
946                         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
947                         return NULL;
948                 }
949
950                 /*WARNING: We now are in interrupt context until we resume the thread. */
951                 if (!is_thread_in_critical_region (info))
952                         break;
953
954                 if (!mono_thread_info_core_resume (info)) {
955                         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
956                         return NULL;
957                 }
958                 THREADS_SUSPEND_DEBUG ("RESTARTED thread tid %p\n", (void*)id);
959
960                 /* Wait for the pending resume to finish */
961                 mono_threads_wait_pending_operations ();
962
963                 if (sleep_duration == 0)
964                         mono_thread_info_yield ();
965                 else
966                         g_usleep (sleep_duration);
967
968                 sleep_duration += 10;
969         }
970         return info;
971 }
972
973 void
974 mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data)
975 {
976         int result;
977         MonoThreadInfo *info = NULL;
978         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
979
980         THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id);
981         /*FIXME: unify this with self-suspend*/
982         g_assert (id != mono_native_thread_id_get ());
983
984         /* This can block during stw */
985         mono_thread_info_suspend_lock ();
986         mono_threads_begin_global_suspend ();
987
988         info = suspend_sync_nolock (id, interrupt_kernel);
989         if (!info)
990                 goto done;
991
992         switch (result = callback (info, user_data)) {
993         case MonoResumeThread:
994                 mono_hazard_pointer_set (hp, 1, info);
995                 mono_thread_info_core_resume (info);
996                 mono_threads_wait_pending_operations ();
997                 break;
998         case KeepSuspended:
999                 break;
1000         default:
1001                 g_error ("Invalid suspend_and_run callback return value %d", result);
1002         }
1003
1004 done:
1005         mono_hazard_pointer_clear (hp, 1);
1006         mono_threads_end_global_suspend ();
1007         mono_thread_info_suspend_unlock ();
1008 }
1009
1010 /**
1011 Inject an assynchronous call into the target thread. The target thread must be suspended and
1012 only a single async call can be setup for a given suspend cycle.
1013 This async call must cause stack unwinding as the current implementation doesn't save enough state
1014 to resume execution of the top-of-stack function. It's an acceptable limitation since this is
1015 currently used only to deliver exceptions.
1016 */
1017 void
1018 mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
1019 {
1020         /* An async call can only be setup on an async suspended thread */
1021         g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED);
1022         /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
1023         g_assert (!info->async_target);
1024         info->async_target = target_func;
1025         /* This is not GC tracked */
1026         info->user_data = user_data;
1027 }
1028
1029 /*
1030 The suspend lock is held during any suspend in progress.
1031 A GC that has safepoints must take this lock as part of its
1032 STW to make sure no unsafe pending suspend is in progress.   
1033 */
1034
1035 static void
1036 mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info)
1037 {
1038         g_assert (info);
1039         g_assert (mono_thread_info_is_current (info));
1040         g_assert (mono_thread_info_is_live (info));
1041
1042         MONO_ENTER_GC_SAFE_WITH_INFO(info);
1043
1044         int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
1045         g_assert (res != -1);
1046
1047         MONO_EXIT_GC_SAFE_WITH_INFO;
1048 }
1049
1050 void
1051 mono_thread_info_suspend_lock (void)
1052 {
1053         mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ());
1054 }
1055
1056 void
1057 mono_thread_info_suspend_unlock (void)
1058 {
1059         mono_os_sem_post (&global_suspend_semaphore);
1060 }
1061
1062 /*
1063  * This is a very specific function whose only purpose is to
1064  * break a given thread from socket syscalls.
1065  *
1066  * This only exists because linux won't fail a call to connect
1067  * if the underlying is closed.
1068  *
1069  * TODO We should cleanup and unify this with the other syscall abort
1070  * facility.
1071  */
1072 void
1073 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
1074 {
1075         MonoThreadHazardPointers *hp;
1076         MonoThreadInfo *info;
1077
1078         if (tid == mono_native_thread_id_get () || !mono_threads_suspend_needs_abort_syscall ())
1079                 return;
1080
1081         hp = mono_hazard_pointer_get ();
1082         info = mono_thread_info_lookup (tid);
1083         if (!info)
1084                 return;
1085
1086         if (mono_thread_info_run_state (info) == STATE_DETACHED) {
1087                 mono_hazard_pointer_clear (hp, 1);
1088                 return;
1089         }
1090
1091         mono_thread_info_suspend_lock ();
1092         mono_threads_begin_global_suspend ();
1093
1094         mono_threads_suspend_abort_syscall (info);
1095         mono_threads_wait_pending_operations ();
1096
1097         mono_hazard_pointer_clear (hp, 1);
1098
1099         mono_threads_end_global_suspend ();
1100         mono_thread_info_suspend_unlock ();
1101 }
1102
1103 gboolean
1104 mono_thread_info_unified_management_enabled (void)
1105 {
1106         return unified_suspend_enabled;
1107 }
1108
1109 /*
1110  * mono_thread_info_set_is_async_context:
1111  *
1112  *   Set whenever the current thread is in an async context. Some runtime functions might behave
1113  * differently while in an async context in order to be async safe.
1114  */
1115 void
1116 mono_thread_info_set_is_async_context (gboolean async_context)
1117 {
1118         MonoThreadInfo *info = mono_thread_info_current ();
1119
1120         if (info)
1121                 info->is_async_context = async_context;
1122 }
1123
1124 gboolean
1125 mono_thread_info_is_async_context (void)
1126 {
1127         MonoThreadInfo *info = mono_thread_info_current ();
1128
1129         if (info)
1130                 return info->is_async_context;
1131         else
1132                 return FALSE;
1133 }
1134
1135 typedef struct {
1136         gint32 ref;
1137         MonoThreadStart start_routine;
1138         gpointer start_routine_arg;
1139         gint32 priority;
1140         MonoCoopSem registered;
1141         gpointer handle;
1142 } CreateThreadData;
1143
1144 static gsize WINAPI
1145 inner_start_thread (gpointer data)
1146 {
1147         CreateThreadData *thread_data;
1148         MonoThreadInfo *info;
1149         MonoThreadStart start_routine;
1150         gpointer start_routine_arg;
1151         guint32 start_routine_res;
1152         gint32 priority;
1153         gsize dummy;
1154
1155         thread_data = (CreateThreadData*) data;
1156         g_assert (thread_data);
1157
1158         start_routine = thread_data->start_routine;
1159         start_routine_arg = thread_data->start_routine_arg;
1160
1161         priority = thread_data->priority;
1162
1163         info = mono_thread_info_attach (&dummy);
1164         info->runtime_thread = TRUE;
1165
1166         mono_threads_platform_set_priority (info, priority);
1167
1168         thread_data->handle = mono_thread_info_duplicate_handle (info);
1169
1170         mono_coop_sem_post (&thread_data->registered);
1171
1172         if (InterlockedDecrement (&thread_data->ref) == 0) {
1173                 mono_coop_sem_destroy (&thread_data->registered);
1174                 g_free (thread_data);
1175         }
1176
1177         /* thread_data is not valid anymore */
1178         thread_data = NULL;
1179
1180         /* Run the actual main function of the thread */
1181         start_routine_res = start_routine (start_routine_arg);
1182
1183         mono_threads_platform_exit (start_routine_res);
1184
1185         g_assert_not_reached ();
1186 }
1187
1188 /*
1189  * mono_threads_create_thread:
1190  *
1191  *   Create a new thread executing START with argument ARG. Store its id into OUT_TID.
1192  * Returns: a windows or io-layer handle for the thread.
1193  */
1194 HANDLE
1195 mono_threads_create_thread (MonoThreadStart start, gpointer arg, MonoThreadParm *tp, MonoNativeThreadId *out_tid)
1196 {
1197         CreateThreadData *thread_data;
1198         gint res;
1199         gpointer ret;
1200
1201         thread_data = g_new0 (CreateThreadData, 1);
1202         thread_data->ref = 2;
1203         thread_data->start_routine = start;
1204         thread_data->start_routine_arg = arg;
1205         thread_data->priority = tp->priority;
1206         mono_coop_sem_init (&thread_data->registered, 0);
1207
1208         res = mono_threads_platform_create_thread (inner_start_thread, (gpointer) thread_data, tp->stack_size, out_tid);
1209         if (res != 0) {
1210                 /* ref is not going to be decremented in inner_start_thread */
1211                 InterlockedDecrement (&thread_data->ref);
1212                 ret = NULL;
1213                 goto done;
1214         }
1215
1216         res = mono_coop_sem_wait (&thread_data->registered, MONO_SEM_FLAGS_NONE);
1217         g_assert (res == 0);
1218
1219         ret = thread_data->handle;
1220         g_assert (ret);
1221
1222 done:
1223         if (InterlockedDecrement (&thread_data->ref) == 0) {
1224                 mono_coop_sem_destroy (&thread_data->registered);
1225                 g_free (thread_data);
1226         }
1227
1228         return ret;
1229 }
1230
1231 /*
1232  * mono_thread_info_get_stack_bounds:
1233  *
1234  *   Return the address and size of the current threads stack. Return NULL as the 
1235  * stack address if the stack address cannot be determined.
1236  */
1237 void
1238 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize)
1239 {
1240         guint8 *current = (guint8 *)&stsize;
1241         mono_threads_platform_get_stack_bounds (staddr, stsize);
1242         if (!*staddr)
1243                 return;
1244
1245         /* Sanity check the result */
1246         g_assert ((current > *staddr) && (current < *staddr + *stsize));
1247
1248         /* When running under emacs, sometimes staddr is not aligned to a page size */
1249         *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
1250 }
1251
1252 gboolean
1253 mono_thread_info_yield (void)
1254 {
1255         return mono_threads_platform_yield ();
1256 }
1257 static mono_lazy_init_t sleep_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
1258 static MonoCoopMutex sleep_mutex;
1259 static MonoCoopCond sleep_cond;
1260
1261 static void
1262 sleep_initialize (void)
1263 {
1264         mono_coop_mutex_init (&sleep_mutex);
1265         mono_coop_cond_init (&sleep_cond);
1266 }
1267
1268 static void
1269 sleep_interrupt (gpointer data)
1270 {
1271         mono_coop_mutex_lock (&sleep_mutex);
1272         mono_coop_cond_broadcast (&sleep_cond);
1273         mono_coop_mutex_unlock (&sleep_mutex);
1274 }
1275
1276 static inline guint32
1277 sleep_interruptable (guint32 ms, gboolean *alerted)
1278 {
1279         gint64 now, end;
1280
1281         g_assert (INFINITE == G_MAXUINT32);
1282
1283         g_assert (alerted);
1284         *alerted = FALSE;
1285
1286         if (ms != INFINITE)
1287                 end = mono_100ns_ticks () + (ms * 1000 * 10);
1288
1289         mono_lazy_initialize (&sleep_init, sleep_initialize);
1290
1291         mono_coop_mutex_lock (&sleep_mutex);
1292
1293         for (;;) {
1294                 if (ms != INFINITE) {
1295                         now = mono_100ns_ticks ();
1296                         if (now > end)
1297                                 break;
1298                 }
1299
1300                 mono_thread_info_install_interrupt (sleep_interrupt, NULL, alerted);
1301                 if (*alerted) {
1302                         mono_coop_mutex_unlock (&sleep_mutex);
1303                         return WAIT_IO_COMPLETION;
1304                 }
1305
1306                 if (ms != INFINITE)
1307                         mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, (end - now) / 10 / 1000);
1308                 else
1309                         mono_coop_cond_wait (&sleep_cond, &sleep_mutex);
1310
1311                 mono_thread_info_uninstall_interrupt (alerted);
1312                 if (*alerted) {
1313                         mono_coop_mutex_unlock (&sleep_mutex);
1314                         return WAIT_IO_COMPLETION;
1315                 }
1316         }
1317
1318         mono_coop_mutex_unlock (&sleep_mutex);
1319
1320         return 0;
1321 }
1322
1323 gint
1324 mono_thread_info_sleep (guint32 ms, gboolean *alerted)
1325 {
1326         if (ms == 0) {
1327                 MonoThreadInfo *info;
1328
1329                 mono_thread_info_yield ();
1330
1331                 info = mono_thread_info_current ();
1332                 if (info && mono_thread_info_is_interrupt_state (info))
1333                         return WAIT_IO_COMPLETION;
1334
1335                 return 0;
1336         }
1337
1338         if (alerted)
1339                 return sleep_interruptable (ms, alerted);
1340
1341         MONO_ENTER_GC_SAFE;
1342
1343         if (ms == INFINITE) {
1344                 do {
1345 #ifdef HOST_WIN32
1346                         Sleep (G_MAXUINT32);
1347 #else
1348                         sleep (G_MAXUINT32);
1349 #endif
1350                 } while (1);
1351         } else {
1352                 int ret;
1353 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
1354                 struct timespec start, target;
1355
1356                 /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
1357                 ret = clock_gettime (CLOCK_MONOTONIC, &start);
1358                 g_assert (ret == 0);
1359
1360                 target = start;
1361                 target.tv_sec += ms / 1000;
1362                 target.tv_nsec += (ms % 1000) * 1000000;
1363                 if (target.tv_nsec > 999999999) {
1364                         target.tv_nsec -= 999999999;
1365                         target.tv_sec ++;
1366                 }
1367
1368                 do {
1369                         ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
1370                 } while (ret != 0);
1371 #elif HOST_WIN32
1372                 Sleep (ms);
1373 #else
1374                 struct timespec req, rem;
1375
1376                 req.tv_sec = ms / 1000;
1377                 req.tv_nsec = (ms % 1000) * 1000000;
1378
1379                 do {
1380                         memset (&rem, 0, sizeof (rem));
1381                         ret = nanosleep (&req, &rem);
1382                 } while (ret != 0);
1383 #endif /* __linux__ */
1384         }
1385
1386         MONO_EXIT_GC_SAFE;
1387
1388         return 0;
1389 }
1390
1391 gint
1392 mono_thread_info_usleep (guint64 us)
1393 {
1394         MONO_ENTER_GC_SAFE;
1395         g_usleep (us);
1396         MONO_EXIT_GC_SAFE;
1397         return 0;
1398 }
1399
1400 gpointer
1401 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key)
1402 {
1403         return ((MonoThreadInfo*)info)->tls [key];
1404 }
1405
1406 /*
1407  * mono_threads_info_tls_set:
1408  *
1409  *   Set the TLS key to VALUE in the info structure. This can be used to obtain
1410  * values of TLS variables for threads other than the current thread.
1411  * This should only be used for infrequently changing TLS variables, and it should
1412  * be paired with setting the real TLS variable since this provides no GC tracking.
1413  */
1414 void
1415 mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value)
1416 {
1417         ((MonoThreadInfo*)info)->tls [key] = value;
1418 }
1419
1420 /*
1421  * mono_thread_info_exit:
1422  *
1423  *   Exit the current thread.
1424  * This function doesn't return.
1425  */
1426 void
1427 mono_thread_info_exit (void)
1428 {
1429         mono_threads_platform_exit (0);
1430 }
1431
1432 /*
1433  * mono_threads_open_thread_handle:
1434  *
1435  *   Return a io-layer/win32 handle for the thread identified by HANDLE/TID.
1436  * The handle need to be closed by calling CloseHandle () when it is no
1437  * longer needed.
1438  */
1439 HANDLE
1440 mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
1441 {
1442         return mono_threads_platform_open_thread_handle (handle, tid);
1443 }
1444
1445 void
1446 mono_threads_close_thread_handle (HANDLE handle)
1447 {
1448         return mono_threads_platform_close_thread_handle (handle);
1449 }
1450
1451 #define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1)
1452
1453 struct _MonoThreadInfoInterruptToken {
1454         void (*callback) (gpointer data);
1455         gpointer data;
1456 };
1457
1458 /*
1459  * mono_thread_info_install_interrupt: install an interruption token for the current thread.
1460  *
1461  *  - @callback: must be able to be called from another thread and always cancel the wait
1462  *  - @data: passed to the callback
1463  *  - @interrupted: will be set to TRUE if a token is already installed, FALSE otherwise
1464  *     if set to TRUE, it must mean that the thread is in interrupted state
1465  */
1466 void
1467 mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted)
1468 {
1469         MonoThreadInfo *info;
1470         MonoThreadInfoInterruptToken *previous_token, *token;
1471
1472         g_assert (callback);
1473
1474         g_assert (interrupted);
1475         *interrupted = FALSE;
1476
1477         info = mono_thread_info_current ();
1478         g_assert (info);
1479
1480         /* The memory of this token can be freed at 2 places:
1481          *  - if the token is not interrupted: it will be freed in uninstall, as info->interrupt_token has not been replaced
1482          *     by the INTERRUPT_STATE flag value, and it still contains the pointer to the memory location
1483          *  - if the token is interrupted: it will be freed in finish, as the token is now owned by the prepare/finish
1484          *     functions, and info->interrupt_token does not contains a pointer to the memory anymore */
1485         token = g_new0 (MonoThreadInfoInterruptToken, 1);
1486         token->callback = callback;
1487         token->data = data;
1488
1489         previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, token, NULL);
1490
1491         if (previous_token) {
1492                 if (previous_token != INTERRUPT_STATE)
1493                         g_error ("mono_thread_info_install_interrupt: previous_token should be INTERRUPT_STATE (%p), but it was %p", INTERRUPT_STATE, previous_token);
1494
1495                 g_free (token);
1496
1497                 *interrupted = TRUE;
1498         }
1499
1500         THREADS_INTERRUPT_DEBUG ("interrupt install    tid %p token %p previous_token %p interrupted %s\n",
1501                 mono_thread_info_get_tid (info), token, previous_token, *interrupted ? "TRUE" : "FALSE");
1502 }
1503
1504 void
1505 mono_thread_info_uninstall_interrupt (gboolean *interrupted)
1506 {
1507         MonoThreadInfo *info;
1508         MonoThreadInfoInterruptToken *previous_token;
1509
1510         g_assert (interrupted);
1511         *interrupted = FALSE;
1512
1513         info = mono_thread_info_current ();
1514         g_assert (info);
1515
1516         previous_token = (MonoThreadInfoInterruptToken *)InterlockedExchangePointer ((gpointer*) &info->interrupt_token, NULL);
1517
1518         /* only the installer can uninstall the token */
1519         g_assert (previous_token);
1520
1521         if (previous_token == INTERRUPT_STATE) {
1522                 /* if it is interrupted, then it is going to be freed in finish interrupt */
1523                 *interrupted = TRUE;
1524         } else {
1525                 g_free (previous_token);
1526         }
1527
1528         THREADS_INTERRUPT_DEBUG ("interrupt uninstall  tid %p previous_token %p interrupted %s\n",
1529                 mono_thread_info_get_tid (info), previous_token, *interrupted ? "TRUE" : "FALSE");
1530 }
1531
1532 static MonoThreadInfoInterruptToken*
1533 set_interrupt_state (MonoThreadInfo *info)
1534 {
1535         MonoThreadInfoInterruptToken *token, *previous_token;
1536
1537         g_assert (info);
1538
1539         /* Atomically obtain the token the thread is
1540         * waiting on, and change it to a flag value. */
1541
1542         do {
1543                 previous_token = info->interrupt_token;
1544
1545                 /* Already interrupted */
1546                 if (previous_token == INTERRUPT_STATE) {
1547                         token = NULL;
1548                         break;
1549                 }
1550
1551                 token = previous_token;
1552         } while (InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, INTERRUPT_STATE, previous_token) != previous_token);
1553
1554         return token;
1555 }
1556
1557 /*
1558  * mono_thread_info_prepare_interrupt:
1559  *
1560  * The state of the thread info interrupt token is set to 'interrupted' which means that :
1561  *  - if the thread calls one of the WaitFor functions, the function will return with
1562  *     WAIT_IO_COMPLETION instead of waiting
1563  *  - if the thread was waiting when this function was called, the wait will be broken
1564  *
1565  * It is possible that the wait functions return WAIT_IO_COMPLETION, but the target thread
1566  * didn't receive the interrupt signal yet, in this case it should call the wait function
1567  * again. This essentially means that the target thread will busy wait until it is ready to
1568  * process the interruption.
1569  */
1570 MonoThreadInfoInterruptToken*
1571 mono_thread_info_prepare_interrupt (MonoThreadInfo *info)
1572 {
1573         MonoThreadInfoInterruptToken *token;
1574
1575         token = set_interrupt_state (info);
1576
1577         THREADS_INTERRUPT_DEBUG ("interrupt prepare    tid %p token %p\n",
1578                 mono_thread_info_get_tid (info), token);
1579
1580         return token;
1581 }
1582
1583 void
1584 mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token)
1585 {
1586         THREADS_INTERRUPT_DEBUG ("interrupt finish     token %p\n", token);
1587
1588         if (token == NULL)
1589                 return;
1590
1591         g_assert (token->callback);
1592
1593         token->callback (token->data);
1594
1595         g_free (token);
1596 }
1597
1598 void
1599 mono_thread_info_self_interrupt (void)
1600 {
1601         MonoThreadInfo *info;
1602         MonoThreadInfoInterruptToken *token;
1603
1604         info = mono_thread_info_current ();
1605         g_assert (info);
1606
1607         token = set_interrupt_state (info);
1608         g_assert (!token);
1609
1610         THREADS_INTERRUPT_DEBUG ("interrupt self       tid %p\n",
1611                 mono_thread_info_get_tid (info));
1612 }
1613
1614 /* Clear the interrupted flag of the current thread, set with
1615  * mono_thread_info_self_interrupt, so it can wait again */
1616 void
1617 mono_thread_info_clear_self_interrupt ()
1618 {
1619         MonoThreadInfo *info;
1620         MonoThreadInfoInterruptToken *previous_token;
1621
1622         info = mono_thread_info_current ();
1623         g_assert (info);
1624
1625         previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, NULL, INTERRUPT_STATE);
1626         g_assert (previous_token == NULL || previous_token == INTERRUPT_STATE);
1627
1628         THREADS_INTERRUPT_DEBUG ("interrupt clear self tid %p previous_token %p\n", mono_thread_info_get_tid (info), previous_token);
1629 }
1630
1631 gboolean
1632 mono_thread_info_is_interrupt_state (MonoThreadInfo *info)
1633 {
1634         g_assert (info);
1635         return InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE;
1636 }
1637
1638 void
1639 mono_thread_info_describe_interrupt_token (MonoThreadInfo *info, GString *text)
1640 {
1641         g_assert (info);
1642
1643         if (!InterlockedReadPointer ((gpointer*) &info->interrupt_token))
1644                 g_string_append_printf (text, "not waiting");
1645         else if (InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE)
1646                 g_string_append_printf (text, "interrupted state");
1647         else
1648                 g_string_append_printf (text, "waiting");
1649 }
1650
1651 gboolean
1652 mono_thread_info_is_current (MonoThreadInfo *info)
1653 {
1654         return mono_thread_info_get_tid (info) == mono_native_thread_id_get ();
1655 }
1656
1657 void
1658 mono_thread_info_set_exited (THREAD_INFO_TYPE *info)
1659 {
1660         g_assert (mono_thread_info_is_current (info));
1661         mono_threads_platform_set_exited (info);
1662 }
1663
1664 gpointer
1665 mono_thread_info_duplicate_handle (MonoThreadInfo *info)
1666 {
1667         g_assert (mono_thread_info_is_current (info));
1668         return mono_threads_platform_duplicate_handle (info);
1669 }
1670
1671 void
1672 mono_thread_info_describe (MonoThreadInfo *info, GString *text)
1673 {
1674         mono_threads_platform_describe (info, text);
1675 }
1676
1677 void
1678 mono_thread_info_own_mutex (MonoThreadInfo *info, gpointer mutex_handle)
1679 {
1680         mono_threads_platform_own_mutex (info, mutex_handle);
1681 }
1682
1683 void
1684 mono_thread_info_disown_mutex (MonoThreadInfo *info, gpointer mutex_handle)
1685 {
1686         mono_threads_platform_disown_mutex (info, mutex_handle);
1687 }
1688
1689 MonoThreadPriority
1690 mono_thread_info_get_priority (MonoThreadInfo *info)
1691 {
1692         return mono_threads_platform_get_priority (info);
1693 }
1694
1695 void
1696 mono_thread_info_set_priority (MonoThreadInfo *info, MonoThreadPriority priority)
1697 {
1698         mono_threads_platform_set_priority (info, priority);
1699 }