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