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