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