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