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