6afb74daf8de35618dbe6a1374f9100aaf64c124
[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         if (mono_threads_is_coop_enabled ()) {
1033                 g_assert (info);
1034                 g_assert (mono_thread_info_is_current (info));
1035                 g_assert (mono_thread_info_is_live (info));
1036
1037                 MONO_ENTER_GC_SAFE_WITH_INFO(info);
1038
1039                 int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
1040                 g_assert (res != -1);
1041
1042                 MONO_EXIT_GC_SAFE_WITH_INFO;
1043         } else {
1044                 int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
1045                 g_assert (res != -1);
1046         }
1047 }
1048
1049 void
1050 mono_thread_info_suspend_lock (void)
1051 {
1052         mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ());
1053 }
1054
1055 void
1056 mono_thread_info_suspend_unlock (void)
1057 {
1058         mono_os_sem_post (&global_suspend_semaphore);
1059 }
1060
1061 /*
1062  * This is a very specific function whose only purpose is to
1063  * break a given thread from socket syscalls.
1064  *
1065  * This only exists because linux won't fail a call to connect
1066  * if the underlying is closed.
1067  *
1068  * TODO We should cleanup and unify this with the other syscall abort
1069  * facility.
1070  */
1071 void
1072 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
1073 {
1074         MonoThreadHazardPointers *hp;
1075         MonoThreadInfo *info;
1076
1077         if (tid == mono_native_thread_id_get ())
1078                 return;
1079
1080         hp = mono_hazard_pointer_get ();
1081         info = mono_thread_info_lookup (tid);
1082         if (!info)
1083                 return;
1084
1085         if (mono_thread_info_run_state (info) == STATE_DETACHED) {
1086                 mono_hazard_pointer_clear (hp, 1);
1087                 return;
1088         }
1089
1090         mono_thread_info_suspend_lock ();
1091         mono_threads_begin_global_suspend ();
1092
1093         mono_threads_suspend_abort_syscall (info);
1094         mono_threads_wait_pending_operations ();
1095
1096         mono_hazard_pointer_clear (hp, 1);
1097
1098         mono_threads_end_global_suspend ();
1099         mono_thread_info_suspend_unlock ();
1100 }
1101
1102 /*
1103  * mono_thread_info_set_is_async_context:
1104  *
1105  *   Set whenever the current thread is in an async context. Some runtime functions might behave
1106  * differently while in an async context in order to be async safe.
1107  */
1108 void
1109 mono_thread_info_set_is_async_context (gboolean async_context)
1110 {
1111         MonoThreadInfo *info = mono_thread_info_current ();
1112
1113         if (info)
1114                 info->is_async_context = async_context;
1115 }
1116
1117 gboolean
1118 mono_thread_info_is_async_context (void)
1119 {
1120         MonoThreadInfo *info = mono_thread_info_current ();
1121
1122         if (info)
1123                 return info->is_async_context;
1124         else
1125                 return FALSE;
1126 }
1127
1128 /*
1129  * mono_thread_info_get_stack_bounds:
1130  *
1131  *   Return the address and size of the current threads stack. Return NULL as the 
1132  * stack address if the stack address cannot be determined.
1133  */
1134 void
1135 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize)
1136 {
1137         guint8 *current = (guint8 *)&stsize;
1138         mono_threads_platform_get_stack_bounds (staddr, stsize);
1139         if (!*staddr)
1140                 return;
1141
1142         /* Sanity check the result */
1143         g_assert ((current > *staddr) && (current < *staddr + *stsize));
1144
1145         /* When running under emacs, sometimes staddr is not aligned to a page size */
1146         *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
1147 }
1148
1149 gboolean
1150 mono_thread_info_yield (void)
1151 {
1152         return mono_threads_platform_yield ();
1153 }
1154
1155 static mono_lazy_init_t sleep_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED;
1156 static MonoCoopMutex sleep_mutex;
1157 static MonoCoopCond sleep_cond;
1158
1159 static void
1160 sleep_initialize (void)
1161 {
1162         mono_coop_mutex_init (&sleep_mutex);
1163         mono_coop_cond_init (&sleep_cond);
1164 }
1165
1166 static void
1167 sleep_interrupt (gpointer data)
1168 {
1169         mono_coop_mutex_lock (&sleep_mutex);
1170         mono_coop_cond_broadcast (&sleep_cond);
1171         mono_coop_mutex_unlock (&sleep_mutex);
1172 }
1173
1174 static inline guint32
1175 sleep_interruptable (guint32 ms, gboolean *alerted)
1176 {
1177         gint64 now, end;
1178
1179         g_assert (MONO_INFINITE_WAIT == G_MAXUINT32);
1180
1181         g_assert (alerted);
1182         *alerted = FALSE;
1183
1184         if (ms != MONO_INFINITE_WAIT)
1185                 end = mono_msec_ticks() + ms;
1186
1187         mono_lazy_initialize (&sleep_init, sleep_initialize);
1188
1189         mono_coop_mutex_lock (&sleep_mutex);
1190
1191         for (;;) {
1192                 if (ms != MONO_INFINITE_WAIT) {
1193                         now = mono_msec_ticks();
1194                         if (now >= end)
1195                                 break;
1196                 }
1197
1198                 mono_thread_info_install_interrupt (sleep_interrupt, NULL, alerted);
1199                 if (*alerted) {
1200                         mono_coop_mutex_unlock (&sleep_mutex);
1201                         return WAIT_IO_COMPLETION;
1202                 }
1203
1204                 if (ms != MONO_INFINITE_WAIT)
1205                         mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, end - now);
1206                 else
1207                         mono_coop_cond_wait (&sleep_cond, &sleep_mutex);
1208
1209                 mono_thread_info_uninstall_interrupt (alerted);
1210                 if (*alerted) {
1211                         mono_coop_mutex_unlock (&sleep_mutex);
1212                         return WAIT_IO_COMPLETION;
1213                 }
1214         }
1215
1216         mono_coop_mutex_unlock (&sleep_mutex);
1217
1218         return 0;
1219 }
1220
1221 gint
1222 mono_thread_info_sleep (guint32 ms, gboolean *alerted)
1223 {
1224         if (ms == 0) {
1225                 MonoThreadInfo *info;
1226
1227                 mono_thread_info_yield ();
1228
1229                 info = mono_thread_info_current ();
1230                 if (info && mono_thread_info_is_interrupt_state (info))
1231                         return WAIT_IO_COMPLETION;
1232
1233                 return 0;
1234         }
1235
1236         if (alerted)
1237                 return sleep_interruptable (ms, alerted);
1238
1239         MONO_ENTER_GC_SAFE;
1240
1241         if (ms == MONO_INFINITE_WAIT) {
1242                 do {
1243 #ifdef HOST_WIN32
1244                         Sleep (G_MAXUINT32);
1245 #else
1246                         sleep (G_MAXUINT32);
1247 #endif
1248                 } while (1);
1249         } else {
1250                 int ret;
1251 #if defined (__linux__) && !defined(PLATFORM_ANDROID)
1252                 struct timespec start, target;
1253
1254                 /* Use clock_nanosleep () to prevent time drifting problems when nanosleep () is interrupted by signals */
1255                 ret = clock_gettime (CLOCK_MONOTONIC, &start);
1256                 g_assert (ret == 0);
1257
1258                 target = start;
1259                 target.tv_sec += ms / 1000;
1260                 target.tv_nsec += (ms % 1000) * 1000000;
1261                 if (target.tv_nsec > 999999999) {
1262                         target.tv_nsec -= 999999999;
1263                         target.tv_sec ++;
1264                 }
1265
1266                 do {
1267                         ret = clock_nanosleep (CLOCK_MONOTONIC, TIMER_ABSTIME, &target, NULL);
1268                 } while (ret != 0);
1269 #elif HOST_WIN32
1270                 Sleep (ms);
1271 #else
1272                 struct timespec req, rem;
1273
1274                 req.tv_sec = ms / 1000;
1275                 req.tv_nsec = (ms % 1000) * 1000000;
1276
1277                 do {
1278                         memset (&rem, 0, sizeof (rem));
1279                         ret = nanosleep (&req, &rem);
1280                 } while (ret != 0);
1281 #endif /* __linux__ */
1282         }
1283
1284         MONO_EXIT_GC_SAFE;
1285
1286         return 0;
1287 }
1288
1289 gint
1290 mono_thread_info_usleep (guint64 us)
1291 {
1292         MONO_ENTER_GC_SAFE;
1293         g_usleep (us);
1294         MONO_EXIT_GC_SAFE;
1295         return 0;
1296 }
1297
1298 gpointer
1299 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key)
1300 {
1301         return ((MonoThreadInfo*)info)->tls [key];
1302 }
1303
1304 /*
1305  * mono_threads_info_tls_set:
1306  *
1307  *   Set the TLS key to VALUE in the info structure. This can be used to obtain
1308  * values of TLS variables for threads other than the current thread.
1309  * This should only be used for infrequently changing TLS variables, and it should
1310  * be paired with setting the real TLS variable since this provides no GC tracking.
1311  */
1312 void
1313 mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value)
1314 {
1315         ((MonoThreadInfo*)info)->tls [key] = value;
1316 }
1317
1318 /*
1319  * mono_thread_info_exit:
1320  *
1321  *   Exit the current thread.
1322  * This function doesn't return.
1323  */
1324 void
1325 mono_thread_info_exit (gsize exit_code)
1326 {
1327         mono_thread_info_detach ();
1328
1329         mono_threads_platform_exit (0);
1330 }
1331
1332 /*
1333  * mono_threads_open_thread_handle:
1334  *
1335  *  Duplicate the handle. The handle needs to be closed by calling
1336  *  mono_threads_close_thread_handle () when it is no longer needed.
1337  */
1338 MonoThreadHandle*
1339 mono_threads_open_thread_handle (MonoThreadHandle *thread_handle)
1340 {
1341         return mono_refcount_inc (thread_handle);
1342 }
1343
1344 void
1345 mono_threads_close_thread_handle (MonoThreadHandle *thread_handle)
1346 {
1347         mono_refcount_dec (thread_handle);
1348 }
1349
1350 static void
1351 mono_threads_signal_thread_handle (MonoThreadHandle* thread_handle)
1352 {
1353         mono_os_event_set (&thread_handle->event);
1354 }
1355
1356 #define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1)
1357
1358 struct _MonoThreadInfoInterruptToken {
1359         void (*callback) (gpointer data);
1360         gpointer data;
1361 };
1362
1363 /*
1364  * mono_thread_info_install_interrupt: install an interruption token for the current thread.
1365  *
1366  *  - @callback: must be able to be called from another thread and always cancel the wait
1367  *  - @data: passed to the callback
1368  *  - @interrupted: will be set to TRUE if a token is already installed, FALSE otherwise
1369  *     if set to TRUE, it must mean that the thread is in interrupted state
1370  */
1371 void
1372 mono_thread_info_install_interrupt (void (*callback) (gpointer data), gpointer data, gboolean *interrupted)
1373 {
1374         MonoThreadInfo *info;
1375         MonoThreadInfoInterruptToken *previous_token, *token;
1376
1377         g_assert (callback);
1378
1379         g_assert (interrupted);
1380         *interrupted = FALSE;
1381
1382         info = mono_thread_info_current ();
1383         g_assert (info);
1384
1385         /* The memory of this token can be freed at 2 places:
1386          *  - if the token is not interrupted: it will be freed in uninstall, as info->interrupt_token has not been replaced
1387          *     by the INTERRUPT_STATE flag value, and it still contains the pointer to the memory location
1388          *  - if the token is interrupted: it will be freed in finish, as the token is now owned by the prepare/finish
1389          *     functions, and info->interrupt_token does not contains a pointer to the memory anymore */
1390         token = g_new0 (MonoThreadInfoInterruptToken, 1);
1391         token->callback = callback;
1392         token->data = data;
1393
1394         previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, token, NULL);
1395
1396         if (previous_token) {
1397                 if (previous_token != INTERRUPT_STATE)
1398                         g_error ("mono_thread_info_install_interrupt: previous_token should be INTERRUPT_STATE (%p), but it was %p", INTERRUPT_STATE, previous_token);
1399
1400                 g_free (token);
1401
1402                 *interrupted = TRUE;
1403         }
1404
1405         THREADS_INTERRUPT_DEBUG ("interrupt install    tid %p token %p previous_token %p interrupted %s\n",
1406                 mono_thread_info_get_tid (info), token, previous_token, *interrupted ? "TRUE" : "FALSE");
1407 }
1408
1409 void
1410 mono_thread_info_uninstall_interrupt (gboolean *interrupted)
1411 {
1412         MonoThreadInfo *info;
1413         MonoThreadInfoInterruptToken *previous_token;
1414
1415         g_assert (interrupted);
1416         *interrupted = FALSE;
1417
1418         info = mono_thread_info_current ();
1419         g_assert (info);
1420
1421         previous_token = (MonoThreadInfoInterruptToken *)InterlockedExchangePointer ((gpointer*) &info->interrupt_token, NULL);
1422
1423         /* only the installer can uninstall the token */
1424         g_assert (previous_token);
1425
1426         if (previous_token == INTERRUPT_STATE) {
1427                 /* if it is interrupted, then it is going to be freed in finish interrupt */
1428                 *interrupted = TRUE;
1429         } else {
1430                 g_free (previous_token);
1431         }
1432
1433         THREADS_INTERRUPT_DEBUG ("interrupt uninstall  tid %p previous_token %p interrupted %s\n",
1434                 mono_thread_info_get_tid (info), previous_token, *interrupted ? "TRUE" : "FALSE");
1435 }
1436
1437 static MonoThreadInfoInterruptToken*
1438 set_interrupt_state (MonoThreadInfo *info)
1439 {
1440         MonoThreadInfoInterruptToken *token, *previous_token;
1441
1442         g_assert (info);
1443
1444         /* Atomically obtain the token the thread is
1445         * waiting on, and change it to a flag value. */
1446
1447         do {
1448                 previous_token = info->interrupt_token;
1449
1450                 /* Already interrupted */
1451                 if (previous_token == INTERRUPT_STATE) {
1452                         token = NULL;
1453                         break;
1454                 }
1455
1456                 token = previous_token;
1457         } while (InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, INTERRUPT_STATE, previous_token) != previous_token);
1458
1459         return token;
1460 }
1461
1462 /*
1463  * mono_thread_info_prepare_interrupt:
1464  *
1465  * The state of the thread info interrupt token is set to 'interrupted' which means that :
1466  *  - if the thread calls one of the WaitFor functions, the function will return with
1467  *     WAIT_IO_COMPLETION instead of waiting
1468  *  - if the thread was waiting when this function was called, the wait will be broken
1469  *
1470  * It is possible that the wait functions return WAIT_IO_COMPLETION, but the target thread
1471  * didn't receive the interrupt signal yet, in this case it should call the wait function
1472  * again. This essentially means that the target thread will busy wait until it is ready to
1473  * process the interruption.
1474  */
1475 MonoThreadInfoInterruptToken*
1476 mono_thread_info_prepare_interrupt (MonoThreadInfo *info)
1477 {
1478         MonoThreadInfoInterruptToken *token;
1479
1480         token = set_interrupt_state (info);
1481
1482         THREADS_INTERRUPT_DEBUG ("interrupt prepare    tid %p token %p\n",
1483                 mono_thread_info_get_tid (info), token);
1484
1485         return token;
1486 }
1487
1488 void
1489 mono_thread_info_finish_interrupt (MonoThreadInfoInterruptToken *token)
1490 {
1491         THREADS_INTERRUPT_DEBUG ("interrupt finish     token %p\n", token);
1492
1493         if (token == NULL)
1494                 return;
1495
1496         g_assert (token->callback);
1497
1498         token->callback (token->data);
1499
1500         g_free (token);
1501 }
1502
1503 void
1504 mono_thread_info_self_interrupt (void)
1505 {
1506         MonoThreadInfo *info;
1507         MonoThreadInfoInterruptToken *token;
1508
1509         info = mono_thread_info_current ();
1510         g_assert (info);
1511
1512         token = set_interrupt_state (info);
1513         g_assert (!token);
1514
1515         THREADS_INTERRUPT_DEBUG ("interrupt self       tid %p\n",
1516                 mono_thread_info_get_tid (info));
1517 }
1518
1519 /* Clear the interrupted flag of the current thread, set with
1520  * mono_thread_info_self_interrupt, so it can wait again */
1521 void
1522 mono_thread_info_clear_self_interrupt ()
1523 {
1524         MonoThreadInfo *info;
1525         MonoThreadInfoInterruptToken *previous_token;
1526
1527         info = mono_thread_info_current ();
1528         g_assert (info);
1529
1530         previous_token = (MonoThreadInfoInterruptToken *)InterlockedCompareExchangePointer ((gpointer*) &info->interrupt_token, NULL, INTERRUPT_STATE);
1531         g_assert (previous_token == NULL || previous_token == INTERRUPT_STATE);
1532
1533         THREADS_INTERRUPT_DEBUG ("interrupt clear self tid %p previous_token %p\n", mono_thread_info_get_tid (info), previous_token);
1534 }
1535
1536 gboolean
1537 mono_thread_info_is_interrupt_state (MonoThreadInfo *info)
1538 {
1539         g_assert (info);
1540         return InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE;
1541 }
1542
1543 void
1544 mono_thread_info_describe_interrupt_token (MonoThreadInfo *info, GString *text)
1545 {
1546         g_assert (info);
1547
1548         if (!InterlockedReadPointer ((gpointer*) &info->interrupt_token))
1549                 g_string_append_printf (text, "not waiting");
1550         else if (InterlockedReadPointer ((gpointer*) &info->interrupt_token) == INTERRUPT_STATE)
1551                 g_string_append_printf (text, "interrupted state");
1552         else
1553                 g_string_append_printf (text, "waiting");
1554 }
1555
1556 gboolean
1557 mono_thread_info_is_current (MonoThreadInfo *info)
1558 {
1559         return mono_thread_info_get_tid (info) == mono_native_thread_id_get ();
1560 }
1561
1562 MonoThreadInfoWaitRet
1563 mono_thread_info_wait_one_handle (MonoThreadHandle *thread_handle, guint32 timeout, gboolean alertable)
1564 {
1565         MonoOSEventWaitRet res;
1566
1567         res = mono_os_event_wait_one (&thread_handle->event, timeout, alertable);
1568         if (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0)
1569                 return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0;
1570         else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
1571                 return MONO_THREAD_INFO_WAIT_RET_ALERTED;
1572         else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT)
1573                 return MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1574         else
1575                 g_error ("%s: unknown res value %d", __func__, res);
1576 }
1577
1578 MonoThreadInfoWaitRet
1579 mono_thread_info_wait_multiple_handle (MonoThreadHandle **thread_handles, gsize nhandles, MonoOSEvent *background_change_event, gboolean waitall, guint32 timeout, gboolean alertable)
1580 {
1581         MonoOSEventWaitRet res;
1582         MonoOSEvent *thread_events [MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS];
1583         gint i;
1584
1585         g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS);
1586         if (background_change_event)
1587                 g_assert (nhandles <= MONO_OS_EVENT_WAIT_MAXIMUM_OBJECTS - 1);
1588
1589         for (i = 0; i < nhandles; ++i)
1590                 thread_events [i] = &thread_handles [i]->event;
1591
1592         if (background_change_event)
1593                 thread_events [nhandles ++] = background_change_event;
1594
1595         res = mono_os_event_wait_multiple (thread_events, nhandles, waitall, timeout, alertable);
1596         if (res >= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 && res <= MONO_OS_EVENT_WAIT_RET_SUCCESS_0 + nhandles - 1)
1597                 return MONO_THREAD_INFO_WAIT_RET_SUCCESS_0 + (res - MONO_OS_EVENT_WAIT_RET_SUCCESS_0);
1598         else if (res == MONO_OS_EVENT_WAIT_RET_ALERTED)
1599                 return MONO_THREAD_INFO_WAIT_RET_ALERTED;
1600         else if (res == MONO_OS_EVENT_WAIT_RET_TIMEOUT)
1601                 return MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1602         else
1603                 g_error ("%s: unknown res value %d", __func__, res);
1604 }
1605
1606 /*
1607  * mono_threads_join_mutex:
1608  *
1609  *   This mutex is used to avoid races between pthread_create () and pthread_join () on osx, see
1610  * https://bugzilla.xamarin.com/show_bug.cgi?id=50529
1611  * The code inside the lock should not block.
1612  */
1613 void
1614 mono_threads_join_lock (void)
1615 {
1616 #ifdef TARGET_OSX
1617         mono_os_mutex_lock (&join_mutex);
1618 #endif
1619 }
1620
1621 void
1622 mono_threads_join_unlock (void)
1623 {
1624 #ifdef TARGET_OSX
1625         mono_os_mutex_unlock (&join_mutex);
1626 #endif
1627 }