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