2 * mono-threads.c: Low-level threading
5 * Rodrigo Kumpera (kumpera@gmail.com)
7 * Copyright 2011 Novell, Inc (http://www.novell.com)
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include <mono/utils/mono-compiler.h>
14 #include <mono/utils/mono-semaphore.h>
15 #include <mono/utils/mono-threads.h>
16 #include <mono/utils/mono-tls.h>
17 #include <mono/utils/hazard-pointer.h>
18 #include <mono/utils/mono-memory-model.h>
19 #include <mono/utils/mono-mmap.h>
20 #include <mono/utils/atomic.h>
21 #include <mono/utils/mono-time.h>
27 #include <mono/utils/mach-support.h>
31 Mutex that makes sure only a single thread can be suspending others.
32 Suspend is a very racy operation since it requires restarting until
33 the target thread is not on an unsafe region.
35 We could implement this using critical regions, but would be much much
36 harder for an operation that is hardly performance critical.
38 The GC has to acquire this lock before starting a STW to make sure
39 a runtime suspend won't make it wronly see a thread in a safepoint
40 when it is in fact not.
42 static MonoSemType global_suspend_semaphore;
44 static size_t thread_info_size;
45 static MonoThreadInfoCallbacks threads_callbacks;
46 static MonoThreadInfoRuntimeCallbacks runtime_callbacks;
47 static MonoNativeTlsKey thread_info_key, thread_exited_key;
49 static __thread guint32 tls_small_id MONO_TLS_FAST;
51 static MonoNativeTlsKey small_id_key;
53 static MonoLinkedListSet thread_list;
54 static gboolean disable_new_interrupt = FALSE;
55 static gboolean mono_threads_inited = FALSE;
57 static MonoSemType suspend_semaphore;
58 static size_t pending_suspends;
59 static gboolean unified_suspend_enabled;
61 #define mono_thread_info_run_state(info) (((MonoThreadInfo*)info)->thread_state & THREAD_STATE_MASK)
64 #define SLEEP_DURATION_BEFORE_WARNING (50)
66 #define SLEEP_DURATION_BEFORE_ABORT 1000
69 wait_for_resume (MonoThreadInfo* info)
71 MONO_SEM_WAIT_UNITERRUPTIBLE (&info->resume_semaphore);
75 mono_threads_notify_initiator_of_suspend (MonoThreadInfo* info)
77 THREADS_SUSPEND_DEBUG ("[INITIATOR-NOTIFY-SUSPEND] %p\n", info);
78 MONO_SEM_POST (&suspend_semaphore);
82 mono_threads_notify_initiator_of_resume (MonoThreadInfo* info)
84 THREADS_SUSPEND_DEBUG ("[INITIATOR-NOTIFY-RESUME] %p\n", info);
85 MONO_SEM_POST (&suspend_semaphore);
89 resume_self_suspended (MonoThreadInfo* info)
91 THREADS_SUSPEND_DEBUG ("begin self-resume %p\n", info);
92 MONO_SEM_POST (&info->resume_semaphore);
96 resume_async_suspended (MonoThreadInfo *info)
98 g_assert (mono_threads_core_begin_async_resume (info));
102 mono_threads_add_to_pending_operation_set (MonoThreadInfo* info)
104 THREADS_SUSPEND_DEBUG ("added %p to pending suspend\n", info);
109 mono_threads_begin_global_suspend (void)
111 g_assert (pending_suspends == 0);
112 THREADS_SUSPEND_DEBUG ("------ BEGIN GLOBAL OP\n");
116 mono_threads_end_global_suspend (void)
118 g_assert (pending_suspends == 0);
119 THREADS_SUSPEND_DEBUG ("------ END GLOBAL OP\n");
125 MonoThreadInfo *info;
126 FOREACH_THREAD_SAFE (info) {
127 THREADS_SUSPEND_DEBUG ("--thread %p id %p state %x\n", info, mono_thread_info_get_tid (info), info->thread_state);
128 } END_FOREACH_THREAD_SAFE
132 mono_threads_wait_pending_operations (void)
135 int c = pending_suspends;
137 /* Wait threads to park */
138 if (pending_suspends) {
139 MonoStopwatch suspension_time;
140 mono_stopwatch_start (&suspension_time);
141 THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-COUNT] %d\n", c);
142 for (i = 0; i < pending_suspends; ++i) {
143 THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-WAITING]\n");
144 if (!MONO_SEM_TIMEDWAIT (&suspend_semaphore, SLEEP_DURATION_BEFORE_ABORT))
146 mono_stopwatch_stop (&suspension_time);
150 THREADS_SUSPEND_DEBUG ("WAITING for %d threads, got %d suspended\n", (int)pending_suspends, i);
151 THREADS_SUSPEND_DEBUG ("cur thread is %p\n", pthread_self ());
152 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);
154 mono_stopwatch_stop (&suspension_time);
155 THREADS_SUSPEND_DEBUG ("Suspending %d threads took %d ms.\n", (int)pending_suspends, (int)mono_stopwatch_elapsed_ms (&suspension_time));
159 pending_suspends = 0;
165 //Thread initialization code
167 static void mono_threads_unregister_current_thread (MonoThreadInfo *info);
170 mono_hazard_pointer_clear_all (MonoThreadHazardPointers *hp, int retain)
173 mono_hazard_pointer_clear (hp, 0);
175 mono_hazard_pointer_clear (hp, 1);
177 mono_hazard_pointer_clear (hp, 2);
181 If return non null Hazard Pointer 1 holds the return value.
184 mono_thread_info_lookup (MonoNativeThreadId id)
186 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
188 if (!mono_lls_find (&thread_list, hp, (uintptr_t)id)) {
189 mono_hazard_pointer_clear_all (hp, -1);
193 mono_hazard_pointer_clear_all (hp, 1);
194 return mono_hazard_pointer_get_val (hp, 1);
198 mono_thread_info_insert (MonoThreadInfo *info)
200 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
202 if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info)) {
203 mono_hazard_pointer_clear_all (hp, -1);
207 mono_hazard_pointer_clear_all (hp, -1);
212 mono_thread_info_remove (MonoThreadInfo *info)
214 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
217 THREADS_DEBUG ("removing info %p\n", info);
218 res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info);
219 mono_hazard_pointer_clear_all (hp, -1);
224 free_thread_info (gpointer mem)
226 MonoThreadInfo *info = mem;
228 MONO_SEM_DESTROY (&info->resume_semaphore);
229 mono_threads_platform_free (info);
235 mono_thread_info_register_small_id (void)
237 int small_id = mono_thread_small_id_alloc ();
238 #ifdef HAVE_KW_THREAD
239 tls_small_id = small_id;
241 mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (small_id + 1));
247 register_thread (MonoThreadInfo *info, gpointer baseptr)
250 guint8 *staddr = NULL;
251 int small_id = mono_thread_info_register_small_id ();
253 mono_thread_info_set_tid (info, mono_native_thread_id_get ());
254 info->small_id = small_id;
256 MONO_SEM_INIT (&info->resume_semaphore, 0);
258 /*set TLS early so SMR works */
259 mono_native_tls_set_value (thread_info_key, info);
261 THREADS_DEBUG ("registering info %p tid %p small id %x\n", info, mono_thread_info_get_tid (info), info->small_id);
263 if (threads_callbacks.thread_register) {
264 if (threads_callbacks.thread_register (info, baseptr) == NULL) {
265 // g_warning ("thread registation failed\n");
271 mono_thread_info_get_stack_bounds (&staddr, &stsize);
274 info->stack_start_limit = staddr;
275 info->stack_end = staddr + stsize;
277 mono_threads_platform_register (info);
280 Transition it before taking any locks or publishing itself to reduce the chance
281 of others witnessing a detached thread.
282 We can reasonably expect that until this thread gets published, no other thread will
283 try to manipulate it.
285 mono_threads_transition_attach (info);
286 mono_thread_info_suspend_lock ();
287 /*If this fail it means a given thread has been registered twice, which doesn't make sense. */
288 result = mono_thread_info_insert (info);
290 mono_thread_info_suspend_unlock ();
295 unregister_thread (void *arg)
297 MonoThreadInfo *info = arg;
298 int small_id = info->small_id;
301 THREADS_DEBUG ("unregistering info %p\n", info);
303 mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
305 mono_threads_core_unregister (info);
308 * TLS destruction order is not reliable so small_id might be cleaned up
311 #ifndef HAVE_KW_THREAD
312 mono_native_tls_set_value (small_id_key, GUINT_TO_POINTER (info->small_id + 1));
316 First perform the callback that requires no locks.
317 This callback has the potential of taking other locks, so we do it before.
318 After it completes, the thread remains functional.
320 if (threads_callbacks.thread_detach)
321 threads_callbacks.thread_detach (info);
323 mono_thread_info_suspend_lock ();
326 Now perform the callback that must be done under locks.
327 This will render the thread useless and non-suspendable, so it must
328 be done while holding the suspend lock to give no other thread chance
331 if (threads_callbacks.thread_unregister)
332 threads_callbacks.thread_unregister (info);
333 mono_threads_unregister_current_thread (info);
334 mono_threads_transition_detach (info);
336 mono_thread_info_suspend_unlock ();
338 /*now it's safe to free the thread info.*/
339 mono_thread_hazardous_free_or_queue (info, free_thread_info, TRUE, FALSE);
340 mono_thread_small_id_free (small_id);
344 thread_exited_dtor (void *arg)
346 #if defined(__MACH__)
348 * Since we use pthread dtors to clean up thread data, if a thread
349 * is attached to the runtime by another pthread dtor after our dtor
350 * has ran, it will never be detached, leading to various problems
351 * since the thread ids etc. will be reused while they are still in
352 * the threads hashtables etc.
353 * Dtors are called in a loop until all user tls entries are 0,
354 * but the loop has a maximum count (4), so if we set the tls
355 * variable every time, it will remain set when system tls dtors
356 * are ran. This allows mono_thread_info_is_exiting () to detect
357 * whenever the thread is exiting, even if it is executed from a
358 * system tls dtor (i.e. obj-c dealloc methods).
360 mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
365 * Removes the current thread from the thread list.
366 * This must be called from the thread unregister callback and nowhere else.
367 * The current thread must be passed as TLS might have already been cleaned up.
370 mono_threads_unregister_current_thread (MonoThreadInfo *info)
373 g_assert (mono_thread_info_get_tid (info) == mono_native_thread_id_get ());
374 result = mono_thread_info_remove (info);
378 static inline MonoThreadInfo*
379 mono_thread_info_current_unchecked (void)
381 return (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
386 mono_thread_info_current (void)
388 MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
392 info = mono_thread_info_lookup (mono_native_thread_id_get ()); /*info on HP1*/
395 We might be called during thread cleanup, but we cannot be called after cleanup as happened.
396 The way to distinguish between before, during and after cleanup is the following:
398 -If the TLS key is set, cleanup has not begun;
399 -If the TLS key is clean, but the thread remains registered, cleanup is in progress;
400 -If the thread is nowhere to be found, cleanup has finished.
402 We cannot function after cleanup since there's no way to ensure what will happen.
406 /*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 */
407 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
413 mono_thread_info_get_small_id (void)
415 #ifdef HAVE_KW_THREAD
418 gpointer val = mono_native_tls_get_value (small_id_key);
421 return GPOINTER_TO_INT (val) - 1;
426 mono_thread_info_list_head (void)
432 * mono_threads_attach_tools_thread
434 * Attach the current thread as a tool thread. DON'T USE THIS FUNCTION WITHOUT READING ALL DISCLAIMERS.
436 * A tools thread is a very special kind of thread that needs access to core runtime facilities but should
437 * not be counted as a regular thread for high order facilities such as executing managed code or accessing
440 * This is intended only to tools such as a profiler than needs to be able to use our lock-free support when
441 * doing things like resolving backtraces in their background processing thread.
444 mono_threads_attach_tools_thread (void)
447 MonoThreadInfo *info;
449 /* Must only be called once */
450 g_assert (!mono_native_tls_get_value (thread_info_key));
452 info = mono_thread_info_attach (&dummy);
453 info->tools_thread = TRUE;
457 mono_thread_info_attach (void *baseptr)
459 MonoThreadInfo *info;
460 if (!mono_threads_inited)
462 /* This can happen from DllMain(DLL_THREAD_ATTACH) on Windows, if a
463 * thread is created before an embedding API user initialized Mono. */
464 THREADS_DEBUG ("mono_thread_info_attach called before mono_threads_init\n");
467 info = mono_native_tls_get_value (thread_info_key);
469 info = g_malloc0 (thread_info_size);
470 THREADS_DEBUG ("attaching %p\n", info);
471 if (!register_thread (info, baseptr))
473 } else if (threads_callbacks.thread_attach) {
474 threads_callbacks.thread_attach (info);
480 mono_thread_info_detach (void)
482 MonoThreadInfo *info;
483 if (!mono_threads_inited)
485 /* This can happen from DllMain(THREAD_DETACH) on Windows, if a thread
486 * is created before an embedding API user initialized Mono. */
487 THREADS_DEBUG ("mono_thread_info_detach called before mono_threads_init\n");
490 info = mono_native_tls_get_value (thread_info_key);
492 THREADS_DEBUG ("detaching %p\n", info);
493 unregister_thread (info);
494 mono_native_tls_set_value (thread_info_key, NULL);
499 * mono_thread_info_is_exiting:
501 * Return whenever the current thread is exiting, i.e. it is running pthread
505 mono_thread_info_is_exiting (void)
507 #if defined(__MACH__)
508 if (mono_native_tls_get_value (thread_exited_key) == GUINT_TO_POINTER (1))
515 mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
518 threads_callbacks = *callbacks;
519 thread_info_size = info_size;
521 res = mono_native_tls_alloc (&thread_info_key, NULL);
522 res = mono_native_tls_alloc (&thread_exited_key, NULL);
524 res = mono_native_tls_alloc (&thread_info_key, unregister_thread);
525 res = mono_native_tls_alloc (&thread_exited_key, thread_exited_dtor);
529 #ifndef HAVE_KW_THREAD
530 res = mono_native_tls_alloc (&small_id_key, NULL);
534 unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL;
536 MONO_SEM_INIT (&global_suspend_semaphore, 1);
537 MONO_SEM_INIT (&suspend_semaphore, 0);
539 mono_lls_init (&thread_list, NULL);
540 mono_thread_smr_init ();
541 mono_threads_init_platform ();
543 #if defined(__MACH__)
544 mono_mach_init (thread_info_key);
547 mono_threads_inited = TRUE;
549 g_assert (sizeof (MonoNativeThreadId) <= sizeof (uintptr_t));
553 mono_threads_runtime_init (MonoThreadInfoRuntimeCallbacks *callbacks)
555 runtime_callbacks = *callbacks;
558 MonoThreadInfoCallbacks *
559 mono_threads_get_callbacks (void)
561 return &threads_callbacks;
564 MonoThreadInfoRuntimeCallbacks *
565 mono_threads_get_runtime_callbacks (void)
567 return &runtime_callbacks;
571 The return value is only valid until a matching mono_thread_info_resume is called
573 static MonoThreadInfo*
574 mono_thread_info_suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel, const char **error_condition)
576 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
577 MonoThreadInfo *info = mono_thread_info_lookup (tid); /*info on HP1*/
579 *error_condition = "Thread not found";
583 switch (mono_threads_transition_request_async_suspension (info)) {
584 case AsyncSuspendAlreadySuspended:
585 mono_hazard_pointer_clear (hp, 1); //XXX this is questionable we got to clean the suspend/resume nonsense of critical sections
587 case AsyncSuspendWait:
588 mono_threads_add_to_pending_operation_set (info);
590 case AsyncSuspendInitSuspend:
591 if (!mono_threads_core_begin_async_suspend (info, interrupt_kernel)) {
592 mono_hazard_pointer_clear (hp, 1);
593 *error_condition = "Could not suspend thread";
598 //Wait for the pending suspend to finish
599 mono_threads_wait_pending_operations ();
601 if (!mono_threads_core_check_suspend_result (info)) {
603 mono_hazard_pointer_clear (hp, 1);
604 *error_condition = "Post suspend failed";
611 Signal that the current thread wants to be suspended.
612 This function can be called without holding the suspend lock held.
613 To finish suspending, call mono_suspend_check.
616 mono_thread_info_begin_self_suspend (void)
618 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
622 THREADS_SUSPEND_DEBUG ("BEGIN SELF SUSPEND OF %p\n", info);
623 mono_threads_transition_request_self_suspension (info);
627 mono_thread_info_end_self_suspend (void)
629 MonoThreadInfo *info;
631 info = mono_thread_info_current ();
634 THREADS_SUSPEND_DEBUG ("FINISH SELF SUSPEND OF %p\n", info);
636 g_assert (mono_threads_get_runtime_callbacks ()->thread_state_init_from_sigctx (&info->thread_saved_state [SELF_SUSPEND_STATE_INDEX], NULL));
638 /* commit the saved state and notify others if needed */
639 switch (mono_threads_transition_state_poll (info)) {
640 case SelfSuspendResumed:
642 case SelfSuspendWait:
643 wait_for_resume (info);
645 case SelfSuspendNotifyAndWait:
646 mono_threads_notify_initiator_of_suspend (info);
647 wait_for_resume (info);
648 mono_threads_notify_initiator_of_resume (info);
654 mono_thread_info_core_resume (MonoThreadInfo *info)
656 gboolean res = FALSE;
657 if (info->create_suspended) {
658 MonoNativeThreadId tid = mono_thread_info_get_tid (info);
659 /* 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 */
660 info->create_suspended = FALSE;
661 mono_threads_core_resume_created (info, tid);
665 switch (mono_threads_transition_request_resume (info)) {
672 case ResumeInitSelfResume:
673 resume_self_suspended (info);
676 case ResumeInitAsyncResume:
677 resume_async_suspended (info);
686 mono_thread_info_resume (MonoNativeThreadId tid)
688 gboolean result; /* don't initialize it so the compiler can catch unitilized paths. */
689 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
690 MonoThreadInfo *info;
692 THREADS_SUSPEND_DEBUG ("RESUMING tid %p\n", (void*)tid);
694 mono_thread_info_suspend_lock ();
696 info = mono_thread_info_lookup (tid); /*info on HP1*/
702 result = mono_thread_info_core_resume (info);
704 //Wait for the pending resume to finish
705 mono_threads_wait_pending_operations ();
708 mono_thread_info_suspend_unlock ();
709 mono_hazard_pointer_clear (hp, 1);
714 mono_thread_info_begin_suspend (MonoThreadInfo *info, gboolean interrupt_kernel)
716 switch (mono_threads_transition_request_async_suspension (info)) {
717 case AsyncSuspendAlreadySuspended:
719 case AsyncSuspendWait:
720 mono_threads_add_to_pending_operation_set (info);
722 case AsyncSuspendInitSuspend:
723 return mono_threads_core_begin_async_suspend (info, interrupt_kernel);
725 g_assert_not_reached ();
730 mono_thread_info_begin_resume (MonoThreadInfo *info)
732 return mono_thread_info_core_resume (info);
736 FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
737 WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
740 is_thread_in_critical_region (MonoThreadInfo *info)
744 gpointer stack_start;
745 MonoThreadUnwindState *state;
747 /* Are we inside a system critical region? */
748 if (info->inside_critical_region)
751 if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
755 /* Are we inside a GC critical region? */
756 if (threads_callbacks.mono_thread_in_critical_region && threads_callbacks.mono_thread_in_critical_region (info)) {
760 /* The target thread might be shutting down and the domain might be null, which means no managed code left to run. */
761 state = mono_thread_info_get_suspend_state (info);
762 if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
765 stack_start = MONO_CONTEXT_GET_SP (&state->ctx);
766 /* altstack signal handler, sgen can't handle them, so we treat them as critical */
767 if (stack_start < info->stack_start_limit || stack_start >= info->stack_end)
770 ji = mono_jit_info_table_find (
771 state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
772 MONO_CONTEXT_GET_IP (&state->ctx));
777 method = mono_jit_info_get_method (ji);
779 return threads_callbacks.mono_method_is_critical (method);
783 mono_thread_info_in_critical_location (MonoThreadInfo *info)
785 return is_thread_in_critical_region (info);
788 static MonoThreadInfo*
789 suspend_sync_nolock (MonoNativeThreadId id, gboolean interrupt_kernel)
791 MonoThreadInfo *info = NULL;
792 int sleep_duration = 0;
794 const char *suspend_error = "Unknown error";
795 if (!(info = mono_thread_info_suspend_sync (id, interrupt_kernel, &suspend_error))) {
796 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
800 /*WARNING: We now are in interrupt context until we resume the thread. */
801 if (!is_thread_in_critical_region (info))
804 if (!mono_thread_info_core_resume (info)) {
805 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
808 THREADS_SUSPEND_DEBUG ("RESTARTED thread tid %p\n", (void*)id);
810 /* Wait for the pending resume to finish */
811 mono_threads_wait_pending_operations ();
813 if (!sleep_duration) {
821 g_usleep (sleep_duration);
823 sleep_duration += 10;
829 mono_thread_info_safe_suspend_and_run (MonoNativeThreadId id, gboolean interrupt_kernel, MonoSuspendThreadCallback callback, gpointer user_data)
832 MonoThreadInfo *info = NULL;
833 MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
835 THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id);
836 /*FIXME: unify this with self-suspend*/
837 g_assert (id != mono_native_thread_id_get ());
839 mono_thread_info_suspend_lock ();
840 mono_threads_begin_global_suspend ();
842 info = suspend_sync_nolock (id, interrupt_kernel);
846 switch (result = callback (info, user_data)) {
847 case MonoResumeThread:
848 mono_hazard_pointer_set (hp, 1, info);
849 mono_thread_info_core_resume (info);
850 mono_threads_wait_pending_operations ();
855 g_error ("Invalid suspend_and_run callback return value %d", result);
859 mono_hazard_pointer_clear (hp, 1);
860 mono_threads_end_global_suspend ();
861 mono_thread_info_suspend_unlock ();
866 If we are trying to suspend a target that is on a critical region
867 and running a syscall we risk looping forever if @interrupt_kernel is FALSE.
868 So, be VERY carefull in calling this with @interrupt_kernel == FALSE.
870 Info is not put on a hazard pointer as a suspended thread cannot exit and be freed.
872 This function MUST be matched with mono_thread_info_finish_suspend or mono_thread_info_finish_suspend_and_resume
875 mono_thread_info_safe_suspend_sync (MonoNativeThreadId id, gboolean interrupt_kernel)
877 MonoThreadInfo *info = NULL;
879 THREADS_SUSPEND_DEBUG ("SUSPENDING tid %p\n", (void*)id);
880 /*FIXME: unify this with self-suspend*/
881 g_assert (id != mono_native_thread_id_get ());
883 mono_thread_info_suspend_lock ();
884 mono_threads_begin_global_suspend ();
886 info = suspend_sync_nolock (id, interrupt_kernel);
888 /* XXX this clears HP 1, so we restated it again */
889 // mono_atomic_store_release (&mono_thread_info_current ()->inside_critical_region, TRUE);
890 mono_threads_end_global_suspend ();
891 mono_thread_info_suspend_unlock ();
897 Inject an assynchronous call into the target thread. The target thread must be suspended and
898 only a single async call can be setup for a given suspend cycle.
899 This async call must cause stack unwinding as the current implementation doesn't save enough state
900 to resume execution of the top-of-stack function. It's an acceptable limitation since this is
901 currently used only to deliver exceptions.
904 mono_thread_info_setup_async_call (MonoThreadInfo *info, void (*target_func)(void*), void *user_data)
906 /* An async call can only be setup on an async suspended thread */
907 g_assert (mono_thread_info_run_state (info) == STATE_ASYNC_SUSPENDED);
908 /*FIXME this is a bad assert, we probably should do proper locking and fail if one is already set*/
909 g_assert (!info->async_target);
910 info->async_target = target_func;
911 /* This is not GC tracked */
912 info->user_data = user_data;
916 The suspend lock is held during any suspend in progress.
917 A GC that has safepoints must take this lock as part of its
918 STW to make sure no unsafe pending suspend is in progress.
921 mono_thread_info_suspend_lock (void)
923 MONO_SEM_WAIT_UNITERRUPTIBLE (&global_suspend_semaphore);
927 mono_thread_info_suspend_unlock (void)
929 MONO_SEM_POST (&global_suspend_semaphore);
933 mono_thread_info_disable_new_interrupt (gboolean disable)
935 disable_new_interrupt = disable;
939 * This is a very specific function whose only purpose is to
940 * break a given thread from socket syscalls.
942 * This only exists because linux won't fail a call to connect
943 * if the underlying is closed.
945 * TODO We should cleanup and unify this with the other syscall abort
949 mono_thread_info_abort_socket_syscall_for_close (MonoNativeThreadId tid)
951 MonoThreadHazardPointers *hp;
952 MonoThreadInfo *info;
954 if (tid == mono_native_thread_id_get () || !mono_threads_core_needs_abort_syscall ())
957 hp = mono_hazard_pointer_get ();
958 info = mono_thread_info_lookup (tid); /*info on HP1*/
962 if (mono_thread_info_run_state (info) > STATE_RUNNING) {
963 mono_hazard_pointer_clear (hp, 1);
967 mono_thread_info_suspend_lock ();
969 mono_threads_core_abort_syscall (info);
971 mono_hazard_pointer_clear (hp, 1);
972 mono_thread_info_suspend_unlock ();
976 mono_thread_info_unified_management_enabled (void)
978 return unified_suspend_enabled;
982 Disabled by default for now.
983 To enable this we need mini to implement the callbacks by MonoThreadInfoRuntimeCallbacks
984 which means mono-context and setup_async_callback, and we need a mono-threads backend.
987 mono_thread_info_new_interrupt_enabled (void)
989 /*We need STW gc events to work correctly*/
990 #if defined (HAVE_BOEHM_GC) && !defined (USE_INCLUDED_LIBGC)
993 #if defined(HOST_WIN32)
994 return !disable_new_interrupt;
996 #if defined (__i386__) || defined(__x86_64__)
997 return !disable_new_interrupt;
999 #if defined(__arm__) || defined(__aarch64__)
1000 return !disable_new_interrupt;
1006 * mono_thread_info_set_is_async_context:
1008 * Set whenever the current thread is in an async context. Some runtime functions might behave
1009 * differently while in an async context in order to be async safe.
1012 mono_thread_info_set_is_async_context (gboolean async_context)
1014 MonoThreadInfo *info = mono_thread_info_current ();
1017 info->is_async_context = async_context;
1021 mono_thread_info_is_async_context (void)
1023 MonoThreadInfo *info = mono_thread_info_current ();
1026 return info->is_async_context;
1032 * mono_threads_create_thread:
1034 * Create a new thread executing START with argument ARG. Store its id into OUT_TID.
1035 * Returns: a windows or io-layer handle for the thread.
1038 mono_threads_create_thread (LPTHREAD_START_ROUTINE start, gpointer arg, guint32 stack_size, guint32 creation_flags, MonoNativeThreadId *out_tid)
1040 return mono_threads_core_create_thread (start, arg, stack_size, creation_flags, out_tid);
1044 * mono_thread_info_get_stack_bounds:
1046 * Return the address and size of the current threads stack. Return NULL as the
1047 * stack address if the stack address cannot be determined.
1050 mono_thread_info_get_stack_bounds (guint8 **staddr, size_t *stsize)
1052 guint8 *current = (guint8 *)&stsize;
1053 mono_threads_core_get_stack_bounds (staddr, stsize);
1057 /* Sanity check the result */
1058 g_assert ((current > *staddr) && (current < *staddr + *stsize));
1060 /* When running under emacs, sometimes staddr is not aligned to a page size */
1061 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
1065 mono_thread_info_yield (void)
1067 return mono_threads_core_yield ();
1071 mono_thread_info_tls_get (THREAD_INFO_TYPE *info, MonoTlsKey key)
1073 return ((MonoThreadInfo*)info)->tls [key];
1077 * mono_threads_info_tls_set:
1079 * Set the TLS key to VALUE in the info structure. This can be used to obtain
1080 * values of TLS variables for threads other than the current thread.
1081 * This should only be used for infrequently changing TLS variables, and it should
1082 * be paired with setting the real TLS variable since this provides no GC tracking.
1085 mono_thread_info_tls_set (THREAD_INFO_TYPE *info, MonoTlsKey key, gpointer value)
1087 ((MonoThreadInfo*)info)->tls [key] = value;
1091 * mono_thread_info_exit:
1093 * Exit the current thread.
1094 * This function doesn't return.
1097 mono_thread_info_exit (void)
1099 mono_threads_core_exit (0);
1103 * mono_thread_info_open_handle:
1105 * Return a io-layer/win32 handle for the current thread.
1106 * The handle need to be closed by calling CloseHandle () when it is no
1110 mono_thread_info_open_handle (void)
1112 return mono_threads_core_open_handle ();
1116 * mono_threads_open_thread_handle:
1118 * Return a io-layer/win32 handle for the thread identified by HANDLE/TID.
1119 * The handle need to be closed by calling CloseHandle () when it is no
1123 mono_threads_open_thread_handle (HANDLE handle, MonoNativeThreadId tid)
1125 return mono_threads_core_open_thread_handle (handle, tid);
1129 mono_thread_info_set_name (MonoNativeThreadId tid, const char *name)
1131 mono_threads_core_set_name (tid, name);
1135 * mono_thread_info_prepare_interrupt:
1137 * See wapi_prepare_interrupt ().
1140 mono_thread_info_prepare_interrupt (HANDLE thread_handle)
1142 return mono_threads_core_prepare_interrupt (thread_handle);
1146 mono_thread_info_finish_interrupt (gpointer wait_handle)
1148 mono_threads_core_finish_interrupt (wait_handle);
1152 mono_thread_info_interrupt (HANDLE thread_handle)
1154 gpointer wait_handle;
1156 wait_handle = mono_thread_info_prepare_interrupt (thread_handle);
1157 mono_thread_info_finish_interrupt (wait_handle);
1161 mono_thread_info_self_interrupt (void)
1163 mono_threads_core_self_interrupt ();
1167 mono_thread_info_clear_interruption (void)
1169 mono_threads_core_clear_interruption ();
1172 /* info must be self or be held in a hazard pointer. */
1174 mono_threads_add_async_job (MonoThreadInfo *info, MonoAsyncJob job)
1176 MonoAsyncJob old_job;
1178 old_job = info->service_requests;
1181 } while (InterlockedCompareExchange (&info->service_requests, old_job | job, old_job) != old_job);
1186 mono_threads_consume_async_jobs (void)
1188 MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
1193 return InterlockedExchange (&info->service_requests, 0);