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