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