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