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