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