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