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