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