e8893039fbf2eb2a89a828c4c4b7607f6a50ac44
[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;
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         /* Pump the HP queue while the thread is alive.*/
430         mono_thread_hazardous_try_free_some ();
431
432         small_id = info->small_id;
433
434         /* We only enter the GC unsafe region, as when exiting this function, the thread
435          * will be detached, and the current MonoThreadInfo* will be destroyed. */
436         mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, &gc_unsafe_stackdata);
437
438         THREADS_DEBUG ("unregistering info %p\n", info);
439
440         mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
441
442         /*
443          * TLS destruction order is not reliable so small_id might be cleaned up
444          * before us.
445          */
446 #ifndef HAVE_KW_THREAD
447         mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
448 #endif
449
450         /* we need to duplicate it, as the info->handle is going
451          * to be closed when unregistering from the platform */
452         handle = mono_threads_open_thread_handle (info->handle);
453
454         /*
455         First perform the callback that requires no locks.
456         This callback has the potential of taking other locks, so we do it before.
457         After it completes, the thread remains functional.
458         */
459         if (threads_callbacks.thread_detach)
460                 threads_callbacks.thread_detach (info);
461
462         mono_thread_info_suspend_lock_with_info (info);
463
464         /*
465         Now perform the callback that must be done under locks.
466         This will render the thread useless and non-suspendable, so it must
467         be done while holding the suspend lock to give no other thread chance
468         to suspend it.
469         */
470         if (threads_callbacks.thread_unregister)
471                 threads_callbacks.thread_unregister (info);
472
473         /* The thread is no longer active, so unref its handle */
474         mono_threads_close_thread_handle (info->handle);
475         info->handle = NULL;
476
477         result = mono_thread_info_remove (info);
478         g_assert (result);
479         mono_threads_transition_detach (info);
480
481         mono_thread_info_suspend_unlock ();
482
483         g_byte_array_free (info->stackdata, /*free_segment=*/TRUE);
484
485         /*now it's safe to free the thread info.*/
486         mono_thread_hazardous_try_free (info, free_thread_info);
487
488         mono_thread_small_id_free (small_id);
489
490         mono_threads_signal_thread_handle (handle);
491
492         mono_threads_close_thread_handle (handle);
493 }
494
495 static void
496 thread_exited_dtor (void *arg)
497 {
498 #if defined(__MACH__)
499         /*
500          * Since we use pthread dtors to clean up thread data, if a thread
501          * is attached to the runtime by another pthread dtor after our dtor
502          * has ran, it will never be detached, leading to various problems
503          * since the thread ids etc. will be reused while they are still in
504          * the threads hashtables etc.
505          * Dtors are called in a loop until all user tls entries are 0,
506          * but the loop has a maximum count (4), so if we set the tls
507          * variable every time, it will remain set when system tls dtors
508          * are ran. This allows mono_thread_info_is_exiting () to detect
509          * whenever the thread is exiting, even if it is executed from a
510          * system tls dtor (i.e. obj-c dealloc methods).
511          */
512         mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
513 #endif
514 }
515
516 MonoThreadInfo*
517 mono_thread_info_current_unchecked (void)
518 {
519         return mono_threads_inited ? (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key) : NULL;
520 }
521
522
523 MonoThreadInfo*
524 mono_thread_info_current (void)
525 {
526         MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
527         if (info)
528                 return info;
529
530         info = mono_thread_info_lookup (mono_native_thread_id_get ()); /*info on HP1*/
531
532         /*
533         We might be called during thread cleanup, but we cannot be called after cleanup as happened.
534         The way to distinguish between before, during and after cleanup is the following:
535
536         -If the TLS key is set, cleanup has not begun;
537         -If the TLS key is clean, but the thread remains registered, cleanup is in progress;
538         -If the thread is nowhere to be found, cleanup has finished.
539
540         We cannot function after cleanup since there's no way to ensure what will happen.
541         */
542         g_assert (info);
543
544         /*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 */
545         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
546
547         return info;
548 }
549
550 int
551 mono_thread_info_get_small_id (void)
552 {
553 #ifdef HAVE_KW_THREAD
554         return tls_small_id;
555 #else
556         gpointer val = mono_native_tls_get_value (small_id_key);
557         if (!val)
558                 return -1;
559         return GPOINTER_TO_INT (val) - 1;
560 #endif
561 }
562
563 MonoLinkedListSet*
564 mono_thread_info_list_head (void)
565 {
566         return &thread_list;
567 }
568
569 /**
570  * mono_threads_attach_tools_thread
571  *
572  * Attach the current thread as a tool thread. DON'T USE THIS FUNCTION WITHOUT READING ALL DISCLAIMERS.
573  *
574  * A tools thread is a very special kind of thread that needs access to core runtime facilities but should
575  * not be counted as a regular thread for high order facilities such as executing managed code or accessing
576  * the managed heap.
577  *
578  * This is intended only to tools such as a profiler than needs to be able to use our lock-free support when
579  * doing things like resolving backtraces in their background processing thread.
580  */
581 void
582 mono_threads_attach_tools_thread (void)
583 {
584         int dummy = 0;
585         MonoThreadInfo *info;
586
587         /* Must only be called once */
588         g_assert (!mono_native_tls_get_value (thread_info_key));
589         
590         while (!mono_threads_inited) { 
591                 mono_thread_info_usleep (10);
592         }
593
594         info = mono_thread_info_attach (&dummy);
595         g_assert (info);
596
597         info->tools_thread = TRUE;
598 }
599
600 MonoThreadInfo*
601 mono_thread_info_attach (void *baseptr)
602 {
603         MonoThreadInfo *info;
604         if (!mono_threads_inited)
605         {
606 #ifdef HOST_WIN32
607                 /* This can happen from DllMain(DLL_THREAD_ATTACH) on Windows, if a
608                  * thread is created before an embedding API user initialized Mono. */
609                 THREADS_DEBUG ("mono_thread_info_attach called before mono_threads_init\n");
610                 return NULL;
611 #else
612                 g_assert (mono_threads_inited);
613 #endif
614         }
615         info = (MonoThreadInfo *) mono_native_tls_get_value (thread_info_key);
616         if (!info) {
617                 info = (MonoThreadInfo *) g_malloc0 (thread_info_size);
618                 THREADS_DEBUG ("attaching %p\n", info);
619                 if (!register_thread (info, baseptr))
620                         return NULL;
621         } else if (threads_callbacks.thread_attach) {
622                 threads_callbacks.thread_attach (info);
623         }
624         return info;
625 }
626
627 void
628 mono_thread_info_detach (void)
629 {
630         MonoThreadInfo *info;
631         if (!mono_threads_inited)
632         {
633                 /* This can happen from DllMain(THREAD_DETACH) on Windows, if a thread
634                  * is created before an embedding API user initialized Mono. */
635                 THREADS_DEBUG ("mono_thread_info_detach called before mono_threads_init\n");
636                 return;
637         }
638         info = (MonoThreadInfo *) mono_native_tls_get_value (thread_info_key);
639         if (info) {
640                 THREADS_DEBUG ("detaching %p\n", info);
641                 unregister_thread (info);
642                 mono_native_tls_set_value (thread_info_key, NULL);
643         }
644 }
645
646 /*
647  * mono_thread_info_is_exiting:
648  *
649  *   Return whenever the current thread is exiting, i.e. it is running pthread
650  * dtors.
651  */
652 gboolean
653 mono_thread_info_is_exiting (void)
654 {
655 #if defined(__MACH__)
656         if (mono_native_tls_get_value (thread_exited_key) == GUINT_TO_POINTER (1))
657                 return TRUE;
658 #endif
659         return FALSE;
660 }
661
662 #ifndef HOST_WIN32
663 static void
664 thread_info_key_dtor (void *arg)
665 {
666         /* Put the MonoThreadInfo back for the duration of the
667          * unregister code.  In some circumstances the thread needs to
668          * take the GC lock which may block which requires a coop
669          * state transition. */
670         mono_native_tls_set_value (thread_info_key, arg);
671         unregister_thread (arg);
672         mono_native_tls_set_value (thread_info_key, NULL);
673 }
674 #endif
675
676 void
677 mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
678 {
679         gboolean res;
680         threads_callbacks = *callbacks;
681         thread_info_size = info_size;
682         const char *sleepLimit;
683 #ifdef HOST_WIN32
684         res = mono_native_tls_alloc (&thread_info_key, NULL);
685         res = mono_native_tls_alloc (&thread_exited_key, NULL);
686 #else
687         res = mono_native_tls_alloc (&thread_info_key, (void *) thread_info_key_dtor);
688         res = mono_native_tls_alloc (&thread_exited_key, (void *) thread_exited_dtor);
689 #endif
690
691         g_assert (res);
692
693 #ifndef HAVE_KW_THREAD
694         res = mono_native_tls_alloc (&small_id_key, NULL);
695 #endif
696         g_assert (res);
697
698         if ((sleepLimit = g_getenv ("MONO_SLEEP_ABORT_LIMIT")) != NULL) {
699                 errno = 0;
700                 long threshold = strtol(sleepLimit, NULL, 10);
701                 if ((errno == 0) && (threshold >= 40))  {
702                         sleepAbortDuration = threshold;
703                         sleepWarnDuration = threshold / 20;
704                 } else
705                         g_warning("MONO_SLEEP_ABORT_LIMIT must be a number >= 40");
706         }
707
708         mono_os_sem_init (&global_suspend_semaphore, 1);
709         mono_os_sem_init (&suspend_semaphore, 0);
710
711         mono_lls_init (&thread_list, NULL);
712         mono_thread_smr_init ();
713         mono_threads_suspend_init ();
714         mono_threads_coop_init ();
715         mono_threads_platform_init ();
716
717 #if defined(__MACH__)
718         mono_mach_init (thread_info_key);
719 #endif
720
721         mono_threads_inited = TRUE;
722
723         g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
724 }
725
726 void
727 mono_threads_signals_init (void)
728 {
729         mono_threads_suspend_init_signals ();
730 }
731
732 void
733 mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks)
734 {
735         runtime_callbacks = *callbacks;
736 }
737
738 MonoThreadInfoRuntimeCallbacks *
739 mono_threads_get_runtime_callbacks (void)
740 {
741         return &runtime_callbacks;
742 }
743
744 static gboolean
745 mono_thread_info_core_resume (MonoThreadInfo *info)
746 {
747         gboolean res = FALSE;
748
749         switch (mono_threads_transition_request_resume (info)) {
750         case ResumeError:
751                 res = FALSE;
752                 break;
753         case ResumeOk:
754                 res = TRUE;
755                 break;
756         case ResumeInitSelfResume:
757                 resume_self_suspended (info);
758                 res = TRUE;
759                 break;
760         case ResumeInitAsyncResume:
761                 resume_async_suspended (info);
762                 res = TRUE;
763                 break;
764         case ResumeInitBlockingResume:
765                 resume_blocking_suspended (info);
766                 res = TRUE;
767                 break;
768         }
769
770         return res;
771 }
772
773 gboolean
774 mono_thread_info_resume (MonoNativeThreadId tid)
775 {
776         gboolean result; /* don't initialize it so the compiler can catch unitilized paths. */
777         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
778         MonoThreadInfo *info;
779
780         THREADS_SUSPEND_DEBUG ("RESUMING tid %p\n", (void*)tid);
781
782         mono_thread_info_suspend_lock ();
783
784         info = mono_thread_info_lookup (tid); /*info on HP1*/
785         if (!info) {
786                 result = FALSE;
787                 goto cleanup;
788         }
789
790         result = mono_thread_info_core_resume (info);
791
792         //Wait for the pending resume to finish
793         mono_threads_wait_pending_operations ();
794
795 cleanup:
796         mono_thread_info_suspend_unlock ();
797         mono_hazard_pointer_clear (hp, 1);
798         return result;
799 }
800
801 gboolean
802 mono_thread_info_begin_suspend (MonoThreadInfo *info)
803 {
804         switch (mono_threads_transition_request_async_suspension (info)) {
805         case AsyncSuspendAlreadySuspended:
806         case AsyncSuspendBlocking:
807                 return TRUE;
808         case AsyncSuspendWait:
809                 mono_threads_add_to_pending_operation_set (info);
810                 return TRUE;
811         case AsyncSuspendInitSuspend:
812                 return begin_async_suspend (info, FALSE);
813         default:
814                 g_assert_not_reached ();
815         }
816 }
817
818 gboolean
819 mono_thread_info_begin_resume (MonoThreadInfo *info)
820 {
821         return mono_thread_info_core_resume (info);
822 }
823
824 /*
825 FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
826 WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
827 */
828 static gboolean
829 is_thread_in_critical_region (MonoThreadInfo *info)
830 {
831         MonoMethod *method;
832         MonoJitInfo *ji;
833         gpointer stack_start;
834         MonoThreadUnwindState *state;
835
836         if (mono_threads_platform_in_critical_region (mono_thread_info_get_tid (info)))
837                 return TRUE;
838
839         /* Are we inside a system critical region? */
840         if (info->inside_critical_region)
841                 return TRUE;
842
843         /* Are we inside a GC critical region? */
844         if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
845                 return TRUE;
846         }
847
848         /* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
849         state = mono_thread_info_get_suspend_state (info);
850         if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
851                 return FALSE;
852
853         stack_start = MONO_CONTEXT_GET_SP (&state->ctx);
854         /* altstack signal handler, sgen can't handle them, so we treat them as critical */
855         if (stack_start < info->stack_start_limit || stack_start >= info->stack_end)
856                 return TRUE;
857
858         if (threads_callbacks.ip_in_critical_region)
859                 return threads_callbacks.ip_in_critical_region ((MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN], (char *) MONO_CONTEXT_GET_IP (&state->ctx));
860
861         ji = mono_jit_info_table_find (
862                 (MonoDomain *) state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
863                 (char *) MONO_CONTEXT_GET_IP (&state->ctx));
864
865         if (!ji)
866                 return FALSE;
867
868         method = mono_jit_info_get_method (ji);
869
870         return threads_callbacks.mono_method_is_critical (method);
871 }
872
873 gboolean
874 mono_thread_info_in_critical_location (MonoThreadInfo *info)
875 {
876         return is_thread_in_critical_region (info);
877 }
878
879 /*
880 The return value is only valid until a matching mono_thread_info_resume is called
881 */
882 static MonoThreadInfo*
883 suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel)
884 {
885         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
886         MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
887         if (!info)
888                 return NULL;
889
890         switch (mono_threads_transition_request_async_suspension (info)) {
891         case AsyncSuspendAlreadySuspended:
892                 mono_hazard_pointer_clear (hp, 1); //XXX this is questionable we got to clean the suspend/resume nonsense of critical sections
893                 return info;
894         case AsyncSuspendWait:
895                 mono_threads_add_to_pending_operation_set (info);
896                 break;
897         case AsyncSuspendInitSuspend:
898                 if (!begin_async_suspend (info, interrupt_kernel)) {
899                         mono_hazard_pointer_clear (hp, 1);
900                         return NULL;
901                 }
902                 break;
903         case AsyncSuspendBlocking:
904                 if (interrupt_kernel && mono_threads_suspend_needs_abort_syscall ())
905                         mono_threads_suspend_abort_syscall (info);
906
907                 break;
908         default:
909                 g_assert_not_reached ();
910         }
911
912         //Wait for the pending suspend to finish
913         mono_threads_wait_pending_operations ();
914
915         if (!check_async_suspend (info)) {
916                 mono_thread_info_core_resume (info);
917                 mono_threads_wait_pending_operations ();
918                 mono_hazard_pointer_clear (hp, 1);
919                 return NULL;
920         }
921         return info;
922 }
923
924 static MonoThreadInfo*
925 suspend_sync_nolock (MonoNativeThreadId id, gboolean interrupt_kernel)
926 {
927         MonoThreadInfo *info = NULL;
928         int sleep_duration = 0;
929         for (;;) {
930                 if (!(info = suspend_sync (id, interrupt_kernel))) {
931                         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
932                         return NULL;
933                 }
934
935                 /*WARNING: We now are in interrupt context until we resume the thread. */
936                 if (!is_thread_in_critical_region (info))
937                         break;
938
939                 if (!mono_thread_info_core_resume (info)) {
940                         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
941                         return NULL;
942                 }
943                 THREADS_SUSPEND_DEBUG ("RESTARTED thread tid %p\n", (void*)id);
944
945                 /* Wait for the pending resume to finish */
946                 mono_threads_wait_pending_operations ();
947
948                 if (sleep_duration == 0)
949                         mono_thread_info_yield ();
950                 else
951                         g_usleep (sleep_duration);
952
953                 sleep_duration += 10;
954         }
955         return info;
956 }
957
958 void
959 mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data)
960 {
961         int result;
962         MonoThreadInfo *info = NULL;
963         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
964
965         THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id);
966         /*FIXME: unify this with self-suspend*/
967         g_assert (id != mono_native_thread_id_get ());
968
969         /* This can block during stw */
970         mono_thread_info_suspend_lock ();
971         mono_threads_begin_global_suspend ();
972
973         info = suspend_sync_nolock (id, interrupt_kernel);
974         if (!info)
975                 goto done;
976
977         switch (result = callback (info, user_data)) {
978         case MonoResumeThread:
979                 mono_hazard_pointer_set (hp, 1, info);
980                 mono_thread_info_core_resume (info);
981                 mono_threads_wait_pending_operations ();
982                 break;
983         case KeepSuspended:
984                 g_assert (!mono_threads_is_coop_enabled ());
985                 break;
986         default:
987                 g_error ("Invalid suspend_and_run callback return value %d", result);
988         }
989
990 done:
991         mono_hazard_pointer_clear (hp, 1);
992         mono_threads_end_global_suspend ();
993         mono_thread_info_suspend_unlock ();
994 }
995
996 /**
997 Inject an assynchronous call into the target thread. The target thread must be suspended and
998 only a single async call can be setup for a given suspend cycle.
999 This async call must cause stack unwinding as the current implementation doesn't save enough state
1000 to resume execution of the top-of-stack function. It's an acceptable limitation since this is
1001 currently used only to deliver exceptions.
1002 */
1003 void
1004 mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
1005 {
1006         /* An async call can only be setup on an async suspended thread */
1007         g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED);
1008         /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
1009         g_assert (!info->async_target);
1010         info->async_target = target_func;
1011         /* This is not GC tracked */
1012         info->user_data = user_data;
1013 }
1014
1015 /*
1016 The suspend lock is held during any suspend in progress.
1017 A GC that has safepoints must take this lock as part of its
1018 STW to make sure no unsafe pending suspend is in progress.   
1019 */
1020
1021 static void
1022 mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info)
1023 {
1024         g_assert (info);
1025         g_assert (mono_thread_info_is_current (info));
1026         g_assert (mono_thread_info_is_live (info));
1027
1028         MONO_ENTER_GC_SAFE_WITH_INFO(info);
1029
1030         int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
1031         g_assert (res != -1);
1032
1033         MONO_EXIT_GC_SAFE_WITH_INFO;
1034 }
1035
1036 void
1037 mono_thread_info_suspend_lock (void)
1038 {
1039         mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ());
1040 }
1041
1042 void
1043 mono_thread_info_suspend_unlock (void)
1044 {
1045         mono_os_sem_post (&global_suspend_semaphore);
1046 }
1047
1048 /*
1049  * This is a very specific function whose only purpose is to
1050  * break a given thread from socket syscalls.
1051  *
1052  * This only exists because linux won't fail a call to connect
1053  * if the underlying is closed.
1054  *
1055  * TODO We should cleanup and unify this with the other syscall abort
1056  * facility.
1057  */
1058 void
1059 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
1060 {
1061         MonoThreadHazardPointers *hp;
1062         MonoThreadInfo *info;
1063
1064         if (tid == mono_native_thread_id_get () || !mono_threads_suspend_needs_abort_syscall ())
1065                 return;
1066
1067         hp = mono_hazard_pointer_get ();
1068         info = mono_thread_info_lookup (tid);
1069         if (!info)
1070                 return;
1071
1072         if (mono_thread_info_run_state (info) == STATE_DETACHED) {
1073                 mono_hazard_pointer_clear (hp, 1);
1074                 return;
1075         }
1076
1077         mono_thread_info_suspend_lock ();
1078         mono_threads_begin_global_suspend ();
1079
1080         mono_threads_suspend_abort_syscall (info);
1081         mono_threads_wait_pending_operations ();
1082
1083         mono_hazard_pointer_clear (hp, 1);
1084
1085         mono_threads_end_global_suspend ();
1086         mono_thread_info_suspend_unlock ();
1087 }
1088
1089 /*
1090  * mono_thread_info_set_is_async_context:
1091  *
1092  *   Set whenever the current thread is in an async context. Some runtime functions might behave
1093  * differently while in an async context in order to be async safe.
1094  */
1095 void
1096 mono_thread_info_set_is_async_context (gboolean async_context)
1097 {
1098         MonoThreadInfo *info = mono_thread_info_current ();
1099
1100         if (info)
1101                 info->is_async_context = async_context;
1102 }
1103
1104 gboolean
1105 mono_thread_info_is_async_context (void)
1106 {
1107         MonoThreadInfo *info = mono_thread_info_current ();
1108
1109         if (info)
1110                 return info->is_async_context;
1111         else
1112                 return FALSE;
1113 }
1114
1115 typedef struct {
1116         MonoRefCount ref;
1117         MonoThreadStart start_routine;
1118         gpointer start_routine_arg;
1119         MonoCoopSem registered;
1120         MonoThreadHandle *handle;
1121 } CreateThreadData;
1122
1123 static void
1124 create_thread_data_destroy (gpointer data)
1125 {
1126         CreateThreadData *thread_data;
1127
1128         thread_data = (CreateThreadData*) data;
1129
1130         mono_coop_sem_destroy (&thread_data->registered);
1131         g_free (thread_data);
1132 }
1133
1134 static gsize WINAPI
1135 inner_start_thread (gpointer data)
1136 {
1137         CreateThreadData *thread_data;
1138         MonoThreadInfo *info;
1139         MonoThreadStart start_routine;
1140         gpointer start_routine_arg;
1141         gsize start_routine_res;
1142         gsize dummy;
1143
1144         thread_data = (CreateThreadData*) data;
1145         g_assert (thread_data);
1146
1147         start_routine = thread_data->start_routine;
1148         start_routine_arg = thread_data->start_routine_arg;
1149
1150         info = mono_thread_info_attach (&dummy);
1151         info->runtime_thread = TRUE;
1152
1153         thread_data->handle = mono_threads_open_thread_handle (info->handle);
1154
1155         mono_coop_sem_post (&thread_data->registered);
1156
1157         mono_refcount_dec (thread_data);
1158
1159         /* thread_data is not valid anymore */
1160         thread_data = NULL;
1161
1162         /* Run the actual main function of the thread */
1163         start_routine_res = start_routine (start_routine_arg);
1164
1165         mono_thread_info_exit (start_routine_res);
1166
1167         g_assert_not_reached ();
1168 }
1169
1170 /*
1171  * mono_threads_create_thread:
1172  *
1173  *   Create a new thread executing START with argument ARG. Store its id into OUT_TID.
1174  * Returns: a windows or io-layer handle for the thread.
1175  */
1176 MonoThreadHandle*
1177 mono_threads_create_thread (MonoThreadStart start, gpointer arg, gsize * const stack_size, MonoNativeThreadId *out_tid)
1178 {
1179         CreateThreadData *thread_data;
1180         gint res;
1181         MonoThreadHandle *ret;
1182
1183         thread_data = g_new0 (CreateThreadData, 1);
1184         mono_refcount_init (thread_data, create_thread_data_destroy);
1185         thread_data->start_routine = start;
1186         thread_data->start_routine_arg = arg;
1187         mono_coop_sem_init (&thread_data->registered, 0);
1188
1189         res = mono_threads_platform_create_thread (inner_start_thread, (gpointer) mono_refcount_inc (thread_data), stack_size, out_tid);
1190         if (res != 0) {
1191                 /* ref is not going to be decremented in inner_start_thread */
1192                 mono_refcount_dec (thread_data);
1193                 ret = NULL;
1194                 goto done;
1195         }
1196
1197         res = mono_coop_sem_wait (&thread_data->registered, MONO_SEM_FLAGS_NONE);
1198         g_assert (res == 0);
1199
1200         ret = thread_data->handle;
1201         g_assert (ret);
1202
1203 done:
1204         mono_refcount_dec (thread_data);
1205
1206         return ret;
1207 }
1208
1209 /*
1210  * mono_thread_info_get_stack_bounds:
1211  *
1212  *   Return the address and size of the current threads stack. Return NULL as the 
1213  * stack address if the stack address cannot be determined.
1214  */
1215 void
1216 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize)
1217 {
1218         guint8 *current = (guint8 *)&stsize;
1219         mono_threads_platform_get_stack_bounds (staddr, stsize);
1220         if (!*staddr)
1221                 return;
1222
1223         /* Sanity check the result */
1224         g_assert ((current > *staddr) && (current < *staddr + *stsize));
1225
1226         /* When running under emacs, sometimes staddr is not aligned to a page size */
1227         *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
1228 }
1229
1230 gboolean
1231 mono_thread_info_yield (void)
1232 {
1233         return mono_threads_platform_yield ();
1234 }
1235 static mono_lazy_init_t sleep_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
1236 static MonoCoopMutex sleep_mutex;
1237 static MonoCoopCond sleep_cond;
1238
1239 static void
1240 sleep_initialize (void)
1241 {
1242         mono_coop_mutex_init (&sleep_mutex);
1243         mono_coop_cond_init (&sleep_cond);
1244 }
1245
1246 static void
1247 sleep_interrupt (gpointer data)
1248 {
1249         mono_coop_mutex_lock (&sleep_mutex);
1250         mono_coop_cond_broadcast (&sleep_cond);
1251         mono_coop_mutex_unlock (&sleep_mutex);
1252 }
1253
1254 static inline guint32
1255 sleep_interruptable (guint32 ms, gboolean *alerted)
1256 {
1257         gint64 now, end;
1258
1259         g_assert (MONO_INFINITE_WAIT == G_MAXUINT32);
1260
1261         g_assert (alerted);
1262         *alerted = FALSE;
1263
1264         if (ms != MONO_INFINITE_WAIT)
1265                 end = mono_msec_ticks() + ms;
1266
1267         mono_lazy_initialize (&sleep_init, sleep_initialize);
1268
1269         mono_coop_mutex_lock (&sleep_mutex);
1270
1271         for (;;) {
1272                 if (ms != MONO_INFINITE_WAIT) {
1273                         now = mono_msec_ticks();
1274                         if (now >= end)
1275                                 break;
1276                 }
1277
1278                 mono_thread_info_install_interrupt (sleep_interrupt, NULL, alerted);
1279                 if (*alerted) {
1280                         mono_coop_mutex_unlock (&sleep_mutex);
1281                         return WAIT_IO_COMPLETION;
1282                 }
1283
1284                 if (ms != MONO_INFINITE_WAIT)
1285                         mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, end - now);
1286                 else
1287                         mono_coop_cond_wait (&sleep_cond, &sleep_mutex);
1288
1289                 mono_thread_info_uninstall_interrupt (alerted);
1290                 if (*alerted) {
1291                         mono_coop_mutex_unlock (&sleep_mutex);
1292                         return WAIT_IO_COMPLETION;
1293                 }
1294         }
1295
1296         mono_coop_mutex_unlock (&sleep_mutex);
1297
1298         return 0;
1299 }
1300
1301 gint
1302 mono_thread_info_sleep (guint32 ms, gboolean *alerted)
1303 {
1304         if (ms == 0) {
1305                 MonoThreadInfo *info;
1306
1307                 mono_thread_info_yield ();
1308
1309                 info = mono_thread_info_current ();
1310                 if (info && mono_thread_info_is_interrupt_state (info))
1311                         return WAIT_IO_COMPLETION;
1312
1313                 return 0;
1314         }
1315
1316         if (alerted)
1317                 return sleep_interruptable (ms, alerted);
1318
1319         MONO_ENTER_GC_SAFE;
1320
1321         if (ms == MONO_INFINITE_WAIT) {
1322                 do {
1323 #ifdef HOST_WIN32
1324                         Sleep (G_MAXUINT32);
1325 #else
1326                         sleep (G_MAXUINT32);
1327 #endif
1328                 } while (1);
1329         } else {
1330                 int ret;
1331 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
1332                 struct timespec start, target;
1333
1334                 /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
1335                 ret = clock_gettime (CLOCK_MONOTONIC, &start);
1336                 g_assert (ret == 0);
1337
1338                 target = start;
1339                 target.tv_sec += ms / 1000;
1340                 target.tv_nsec += (ms % 1000) * 1000000;
1341                 if (target.tv_nsec > 999999999) {
1342                         target.tv_nsec -= 999999999;
1343                         target.tv_sec ++;
1344                 }
1345
1346                 do {
1347                         ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
1348                 } while (ret != 0);
1349 #elif HOST_WIN32
1350                 Sleep (ms);
1351 #else
1352                 struct timespec req, rem;
1353
1354                 req.tv_sec = ms / 1000;
1355                 req.tv_nsec = (ms % 1000) * 1000000;
1356
1357                 do {
1358                         memset (&rem, 0, sizeof (rem));
1359                         ret = nanosleep (&req, &rem);
1360                 } while (ret != 0);
1361 #endif /* __linux__ */
1362         }
1363
1364         MONO_EXIT_GC_SAFE;
1365
1366         return 0;
1367 }
1368
1369 gint
1370 mono_thread_info_usleep (guint64 us)
1371 {
1372         MONO_ENTER_GC_SAFE;
1373         g_usleep (us);
1374         MONO_EXIT_GC_SAFE;
1375         return 0;
1376 }
1377
1378 gpointer
1379 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key)
1380 {
1381         return ((MonoThreadInfo*)info)->tls [key];
1382 }
1383
1384 /*
1385  * mono_threads_info_tls_set:
1386  *
1387  *   Set the TLS key to VALUE in the info structure. This can be used to obtain
1388  * values of TLS variables for threads other than the current thread.
1389  * This should only be used for infrequently changing TLS variables, and it should
1390  * be paired with setting the real TLS variable since this provides no GC tracking.
1391  */
1392 void
1393 mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value)
1394 {
1395         ((MonoThreadInfo*)info)->tls [key] = value;
1396 }
1397
1398 #if defined(__native_client__)
1399 void nacl_shutdown_gc_thread(void);
1400 #endif
1401
1402 /*
1403  * mono_thread_info_exit:
1404  *
1405  *   Exit the current thread.
1406  * This function doesn't return.
1407  */
1408 void
1409 mono_thread_info_exit (gsize exit_code)
1410 {
1411 #if defined(__native_client__)
1412         nacl_shutdown_gc_thread();
1413 #endif
1414
1415         mono_thread_info_detach ();
1416
1417         mono_threads_platform_exit (0);
1418 }
1419
1420 /*
1421  * mono_threads_open_thread_handle:
1422  *
1423  *  Duplicate the handle. The handle needs to be closed by calling
1424  *  mono_threads_close_thread_handle () when it is no longer needed.
1425  */
1426 MonoThreadHandle*
1427 mono_threads_open_thread_handle (MonoThreadHandle *thread_handle)
1428 {
1429         return mono_refcount_inc (thread_handle);
1430 }
1431
1432 void
1433 mono_threads_close_thread_handle (MonoThreadHandle *thread_handle)
1434 {
1435         mono_refcount_dec (thread_handle);
1436 }
1437
1438 static void
1439 mono_threads_signal_thread_handle (MonoThreadHandle* thread_handle)
1440 {
1441         mono_os_event_set (&thread_handle->event);
1442 }
1443
1444 #define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1)
1445
1446 struct _MonoThreadInfoInterruptToken {
1447         void (*callback) (gpointer data);
1448         gpointer data;
1449 };
1450
1451 /*
1452  * mono_thread_info_install_interrupt: install an interruption token for the current thread.
1453  *
1454  *  - @callback: must be able to be called from another thread and always cancel the wait
1455  *  - @data: passed to the callback
1456  *  - @interrupted: will be set to TRUE if a token is already installed, FALSE otherwise
1457  *     if set to TRUE, it must mean that the thread is in interrupted state
1458  */
1459 void
1460 mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted)
1461 {
1462         MonoThreadInfo *info;
1463         MonoThreadInfoInterruptToken *previous_token, *token;
1464
1465         g_assert (callback);
1466
1467         g_assert (interrupted);
1468         *interrupted = FALSE;
1469
1470         info = mono_thread_info_current ();
1471         g_assert (info);
1472
1473         /* The memory of this token can be freed at 2 places:
1474          *  - if the token is not interrupted: it will be freed in uninstall, as info->interrupt_token has not been replaced
1475          *     by the INTERRUPT_STATE flag value, and it still contains the pointer to the memory location
1476          *  - if the token is interrupted: it will be freed in finish, as the token is now owned by the prepare/finish
1477          *     functions, and info->interrupt_token does not contains a pointer to the memory anymore */
1478         token = g_new0 (MonoThreadInfoInterruptToken, 1);
1479         token->callback = callback;
1480         token->data = data;
1481
1482         previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, token, NULL);
1483
1484         if (previous_token) {
1485                 if (previous_token != INTERRUPT_STATE)
1486                         g_error ("mono_thread_info_install_interrupt: previous_token should be INTERRUPT_STATE (%p), but it was %p", INTERRUPT_STATE, previous_token);
1487
1488                 g_free (token);
1489
1490                 *interrupted = TRUE;
1491         }
1492
1493         THREADS_INTERRUPT_DEBUG ("interrupt install    tid %p token %p previous_token %p interrupted %s\n",
1494                 mono_thread_info_get_tid (info), token, previous_token, *interrupted ? "TRUE" : "FALSE");
1495 }
1496
1497 void
1498 mono_thread_info_uninstall_interrupt (gboolean *interrupted)
1499 {
1500         MonoThreadInfo *info;
1501         MonoThreadInfoInterruptToken *previous_token;
1502
1503         g_assert (interrupted);
1504         *interrupted = FALSE;
1505
1506         info = mono_thread_info_current ();
1507         g_assert (info);
1508
1509         previous_token = (MonoThreadInfoInterruptToken *)InterlockedExchangePointer ((gpointer*) &info->interrupt_token, NULL);
1510
1511         /* only the installer can uninstall the token */
1512         g_assert (previous_token);
1513
1514         if (previous_token == INTERRUPT_STATE) {
1515                 /* if it is interrupted, then it is going to be freed in finish interrupt */
1516                 *interrupted = TRUE;
1517         } else {
1518                 g_free (previous_token);
1519         }
1520
1521         THREADS_INTERRUPT_DEBUG ("interrupt uninstall  tid %p previous_token %p interrupted %s\n",
1522                 mono_thread_info_get_tid (info), previous_token, *interrupted ? "TRUE" : "FALSE");
1523 }
1524
1525 static MonoThreadInfoInterruptToken*
1526 set_interrupt_state (MonoThreadInfo *info)
1527 {
1528         MonoThreadInfoInterruptToken *token, *previous_token;
1529
1530         g_assert (info);
1531
1532         /* Atomically obtain the token the thread is
1533         * waiting on, and change it to a flag value. */
1534
1535         do {
1536                 previous_token = info->interrupt_token;
1537
1538                 /* Already interrupted */
1539                 if (previous_token == INTERRUPT_STATE) {
1540                         token = NULL;
1541                         break;
1542                 }
1543
1544                 token = previous_token;
1545         } while (InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, INTERRUPT_STATE, previous_token) != previous_token);
1546
1547         return token;
1548 }
1549
1550 /*
1551  * mono_thread_info_prepare_interrupt:
1552  *
1553  * The state of the thread info interrupt token is set to 'interrupted' which means that :
1554  *  - if the thread calls one of the WaitFor functions, the function will return with
1555  *     WAIT_IO_COMPLETION instead of waiting
1556  *  - if the thread was waiting when this function was called, the wait will be broken
1557  *
1558  * It is possible that the wait functions return WAIT_IO_COMPLETION, but the target thread
1559  * didn't receive the interrupt signal yet, in this case it should call the wait function
1560  * again. This essentially means that the target thread will busy wait until it is ready to
1561  * process the interruption.
1562  */
1563 MonoThreadInfoInterruptToken*
1564 mono_thread_info_prepare_interrupt (MonoThreadInfo *info)
1565 {
1566         MonoThreadInfoInterruptToken *token;
1567
1568         token = set_interrupt_state (info);
1569
1570         THREADS_INTERRUPT_DEBUG ("interrupt prepare    tid %p token %p\n",
1571                 mono_thread_info_get_tid (info), token);
1572
1573         return token;
1574 }
1575
1576 void
1577 mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token)
1578 {
1579         THREADS_INTERRUPT_DEBUG ("interrupt finish     token %p\n", token);
1580
1581         if (token == NULL)
1582                 return;
1583
1584         g_assert (token->callback);
1585
1586         token->callback (token->data);
1587
1588         g_free (token);
1589 }
1590
1591 void
1592 mono_thread_info_self_interrupt (void)
1593 {
1594         MonoThreadInfo *info;
1595         MonoThreadInfoInterruptToken *token;
1596
1597         info = mono_thread_info_current ();
1598         g_assert (info);
1599
1600         token = set_interrupt_state (info);
1601         g_assert (!token);
1602
1603         THREADS_INTERRUPT_DEBUG ("interrupt self       tid %p\n",
1604                 mono_thread_info_get_tid (info));
1605 }
1606
1607 /* Clear the interrupted flag of the current thread, set with
1608  * mono_thread_info_self_interrupt, so it can wait again */
1609 void
1610 mono_thread_info_clear_self_interrupt ()
1611 {
1612         MonoThreadInfo *info;
1613         MonoThreadInfoInterruptToken *previous_token;
1614
1615         info = mono_thread_info_current ();
1616         g_assert (info);
1617
1618         previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, NULL, INTERRUPT_STATE);
1619         g_assert (previous_token == NULL || previous_token == INTERRUPT_STATE);
1620
1621         THREADS_INTERRUPT_DEBUG ("interrupt clear self tid %p previous_token %p\n", mono_thread_info_get_tid (info), previous_token);
1622 }
1623
1624 gboolean
1625 mono_thread_info_is_interrupt_state (MonoThreadInfo *info)
1626 {
1627         g_assert (info);
1628         return InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE;
1629 }
1630
1631 void
1632 mono_thread_info_describe_interrupt_token (MonoThreadInfo *info, GString *text)
1633 {
1634         g_assert (info);
1635
1636         if (!InterlockedReadPointer ((gpointer*) &info->interrupt_token))
1637                 g_string_append_printf (text, "not waiting");
1638         else if (InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE)
1639                 g_string_append_printf (text, "interrupted state");
1640         else
1641                 g_string_append_printf (text, "waiting");
1642 }
1643
1644 gboolean
1645 mono_thread_info_is_current (MonoThreadInfo *info)
1646 {
1647         return mono_thread_info_get_tid (info) == mono_native_thread_id_get ();
1648 }
1649
1650 MonoThreadInfoWaitRet
1651 mono_thread_info_wait_one_handle (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
1652 {
1653         MonoOSEventWaitRet res;
1654
1655         res = mono_os_event_wait_one (&thread_handle->event, timeout);
1656         if (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0)
1657                 return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0;
1658         else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
1659                 return MONO_THREAD_INFO_WAIT_RET_ALERTED;
1660         else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT)
1661                 return MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1662         else
1663                 g_error ("%s: unknown res value %d", __func__, res);
1664 }
1665
1666 MonoThreadInfoWaitRet
1667 mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize nhandles, MonoOSEvent *background_change_event, gboolean waitall, guint32 timeout, gboolean alertable)
1668 {
1669         MonoOSEventWaitRet res;
1670         MonoOSEvent *thread_events [MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS];
1671         gint i;
1672
1673         g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS);
1674         if (background_change_event)
1675                 g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS - 1);
1676
1677         for (i = 0; i < nhandles; ++i)
1678                 thread_events [i] = &thread_handles [i]->event;
1679
1680         if (background_change_event)
1681                 thread_events [nhandles ++] = background_change_event;
1682
1683         res = mono_os_event_wait_multiple (thread_events, nhandles, waitall, timeout);
1684         if (res >= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 && res <= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + nhandles - 1)
1685                 return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 + (res - MONO_OS_EVENT_WAIT_RET_SUCCESS_0);
1686         else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
1687                 return MONO_THREAD_INFO_WAIT_RET_ALERTED;
1688         else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT)
1689                 return MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1690         else
1691                 g_error ("%s: unknown res value %d", __func__, res);
1692 }