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