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