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