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