Merge pull request #1326 from BrzVlad/master
[mono.git] / mono / utils / mono-threads.c
1 /*
2  * mono-threads.c: Low-level threading
3  *
4  * Author:
5  *      Rodrigo Kumpera (kumpera@gmail.com)
6  *
7  * Copyright 2011 Novell, Inc (http://www.novell.com)
8  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9  */
10
11 #include <mono/utils/mono-compiler.h>
12 #include <mono/utils/mono-semaphore.h>
13 #include <mono/utils/mono-threads.h>
14 #include <mono/utils/mono-tls.h>
15 #include <mono/utils/hazard-pointer.h>
16 #include <mono/utils/mono-memory-model.h>
17 #include <mono/utils/mono-mmap.h>
18
19 #include <errno.h>
20
21 #if defined(__MACH__)
22 #include <mono/utils/mach-support.h>
23 #endif
24
25 #define THREADS_DEBUG(...)
26 //#define THREADS_DEBUG(...) g_message(__VA_ARGS__)
27
28 /*
29 Mutex that makes sure only a single thread can be suspending others.
30 Suspend is a very racy operation since it requires restarting until
31 the target thread is not on an unsafe region.
32
33 We could implement this using critical regions, but would be much much
34 harder for an operation that is hardly performance critical.
35
36 The GC has to acquire this lock before starting a STW to make sure
37 a runtime suspend won't make it wronly see a thread in a safepoint
38 when it is in fact not.
39 */
40 static MonoSemType global_suspend_semaphore;
41
42 static size_t thread_info_size;
43 static MonoThreadInfoCallbacks threads_callbacks;
44 static MonoThreadInfoRuntimeCallbacks runtime_callbacks;
45 static MonoNativeTlsKey thread_info_key, thread_exited_key, small_id_key;
46 static MonoLinkedListSet thread_list;
47 static gboolean disable_new_interrupt = FALSE;
48 static gboolean mono_threads_inited = FALSE;
49
50 static void mono_threads_unregister_current_thread (MonoThreadInfo *info);
51
52
53 static inline void
54 mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
55 {
56         if (retain != 0)
57                 mono_hazard_pointer_clear (hp, 0);
58         if (retain != 1)
59                 mono_hazard_pointer_clear (hp, 1);
60         if (retain != 2)
61                 mono_hazard_pointer_clear (hp, 2);
62 }
63
64 /*
65 If return non null Hazard Pointer 1 holds the return value.
66 */
67 MonoThreadInfo*
68 mono_thread_info_lookup (MonoNativeThreadId id)
69 {
70                 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
71
72         if (!mono_lls_find (&thread_list, hp, (uintptr_t)id)) {
73                 mono_hazard_pointer_clear_all (hp, -1);
74                 return NULL;
75         } 
76
77         mono_hazard_pointer_clear_all (hp, 1);
78         return mono_hazard_pointer_get_val (hp, 1);
79 }
80
81 static gboolean
82 mono_thread_info_insert (MonoThreadInfo *info)
83 {
84         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
85
86         if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info)) {
87                 mono_hazard_pointer_clear_all (hp, -1);
88                 return FALSE;
89         } 
90
91         mono_hazard_pointer_clear_all (hp, -1);
92         return TRUE;
93 }
94
95 static gboolean
96 mono_thread_info_remove (MonoThreadInfo *info)
97 {
98         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
99         gboolean res;
100
101         THREADS_DEBUG ("removing info %p\n", info);
102         res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info);
103         mono_hazard_pointer_clear_all (hp, -1);
104         return res;
105 }
106
107 static void
108 free_thread_info (gpointer mem)
109 {
110         MonoThreadInfo *info = mem;
111
112         MONO_SEM_DESTROY (&info->suspend_semaphore);
113         MONO_SEM_DESTROY (&info->resume_semaphore);
114         MONO_SEM_DESTROY (&info->finish_resume_semaphore);
115         mono_threads_platform_free (info);
116
117         g_free (info);
118 }
119
120 int
121 mono_thread_info_register_small_id (void)
122 {
123         int small_id = mono_thread_small_id_alloc ();
124         mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (small_id + 1));
125         return small_id;
126 }
127
128 static void*
129 register_thread (MonoThreadInfo *info, gpointer baseptr)
130 {
131         int small_id = mono_thread_info_register_small_id ();
132         gboolean result;
133         mono_thread_info_set_tid (info, mono_native_thread_id_get ());
134         info->small_id = small_id;
135
136         MONO_SEM_INIT (&info->suspend_semaphore, 1);
137         MONO_SEM_INIT (&info->resume_semaphore, 0);
138         MONO_SEM_INIT (&info->finish_resume_semaphore, 0);
139
140         /*set TLS early so SMR works */
141         mono_native_tls_set_value (thread_info_key, info);
142
143         THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);
144
145         if (threads_callbacks.thread_register) {
146                 if (threads_callbacks.thread_register (info, baseptr) == NULL) {
147                         // g_warning ("thread registation failed\n");
148                         g_free (info);
149                         return NULL;
150                 }
151         }
152
153         mono_threads_platform_register (info);
154         info->thread_state = STATE_RUNNING;
155         mono_thread_info_suspend_lock ();
156         /*If this fail it means a given thread has been registered twice, which doesn't make sense. */
157         result = mono_thread_info_insert (info);
158         g_assert (result);
159         mono_thread_info_suspend_unlock ();
160         return info;
161 }
162
163 static void
164 unregister_thread (void *arg)
165 {
166         MonoThreadInfo *info = arg;
167         int small_id = info->small_id;
168         g_assert (info);
169
170         THREADS_DEBUG ("unregistering info %p\n", info);
171
172         mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
173
174         mono_threads_core_unregister (info);
175
176         /*
177          * TLS destruction order is not reliable so small_id might be cleaned up
178          * before us.
179          */
180         mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
181
182         info->thread_state = STATE_SHUTTING_DOWN;
183
184         /*
185         First perform the callback that requires no locks.
186         This callback has the potential of taking other locks, so we do it before.
187         After it completes, the thread remains functional.
188         */
189         if (threads_callbacks.thread_detach)
190                 threads_callbacks.thread_detach (info);
191
192         mono_thread_info_suspend_lock ();
193
194         /*
195         Now perform the callback that must be done under locks.
196         This will render the thread useless and non-suspendable, so it must
197         be done while holding the suspend lock to give no other thread chance
198         to suspend it.
199         */
200         if (threads_callbacks.thread_unregister)
201                 threads_callbacks.thread_unregister (info);
202         mono_threads_unregister_current_thread (info);
203
204         info->thread_state = STATE_DEAD;
205         mono_thread_info_suspend_unlock ();
206
207         /*now it's safe to free the thread info.*/
208         mono_thread_hazardous_free_or_queue (info, free_thread_info, TRUE, FALSE);
209         mono_thread_small_id_free (small_id);
210 }
211
212 static void
213 thread_exited_dtor (void *arg)
214 {
215 #if defined(__MACH__)
216         /*
217          * Since we use pthread dtors to clean up thread data, if a thread
218          * is attached to the runtime by another pthread dtor after our dtor
219          * has ran, it will never be detached, leading to various problems
220          * since the thread ids etc. will be reused while they are still in
221          * the threads hashtables etc.
222          * Dtors are called in a loop until all user tls entries are 0,
223          * but the loop has a maximum count (4), so if we set the tls
224          * variable every time, it will remain set when system tls dtors
225          * are ran. This allows mono_thread_info_is_exiting () to detect
226          * whenever the thread is exiting, even if it is executed from a
227          * system tls dtor (i.e. obj-c dealloc methods).
228          */
229         mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
230 #endif
231 }
232
233 /**
234  * Removes the current thread from the thread list.
235  * This must be called from the thread unregister callback and nowhere else.
236  * The current thread must be passed as TLS might have already been cleaned up.
237 */
238 static void
239 mono_threads_unregister_current_thread (MonoThreadInfo *info)
240 {
241         gboolean result;
242         g_assert (mono_thread_info_get_tid (info) == mono_native_thread_id_get ());
243         result = mono_thread_info_remove (info);
244         g_assert (result);
245 }
246
247 MonoThreadInfo*
248 mono_thread_info_current (void)
249 {
250         MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
251         if (info)
252                 return info;
253
254         info = mono_thread_info_lookup (mono_native_thread_id_get ()); /*info on HP1*/
255
256         /*
257         We might be called during thread cleanup, but we cannot be called after cleanup as happened.
258         The way to distinguish between before, during and after cleanup is the following:
259
260         -If the TLS key is set, cleanup has not begun;
261         -If the TLS key is clean, but the thread remains registered, cleanup is in progress;
262         -If the thread is nowhere to be found, cleanup has finished.
263
264         We cannot function after cleanup since there's no way to ensure what will happen.
265         */
266         g_assert (info);
267
268         /*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 */
269         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
270
271         return info;
272 }
273
274 int
275 mono_thread_info_get_small_id (void)
276 {
277         gpointer val = mono_native_tls_get_value (small_id_key);
278         if (!val)
279                 return -1;
280         return GPOINTER_TO_INT (val) - 1;
281 }
282
283 MonoLinkedListSet*
284 mono_thread_info_list_head (void)
285 {
286         return &thread_list;
287 }
288
289 MonoThreadInfo*
290 mono_thread_info_attach (void *baseptr)
291 {
292         MonoThreadInfo *info;
293         if (!mono_threads_inited)
294         {
295                 /* This can happen from DllMain(DLL_THREAD_ATTACH) on Windows, if a
296                  * thread is created before an embedding API user initialized Mono. */
297                 THREADS_DEBUG ("mono_thread_info_attach called before mono_threads_init\n");
298                 return NULL;
299         }
300         info = mono_native_tls_get_value (thread_info_key);
301         if (!info) {
302                 info = g_malloc0 (thread_info_size);
303                 THREADS_DEBUG ("attaching %p\n", info);
304                 if (!register_thread (info, baseptr))
305                         return NULL;
306         } else if (threads_callbacks.thread_attach) {
307                 threads_callbacks.thread_attach (info);
308         }
309         return info;
310 }
311
312 void
313 mono_thread_info_detach (void)
314 {
315         MonoThreadInfo *info;
316         if (!mono_threads_inited)
317         {
318                 /* This can happen from DllMain(THREAD_DETACH) on Windows, if a thread
319                  * is created before an embedding API user initialized Mono. */
320                 THREADS_DEBUG ("mono_thread_info_detach called before mono_threads_init\n");
321                 return;
322         }
323         info = mono_native_tls_get_value (thread_info_key);
324         if (info) {
325                 THREADS_DEBUG ("detaching %p\n", info);
326                 unregister_thread (info);
327                 mono_native_tls_set_value (thread_info_key, NULL);
328         }
329 }
330
331 /*
332  * mono_thread_info_is_exiting:
333  *
334  *   Return whenever the current thread is exiting, i.e. it is running pthread
335  * dtors.
336  */
337 gboolean
338 mono_thread_info_is_exiting (void)
339 {
340 #if defined(__MACH__)
341         if (mono_native_tls_get_value (thread_exited_key) == GUINT_TO_POINTER (1))
342                 return TRUE;
343 #endif
344         return FALSE;
345 }
346
347 void
348 mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
349 {
350         gboolean res;
351         threads_callbacks = *callbacks;
352         thread_info_size = info_size;
353 #ifdef HOST_WIN32
354         res = mono_native_tls_alloc (&thread_info_key, NULL);
355         res = mono_native_tls_alloc (&thread_exited_key, NULL);
356 #else
357         res = mono_native_tls_alloc (&thread_info_key, unregister_thread);
358         res = mono_native_tls_alloc (&thread_exited_key, thread_exited_dtor);
359 #endif
360         g_assert (res);
361
362         res = mono_native_tls_alloc (&small_id_key, NULL);
363         g_assert (res);
364
365         MONO_SEM_INIT (&global_suspend_semaphore, 1);
366
367         mono_lls_init (&thread_list, NULL);
368         mono_thread_smr_init ();
369         mono_threads_init_platform ();
370
371 #if defined(__MACH__)
372         mono_mach_init (thread_info_key);
373 #endif
374
375         mono_threads_inited = TRUE;
376
377         g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
378 }
379
380 void
381 mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks)
382 {
383         runtime_callbacks = *callbacks;
384 }
385
386 MonoThreadInfoCallbacks *
387 mono_threads_get_callbacks (void)
388 {
389         return &threads_callbacks;
390 }
391
392 MonoThreadInfoRuntimeCallbacks *
393 mono_threads_get_runtime_callbacks (void)
394 {
395         return &runtime_callbacks;
396 }
397
398 /*
399 The return value is only valid until a matching mono_thread_info_resume is called
400 */
401 static MonoThreadInfo*
402 mono_thread_info_suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel, const char **error_condition)
403 {
404         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();      
405         MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
406         if (!info) {
407                 *error_condition = "Thread not found";
408                 return NULL;
409         }
410
411         MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
412
413         /*thread is on the process of detaching*/
414         if (mono_thread_info_run_state (info) > STATE_RUNNING) {
415                 mono_hazard_pointer_clear (hp, 1);
416                 *error_condition = "Thread is detaching";
417                 return NULL;
418         }
419
420         THREADS_DEBUG ("suspend %x IN COUNT %d\n", tid, info->suspend_count);
421
422         if (info->suspend_count) {
423                 ++info->suspend_count;
424                 mono_hazard_pointer_clear (hp, 1);
425                 MONO_SEM_POST (&info->suspend_semaphore);
426                 return info;
427         }
428
429         if (!mono_threads_core_suspend (info)) {
430                 MONO_SEM_POST (&info->suspend_semaphore);
431                 mono_hazard_pointer_clear (hp, 1);
432                 *error_condition = "Could not suspend thread";
433                 return NULL;
434         }
435
436         if (interrupt_kernel) 
437                 mono_threads_core_interrupt (info);
438
439         ++info->suspend_count;
440         info->thread_state |= STATE_SUSPENDED;
441         MONO_SEM_POST (&info->suspend_semaphore);
442
443         return info;
444 }
445
446 void
447 mono_thread_info_self_suspend (void)
448 {
449         gboolean ret;
450         MonoThreadInfo *info = mono_thread_info_current ();
451         if (!info)
452                 return;
453
454         MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
455
456         THREADS_DEBUG ("self suspend IN COUNT %d\n", info->suspend_count);
457
458         g_assert (info->suspend_count == 0);
459         ++info->suspend_count;
460
461         info->thread_state |= STATE_SELF_SUSPENDED;
462
463         ret = mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->suspend_state, NULL);
464         g_assert (ret);
465
466         MONO_SEM_POST (&info->suspend_semaphore);
467
468         MONO_SEM_WAIT_UNITERRUPTIBLE (&info->resume_semaphore);
469
470         g_assert (!info->async_target); /*FIXME this should happen normally for suspend. */
471         MONO_SEM_POST (&info->finish_resume_semaphore);
472 }
473
474 static gboolean
475 mono_thread_info_core_resume (MonoThreadInfo *info)
476 {
477         gboolean result;
478         MonoNativeThreadId tid = mono_thread_info_get_tid (info);
479         if (info->create_suspended) {
480                 /* 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 */
481                 info->create_suspended = FALSE;
482                 mono_threads_core_resume_created (info, tid);
483                 return TRUE;
484         }
485
486         MONO_SEM_WAIT_UNITERRUPTIBLE (&info->suspend_semaphore);
487
488         THREADS_DEBUG ("resume %x IN COUNT %d\n", tid, info->suspend_count);
489
490         if (info->suspend_count <= 0) {
491                 MONO_SEM_POST (&info->suspend_semaphore);
492                 return FALSE;
493         }
494
495         /*
496          * The theory here is that if we manage to suspend the thread it means it did not
497          * start cleanup since it take the same lock. 
498         */
499         g_assert (mono_thread_info_get_tid (info));
500
501         if (--info->suspend_count == 0) {
502                 if (mono_thread_info_suspend_state (info) == STATE_SELF_SUSPENDED) {
503                         MONO_SEM_POST (&info->resume_semaphore);
504                         MONO_SEM_WAIT_UNITERRUPTIBLE (&info->finish_resume_semaphore);
505                         result = TRUE;
506                 } else {
507                         result = mono_threads_core_resume (info);
508                 }
509                 info->thread_state &= ~SUSPEND_STATE_MASK;
510         } else {
511                 result = TRUE;
512         }
513
514         MONO_SEM_POST (&info->suspend_semaphore);
515         return result;
516 }
517
518 gboolean
519 mono_thread_info_resume (MonoNativeThreadId tid)
520 {
521         gboolean result; /* don't initialize it so the compiler can catch unitilized paths. */
522         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
523         MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
524
525         if (!info) {
526                 result = FALSE;
527                 goto cleanup;
528         }
529         result = mono_thread_info_core_resume (info);
530
531 cleanup:
532         mono_hazard_pointer_clear (hp, 1);
533         return result;
534 }
535
536 void
537 mono_thread_info_finish_suspend (MonoThreadInfo *info)
538 {
539         mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, FALSE);
540 }
541
542 void
543 mono_thread_info_finish_suspend_and_resume (MonoThreadInfo *info)
544 {
545         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
546
547         /*Resume can access info after the target has resumed, so we must ensure it won't touch freed memory. */
548         mono_hazard_pointer_set (hp, 1, info);
549         mono_thread_info_core_resume (info);
550         mono_hazard_pointer_clear (hp, 1);
551
552         mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, FALSE);
553 }
554
555 /*
556 FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
557 WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
558 */
559 static gboolean
560 is_thread_in_critical_region (MonoThreadInfo *info)
561 {
562         MonoMethod *method;
563         MonoJitInfo *ji;
564
565         if (info->inside_critical_region)
566                 return TRUE;
567
568         /* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
569         if (!info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN])
570                 return FALSE;
571
572         ji = mono_jit_info_table_find (
573                 info->suspend_state.unwind_data [MONO_UNWIND_DATA_DOMAIN],
574                 MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
575
576         if (!ji)
577                 return FALSE;
578
579         method = mono_jit_info_get_method (ji);
580
581         return threads_callbacks.mono_method_is_critical (method);
582 }
583
584 /*
585 WARNING:
586 If we are trying to suspend a target that is on a critical region
587 and running a syscall we risk looping forever if @interrupt_kernel is FALSE.
588 So, be VERY carefull in calling this with @interrupt_kernel == FALSE.
589
590 Info is not put on a hazard pointer as a suspended thread cannot exit and be freed.
591
592 This function MUST be matched with mono_thread_info_finish_suspend or mono_thread_info_finish_suspend_and_resume
593 */
594 MonoThreadInfo*
595 mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel)
596 {
597         MonoThreadInfo *info = NULL;
598         int sleep_duration = 0;
599
600         /*FIXME: unify this with self-suspend*/
601         g_assert (id != mono_native_thread_id_get ());
602
603         mono_thread_info_suspend_lock ();
604
605         for (;;) {
606                 const char *suspend_error = "Unknown error";
607                 if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel, &suspend_error))) {
608                         // g_warning ("failed to suspend thread %p due to %s, hopefully it is dead", (gpointer)id, suspend_error);
609                         mono_thread_info_suspend_unlock ();
610                         return NULL;
611                 }
612                 /*WARNING: We now are in interrupt context until we resume the thread. */
613                 if (!is_thread_in_critical_region (info))
614                         break;
615
616                 if (!mono_thread_info_core_resume (info)) {
617                         // g_warning ("failed to resume thread %p, hopefully it is dead", (gpointer)id);
618                         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
619                         mono_thread_info_suspend_unlock ();
620                         return NULL;
621                 }
622                 THREADS_DEBUG ("restarted thread %p\n", (gpointer)id);
623
624                 if (!sleep_duration) {
625 #ifdef HOST_WIN32
626                         SwitchToThread ();
627 #else
628                         sched_yield ();
629 #endif
630                 }
631                 else {
632                         g_usleep (sleep_duration);
633                 }
634                 sleep_duration += 10;
635         }
636
637         /* XXX this clears HP 1, so we restated it again */
638         mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, TRUE);
639         mono_thread_info_suspend_unlock ();
640
641         return info;
642 }
643
644 /**
645 Inject an assynchronous call into the target thread. The target thread must be suspended and
646 only a single async call can be setup for a given suspend cycle.
647 This async call must cause stack unwinding as the current implementation doesn't save enough state
648 to resume execution of the top-of-stack function. It's an acceptable limitation since this is
649 currently used only to deliver exceptions.
650 */
651 void
652 mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
653 {
654         g_assert (info->suspend_count);
655         /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
656         g_assert (!info->async_target);
657         info->async_target = target_func;
658         /* This is not GC tracked */
659         info->user_data = user_data;
660 }
661
662 /*
663 The suspend lock is held during any suspend in progress.
664 A GC that has safepoints must take this lock as part of its
665 STW to make sure no unsafe pending suspend is in progress.   
666 */
667 void
668 mono_thread_info_suspend_lock (void)
669 {
670         MONO_SEM_WAIT_UNITERRUPTIBLE (&global_suspend_semaphore);
671 }
672
673 void
674 mono_thread_info_suspend_unlock (void)
675 {
676         MONO_SEM_POST (&global_suspend_semaphore);
677 }
678
679 void
680 mono_thread_info_disable_new_interrupt (gboolean disable)
681 {
682         disable_new_interrupt = disable;
683 }
684
685 /*
686  * This is a very specific function whose only purpose is to
687  * break a given thread from socket syscalls.
688  *
689  * This only exists because linux won't fail a call to connect
690  * if the underlying is closed.
691  *
692  * TODO We should cleanup and unify this with the other syscall abort
693  * facility.
694  */
695 void
696 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
697 {
698         MonoThreadHazardPointers *hp;
699         MonoThreadInfo *info;
700         
701         if (tid == mono_native_thread_id_get () || !mono_threads_core_needs_abort_syscall ())
702                 return;
703
704         hp = mono_hazard_pointer_get ();        
705         info = mono_thread_info_lookup (tid); /*info on HP1*/
706         if (!info)
707                 return;
708
709         if (mono_thread_info_run_state (info) > STATE_RUNNING) {
710                 mono_hazard_pointer_clear (hp, 1);
711                 return;
712         }
713
714         mono_thread_info_suspend_lock ();
715
716         mono_threads_core_abort_syscall (info);
717
718         mono_hazard_pointer_clear (hp, 1);
719         mono_thread_info_suspend_unlock ();
720 }
721
722 /*
723 Disabled by default for now.
724 To enable this we need mini to implement the callbacks by MonoThreadInfoRuntimeCallbacks
725 which means mono-context and setup_async_callback, and we need a mono-threads backend.
726 */
727 gboolean
728 mono_thread_info_new_interrupt_enabled (void)
729 {
730         /*We need STW gc events to work correctly*/
731 #if defined (HAVE_BOEHM_GC) && !defined (USE_INCLUDED_LIBGC)
732         return FALSE;
733 #endif
734 #if defined(HOST_WIN32)
735         return !disable_new_interrupt;
736 #endif
737 #if defined (__i386__) || defined(__x86_64__)
738         return !disable_new_interrupt;
739 #endif
740 #if defined(__arm__)
741         return !disable_new_interrupt;
742 #endif
743         return FALSE;
744 }
745
746 /*
747  * mono_thread_info_set_is_async_context:
748  *
749  *   Set whenever the current thread is in an async context. Some runtime functions might behave
750  * differently while in an async context in order to be async safe.
751  */
752 void
753 mono_thread_info_set_is_async_context (gboolean async_context)
754 {
755         MonoThreadInfo *info = mono_thread_info_current ();
756
757         if (info)
758                 info->is_async_context = async_context;
759 }
760
761 gboolean
762 mono_thread_info_is_async_context (void)
763 {
764         MonoThreadInfo *info = mono_thread_info_current ();
765
766         if (info)
767                 return info->is_async_context;
768         else
769                 return FALSE;
770 }
771
772 /*
773  * mono_threads_create_thread:
774  *
775  *   Create a new thread executing START with argument ARG. Store its id into OUT_TID.
776  * Returns: a windows or io-layer handle for the thread.
777  */
778 HANDLE
779 mono_threads_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
780 {
781         return mono_threads_core_create_thread (start, arg, stack_size, creation_flags, out_tid);
782 }
783
784 /*
785  * mono_thread_info_get_stack_bounds:
786  *
787  *   Return the address and size of the current threads stack. Return NULL as the 
788  * stack address if the stack address cannot be determined.
789  */
790 void
791 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize)
792 {
793         guint8 *current = (guint8 *)&stsize;
794         mono_threads_core_get_stack_bounds (staddr, stsize);
795         if (!*staddr)
796                 return;
797
798         /* Sanity check the result */
799         g_assert ((current > *staddr) && (current < *staddr + *stsize));
800
801         /* When running under emacs, sometimes staddr is not aligned to a page size */
802         *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
803 }
804
805 gboolean
806 mono_thread_info_yield (void)
807 {
808         return mono_threads_core_yield ();
809 }
810
811 gpointer
812 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key)
813 {
814         return ((MonoThreadInfo*)info)->tls [key];
815 }
816
817 /*
818  * mono_threads_info_tls_set:
819  *
820  *   Set the TLS key to VALUE in the info structure. This can be used to obtain
821  * values of TLS variables for threads other than the current thread.
822  * This should only be used for infrequently changing TLS variables, and it should
823  * be paired with setting the real TLS variable since this provides no GC tracking.
824  */
825 void
826 mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value)
827 {
828         ((MonoThreadInfo*)info)->tls [key] = value;
829 }
830
831 /*
832  * mono_thread_info_exit:
833  *
834  *   Exit the current thread.
835  * This function doesn't return.
836  */
837 void
838 mono_thread_info_exit (void)
839 {
840         mono_threads_core_exit (0);
841 }
842
843 /*
844  * mono_thread_info_open_handle:
845  *
846  *   Return a io-layer/win32 handle for the current thread.
847  * The handle need to be closed by calling CloseHandle () when it is no
848  * longer needed.
849  */
850 HANDLE
851 mono_thread_info_open_handle (void)
852 {
853         return mono_threads_core_open_handle ();
854 }
855
856 /*
857  * mono_threads_open_thread_handle:
858  *
859  *   Return a io-layer/win32 handle for the thread identified by HANDLE/TID.
860  * The handle need to be closed by calling CloseHandle () when it is no
861  * longer needed.
862  */
863 HANDLE
864 mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
865 {
866         return mono_threads_core_open_thread_handle (handle, tid);
867 }
868
869 void
870 mono_thread_info_set_name (MonoNativeThreadId tid, const char *name)
871 {
872         mono_threads_core_set_name (tid, name);
873 }
874
875 /*
876  * mono_thread_info_prepare_interrupt:
877  *
878  *   See wapi_prepare_interrupt ().
879  */
880 gpointer
881 mono_thread_info_prepare_interrupt (HANDLE thread_handle)
882 {
883         return mono_threads_core_prepare_interrupt (thread_handle);
884 }
885
886 void
887 mono_thread_info_finish_interrupt (gpointer wait_handle)
888 {
889         mono_threads_core_finish_interrupt (wait_handle);
890 }
891
892 void
893 mono_thread_info_interrupt (HANDLE thread_handle)
894 {
895         gpointer wait_handle;
896
897         wait_handle = mono_thread_info_prepare_interrupt (thread_handle);
898         mono_thread_info_finish_interrupt (wait_handle);
899 }
900         
901 void
902 mono_thread_info_self_interrupt (void)
903 {
904         mono_threads_core_self_interrupt ();
905 }
906
907 void
908 mono_thread_info_clear_interruption (void)
909 {
910         mono_threads_core_clear_interruption ();
911 }