Merge pull request #3716 from vargaz/unbox-stobj-null
[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         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         unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || mono_threads_is_coop_enabled ();
678         
679         if ((sleepLimit = g_getenv ("MONO_SLEEP_ABORT_LIMIT")) != NULL) {
680                 errno = 0;
681                 long threshold = strtol(sleepLimit, NULL, 10);
682                 if ((errno == 0) && (threshold >= 40))  {
683                         sleepAbortDuration = threshold;
684                         sleepWarnDuration = threshold / 20;
685                 } else
686                         g_warning("MONO_SLEEP_ABORT_LIMIT must be a number >= 40");
687         }
688
689         mono_os_sem_init (&global_suspend_semaphore, 1);
690         mono_os_sem_init (&suspend_semaphore, 0);
691
692         mono_lls_init (&thread_list, NULL);
693         mono_thread_smr_init ();
694         mono_threads_platform_init ();
695         mono_threads_suspend_init ();
696         mono_threads_coop_init ();
697         mono_threads_abort_syscall_init ();
698
699 #if defined(__MACH__)
700         mono_mach_init (thread_info_key);
701 #endif
702
703         mono_threads_inited = TRUE;
704
705         g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
706 }
707
708 void
709 mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks)
710 {
711         runtime_callbacks = *callbacks;
712 }
713
714 MonoThreadInfoRuntimeCallbacks *
715 mono_threads_get_runtime_callbacks (void)
716 {
717         return &runtime_callbacks;
718 }
719
720 /*
721 Signal that the current thread wants to be suspended.
722 This function can be called without holding the suspend lock held.
723 To finish suspending, call mono_suspend_check.
724 */
725 void
726 mono_thread_info_begin_self_suspend (void)
727 {
728         MonoThreadInfo *info = mono_thread_info_current_unchecked ();
729         if (!info)
730                 return;
731
732         THREADS_SUSPEND_DEBUG ("BEGIN SELF SUSPEND OF %p\n", info);
733         mono_threads_transition_request_self_suspension (info);
734 }
735
736 void
737 mono_thread_info_end_self_suspend (void)
738 {
739         MonoThreadInfo *info;
740
741         info = mono_thread_info_current ();
742         if (!info)
743                 return;
744         THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", info);
745
746         mono_threads_get_runtime_callbacks ()->thread_state_init (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX]);
747
748         /* commit the saved state and notify others if needed */
749         switch (mono_threads_transition_state_poll (info)) {
750         case SelfSuspendResumed:
751                 return;
752         case SelfSuspendWait:
753                 mono_thread_info_wait_for_resume (info);
754                 break;
755         case SelfSuspendNotifyAndWait:
756                 mono_threads_notify_initiator_of_suspend (info);
757                 mono_thread_info_wait_for_resume (info);
758                 mono_threads_notify_initiator_of_resume (info);
759                 break;
760         }
761 }
762
763 static gboolean
764 mono_thread_info_core_resume (MonoThreadInfo *info)
765 {
766         gboolean res = FALSE;
767
768         switch (mono_threads_transition_request_resume (info)) {
769         case ResumeError:
770                 res = FALSE;
771                 break;
772         case ResumeOk:
773                 res = TRUE;
774                 break;
775         case ResumeInitSelfResume:
776                 resume_self_suspended (info);
777                 res = TRUE;
778                 break;
779         case ResumeInitAsyncResume:
780                 resume_async_suspended (info);
781                 res = TRUE;
782                 break;
783         case ResumeInitBlockingResume:
784                 resume_blocking_suspended (info);
785                 res = TRUE;
786                 break;
787         }
788
789         return res;
790 }
791
792 gboolean
793 mono_thread_info_resume (MonoNativeThreadId tid)
794 {
795         gboolean result; /* don't initialize it so the compiler can catch unitilized paths. */
796         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
797         MonoThreadInfo *info;
798
799         THREADS_SUSPEND_DEBUG ("RESUMING tid %p\n", (void*)tid);
800
801         mono_thread_info_suspend_lock ();
802
803         info = mono_thread_info_lookup (tid); /*info on HP1*/
804         if (!info) {
805                 result = FALSE;
806                 goto cleanup;
807         }
808
809         result = mono_thread_info_core_resume (info);
810
811         //Wait for the pending resume to finish
812         mono_threads_wait_pending_operations ();
813
814 cleanup:
815         mono_thread_info_suspend_unlock ();
816         mono_hazard_pointer_clear (hp, 1);
817         return result;
818 }
819
820 gboolean
821 mono_thread_info_begin_suspend (MonoThreadInfo *info)
822 {
823         switch (mono_threads_transition_request_async_suspension (info)) {
824         case AsyncSuspendAlreadySuspended:
825         case AsyncSuspendBlocking:
826                 return TRUE;
827         case AsyncSuspendWait:
828                 mono_threads_add_to_pending_operation_set (info);
829                 return TRUE;
830         case AsyncSuspendInitSuspend:
831                 return begin_async_suspend (info, FALSE);
832         default:
833                 g_assert_not_reached ();
834         }
835 }
836
837 gboolean
838 mono_thread_info_begin_resume (MonoThreadInfo *info)
839 {
840         return mono_thread_info_core_resume (info);
841 }
842
843 /*
844 FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
845 WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
846 */
847 static gboolean
848 is_thread_in_critical_region (MonoThreadInfo *info)
849 {
850         MonoMethod *method;
851         MonoJitInfo *ji;
852         gpointer stack_start;
853         MonoThreadUnwindState *state;
854
855         /* Are we inside a system critical region? */
856         if (info->inside_critical_region)
857                 return TRUE;
858
859         /* Are we inside a GC critical region? */
860         if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
861                 return TRUE;
862         }
863
864         /* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
865         state = mono_thread_info_get_suspend_state (info);
866         if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
867                 return FALSE;
868
869         stack_start = MONO_CONTEXT_GET_SP (&state->ctx);
870         /* altstack signal handler, sgen can't handle them, so we treat them as critical */
871         if (stack_start < info->stack_start_limit || stack_start >= info->stack_end)
872                 return TRUE;
873
874         ji = mono_jit_info_table_find (
875                 (MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
876                 (char *) MONO_CONTEXT_GET_IP (&state->ctx));
877
878         if (!ji)
879                 return FALSE;
880
881         method = mono_jit_info_get_method (ji);
882
883         return threads_callbacks.mono_method_is_critical (method);
884 }
885
886 gboolean
887 mono_thread_info_in_critical_location (MonoThreadInfo *info)
888 {
889         return is_thread_in_critical_region (info);
890 }
891
892 /*
893 The return value is only valid until a matching mono_thread_info_resume is called
894 */
895 static MonoThreadInfo*
896 suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel)
897 {
898         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
899         MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
900         if (!info)
901                 return NULL;
902
903         switch (mono_threads_transition_request_async_suspension (info)) {
904         case AsyncSuspendAlreadySuspended:
905                 mono_hazard_pointer_clear (hp, 1); //XXX this is questionable we got to clean the suspend/resume nonsense of critical sections
906                 return info;
907         case AsyncSuspendWait:
908                 mono_threads_add_to_pending_operation_set (info);
909                 break;
910         case AsyncSuspendInitSuspend:
911                 if (!begin_async_suspend (info, interrupt_kernel)) {
912                         mono_hazard_pointer_clear (hp, 1);
913                         return NULL;
914                 }
915                 break;
916         case AsyncSuspendBlocking:
917                 if (interrupt_kernel)
918                         mono_threads_suspend_abort_syscall (info);
919
920                 break;
921         default:
922                 g_assert_not_reached ();
923         }
924
925         //Wait for the pending suspend to finish
926         mono_threads_wait_pending_operations ();
927
928         if (!check_async_suspend (info)) {
929                 mono_thread_info_core_resume (info);
930                 mono_threads_wait_pending_operations ();
931                 mono_hazard_pointer_clear (hp, 1);
932                 return NULL;
933         }
934         return info;
935 }
936
937 static MonoThreadInfo*
938 suspend_sync_nolock (MonoNativeThreadId id, gboolean interrupt_kernel)
939 {
940         MonoThreadInfo *info = NULL;
941         int sleep_duration = 0;
942         for (;;) {
943                 if (!(info = suspend_sync (id, interrupt_kernel))) {
944                         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
945                         return NULL;
946                 }
947
948                 /*WARNING: We now are in interrupt context until we resume the thread. */
949                 if (!is_thread_in_critical_region (info))
950                         break;
951
952                 if (!mono_thread_info_core_resume (info)) {
953                         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
954                         return NULL;
955                 }
956                 THREADS_SUSPEND_DEBUG ("RESTARTED thread tid %p\n", (void*)id);
957
958                 /* Wait for the pending resume to finish */
959                 mono_threads_wait_pending_operations ();
960
961                 if (sleep_duration == 0)
962                         mono_thread_info_yield ();
963                 else
964                         g_usleep (sleep_duration);
965
966                 sleep_duration += 10;
967         }
968         return info;
969 }
970
971 void
972 mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data)
973 {
974         int result;
975         MonoThreadInfo *info = NULL;
976         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
977
978         THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id);
979         /*FIXME: unify this with self-suspend*/
980         g_assert (id != mono_native_thread_id_get ());
981
982         /* This can block during stw */
983         mono_thread_info_suspend_lock ();
984         mono_threads_begin_global_suspend ();
985
986         info = suspend_sync_nolock (id, interrupt_kernel);
987         if (!info)
988                 goto done;
989
990         switch (result = callback (info, user_data)) {
991         case MonoResumeThread:
992                 mono_hazard_pointer_set (hp, 1, info);
993                 mono_thread_info_core_resume (info);
994                 mono_threads_wait_pending_operations ();
995                 break;
996         case KeepSuspended:
997                 break;
998         default:
999                 g_error ("Invalid suspend_and_run callback return value %d", result);
1000         }
1001
1002 done:
1003         mono_hazard_pointer_clear (hp, 1);
1004         mono_threads_end_global_suspend ();
1005         mono_thread_info_suspend_unlock ();
1006 }
1007
1008 /**
1009 Inject an assynchronous call into the target thread. The target thread must be suspended and
1010 only a single async call can be setup for a given suspend cycle.
1011 This async call must cause stack unwinding as the current implementation doesn't save enough state
1012 to resume execution of the top-of-stack function. It's an acceptable limitation since this is
1013 currently used only to deliver exceptions.
1014 */
1015 void
1016 mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
1017 {
1018         /* An async call can only be setup on an async suspended thread */
1019         g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED);
1020         /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
1021         g_assert (!info->async_target);
1022         info->async_target = target_func;
1023         /* This is not GC tracked */
1024         info->user_data = user_data;
1025 }
1026
1027 /*
1028 The suspend lock is held during any suspend in progress.
1029 A GC that has safepoints must take this lock as part of its
1030 STW to make sure no unsafe pending suspend is in progress.   
1031 */
1032
1033 static void
1034 mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info)
1035 {
1036         g_assert (info);
1037         g_assert (mono_thread_info_is_current (info));
1038         g_assert (mono_thread_info_is_live (info));
1039
1040         MONO_ENTER_GC_SAFE_WITH_INFO(info);
1041
1042         int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
1043         g_assert (res != -1);
1044
1045         MONO_EXIT_GC_SAFE_WITH_INFO;
1046 }
1047
1048 void
1049 mono_thread_info_suspend_lock (void)
1050 {
1051         mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ());
1052 }
1053
1054 void
1055 mono_thread_info_suspend_unlock (void)
1056 {
1057         mono_os_sem_post (&global_suspend_semaphore);
1058 }
1059
1060 /*
1061  * This is a very specific function whose only purpose is to
1062  * break a given thread from socket syscalls.
1063  *
1064  * This only exists because linux won't fail a call to connect
1065  * if the underlying is closed.
1066  *
1067  * TODO We should cleanup and unify this with the other syscall abort
1068  * facility.
1069  */
1070 void
1071 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
1072 {
1073         MonoThreadHazardPointers *hp;
1074         MonoThreadInfo *info;
1075
1076         if (tid == mono_native_thread_id_get () || !mono_threads_suspend_needs_abort_syscall ())
1077                 return;
1078
1079         hp = mono_hazard_pointer_get ();
1080         info = mono_thread_info_lookup (tid);
1081         if (!info)
1082                 return;
1083
1084         if (mono_thread_info_run_state (info) == STATE_DETACHED) {
1085                 mono_hazard_pointer_clear (hp, 1);
1086                 return;
1087         }
1088
1089         mono_thread_info_suspend_lock ();
1090         mono_threads_begin_global_suspend ();
1091
1092         mono_threads_suspend_abort_syscall (info);
1093         mono_threads_wait_pending_operations ();
1094
1095         mono_hazard_pointer_clear (hp, 1);
1096
1097         mono_threads_end_global_suspend ();
1098         mono_thread_info_suspend_unlock ();
1099 }
1100
1101 gboolean
1102 mono_thread_info_unified_management_enabled (void)
1103 {
1104         return unified_suspend_enabled;
1105 }
1106
1107 /*
1108  * mono_thread_info_set_is_async_context:
1109  *
1110  *   Set whenever the current thread is in an async context. Some runtime functions might behave
1111  * differently while in an async context in order to be async safe.
1112  */
1113 void
1114 mono_thread_info_set_is_async_context (gboolean async_context)
1115 {
1116         MonoThreadInfo *info = mono_thread_info_current ();
1117
1118         if (info)
1119                 info->is_async_context = async_context;
1120 }
1121
1122 gboolean
1123 mono_thread_info_is_async_context (void)
1124 {
1125         MonoThreadInfo *info = mono_thread_info_current ();
1126
1127         if (info)
1128                 return info->is_async_context;
1129         else
1130                 return FALSE;
1131 }
1132
1133 typedef struct {
1134         gint32 ref;
1135         MonoThreadStart start_routine;
1136         gpointer start_routine_arg;
1137         gint32 priority;
1138         MonoCoopSem registered;
1139         gpointer handle;
1140 } CreateThreadData;
1141
1142 static gsize WINAPI
1143 inner_start_thread (gpointer data)
1144 {
1145         CreateThreadData *thread_data;
1146         MonoThreadInfo *info;
1147         MonoThreadStart start_routine;
1148         gpointer start_routine_arg;
1149         guint32 start_routine_res;
1150         gsize dummy;
1151
1152         thread_data = (CreateThreadData*) data;
1153         g_assert (thread_data);
1154
1155         start_routine = thread_data->start_routine;
1156         start_routine_arg = thread_data->start_routine_arg;
1157
1158         info = mono_thread_info_attach (&dummy);
1159         info->runtime_thread = TRUE;
1160
1161         thread_data->handle = mono_thread_info_duplicate_handle (info);
1162
1163         mono_coop_sem_post (&thread_data->registered);
1164
1165         if (InterlockedDecrement (&thread_data->ref) == 0) {
1166                 mono_coop_sem_destroy (&thread_data->registered);
1167                 g_free (thread_data);
1168         }
1169
1170         /* thread_data is not valid anymore */
1171         thread_data = NULL;
1172
1173         /* Run the actual main function of the thread */
1174         start_routine_res = start_routine (start_routine_arg);
1175
1176         mono_threads_platform_exit (start_routine_res);
1177
1178         g_assert_not_reached ();
1179 }
1180
1181 /*
1182  * mono_threads_create_thread:
1183  *
1184  *   Create a new thread executing START with argument ARG. Store its id into OUT_TID.
1185  * Returns: a windows or io-layer handle for the thread.
1186  */
1187 HANDLE
1188 mono_threads_create_thread (MonoThreadStart start, gpointer arg, gsize * const stack_size, MonoNativeThreadId *out_tid)
1189 {
1190         CreateThreadData *thread_data;
1191         gint res;
1192         gpointer ret;
1193
1194         thread_data = g_new0 (CreateThreadData, 1);
1195         thread_data->ref = 2;
1196         thread_data->start_routine = start;
1197         thread_data->start_routine_arg = arg;
1198         mono_coop_sem_init (&thread_data->registered, 0);
1199
1200         res = mono_threads_platform_create_thread (inner_start_thread, (gpointer) thread_data, stack_size, out_tid);
1201         if (res != 0) {
1202                 /* ref is not going to be decremented in inner_start_thread */
1203                 InterlockedDecrement (&thread_data->ref);
1204                 ret = NULL;
1205                 goto done;
1206         }
1207
1208         res = mono_coop_sem_wait (&thread_data->registered, MONO_SEM_FLAGS_NONE);
1209         g_assert (res == 0);
1210
1211         ret = thread_data->handle;
1212         g_assert (ret);
1213
1214 done:
1215         if (InterlockedDecrement (&thread_data->ref) == 0) {
1216                 mono_coop_sem_destroy (&thread_data->registered);
1217                 g_free (thread_data);
1218         }
1219
1220         return ret;
1221 }
1222
1223 /*
1224  * mono_thread_info_get_stack_bounds:
1225  *
1226  *   Return the address and size of the current threads stack. Return NULL as the 
1227  * stack address if the stack address cannot be determined.
1228  */
1229 void
1230 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize)
1231 {
1232         guint8 *current = (guint8 *)&stsize;
1233         mono_threads_platform_get_stack_bounds (staddr, stsize);
1234         if (!*staddr)
1235                 return;
1236
1237         /* Sanity check the result */
1238         g_assert ((current > *staddr) && (current < *staddr + *stsize));
1239
1240         /* When running under emacs, sometimes staddr is not aligned to a page size */
1241         *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
1242 }
1243
1244 gboolean
1245 mono_thread_info_yield (void)
1246 {
1247         return mono_threads_platform_yield ();
1248 }
1249 static mono_lazy_init_t sleep_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
1250 static MonoCoopMutex sleep_mutex;
1251 static MonoCoopCond sleep_cond;
1252
1253 static void
1254 sleep_initialize (void)
1255 {
1256         mono_coop_mutex_init (&sleep_mutex);
1257         mono_coop_cond_init (&sleep_cond);
1258 }
1259
1260 static void
1261 sleep_interrupt (gpointer data)
1262 {
1263         mono_coop_mutex_lock (&sleep_mutex);
1264         mono_coop_cond_broadcast (&sleep_cond);
1265         mono_coop_mutex_unlock (&sleep_mutex);
1266 }
1267
1268 static inline guint32
1269 sleep_interruptable (guint32 ms, gboolean *alerted)
1270 {
1271         gint64 now, end;
1272
1273         g_assert (INFINITE == G_MAXUINT32);
1274
1275         g_assert (alerted);
1276         *alerted = FALSE;
1277
1278         if (ms != INFINITE)
1279                 end = mono_msec_ticks() + ms;
1280
1281         mono_lazy_initialize (&sleep_init, sleep_initialize);
1282
1283         mono_coop_mutex_lock (&sleep_mutex);
1284
1285         for (;;) {
1286                 if (ms != INFINITE) {
1287                         now = mono_msec_ticks();
1288                         if (now >= end)
1289                                 break;
1290                 }
1291
1292                 mono_thread_info_install_interrupt (sleep_interrupt, NULL, alerted);
1293                 if (*alerted) {
1294                         mono_coop_mutex_unlock (&sleep_mutex);
1295                         return WAIT_IO_COMPLETION;
1296                 }
1297
1298                 if (ms != INFINITE)
1299                         mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, end - now);
1300                 else
1301                         mono_coop_cond_wait (&sleep_cond, &sleep_mutex);
1302
1303                 mono_thread_info_uninstall_interrupt (alerted);
1304                 if (*alerted) {
1305                         mono_coop_mutex_unlock (&sleep_mutex);
1306                         return WAIT_IO_COMPLETION;
1307                 }
1308         }
1309
1310         mono_coop_mutex_unlock (&sleep_mutex);
1311
1312         return 0;
1313 }
1314
1315 gint
1316 mono_thread_info_sleep (guint32 ms, gboolean *alerted)
1317 {
1318         if (ms == 0) {
1319                 MonoThreadInfo *info;
1320
1321                 mono_thread_info_yield ();
1322
1323                 info = mono_thread_info_current ();
1324                 if (info && mono_thread_info_is_interrupt_state (info))
1325                         return WAIT_IO_COMPLETION;
1326
1327                 return 0;
1328         }
1329
1330         if (alerted)
1331                 return sleep_interruptable (ms, alerted);
1332
1333         MONO_ENTER_GC_SAFE;
1334
1335         if (ms == INFINITE) {
1336                 do {
1337 #ifdef HOST_WIN32
1338                         Sleep (G_MAXUINT32);
1339 #else
1340                         sleep (G_MAXUINT32);
1341 #endif
1342                 } while (1);
1343         } else {
1344                 int ret;
1345 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
1346                 struct timespec start, target;
1347
1348                 /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
1349                 ret = clock_gettime (CLOCK_MONOTONIC, &start);
1350                 g_assert (ret == 0);
1351
1352                 target = start;
1353                 target.tv_sec += ms / 1000;
1354                 target.tv_nsec += (ms % 1000) * 1000000;
1355                 if (target.tv_nsec > 999999999) {
1356                         target.tv_nsec -= 999999999;
1357                         target.tv_sec ++;
1358                 }
1359
1360                 do {
1361                         ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
1362                 } while (ret != 0);
1363 #elif HOST_WIN32
1364                 Sleep (ms);
1365 #else
1366                 struct timespec req, rem;
1367
1368                 req.tv_sec = ms / 1000;
1369                 req.tv_nsec = (ms % 1000) * 1000000;
1370
1371                 do {
1372                         memset (&rem, 0, sizeof (rem));
1373                         ret = nanosleep (&req, &rem);
1374                 } while (ret != 0);
1375 #endif /* __linux__ */
1376         }
1377
1378         MONO_EXIT_GC_SAFE;
1379
1380         return 0;
1381 }
1382
1383 gint
1384 mono_thread_info_usleep (guint64 us)
1385 {
1386         MONO_ENTER_GC_SAFE;
1387         g_usleep (us);
1388         MONO_EXIT_GC_SAFE;
1389         return 0;
1390 }
1391
1392 gpointer
1393 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key)
1394 {
1395         return ((MonoThreadInfo*)info)->tls [key];
1396 }
1397
1398 /*
1399  * mono_threads_info_tls_set:
1400  *
1401  *   Set the TLS key to VALUE in the info structure. This can be used to obtain
1402  * values of TLS variables for threads other than the current thread.
1403  * This should only be used for infrequently changing TLS variables, and it should
1404  * be paired with setting the real TLS variable since this provides no GC tracking.
1405  */
1406 void
1407 mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value)
1408 {
1409         ((MonoThreadInfo*)info)->tls [key] = value;
1410 }
1411
1412 /*
1413  * mono_thread_info_exit:
1414  *
1415  *   Exit the current thread.
1416  * This function doesn't return.
1417  */
1418 void
1419 mono_thread_info_exit (void)
1420 {
1421         mono_threads_platform_exit (0);
1422 }
1423
1424 /*
1425  * mono_threads_open_thread_handle:
1426  *
1427  *   Return a io-layer/win32 handle for the thread identified by HANDLE/TID.
1428  * The handle need to be closed by calling CloseHandle () when it is no
1429  * longer needed.
1430  */
1431 HANDLE
1432 mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
1433 {
1434         return mono_threads_platform_open_thread_handle (handle, tid);
1435 }
1436
1437 void
1438 mono_threads_close_thread_handle (HANDLE handle)
1439 {
1440         return mono_threads_platform_close_thread_handle (handle);
1441 }
1442
1443 #define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1)
1444
1445 struct _MonoThreadInfoInterruptToken {
1446         void (*callback) (gpointer data);
1447         gpointer data;
1448 };
1449
1450 /*
1451  * mono_thread_info_install_interrupt: install an interruption token for the current thread.
1452  *
1453  *  - @callback: must be able to be called from another thread and always cancel the wait
1454  *  - @data: passed to the callback
1455  *  - @interrupted: will be set to TRUE if a token is already installed, FALSE otherwise
1456  *     if set to TRUE, it must mean that the thread is in interrupted state
1457  */
1458 void
1459 mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted)
1460 {
1461         MonoThreadInfo *info;
1462         MonoThreadInfoInterruptToken *previous_token, *token;
1463
1464         g_assert (callback);
1465
1466         g_assert (interrupted);
1467         *interrupted = FALSE;
1468
1469         info = mono_thread_info_current ();
1470         g_assert (info);
1471
1472         /* The memory of this token can be freed at 2 places:
1473          *  - if the token is not interrupted: it will be freed in uninstall, as info->interrupt_token has not been replaced
1474          *     by the INTERRUPT_STATE flag value, and it still contains the pointer to the memory location
1475          *  - if the token is interrupted: it will be freed in finish, as the token is now owned by the prepare/finish
1476          *     functions, and info->interrupt_token does not contains a pointer to the memory anymore */
1477         token = g_new0 (MonoThreadInfoInterruptToken, 1);
1478         token->callback = callback;
1479         token->data = data;
1480
1481         previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, token, NULL);
1482
1483         if (previous_token) {
1484                 if (previous_token != INTERRUPT_STATE)
1485                         g_error ("mono_thread_info_install_interrupt: previous_token should be INTERRUPT_STATE (%p), but it was %p", INTERRUPT_STATE, previous_token);
1486
1487                 g_free (token);
1488
1489                 *interrupted = TRUE;
1490         }
1491
1492         THREADS_INTERRUPT_DEBUG ("interrupt install    tid %p token %p previous_token %p interrupted %s\n",
1493                 mono_thread_info_get_tid (info), token, previous_token, *interrupted ? "TRUE" : "FALSE");
1494 }
1495
1496 void
1497 mono_thread_info_uninstall_interrupt (gboolean *interrupted)
1498 {
1499         MonoThreadInfo *info;
1500         MonoThreadInfoInterruptToken *previous_token;
1501
1502         g_assert (interrupted);
1503         *interrupted = FALSE;
1504
1505         info = mono_thread_info_current ();
1506         g_assert (info);
1507
1508         previous_token = (MonoThreadInfoInterruptToken *)InterlockedExchangePointer ((gpointer*) &info->interrupt_token, NULL);
1509
1510         /* only the installer can uninstall the token */
1511         g_assert (previous_token);
1512
1513         if (previous_token == INTERRUPT_STATE) {
1514                 /* if it is interrupted, then it is going to be freed in finish interrupt */
1515                 *interrupted = TRUE;
1516         } else {
1517                 g_free (previous_token);
1518         }
1519
1520         THREADS_INTERRUPT_DEBUG ("interrupt uninstall  tid %p previous_token %p interrupted %s\n",
1521                 mono_thread_info_get_tid (info), previous_token, *interrupted ? "TRUE" : "FALSE");
1522 }
1523
1524 static MonoThreadInfoInterruptToken*
1525 set_interrupt_state (MonoThreadInfo *info)
1526 {
1527         MonoThreadInfoInterruptToken *token, *previous_token;
1528
1529         g_assert (info);
1530
1531         /* Atomically obtain the token the thread is
1532         * waiting on, and change it to a flag value. */
1533
1534         do {
1535                 previous_token = info->interrupt_token;
1536
1537                 /* Already interrupted */
1538                 if (previous_token == INTERRUPT_STATE) {
1539                         token = NULL;
1540                         break;
1541                 }
1542
1543                 token = previous_token;
1544         } while (InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, INTERRUPT_STATE, previous_token) != previous_token);
1545
1546         return token;
1547 }
1548
1549 /*
1550  * mono_thread_info_prepare_interrupt:
1551  *
1552  * The state of the thread info interrupt token is set to 'interrupted' which means that :
1553  *  - if the thread calls one of the WaitFor functions, the function will return with
1554  *     WAIT_IO_COMPLETION instead of waiting
1555  *  - if the thread was waiting when this function was called, the wait will be broken
1556  *
1557  * It is possible that the wait functions return WAIT_IO_COMPLETION, but the target thread
1558  * didn't receive the interrupt signal yet, in this case it should call the wait function
1559  * again. This essentially means that the target thread will busy wait until it is ready to
1560  * process the interruption.
1561  */
1562 MonoThreadInfoInterruptToken*
1563 mono_thread_info_prepare_interrupt (MonoThreadInfo *info)
1564 {
1565         MonoThreadInfoInterruptToken *token;
1566
1567         token = set_interrupt_state (info);
1568
1569         THREADS_INTERRUPT_DEBUG ("interrupt prepare    tid %p token %p\n",
1570                 mono_thread_info_get_tid (info), token);
1571
1572         return token;
1573 }
1574
1575 void
1576 mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token)
1577 {
1578         THREADS_INTERRUPT_DEBUG ("interrupt finish     token %p\n", token);
1579
1580         if (token == NULL)
1581                 return;
1582
1583         g_assert (token->callback);
1584
1585         token->callback (token->data);
1586
1587         g_free (token);
1588 }
1589
1590 void
1591 mono_thread_info_self_interrupt (void)
1592 {
1593         MonoThreadInfo *info;
1594         MonoThreadInfoInterruptToken *token;
1595
1596         info = mono_thread_info_current ();
1597         g_assert (info);
1598
1599         token = set_interrupt_state (info);
1600         g_assert (!token);
1601
1602         THREADS_INTERRUPT_DEBUG ("interrupt self       tid %p\n",
1603                 mono_thread_info_get_tid (info));
1604 }
1605
1606 /* Clear the interrupted flag of the current thread, set with
1607  * mono_thread_info_self_interrupt, so it can wait again */
1608 void
1609 mono_thread_info_clear_self_interrupt ()
1610 {
1611         MonoThreadInfo *info;
1612         MonoThreadInfoInterruptToken *previous_token;
1613
1614         info = mono_thread_info_current ();
1615         g_assert (info);
1616
1617         previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, NULL, INTERRUPT_STATE);
1618         g_assert (previous_token == NULL || previous_token == INTERRUPT_STATE);
1619
1620         THREADS_INTERRUPT_DEBUG ("interrupt clear self tid %p previous_token %p\n", mono_thread_info_get_tid (info), previous_token);
1621 }
1622
1623 gboolean
1624 mono_thread_info_is_interrupt_state (MonoThreadInfo *info)
1625 {
1626         g_assert (info);
1627         return InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE;
1628 }
1629
1630 void
1631 mono_thread_info_describe_interrupt_token (MonoThreadInfo *info, GString *text)
1632 {
1633         g_assert (info);
1634
1635         if (!InterlockedReadPointer ((gpointer*) &info->interrupt_token))
1636                 g_string_append_printf (text, "not waiting");
1637         else if (InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE)
1638                 g_string_append_printf (text, "interrupted state");
1639         else
1640                 g_string_append_printf (text, "waiting");
1641 }
1642
1643 gboolean
1644 mono_thread_info_is_current (MonoThreadInfo *info)
1645 {
1646         return mono_thread_info_get_tid (info) == mono_native_thread_id_get ();
1647 }
1648
1649 void
1650 mono_thread_info_set_exited (THREAD_INFO_TYPE *info)
1651 {
1652         g_assert (mono_thread_info_is_current (info));
1653
1654         g_assert (info->handle);
1655         mono_threads_platform_set_exited (info->handle);
1656 }
1657
1658 gpointer
1659 mono_thread_info_duplicate_handle (MonoThreadInfo *info)
1660 {
1661         g_assert (mono_thread_info_is_current (info));
1662         return mono_threads_platform_duplicate_handle (info);
1663 }