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