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