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