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