2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/threads.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internals.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/mono-threads-coop.h>
41 #include <mono/utils/hazard-pointer.h>
42 #include <mono/utils/mono-tls.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/mono-threads-coop.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/os-event.h>
48 #include <mono/utils/mono-threads-debug.h>
49 #include <mono/metadata/w32handle.h>
50 #include <mono/metadata/w32event.h>
51 #include <mono/metadata/w32mutex.h>
53 #include <mono/metadata/gc-internals.h>
54 #include <mono/metadata/reflection-internals.h>
55 #include <mono/metadata/abi-details.h>
61 #if defined(HOST_WIN32)
65 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
66 #define USE_TKILL_ON_ANDROID 1
69 #ifdef PLATFORM_ANDROID
72 #ifdef USE_TKILL_ON_ANDROID
73 extern int tkill (pid_t tid, int signal);
77 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
78 #define THREAD_DEBUG(a)
79 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
80 #define THREAD_WAIT_DEBUG(a)
81 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
82 #define LIBGC_DEBUG(a)
84 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
85 #define SPIN_LOCK(i) do { \
86 if (SPIN_TRYLOCK (i)) \
90 #define SPIN_UNLOCK(i) i = 0
92 #define LOCK_THREAD(thread) lock_thread((thread))
93 #define UNLOCK_THREAD(thread) unlock_thread((thread))
105 typedef struct _StaticDataFreeList StaticDataFreeList;
106 struct _StaticDataFreeList {
107 StaticDataFreeList *next;
115 StaticDataFreeList *freelist;
118 /* Number of cached culture objects in the MonoThread->cached_culture_info array
119 * (per-type): we use the first NUM entries for CultureInfo and the last for
120 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
122 #define NUM_CACHED_CULTURES 4
123 #define CULTURES_START_IDX 0
124 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
126 /* Controls access to the 'threads' hash table */
127 static void mono_threads_lock (void);
128 static void mono_threads_unlock (void);
129 static MonoCoopMutex threads_mutex;
131 /* Controls access to the 'joinable_threads' hash table */
132 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
133 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
134 static mono_mutex_t joinable_threads_mutex;
136 /* Holds current status of static data heap */
137 static StaticDataInfo thread_static_info;
138 static StaticDataInfo context_static_info;
140 /* The hash of existing threads (key is thread ID, value is
141 * MonoInternalThread*) that need joining before exit
143 static MonoGHashTable *threads;
145 /* List of app context GC handles.
146 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
148 static GHashTable *contexts;
150 /* Cleanup queue for contexts. */
151 static MonoReferenceQueue *context_queue;
154 * Threads which are starting up and they are not in the 'threads' hash yet.
155 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
156 * Protected by mono_threads_lock ().
158 static MonoGHashTable *threads_starting_up;
160 /* The TLS key that holds the MonoObject assigned to each thread */
161 static MonoNativeTlsKey current_object_key;
164 /* Protected by the threads lock */
165 static GHashTable *joinable_threads;
166 static int joinable_thread_count;
168 #define thread_wait_lock() mono_os_mutex_lock (&thread_wait_mutex)
169 #define thread_wait_unlock() mono_os_mutex_unlock (&thread_wait_mutex)
170 static mono_mutex_t thread_wait_mutex;
171 /* Used to wait for a thread to be joined or to change state */
172 /* Used to wait for njoined_threads to increase or for background_change to become true */
173 static mono_cond_t thread_wait_cond;
174 static int njoined_threads;
175 static gboolean background_changed;
177 #ifdef MONO_HAVE_FAST_TLS
178 /* we need to use both the Tls* functions and __thread because
179 * the gc needs to see all the threads
181 MONO_FAST_TLS_DECLARE(tls_current_object);
182 #define SET_CURRENT_OBJECT(x) do { \
183 MONO_FAST_TLS_SET (tls_current_object, x); \
184 mono_native_tls_set_value (current_object_key, x); \
186 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
188 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
189 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
192 /* function called at thread start */
193 static MonoThreadStartCB mono_thread_start_cb = NULL;
195 /* function called at thread attach */
196 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
198 /* function called at thread cleanup */
199 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
201 /* The default stack size for each thread */
202 static guint32 default_stacksize = 0;
203 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
205 static void context_adjust_static_data (MonoAppContext *ctx);
206 static void mono_free_static_data (gpointer* static_data);
207 static void mono_init_static_data_info (StaticDataInfo *static_data);
208 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
209 static gboolean mono_thread_resume (MonoInternalThread* thread);
210 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
211 static void self_abort_internal (MonoError *error);
212 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
213 static void self_suspend_internal (void);
215 static MonoException* mono_thread_execute_interruption (void);
216 static void ref_stack_destroy (gpointer rs);
218 /* Spin lock for InterlockedXXX 64 bit functions */
219 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
220 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
221 static mono_mutex_t interlocked_mutex;
223 /* global count of thread interruptions requested */
224 static gint32 thread_interruption_requested = 0;
227 /* Event signaled when a thread changes its background mode */
228 static MonoOSEvent background_change_event;
231 static gboolean shutting_down = FALSE;
233 static gint32 managed_thread_id_counter = 0;
235 /* Class lazy loading functions */
236 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
239 mono_threads_lock (void)
241 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
245 mono_threads_unlock (void)
247 mono_locks_coop_release (&threads_mutex, ThreadsLock);
252 get_next_managed_thread_id (void)
254 return InterlockedIncrement (&managed_thread_id_counter);
258 mono_thread_get_tls_key (void)
260 return current_object_key;
264 mono_thread_get_tls_offset (void)
269 if (current_object_key)
270 offset = current_object_key;
272 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
277 static inline MonoNativeThreadId
278 thread_get_tid (MonoInternalThread *thread)
280 /* We store the tid as a guint64 to keep the object layout constant between platforms */
281 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
284 static void ensure_synch_cs_set (MonoInternalThread *thread)
286 MonoCoopMutex *synch_cs;
288 if (thread->synch_cs != NULL) {
292 synch_cs = g_new0 (MonoCoopMutex, 1);
293 mono_coop_mutex_init_recursive (synch_cs);
295 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
296 synch_cs, NULL) != NULL) {
297 /* Another thread must have installed this CS */
298 mono_coop_mutex_destroy (synch_cs);
304 lock_thread (MonoInternalThread *thread)
306 if (!thread->synch_cs)
307 ensure_synch_cs_set (thread);
309 g_assert (thread->synch_cs);
311 mono_coop_mutex_lock (thread->synch_cs);
315 unlock_thread (MonoInternalThread *thread)
317 mono_coop_mutex_unlock (thread->synch_cs);
320 static inline gboolean
321 is_appdomainunloaded_exception (MonoClass *klass)
323 return klass == mono_class_get_appdomain_unloaded_exception_class ();
326 static inline gboolean
327 is_threadabort_exception (MonoClass *klass)
329 return klass == mono_defaults.threadabortexception_class;
333 * NOTE: this function can be called also for threads different from the current one:
334 * make sure no code called from it will ever assume it is run on the thread that is
335 * getting cleaned up.
337 static void thread_cleanup (MonoInternalThread *thread)
341 g_assert (thread != NULL);
343 if (thread->abort_state_handle) {
344 mono_gchandle_free (thread->abort_state_handle);
345 thread->abort_state_handle = 0;
347 thread->abort_exc = NULL;
348 thread->current_appcontext = NULL;
351 * This is necessary because otherwise we might have
352 * cross-domain references which will not get cleaned up when
353 * the target domain is unloaded.
355 if (thread->cached_culture_info) {
357 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
358 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
362 * thread->synch_cs can be NULL if this was called after
363 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
364 * This can happen only during shutdown.
365 * The shutting_down flag is not always set, so we can't assert on it.
367 if (thread->synch_cs)
368 LOCK_THREAD (thread);
370 thread->state |= ThreadState_Stopped;
371 thread->state &= ~ThreadState_Background;
373 if (thread->synch_cs)
374 UNLOCK_THREAD (thread);
377 An interruption request has leaked to cleanup. Adjust the global counter.
379 This can happen is the abort source thread finds the abortee (this) thread
380 in unmanaged code. If this thread never trips back to managed code or check
381 the local flag it will be left set and positively unbalance the global counter.
383 Leaving the counter unbalanced will cause a performance degradation since all threads
384 will now keep checking their local flags all the time.
386 if (InterlockedExchange (&thread->interruption_requested, 0))
387 InterlockedDecrement (&thread_interruption_requested);
389 mono_threads_lock ();
393 } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
394 /* We have to check whether the thread object for the
395 * tid is still the same in the table because the
396 * thread might have been destroyed and the tid reused
397 * in the meantime, in which case the tid would be in
398 * the table, but with another thread object.
402 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
406 mono_threads_unlock ();
408 /* Don't close the handle here, wait for the object finalizer
409 * to do it. Otherwise, the following race condition applies:
411 * 1) Thread exits (and thread_cleanup() closes the handle)
413 * 2) Some other handle is reassigned the same slot
415 * 3) Another thread tries to join the first thread, and
416 * blocks waiting for the reassigned handle to be signalled
417 * (which might never happen). This is possible, because the
418 * thread calling Join() still has a reference to the first
422 /* if the thread is not in the hash it has been removed already */
424 if (thread == mono_thread_internal_current ()) {
425 mono_domain_unset ();
426 mono_memory_barrier ();
428 if (mono_thread_cleanup_fn)
429 mono_thread_cleanup_fn (thread_get_tid (thread));
432 mono_release_type_locks (thread);
434 /* Can happen when we attach the profiler helper thread in order to heapshot. */
435 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
436 mono_profiler_thread_end (thread->tid);
438 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
440 if (thread == mono_thread_internal_current ()) {
442 * This will signal async signal handlers that the thread has exited.
443 * The profiler callback needs this to be set, so it cannot be done earlier.
445 mono_domain_unset ();
446 mono_memory_barrier ();
449 if (thread == mono_thread_internal_current ())
450 mono_thread_pop_appdomain_ref ();
452 thread->cached_culture_info = NULL;
454 mono_free_static_data (thread->static_data);
455 thread->static_data = NULL;
456 ref_stack_destroy (thread->appdomain_refs);
457 thread->appdomain_refs = NULL;
459 if (mono_thread_cleanup_fn)
460 mono_thread_cleanup_fn (thread_get_tid (thread));
462 if (mono_gc_is_moving ()) {
463 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
464 thread->thread_pinning_ref = NULL;
467 g_assert (thread->suspended);
468 mono_os_event_destroy (thread->suspended);
469 g_free (thread->suspended);
470 thread->suspended = NULL;
474 * A special static data offset (guint32) consists of 3 parts:
476 * [0] 6-bit index into the array of chunks.
477 * [6] 25-bit offset into the array.
478 * [31] Bit indicating thread or context static.
483 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
494 } SpecialStaticOffset;
496 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
497 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
499 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
500 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
501 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
502 (((SpecialStaticOffset *) &(x))->fields.f)
505 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
507 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
509 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
510 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
512 return ((char *) thread->static_data [idx]) + off;
516 get_context_static_data (MonoAppContext *ctx, guint32 offset)
518 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
520 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
521 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
523 return ((char *) ctx->static_data [idx]) + off;
527 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
529 static MonoClassField *current_thread_field = NULL;
533 if (!current_thread_field) {
534 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
535 g_assert (current_thread_field);
538 mono_class_vtable (domain, mono_defaults.thread_class);
539 mono_domain_lock (domain);
540 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
541 mono_domain_unlock (domain);
544 return (MonoThread **)get_thread_static_data (thread, offset);
548 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
550 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
552 g_assert (current->obj.vtable->domain == domain);
554 g_assert (!*current_thread_ptr);
555 *current_thread_ptr = current;
559 create_thread_object (MonoDomain *domain, MonoInternalThread *internal)
565 vtable = mono_class_vtable (domain, mono_defaults.thread_class);
568 thread = (MonoThread*)mono_object_new_mature (vtable, &error);
569 /* only possible failure mode is OOM, from which we don't expect to recover. */
570 mono_error_assert_ok (&error);
572 MONO_OBJECT_SETREF (thread, internal_thread, internal);
577 static MonoInternalThread*
578 create_internal_thread_object (void)
581 MonoInternalThread *thread;
584 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
585 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
586 /* only possible failure mode is OOM, from which we don't exect to recover */
587 mono_error_assert_ok (&error);
589 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
590 mono_coop_mutex_init_recursive (thread->synch_cs);
592 thread->apartment_state = ThreadApartmentState_Unknown;
593 thread->managed_id = get_next_managed_thread_id ();
594 if (mono_gc_is_moving ()) {
595 thread->thread_pinning_ref = thread;
596 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
599 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
601 thread->suspended = g_new0 (MonoOSEvent, 1);
602 mono_os_event_init (thread->suspended, TRUE);
608 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
612 g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
613 g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
614 g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
619 g_assert (internal->native_handle);
621 res = SetThreadPriority (internal->native_handle, priority - 2);
623 g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
624 #else /* HOST_WIN32 */
627 struct sched_param param;
630 tid = thread_get_tid (internal);
632 res = pthread_getschedparam (tid, &policy, ¶m);
634 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
636 #ifdef _POSIX_PRIORITY_SCHEDULING
639 /* Necessary to get valid priority range */
641 min = sched_get_priority_min (policy);
642 max = sched_get_priority_max (policy);
644 if (max > 0 && min >= 0 && max > min) {
645 double srange, drange, sposition, dposition;
646 srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
648 sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
649 dposition = (sposition / srange) * drange;
650 param.sched_priority = (int)(dposition + min);
657 param.sched_priority = 50;
663 param.sched_priority = 0;
666 g_error ("%s: unknown policy %d", __func__, policy);
670 res = pthread_setschedparam (tid, policy, ¶m);
673 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
676 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
678 #endif /* HOST_WIN32 */
682 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
685 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
687 MonoThreadInfo *info;
688 MonoInternalThread *internal;
689 MonoDomain *domain, *root_domain;
693 info = mono_thread_info_current ();
695 internal = thread->internal_thread;
696 internal->handle = mono_threads_open_thread_handle (info->handle);
698 internal->native_handle = OpenThread (THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId ());
700 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
701 internal->thread_info = info;
702 internal->small_id = info->small_id;
703 internal->stack_ptr = stack_ptr;
705 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
707 SET_CURRENT_OBJECT (internal);
709 domain = mono_object_domain (thread);
711 mono_thread_push_appdomain_ref (domain);
712 if (!mono_domain_set (domain, force_domain)) {
713 mono_thread_pop_appdomain_ref ();
717 mono_threads_lock ();
719 if (threads_starting_up)
720 mono_g_hash_table_remove (threads_starting_up, thread);
722 if (shutting_down && !force_attach) {
723 mono_threads_unlock ();
728 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
729 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
732 /* We don't need to duplicate thread->handle, because it is
733 * only closed when the thread object is finalized by the GC. */
734 mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
736 /* We have to do this here because mono_thread_start_cb
737 * requires that root_domain_thread is set up. */
738 if (thread_static_info.offset || thread_static_info.idx > 0) {
739 /* get the current allocated size */
740 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
741 mono_alloc_static_data (&internal->static_data, offset, TRUE);
744 mono_threads_unlock ();
746 root_domain = mono_get_root_domain ();
748 g_assert (!internal->root_domain_thread);
749 if (domain != root_domain)
750 MONO_OBJECT_SETREF (internal, root_domain_thread, create_thread_object (root_domain, internal));
752 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
754 if (domain != root_domain)
755 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
757 set_current_thread_for_domain (domain, internal, thread);
759 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
767 MonoObject *start_delegate;
768 MonoObject *start_delegate_arg;
769 MonoThreadStart start_func;
770 gpointer start_func_arg;
772 MonoCoopSem registered;
775 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
778 MonoThreadStart start_func;
779 void *start_func_arg;
782 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
786 MonoInternalThread *internal;
787 MonoObject *start_delegate;
788 MonoObject *start_delegate_arg;
791 thread = start_info->thread;
792 internal = thread->internal_thread;
793 domain = mono_object_domain (start_info->thread);
795 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
797 if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
798 start_info->failed = TRUE;
800 mono_coop_sem_post (&start_info->registered);
802 if (InterlockedDecrement (&start_info->ref) == 0) {
803 mono_coop_sem_destroy (&start_info->registered);
810 mono_thread_internal_set_priority (internal, internal->priority);
814 start_delegate = start_info->start_delegate;
815 start_delegate_arg = start_info->start_delegate_arg;
816 start_func = start_info->start_func;
817 start_func_arg = start_info->start_func_arg;
819 /* This MUST be called before any managed code can be
820 * executed, as it calls the callback function that (for the
821 * jit) sets the lmf marker.
824 if (mono_thread_start_cb)
825 mono_thread_start_cb (tid, stack_ptr, start_func);
827 /* On 2.0 profile (and higher), set explicitly since state might have been
829 if (internal->apartment_state == ThreadApartmentState_Unknown)
830 internal->apartment_state = ThreadApartmentState_MTA;
832 mono_thread_init_apartment_state ();
834 /* Let the thread that called Start() know we're ready */
835 mono_coop_sem_post (&start_info->registered);
837 if (InterlockedDecrement (&start_info->ref) == 0) {
838 mono_coop_sem_destroy (&start_info->registered);
842 /* start_info is not valid anymore */
846 * Call this after calling start_notify, since the profiler callback might want
847 * to lock the thread, and the lock is held by thread_start () which waits for
850 mono_profiler_thread_start (tid);
852 /* if the name was set before starting, we didn't invoke the profiler callback */
853 if (internal->name) {
854 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
855 mono_profiler_thread_name (internal->tid, tname);
856 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
860 /* start_func is set only for unmanaged start functions */
862 start_func (start_func_arg);
866 g_assert (start_delegate != NULL);
868 /* we may want to handle the exception here. See comment below on unhandled exceptions */
869 args [0] = (gpointer) start_delegate_arg;
870 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
872 if (!mono_error_ok (&error)) {
873 MonoException *ex = mono_error_convert_to_exception (&error);
875 g_assert (ex != NULL);
876 MonoClass *klass = mono_object_get_class (&ex->object);
877 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
878 !is_threadabort_exception (klass)) {
879 mono_unhandled_exception (&ex->object);
880 mono_invoke_unhandled_exception_hook (&ex->object);
881 g_assert_not_reached ();
884 mono_error_cleanup (&error);
888 /* If the thread calls ExitThread at all, this remaining code
889 * will not be executed, but the main thread will eventually
890 * call thread_cleanup() on this thread's behalf.
893 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
895 /* Do any cleanup needed for apartment state. This
896 * cannot be done in thread_cleanup since thread_cleanup could be
897 * called for a thread other than the current thread.
898 * mono_thread_cleanup_apartment_state cleans up apartment
899 * for the current thead */
900 mono_thread_cleanup_apartment_state ();
902 mono_thread_detach_internal (internal);
909 static gsize WINAPI start_wrapper(void *data)
911 volatile gsize dummy;
913 return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
919 * Common thread creation code.
920 * LOCKING: Acquires the threads lock.
923 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
924 gboolean threadpool_thread, guint32 stack_size, MonoError *error)
926 StartInfo *start_info = NULL;
927 MonoThreadHandle *thread_handle;
928 MonoNativeThreadId tid;
930 gsize stack_set_size;
933 g_assert (!start_func && !start_func_arg);
935 g_assert (!start_delegate);
938 * Join joinable threads to prevent running out of threads since the finalizer
939 * thread might be blocked/backlogged.
941 mono_threads_join_threads ();
943 mono_error_init (error);
945 mono_threads_lock ();
947 mono_threads_unlock ();
950 if (threads_starting_up == NULL) {
951 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
952 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
954 mono_g_hash_table_insert (threads_starting_up, thread, thread);
955 mono_threads_unlock ();
957 internal->threadpool_thread = threadpool_thread;
958 if (threadpool_thread)
959 mono_thread_set_state (internal, ThreadState_Background);
961 start_info = g_new0 (StartInfo, 1);
963 start_info->thread = thread;
964 start_info->start_delegate = start_delegate;
965 start_info->start_delegate_arg = thread->start_obj;
966 start_info->start_func = start_func;
967 start_info->start_func_arg = start_func_arg;
968 start_info->failed = FALSE;
969 mono_coop_sem_init (&start_info->registered, 0);
972 stack_set_size = default_stacksize_for_thread (internal);
976 thread_handle = mono_threads_create_thread (start_wrapper, start_info, &stack_set_size, &tid);
978 if (thread_handle == NULL) {
979 /* The thread couldn't be created, so set an exception */
980 mono_threads_lock ();
981 mono_g_hash_table_remove (threads_starting_up, thread);
982 mono_threads_unlock ();
983 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
984 /* ref is not going to be decremented in start_wrapper_internal */
985 InterlockedDecrement (&start_info->ref);
990 internal->stack_size = (int) stack_set_size;
992 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
995 * Wait for the thread to set up its TLS data etc, so
996 * theres no potential race condition if someone tries
997 * to look up the data believing the thread has
1001 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
1003 mono_threads_close_thread_handle (thread_handle);
1005 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
1007 ret = !start_info->failed;
1010 if (InterlockedDecrement (&start_info->ref) == 0) {
1011 mono_coop_sem_destroy (&start_info->registered);
1012 g_free (start_info);
1018 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
1020 if (mono_thread_start_cb) {
1021 mono_thread_start_cb (tid, stack_start, func);
1025 void mono_threads_set_default_stacksize (guint32 stacksize)
1027 default_stacksize = stacksize;
1030 guint32 mono_threads_get_default_stacksize (void)
1032 return default_stacksize;
1036 * mono_thread_create_internal:
1038 * ARG should not be a GC reference.
1041 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
1044 MonoInternalThread *internal;
1047 mono_error_init (error);
1049 internal = create_internal_thread_object ();
1051 thread = create_thread_object (domain, internal);
1053 LOCK_THREAD (internal);
1055 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
1056 return_val_if_nok (error, NULL);
1058 UNLOCK_THREAD (internal);
1064 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1067 if (!mono_thread_create_checked (domain, func, arg, &error))
1068 mono_error_cleanup (&error);
1072 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1074 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
1078 mono_thread_attach (MonoDomain *domain)
1080 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1086 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1088 MonoInternalThread *internal;
1090 MonoNativeThreadId tid;
1093 if (mono_thread_internal_current_is_attached ()) {
1094 if (domain != mono_domain_get ())
1095 mono_domain_set (domain, TRUE);
1096 /* Already attached */
1097 return mono_thread_current ();
1100 if (!mono_gc_register_thread (&domain)) {
1101 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", mono_native_thread_id_get ());
1104 tid=mono_native_thread_id_get ();
1106 internal = create_internal_thread_object ();
1108 thread = create_thread_object (domain, internal);
1110 if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
1111 /* Mono is shutting down, so just wait for the end */
1113 mono_thread_info_sleep (10000, NULL);
1116 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1118 if (mono_thread_attach_cb) {
1122 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1125 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1127 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1130 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1131 if (!mono_thread_info_current ()->tools_thread)
1132 // FIXME: Need a separate callback
1133 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1139 mono_thread_detach_internal (MonoInternalThread *thread)
1141 g_return_if_fail (thread != NULL);
1143 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1146 mono_w32mutex_abandon ();
1149 thread_cleanup (thread);
1151 SET_CURRENT_OBJECT (NULL);
1152 mono_domain_unset ();
1154 /* Don't need to close the handle to this thread, even though we took a
1155 * reference in mono_thread_attach (), because the GC will do it
1156 * when the Thread object is finalised.
1161 mono_thread_detach (MonoThread *thread)
1164 mono_thread_detach_internal (thread->internal_thread);
1168 * mono_thread_detach_if_exiting:
1170 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1171 * This should be used at the end of embedding code which calls into managed code, and which
1172 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1175 mono_thread_detach_if_exiting (void)
1177 if (mono_thread_info_is_exiting ()) {
1178 MonoInternalThread *thread;
1180 thread = mono_thread_internal_current ();
1182 mono_thread_detach_internal (thread);
1183 mono_thread_info_detach ();
1191 mono_thread_internal_current_is_attached (void)
1193 MonoInternalThread *internal;
1195 internal = GET_CURRENT_OBJECT ();
1203 mono_thread_exit (void)
1205 MonoInternalThread *thread = mono_thread_internal_current ();
1207 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1209 mono_thread_detach_internal (thread);
1211 /* we could add a callback here for embedders to use. */
1212 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1213 exit (mono_environment_exitcode_get ());
1215 mono_thread_info_exit (0);
1219 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1221 MonoInternalThread *internal;
1223 internal = create_internal_thread_object ();
1225 internal->state = ThreadState_Unstarted;
1227 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1231 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1235 MonoInternalThread *internal;
1238 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1240 if (!this_obj->internal_thread)
1241 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1242 internal = this_obj->internal_thread;
1244 LOCK_THREAD (internal);
1246 if ((internal->state & ThreadState_Unstarted) == 0) {
1247 UNLOCK_THREAD (internal);
1248 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1252 if ((internal->state & ThreadState_Aborted) != 0) {
1253 UNLOCK_THREAD (internal);
1257 res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1259 mono_error_cleanup (&error);
1260 UNLOCK_THREAD (internal);
1264 internal->state &= ~ThreadState_Unstarted;
1266 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1268 UNLOCK_THREAD (internal);
1269 return internal->handle;
1273 * This is called from the finalizer of the internal thread object.
1276 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj)
1278 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle));
1281 * Since threads keep a reference to their thread object while running, by the time this function is called,
1282 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1283 * when thread_cleanup () can be called after this.
1285 if (this_obj->handle) {
1286 mono_threads_close_thread_handle (this_obj->handle);
1287 this_obj->handle = NULL;
1291 CloseHandle (this_obj->native_handle);
1294 if (this_obj->synch_cs) {
1295 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1296 this_obj->synch_cs = NULL;
1297 mono_coop_mutex_destroy (synch_cs);
1301 if (this_obj->name) {
1302 void *name = this_obj->name;
1303 this_obj->name = NULL;
1309 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1312 MonoInternalThread *thread = mono_thread_internal_current ();
1314 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1316 if (mono_thread_current_check_pending_interrupt ())
1320 gboolean alerted = FALSE;
1322 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1324 res = mono_thread_info_sleep (ms, &alerted);
1326 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1329 MonoException* exc = mono_thread_execute_interruption ();
1331 mono_raise_exception (exc);
1343 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1348 ves_icall_System_Threading_Thread_GetDomainID (void)
1350 return mono_domain_get()->domain_id;
1354 ves_icall_System_Threading_Thread_Yield (void)
1356 return mono_thread_info_yield ();
1360 * mono_thread_get_name:
1362 * Return the name of the thread. NAME_LEN is set to the length of the name.
1363 * Return NULL if the thread has no name. The returned memory is owned by the
1367 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1371 LOCK_THREAD (this_obj);
1373 if (!this_obj->name) {
1377 *name_len = this_obj->name_len;
1378 res = g_new (gunichar2, this_obj->name_len);
1379 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1382 UNLOCK_THREAD (this_obj);
1388 * mono_thread_get_name_utf8:
1390 * Return the name of the thread in UTF-8.
1391 * Return NULL if the thread has no name.
1392 * The returned memory is owned by the caller.
1395 mono_thread_get_name_utf8 (MonoThread *thread)
1400 MonoInternalThread *internal = thread->internal_thread;
1401 if (internal == NULL)
1404 LOCK_THREAD (internal);
1406 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1408 UNLOCK_THREAD (internal);
1414 * mono_thread_get_managed_id:
1416 * Return the Thread.ManagedThreadId value of `thread`.
1417 * Returns -1 if `thread` is NULL.
1420 mono_thread_get_managed_id (MonoThread *thread)
1425 MonoInternalThread *internal = thread->internal_thread;
1426 if (internal == NULL)
1429 int32_t id = internal->managed_id;
1435 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1440 mono_error_init (&error);
1442 LOCK_THREAD (this_obj);
1444 if (!this_obj->name)
1447 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1449 UNLOCK_THREAD (this_obj);
1451 if (mono_error_set_pending_exception (&error))
1458 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1460 LOCK_THREAD (this_obj);
1462 mono_error_init (error);
1464 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1465 UNLOCK_THREAD (this_obj);
1467 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1470 if (this_obj->name) {
1471 g_free (this_obj->name);
1472 this_obj->name_len = 0;
1475 this_obj->name = g_new (gunichar2, mono_string_length (name));
1476 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1477 this_obj->name_len = mono_string_length (name);
1480 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1483 this_obj->name = NULL;
1486 UNLOCK_THREAD (this_obj);
1488 if (this_obj->name && this_obj->tid) {
1489 char *tname = mono_string_to_utf8_checked (name, error);
1490 return_if_nok (error);
1491 mono_profiler_thread_name (this_obj->tid, tname);
1492 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1498 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1501 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1502 mono_error_set_pending_exception (&error);
1506 * ves_icall_System_Threading_Thread_GetPriority_internal:
1507 * @param this_obj: The MonoInternalThread on which to operate.
1509 * Gets the priority of the given thread.
1510 * @return: The priority of the given thread.
1513 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1516 MonoInternalThread *internal = this_obj->internal_thread;
1518 LOCK_THREAD (internal);
1519 priority = internal->priority;
1520 UNLOCK_THREAD (internal);
1526 * ves_icall_System_Threading_Thread_SetPriority_internal:
1527 * @param this_obj: The MonoInternalThread on which to operate.
1528 * @param priority: The priority to set.
1530 * Sets the priority of the given thread.
1533 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1535 MonoInternalThread *internal = this_obj->internal_thread;
1537 LOCK_THREAD (internal);
1538 internal->priority = priority;
1539 if (internal->thread_info != NULL)
1540 mono_thread_internal_set_priority (internal, priority);
1541 UNLOCK_THREAD (internal);
1544 /* If the array is already in the requested domain, we just return it,
1545 otherwise we return a copy in that domain. */
1547 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1551 mono_error_init (error);
1555 if (mono_object_domain (arr) == domain)
1558 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1559 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1564 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1567 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1568 mono_error_set_pending_exception (&error);
1573 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1576 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1577 mono_error_set_pending_exception (&error);
1582 mono_thread_current (void)
1584 MonoDomain *domain = mono_domain_get ();
1585 MonoInternalThread *internal = mono_thread_internal_current ();
1586 MonoThread **current_thread_ptr;
1588 g_assert (internal);
1589 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1591 if (!*current_thread_ptr) {
1592 g_assert (domain != mono_get_root_domain ());
1593 *current_thread_ptr = create_thread_object (domain, internal);
1595 return *current_thread_ptr;
1598 /* Return the thread object belonging to INTERNAL in the current domain */
1600 mono_thread_current_for_thread (MonoInternalThread *internal)
1602 MonoDomain *domain = mono_domain_get ();
1603 MonoThread **current_thread_ptr;
1605 g_assert (internal);
1606 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1608 if (!*current_thread_ptr) {
1609 g_assert (domain != mono_get_root_domain ());
1610 *current_thread_ptr = create_thread_object (domain, internal);
1612 return *current_thread_ptr;
1616 mono_thread_internal_current (void)
1618 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1619 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1624 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1626 MonoInternalThread *thread = this_obj->internal_thread;
1627 MonoThreadHandle *handle = thread->handle;
1628 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1631 if (mono_thread_current_check_pending_interrupt ())
1634 LOCK_THREAD (thread);
1636 if ((thread->state & ThreadState_Unstarted) != 0) {
1637 UNLOCK_THREAD (thread);
1639 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1643 UNLOCK_THREAD (thread);
1648 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1650 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1653 ret=mono_thread_info_wait_one_handle (handle, ms, TRUE);
1656 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1658 if(ret==MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
1659 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1664 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1669 #define MANAGED_WAIT_FAILED 0x7fffffff
1672 map_native_wait_result_to_managed (gint32 val)
1674 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1675 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1679 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1687 mono_error_init (error);
1689 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1692 if (numhandles != 1)
1693 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1695 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1698 if (ret != WAIT_IO_COMPLETION)
1701 exc = mono_thread_execute_interruption ();
1703 mono_error_set_exception_instance (error, exc);
1710 /* Re-calculate ms according to the time passed */
1711 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1712 if (diff_ms >= ms) {
1716 wait = ms - diff_ms;
1722 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1729 MonoObject *waitHandle;
1730 MonoInternalThread *thread = mono_thread_internal_current ();
1732 /* Do this WaitSleepJoin check before creating objects */
1733 if (mono_thread_current_check_pending_interrupt ())
1734 return map_native_wait_result_to_managed (WAIT_FAILED);
1736 /* We fail in managed if the array has more than 64 elements */
1737 numhandles = (guint32)mono_array_length(mono_handles);
1738 handles = g_new0(HANDLE, numhandles);
1740 for(i = 0; i < numhandles; i++) {
1741 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1742 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1749 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1751 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1753 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1757 mono_error_set_pending_exception (&error);
1759 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1760 return map_native_wait_result_to_managed (ret);
1763 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1766 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1767 uintptr_t numhandles;
1770 MonoObject *waitHandle;
1771 MonoInternalThread *thread = mono_thread_internal_current ();
1773 /* Do this WaitSleepJoin check before creating objects */
1774 if (mono_thread_current_check_pending_interrupt ())
1775 return map_native_wait_result_to_managed (WAIT_FAILED);
1777 numhandles = mono_array_length(mono_handles);
1778 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1779 return map_native_wait_result_to_managed (WAIT_FAILED);
1781 for(i = 0; i < numhandles; i++) {
1782 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1783 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1790 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1792 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1794 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1796 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1798 mono_error_set_pending_exception (&error);
1800 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1801 return map_native_wait_result_to_managed (ret);
1804 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1808 MonoInternalThread *thread = mono_thread_internal_current ();
1810 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1816 if (mono_thread_current_check_pending_interrupt ())
1817 return map_native_wait_result_to_managed (WAIT_FAILED);
1819 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1821 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1823 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1825 mono_error_set_pending_exception (&error);
1826 return map_native_wait_result_to_managed (ret);
1830 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1833 MonoInternalThread *thread = mono_thread_internal_current ();
1838 if (mono_thread_current_check_pending_interrupt ())
1839 return map_native_wait_result_to_managed (WAIT_FAILED);
1841 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1844 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1847 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1849 return map_native_wait_result_to_managed (ret);
1852 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1854 return InterlockedIncrement (location);
1857 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1859 #if SIZEOF_VOID_P == 4
1860 if (G_UNLIKELY ((size_t)location & 0x7)) {
1862 mono_interlocked_lock ();
1865 mono_interlocked_unlock ();
1869 return InterlockedIncrement64 (location);
1872 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1874 return InterlockedDecrement(location);
1877 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1879 #if SIZEOF_VOID_P == 4
1880 if (G_UNLIKELY ((size_t)location & 0x7)) {
1882 mono_interlocked_lock ();
1885 mono_interlocked_unlock ();
1889 return InterlockedDecrement64 (location);
1892 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1894 return InterlockedExchange(location, value);
1897 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1900 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1901 mono_gc_wbarrier_generic_nostore (location);
1905 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1907 return InterlockedExchangePointer(location, value);
1910 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1912 IntFloatUnion val, ret;
1915 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1921 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1923 #if SIZEOF_VOID_P == 4
1924 if (G_UNLIKELY ((size_t)location & 0x7)) {
1926 mono_interlocked_lock ();
1929 mono_interlocked_unlock ();
1933 return InterlockedExchange64 (location, value);
1937 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1939 LongDoubleUnion val, ret;
1942 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1947 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1949 return InterlockedCompareExchange(location, value, comparand);
1952 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1954 gint32 r = InterlockedCompareExchange(location, value, comparand);
1955 *success = r == comparand;
1959 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1962 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1963 mono_gc_wbarrier_generic_nostore (location);
1967 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1969 return InterlockedCompareExchangePointer(location, value, comparand);
1972 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1974 IntFloatUnion val, ret, cmp;
1977 cmp.fval = comparand;
1978 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1984 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1986 #if SIZEOF_VOID_P == 8
1987 LongDoubleUnion val, comp, ret;
1990 comp.fval = comparand;
1991 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1997 mono_interlocked_lock ();
1999 if (old == comparand)
2001 mono_interlocked_unlock ();
2008 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2010 #if SIZEOF_VOID_P == 4
2011 if (G_UNLIKELY ((size_t)location & 0x7)) {
2013 mono_interlocked_lock ();
2015 if (old == comparand)
2017 mono_interlocked_unlock ();
2021 return InterlockedCompareExchange64 (location, value, comparand);
2025 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2028 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2029 mono_gc_wbarrier_generic_nostore (location);
2034 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2037 MONO_CHECK_NULL (location, NULL);
2038 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2039 mono_gc_wbarrier_generic_nostore (location);
2044 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2046 return InterlockedAdd (location, value);
2050 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2052 #if SIZEOF_VOID_P == 4
2053 if (G_UNLIKELY ((size_t)location & 0x7)) {
2055 mono_interlocked_lock ();
2058 mono_interlocked_unlock ();
2062 return InterlockedAdd64 (location, value);
2066 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2068 #if SIZEOF_VOID_P == 4
2069 if (G_UNLIKELY ((size_t)location & 0x7)) {
2071 mono_interlocked_lock ();
2073 mono_interlocked_unlock ();
2077 return InterlockedRead64 (location);
2081 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2083 mono_memory_barrier ();
2087 signal_background_change (void)
2089 thread_wait_lock ();
2090 background_changed = TRUE;
2091 mono_os_cond_signal (&thread_wait_cond);
2092 thread_wait_unlock ();
2094 mono_os_event_set (&background_change_event);
2099 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2101 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2103 if (state & ThreadState_Background) {
2104 /* If the thread changes the background mode, the main thread has to
2105 * be notified, since it has to rebuild the list of threads to
2108 signal_background_change ();
2113 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2115 mono_thread_set_state (this_obj, (MonoThreadState)state);
2117 if (state & ThreadState_Background) {
2118 /* If the thread changes the background mode, the main thread has to
2119 * be notified, since it has to rebuild the list of threads to
2122 signal_background_change ();
2127 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2131 LOCK_THREAD (this_obj);
2133 state = this_obj->state;
2135 UNLOCK_THREAD (this_obj);
2140 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2142 MonoInternalThread *current;
2144 MonoInternalThread *thread = this_obj->internal_thread;
2146 LOCK_THREAD (thread);
2148 current = mono_thread_internal_current ();
2150 thread->thread_interrupt_requested = TRUE;
2151 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2153 UNLOCK_THREAD (thread);
2156 async_abort_internal (thread, FALSE);
2161 * mono_thread_current_check_pending_interrupt:
2163 * Checks if there's a interruption request and set the pending exception if so.
2165 * @returns true if a pending exception was set
2168 mono_thread_current_check_pending_interrupt (void)
2170 MonoInternalThread *thread = mono_thread_internal_current ();
2171 gboolean throw_ = FALSE;
2173 LOCK_THREAD (thread);
2175 if (thread->thread_interrupt_requested) {
2177 thread->thread_interrupt_requested = FALSE;
2180 UNLOCK_THREAD (thread);
2183 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2188 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2190 LOCK_THREAD (thread);
2192 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2193 (thread->state & ThreadState_StopRequested) != 0 ||
2194 (thread->state & ThreadState_Stopped) != 0)
2196 UNLOCK_THREAD (thread);
2200 if ((thread->state & ThreadState_Unstarted) != 0) {
2201 thread->state |= ThreadState_Aborted;
2202 UNLOCK_THREAD (thread);
2206 thread->state |= ThreadState_AbortRequested;
2207 if (thread->abort_state_handle)
2208 mono_gchandle_free (thread->abort_state_handle);
2210 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2211 g_assert (thread->abort_state_handle);
2213 thread->abort_state_handle = 0;
2215 thread->abort_exc = NULL;
2217 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), thread, (gsize)thread->tid));
2219 /* During shutdown, we can't wait for other threads */
2221 /* Make sure the thread is awake */
2222 mono_thread_resume (thread);
2224 UNLOCK_THREAD (thread);
2229 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2231 if (!request_thread_abort (thread, state))
2234 if (thread == mono_thread_internal_current ()) {
2236 self_abort_internal (&error);
2237 mono_error_set_pending_exception (&error);
2239 async_abort_internal (thread, TRUE);
2244 * mono_thread_internal_abort:
2246 * Request thread @thread to be aborted.
2248 * @thread MUST NOT be the current thread.
2251 mono_thread_internal_abort (MonoInternalThread *thread)
2253 g_assert (thread != mono_thread_internal_current ());
2255 if (!request_thread_abort (thread, NULL))
2257 async_abort_internal (thread, TRUE);
2261 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2263 MonoInternalThread *thread = mono_thread_internal_current ();
2264 gboolean was_aborting;
2266 LOCK_THREAD (thread);
2267 was_aborting = thread->state & ThreadState_AbortRequested;
2268 thread->state &= ~ThreadState_AbortRequested;
2269 UNLOCK_THREAD (thread);
2271 if (!was_aborting) {
2272 const char *msg = "Unable to reset abort because no abort was requested";
2273 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2276 thread->abort_exc = NULL;
2277 if (thread->abort_state_handle) {
2278 mono_gchandle_free (thread->abort_state_handle);
2279 /* This is actually not necessary - the handle
2280 only counts if the exception is set */
2281 thread->abort_state_handle = 0;
2286 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2288 LOCK_THREAD (thread);
2290 thread->state &= ~ThreadState_AbortRequested;
2292 if (thread->abort_exc) {
2293 thread->abort_exc = NULL;
2294 if (thread->abort_state_handle) {
2295 mono_gchandle_free (thread->abort_state_handle);
2296 /* This is actually not necessary - the handle
2297 only counts if the exception is set */
2298 thread->abort_state_handle = 0;
2302 UNLOCK_THREAD (thread);
2306 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2309 MonoInternalThread *thread = this_obj->internal_thread;
2310 MonoObject *state, *deserialized = NULL;
2313 if (!thread->abort_state_handle)
2316 state = mono_gchandle_get_target (thread->abort_state_handle);
2319 domain = mono_domain_get ();
2320 if (mono_object_domain (state) == domain)
2323 deserialized = mono_object_xdomain_representation (state, domain, &error);
2325 if (!deserialized) {
2326 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2327 if (!is_ok (&error)) {
2328 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2329 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2331 mono_set_pending_exception (invalid_op_exc);
2335 return deserialized;
2339 mono_thread_suspend (MonoInternalThread *thread)
2341 LOCK_THREAD (thread);
2343 if ((thread->state & ThreadState_Unstarted) != 0 ||
2344 (thread->state & ThreadState_Aborted) != 0 ||
2345 (thread->state & ThreadState_Stopped) != 0)
2347 UNLOCK_THREAD (thread);
2351 if ((thread->state & ThreadState_Suspended) != 0 ||
2352 (thread->state & ThreadState_SuspendRequested) != 0 ||
2353 (thread->state & ThreadState_StopRequested) != 0)
2355 UNLOCK_THREAD (thread);
2359 thread->state |= ThreadState_SuspendRequested;
2360 mono_os_event_reset (thread->suspended);
2362 if (thread == mono_thread_internal_current ()) {
2363 /* calls UNLOCK_THREAD (thread) */
2364 self_suspend_internal ();
2366 /* calls UNLOCK_THREAD (thread) */
2367 async_suspend_internal (thread, FALSE);
2374 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2376 if (!mono_thread_suspend (this_obj->internal_thread)) {
2377 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2382 /* LOCKING: LOCK_THREAD(thread) must be held */
2384 mono_thread_resume (MonoInternalThread *thread)
2386 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2387 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread));
2388 thread->state &= ~ThreadState_SuspendRequested;
2389 mono_os_event_set (thread->suspended);
2393 if ((thread->state & ThreadState_Suspended) == 0 ||
2394 (thread->state & ThreadState_Unstarted) != 0 ||
2395 (thread->state & ThreadState_Aborted) != 0 ||
2396 (thread->state & ThreadState_Stopped) != 0)
2398 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread));
2402 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread));
2404 mono_os_event_set (thread->suspended);
2406 if (!thread->self_suspended) {
2407 UNLOCK_THREAD (thread);
2409 /* Awake the thread */
2410 if (!mono_thread_info_resume (thread_get_tid (thread)))
2413 LOCK_THREAD (thread);
2416 thread->state &= ~ThreadState_Suspended;
2422 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2424 if (!thread->internal_thread) {
2425 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2427 LOCK_THREAD (thread->internal_thread);
2428 if (!mono_thread_resume (thread->internal_thread))
2429 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2430 UNLOCK_THREAD (thread->internal_thread);
2435 mono_threads_is_critical_method (MonoMethod *method)
2437 switch (method->wrapper_type) {
2438 case MONO_WRAPPER_RUNTIME_INVOKE:
2439 case MONO_WRAPPER_XDOMAIN_INVOKE:
2440 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2447 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2452 if (mono_threads_is_critical_method (m)) {
2453 *((gboolean*)data) = TRUE;
2460 is_running_protected_wrapper (void)
2462 gboolean found = FALSE;
2463 mono_stack_walk (find_wrapper, &found);
2468 request_thread_stop (MonoInternalThread *thread)
2470 LOCK_THREAD (thread);
2472 if ((thread->state & ThreadState_StopRequested) != 0 ||
2473 (thread->state & ThreadState_Stopped) != 0)
2475 UNLOCK_THREAD (thread);
2479 /* Make sure the thread is awake */
2480 mono_thread_resume (thread);
2482 thread->state |= ThreadState_StopRequested;
2483 thread->state &= ~ThreadState_AbortRequested;
2485 UNLOCK_THREAD (thread);
2490 * mono_thread_internal_stop:
2492 * Request thread @thread to stop.
2494 * @thread MUST NOT be the current thread.
2497 mono_thread_internal_stop (MonoInternalThread *thread)
2499 g_assert (thread != mono_thread_internal_current ());
2501 if (!request_thread_stop (thread))
2504 async_abort_internal (thread, TRUE);
2507 void mono_thread_stop (MonoThread *thread)
2509 MonoInternalThread *internal = thread->internal_thread;
2511 if (!request_thread_stop (internal))
2514 if (internal == mono_thread_internal_current ()) {
2516 self_abort_internal (&error);
2518 This function is part of the embeding API and has no way to return the exception
2519 to be thrown. So what we do is keep the old behavior and raise the exception.
2521 mono_error_raise_exception (&error); /* OK to throw, see note */
2523 async_abort_internal (internal, TRUE);
2528 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2530 gint8 tmp = *(volatile gint8 *)ptr;
2531 mono_memory_barrier ();
2536 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2538 gint16 tmp = *(volatile gint16 *)ptr;
2539 mono_memory_barrier ();
2544 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2546 gint32 tmp = *(volatile gint32 *)ptr;
2547 mono_memory_barrier ();
2552 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2554 gint64 tmp = *(volatile gint64 *)ptr;
2555 mono_memory_barrier ();
2560 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2562 volatile void *tmp = *(volatile void **)ptr;
2563 mono_memory_barrier ();
2564 return (void *) tmp;
2568 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2570 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2571 mono_memory_barrier ();
2572 return (MonoObject *) tmp;
2576 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2578 double tmp = *(volatile double *)ptr;
2579 mono_memory_barrier ();
2584 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2586 float tmp = *(volatile float *)ptr;
2587 mono_memory_barrier ();
2592 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2594 return InterlockedRead8 ((volatile gint8 *)ptr);
2598 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2600 return InterlockedRead16 ((volatile gint16 *)ptr);
2604 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2606 return InterlockedRead ((volatile gint32 *)ptr);
2610 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2612 #if SIZEOF_VOID_P == 4
2613 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2615 mono_interlocked_lock ();
2616 val = *(gint64*)ptr;
2617 mono_interlocked_unlock ();
2621 return InterlockedRead64 ((volatile gint64 *)ptr);
2625 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2627 return InterlockedReadPointer ((volatile gpointer *)ptr);
2631 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2635 #if SIZEOF_VOID_P == 4
2636 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2638 mono_interlocked_lock ();
2639 val = *(double*)ptr;
2640 mono_interlocked_unlock ();
2645 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2651 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2655 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2661 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2663 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2667 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2669 mono_memory_barrier ();
2670 *(volatile gint8 *)ptr = value;
2674 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2676 mono_memory_barrier ();
2677 *(volatile gint16 *)ptr = value;
2681 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2683 mono_memory_barrier ();
2684 *(volatile gint32 *)ptr = value;
2688 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2690 mono_memory_barrier ();
2691 *(volatile gint64 *)ptr = value;
2695 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2697 mono_memory_barrier ();
2698 *(volatile void **)ptr = value;
2702 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2704 mono_memory_barrier ();
2705 mono_gc_wbarrier_generic_store (ptr, value);
2709 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2711 mono_memory_barrier ();
2712 *(volatile double *)ptr = value;
2716 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2718 mono_memory_barrier ();
2719 *(volatile float *)ptr = value;
2723 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2725 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2729 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2731 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2735 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2737 InterlockedWrite ((volatile gint32 *)ptr, value);
2741 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2743 #if SIZEOF_VOID_P == 4
2744 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2745 mono_interlocked_lock ();
2746 *(gint64*)ptr = value;
2747 mono_interlocked_unlock ();
2752 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2756 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2758 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2762 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2766 #if SIZEOF_VOID_P == 4
2767 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2768 mono_interlocked_lock ();
2769 *(double*)ptr = value;
2770 mono_interlocked_unlock ();
2777 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2781 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2787 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2791 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2793 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2797 free_context (void *user_data)
2799 ContextStaticData *data = user_data;
2801 mono_threads_lock ();
2804 * There is no guarantee that, by the point this reference queue callback
2805 * has been invoked, the GC handle associated with the object will fail to
2806 * resolve as one might expect. So if we don't free and remove the GC
2807 * handle here, free_context_static_data_helper () could end up resolving
2808 * a GC handle to an actually-dead context which would contain a pointer
2809 * to an already-freed static data segment, resulting in a crash when
2812 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2814 mono_threads_unlock ();
2816 mono_gchandle_free (data->gc_handle);
2817 mono_free_static_data (data->static_data);
2822 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2824 mono_threads_lock ();
2826 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2829 contexts = g_hash_table_new (NULL, NULL);
2832 context_queue = mono_gc_reference_queue_new (free_context);
2834 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2835 g_hash_table_insert (contexts, gch, gch);
2838 * We use this intermediate structure to contain a duplicate pointer to
2839 * the static data because we can't rely on being able to resolve the GC
2840 * handle in the reference queue callback.
2842 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2843 data->gc_handle = GPOINTER_TO_UINT (gch);
2846 context_adjust_static_data (ctx);
2847 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2849 mono_threads_unlock ();
2851 mono_profiler_context_loaded (ctx);
2855 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2858 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2859 * cleanup in exceptional circumstances, we don't actually do any
2860 * cleanup work here. We instead do this via a reference queue.
2863 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2865 mono_profiler_context_unloaded (ctx);
2869 mono_thread_init_tls (void)
2871 MONO_FAST_TLS_INIT (tls_current_object);
2872 mono_native_tls_alloc (¤t_object_key, NULL);
2875 void mono_thread_init (MonoThreadStartCB start_cb,
2876 MonoThreadAttachCB attach_cb)
2878 mono_coop_mutex_init_recursive (&threads_mutex);
2880 mono_os_mutex_init_recursive(&interlocked_mutex);
2881 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2883 mono_os_mutex_init_recursive(&thread_wait_mutex);
2884 mono_os_cond_init(&thread_wait_cond);
2887 mono_os_event_init (&background_change_event, FALSE);
2890 mono_init_static_data_info (&thread_static_info);
2891 mono_init_static_data_info (&context_static_info);
2893 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2895 mono_thread_start_cb = start_cb;
2896 mono_thread_attach_cb = attach_cb;
2899 void mono_thread_cleanup (void)
2901 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
2902 /* The main thread must abandon any held mutexes (particularly
2903 * important for named mutexes as they are shared across
2904 * processes, see bug 74680.) This will happen when the
2905 * thread exits, but if it's not running in a subthread it
2906 * won't exit in time.
2908 mono_w32mutex_abandon ();
2912 /* This stuff needs more testing, it seems one of these
2913 * critical sections can be locked when mono_thread_cleanup is
2916 mono_coop_mutex_destroy (&threads_mutex);
2917 mono_os_mutex_destroy (&interlocked_mutex);
2918 mono_os_mutex_destroy (&delayed_free_table_mutex);
2919 mono_os_mutex_destroy (&small_id_mutex);
2921 mono_os_event_destroy (&background_change_event);
2925 mono_native_tls_free (current_object_key);
2929 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2931 mono_thread_cleanup_fn = func;
2935 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2937 thread->internal_thread->manage_callback = func;
2941 static void print_tids (gpointer key, gpointer value, gpointer user)
2943 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2944 * sizeof(uint) and a cast to uint would overflow
2946 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2947 * print this as a pointer.
2949 g_message ("Waiting for: %p", key);
2954 MonoThreadHandle *handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2955 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2962 * Wait until either:
2963 * - wait->num threads are joined
2964 * - @check_state_change is TRUE and a thread changes background state
2968 wait_for_tids (WaitData *wait, guint32 timeout, gboolean check_state_change)
2972 * Its is complicated to wait for a given set of threads, so we wait for a given
2973 * number of threads instead, the caller needs to call us until the set of threads
2974 * it is waiting for are terminated.
2976 gboolean finished = FALSE;
2977 gint64 start = mono_msec_ticks ();
2979 thread_wait_lock ();
2980 if (njoined_threads >= wait->njoined + wait->num || (check_state_change && background_changed)) {
2983 int res = mono_os_cond_timedwait (&thread_wait_cond, &thread_wait_mutex, timeout);
2986 if (timeout != INFINITE) {
2987 gint64 now = mono_msec_ticks ();
2988 if (now - start >= timeout) {
2991 timeout -= now - start;
2996 thread_wait_unlock ();
3000 MonoThreadInfoWaitRet ret;
3002 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3004 /* Add the thread state change event, so it wakes
3005 * up if a thread changes to background mode. */
3008 if (check_state_change)
3009 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, &background_change_event, FALSE, timeout, TRUE);
3011 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, NULL, TRUE, timeout, TRUE);
3014 if (ret == MONO_THREAD_INFO_WAIT_RET_FAILED) {
3015 /* See the comment in build_wait_tids() */
3016 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3020 for( i = 0; i < wait->num; i++)
3021 mono_threads_close_thread_handle (wait->handles [i]);
3023 if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT)
3026 if (ret < wait->num) {
3027 MonoInternalThread *internal;
3029 internal = wait->threads [ret];
3031 mono_threads_lock ();
3032 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
3033 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
3034 mono_threads_unlock ();
3040 init_wait_data (WaitData *wait)
3042 /* This is used calculate the number of joined threads in wait_for_tids () */
3043 thread_wait_lock ();
3044 wait->njoined = njoined_threads;
3045 thread_wait_unlock ();
3047 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3048 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3052 add_wait_thread (WaitData *wait, MonoInternalThread *thread)
3055 /* These are not used by the wait_for_tids () code on unix */
3056 wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle);
3058 wait->threads [wait->num] = thread;
3063 build_wait_tids (gpointer key, gpointer value, gpointer user)
3065 WaitData *wait = (WaitData *)user;
3066 MonoInternalThread *thread = (MonoInternalThread *)value;
3068 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS - 1) {
3069 /* Just ignore the rest, we can't do anything with
3075 /* Ignore background threads, we abort them later */
3076 /* Do not lock here since it is not needed and the caller holds threads_lock */
3077 if (thread->state & ThreadState_Background) {
3078 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3079 return; /* just leave, ignore */
3082 if (mono_gc_is_finalizer_internal_thread (thread)) {
3083 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3087 if (thread == mono_thread_internal_current ()) {
3088 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3092 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3093 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3097 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3098 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3102 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3103 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3104 add_wait_thread (wait, thread);
3106 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3108 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3113 collect_and_abort_threads (gpointer key, gpointer value, gpointer user)
3115 WaitData *wait = (WaitData *)user;
3116 MonoNativeThreadId self = mono_native_thread_id_get ();
3117 MonoInternalThread *thread = (MonoInternalThread *)value;
3119 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3122 /* The finalizer thread is not a background thread */
3123 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3124 && (thread->state & ThreadState_Background) != 0
3125 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0) {
3126 add_wait_thread (wait, thread);
3128 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3129 mono_thread_internal_abort (thread);
3135 * mono_threads_set_shutting_down:
3137 * Is called by a thread that wants to shut down Mono. If the runtime is already
3138 * shutting down, the calling thread is suspended/stopped, and this function never
3142 mono_threads_set_shutting_down (void)
3144 MonoInternalThread *current_thread = mono_thread_internal_current ();
3146 mono_threads_lock ();
3148 if (shutting_down) {
3149 mono_threads_unlock ();
3151 /* Make sure we're properly suspended/stopped */
3153 LOCK_THREAD (current_thread);
3155 if ((current_thread->state & ThreadState_SuspendRequested) ||
3156 (current_thread->state & ThreadState_AbortRequested) ||
3157 (current_thread->state & ThreadState_StopRequested)) {
3158 UNLOCK_THREAD (current_thread);
3159 mono_thread_execute_interruption ();
3161 current_thread->state |= ThreadState_Stopped;
3162 UNLOCK_THREAD (current_thread);
3165 /*since we're killing the thread, detach it.*/
3166 mono_thread_detach_internal (current_thread);
3168 /* Wake up other threads potentially waiting for us */
3169 mono_thread_info_exit (0);
3171 shutting_down = TRUE;
3173 /* Not really a background state change, but this will
3174 * interrupt the main thread if it is waiting for all
3175 * the other threads.
3177 signal_background_change ();
3179 mono_threads_unlock ();
3184 mono_thread_manage (void)
3187 WaitData *wait = &wait_data;
3189 memset (wait, 0, sizeof (WaitData));
3190 /* join each thread that's still running */
3191 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3193 mono_threads_lock ();
3195 THREAD_DEBUG (g_message("%s: No threads", __func__));
3196 mono_threads_unlock ();
3199 mono_threads_unlock ();
3202 mono_threads_lock ();
3203 if (shutting_down) {
3204 /* somebody else is shutting down */
3205 mono_threads_unlock ();
3208 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3209 mono_g_hash_table_foreach (threads, print_tids, NULL));
3212 mono_os_event_reset (&background_change_event);
3214 background_changed = FALSE;
3215 init_wait_data (wait);
3216 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3217 mono_threads_unlock ();
3219 /* Something to wait for */
3220 wait_for_tids (wait, INFINITE, TRUE);
3221 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3222 } while (wait->num > 0);
3224 /* Mono is shutting down, so just wait for the end */
3225 if (!mono_runtime_try_shutdown ()) {
3226 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3227 mono_thread_suspend (mono_thread_internal_current ());
3228 mono_thread_execute_interruption ();
3232 * Remove everything but the finalizer thread and self.
3233 * Also abort all the background threads
3236 mono_threads_lock ();
3238 init_wait_data (wait);
3239 mono_g_hash_table_foreach (threads, collect_and_abort_threads, wait);
3241 mono_threads_unlock ();
3243 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3244 if (wait->num > 0) {
3245 /* Something to wait for */
3246 wait_for_tids (wait, INFINITE, FALSE);
3248 } while (wait->num > 0);
3251 * give the subthreads a chance to really quit (this is mainly needed
3252 * to get correct user and system times from getrusage/wait/time(1)).
3253 * This could be removed if we avoid pthread_detach() and use pthread_join().
3255 mono_thread_info_yield ();
3259 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3261 MonoInternalThread *thread = (MonoInternalThread*)value;
3262 WaitData *wait = (WaitData*)user_data;
3265 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3267 * This needs no locking.
3269 if ((thread->state & ThreadState_Suspended) != 0 ||
3270 (thread->state & ThreadState_Stopped) != 0)
3273 if (wait->num < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3274 wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
3275 wait->threads[wait->num] = thread;
3281 * mono_thread_suspend_all_other_threads:
3283 * Suspend all managed threads except the finalizer thread and this thread. It is
3284 * not possible to resume them later.
3287 mono_thread_suspend_all_other_threads (void)
3290 WaitData *wait = &wait_data;
3292 MonoNativeThreadId self = mono_native_thread_id_get ();
3293 guint32 eventidx = 0;
3294 gboolean starting, finished;
3296 memset (wait, 0, sizeof (WaitData));
3298 * The other threads could be in an arbitrary state at this point, i.e.
3299 * they could be starting up, shutting down etc. This means that there could be
3300 * threads which are not even in the threads hash table yet.
3304 * First we set a barrier which will be checked by all threads before they
3305 * are added to the threads hash table, and they will exit if the flag is set.
3306 * This ensures that no threads could be added to the hash later.
3307 * We will use shutting_down as the barrier for now.
3309 g_assert (shutting_down);
3312 * We make multiple calls to WaitForMultipleObjects since:
3313 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3314 * - some threads could exit without becoming suspended
3319 * Make a copy of the hashtable since we can't do anything with
3320 * threads while threads_mutex is held.
3322 init_wait_data (wait);
3323 mono_threads_lock ();
3324 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3325 mono_threads_unlock ();
3328 /* Get the suspended events that we'll be waiting for */
3329 for (i = 0; i < wait->num; ++i) {
3330 MonoInternalThread *thread = wait->threads [i];
3332 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3333 || mono_gc_is_finalizer_internal_thread (thread)
3334 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3336 mono_threads_close_thread_handle (wait->handles [i]);
3337 wait->threads [i] = NULL;
3341 LOCK_THREAD (thread);
3343 if ((thread->state & ThreadState_Suspended) != 0 ||
3344 (thread->state & ThreadState_StopRequested) != 0 ||
3345 (thread->state & ThreadState_Stopped) != 0) {
3346 UNLOCK_THREAD (thread);
3347 mono_threads_close_thread_handle (wait->handles [i]);
3348 wait->threads [i] = NULL;
3354 /* Convert abort requests into suspend requests */
3355 if ((thread->state & ThreadState_AbortRequested) != 0)
3356 thread->state &= ~ThreadState_AbortRequested;
3358 thread->state |= ThreadState_SuspendRequested;
3359 mono_os_event_reset (thread->suspended);
3361 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3362 async_suspend_internal (thread, TRUE);
3364 mono_threads_close_thread_handle (wait->handles [i]);
3365 wait->threads [i] = NULL;
3367 if (eventidx <= 0) {
3369 * If there are threads which are starting up, we wait until they
3370 * are suspended when they try to register in the threads hash.
3371 * This is guaranteed to finish, since the threads which can create new
3372 * threads get suspended after a while.
3373 * FIXME: The finalizer thread can still create new threads.
3375 mono_threads_lock ();
3376 if (threads_starting_up)
3377 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3380 mono_threads_unlock ();
3382 mono_thread_info_sleep (100, NULL);
3390 MonoInternalThread *thread;
3391 MonoStackFrameInfo *frames;
3392 int nframes, max_frames;
3393 int nthreads, max_threads;
3394 MonoInternalThread **threads;
3395 } ThreadDumpUserData;
3397 static gboolean thread_dump_requested;
3399 /* This needs to be async safe */
3401 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3403 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3405 if (ud->nframes < ud->max_frames) {
3406 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3413 /* This needs to be async safe */
3414 static SuspendThreadResult
3415 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3417 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3418 MonoInternalThread *thread = user_data->thread;
3421 /* This no longer works with remote unwinding */
3422 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3423 mono_thread_internal_describe (thread, text);
3424 g_string_append (text, "\n");
3427 if (thread == mono_thread_internal_current ())
3428 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3430 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3432 return MonoResumeThread;
3436 int nthreads, max_threads;
3437 MonoInternalThread **threads;
3438 } CollectThreadsUserData;
3441 collect_thread (gpointer key, gpointer value, gpointer user)
3443 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3444 MonoInternalThread *thread = (MonoInternalThread *)value;
3446 if (ud->nthreads < ud->max_threads)
3447 ud->threads [ud->nthreads ++] = thread;
3451 * Collect running threads into the THREADS array.
3452 * THREADS should be an array allocated on the stack.
3455 collect_threads (MonoInternalThread **thread_array, int max_threads)
3457 CollectThreadsUserData ud;
3459 memset (&ud, 0, sizeof (ud));
3460 /* This array contains refs, but its on the stack, so its ok */
3461 ud.threads = thread_array;
3462 ud.max_threads = max_threads;
3464 mono_threads_lock ();
3465 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3466 mono_threads_unlock ();
3472 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3474 GString* text = g_string_new (0);
3476 GError *error = NULL;
3479 ud->thread = thread;
3482 /* Collect frames for the thread */
3483 if (thread == mono_thread_internal_current ()) {
3484 get_thread_dump (mono_thread_info_current (), ud);
3486 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3490 * Do all the non async-safe work outside of get_thread_dump.
3493 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3495 g_string_append_printf (text, "\n\"%s\"", name);
3498 else if (thread->threadpool_thread) {
3499 g_string_append (text, "\n\"<threadpool thread>\"");
3501 g_string_append (text, "\n\"<unnamed thread>\"");
3504 for (i = 0; i < ud->nframes; ++i) {
3505 MonoStackFrameInfo *frame = &ud->frames [i];
3506 MonoMethod *method = NULL;
3508 if (frame->type == FRAME_TYPE_MANAGED)
3509 method = mono_jit_info_get_method (frame->ji);
3512 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3513 g_string_append_printf (text, " %s\n", location);
3516 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3520 fprintf (stdout, "%s", text->str);
3522 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3523 OutputDebugStringA(text->str);
3526 g_string_free (text, TRUE);
3531 mono_threads_perform_thread_dump (void)
3533 ThreadDumpUserData ud;
3534 MonoInternalThread *thread_array [128];
3535 int tindex, nthreads;
3537 if (!thread_dump_requested)
3540 printf ("Full thread dump:\n");
3542 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3543 nthreads = collect_threads (thread_array, 128);
3545 memset (&ud, 0, sizeof (ud));
3546 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3547 ud.max_frames = 256;
3549 for (tindex = 0; tindex < nthreads; ++tindex)
3550 dump_thread (thread_array [tindex], &ud);
3554 thread_dump_requested = FALSE;
3557 /* Obtain the thread dump of all threads */
3559 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3562 ThreadDumpUserData ud;
3563 MonoInternalThread *thread_array [128];
3564 MonoDomain *domain = mono_domain_get ();
3565 MonoDebugSourceLocation *location;
3566 int tindex, nthreads;
3568 mono_error_init (error);
3570 *out_threads = NULL;
3571 *out_stack_frames = NULL;
3573 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3574 nthreads = collect_threads (thread_array, 128);
3576 memset (&ud, 0, sizeof (ud));
3577 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3578 ud.max_frames = 256;
3580 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3583 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3587 for (tindex = 0; tindex < nthreads; ++tindex) {
3588 MonoInternalThread *thread = thread_array [tindex];
3589 MonoArray *thread_frames;
3595 /* Collect frames for the thread */
3596 if (thread == mono_thread_internal_current ()) {
3597 get_thread_dump (mono_thread_info_current (), &ud);
3599 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3602 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3604 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3607 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3609 for (i = 0; i < ud.nframes; ++i) {
3610 MonoStackFrameInfo *frame = &ud.frames [i];
3611 MonoMethod *method = NULL;
3612 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3616 sf->native_offset = frame->native_offset;
3618 if (frame->type == FRAME_TYPE_MANAGED)
3619 method = mono_jit_info_get_method (frame->ji);
3622 sf->method_address = (gsize) frame->ji->code_start;
3624 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3627 MONO_OBJECT_SETREF (sf, method, rm);
3629 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3631 sf->il_offset = location->il_offset;
3633 if (location && location->source_file) {
3634 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3635 sf->line = location->row;
3636 sf->column = location->column;
3638 mono_debug_free_source_location (location);
3643 mono_array_setref (thread_frames, i, sf);
3649 return is_ok (error);
3653 * mono_threads_request_thread_dump:
3655 * Ask all threads except the current to print their stacktrace to stdout.
3658 mono_threads_request_thread_dump (void)
3660 /*The new thread dump code runs out of the finalizer thread. */
3661 thread_dump_requested = TRUE;
3662 mono_gc_finalize_notify ();
3667 gint allocated; /* +1 so that refs [allocated] == NULL */
3671 typedef struct ref_stack RefStack;
3674 ref_stack_new (gint initial_size)
3678 initial_size = MAX (initial_size, 16) + 1;
3679 rs = g_new0 (RefStack, 1);
3680 rs->refs = g_new0 (gpointer, initial_size);
3681 rs->allocated = initial_size;
3686 ref_stack_destroy (gpointer ptr)
3688 RefStack *rs = (RefStack *)ptr;
3697 ref_stack_push (RefStack *rs, gpointer ptr)
3699 g_assert (rs != NULL);
3701 if (rs->bottom >= rs->allocated) {
3702 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3703 rs->allocated <<= 1;
3704 rs->refs [rs->allocated] = NULL;
3706 rs->refs [rs->bottom++] = ptr;
3710 ref_stack_pop (RefStack *rs)
3712 if (rs == NULL || rs->bottom == 0)
3716 rs->refs [rs->bottom] = NULL;
3720 ref_stack_find (RefStack *rs, gpointer ptr)
3727 for (refs = rs->refs; refs && *refs; refs++) {
3735 * mono_thread_push_appdomain_ref:
3737 * Register that the current thread may have references to objects in domain
3738 * @domain on its stack. Each call to this function should be paired with a
3739 * call to pop_appdomain_ref.
3742 mono_thread_push_appdomain_ref (MonoDomain *domain)
3744 MonoInternalThread *thread = mono_thread_internal_current ();
3747 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3748 SPIN_LOCK (thread->lock_thread_id);
3749 if (thread->appdomain_refs == NULL)
3750 thread->appdomain_refs = ref_stack_new (16);
3751 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3752 SPIN_UNLOCK (thread->lock_thread_id);
3757 mono_thread_pop_appdomain_ref (void)
3759 MonoInternalThread *thread = mono_thread_internal_current ();
3762 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3763 SPIN_LOCK (thread->lock_thread_id);
3764 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3765 SPIN_UNLOCK (thread->lock_thread_id);
3770 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3773 SPIN_LOCK (thread->lock_thread_id);
3774 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3775 SPIN_UNLOCK (thread->lock_thread_id);
3780 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3782 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3785 typedef struct abort_appdomain_data {
3788 } abort_appdomain_data;
3791 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3793 MonoInternalThread *thread = (MonoInternalThread*)value;
3794 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3795 MonoDomain *domain = data->domain;
3797 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3798 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3800 if (data->wait.num < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3801 add_wait_thread (&data->wait, thread);
3803 /* Just ignore the rest, we can't do anything with
3811 * mono_threads_abort_appdomain_threads:
3813 * Abort threads which has references to the given appdomain.
3816 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3818 #ifdef __native_client__
3822 abort_appdomain_data user_data;
3824 int orig_timeout = timeout;
3827 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3829 start_time = mono_msec_ticks ();
3831 mono_threads_lock ();
3833 user_data.domain = domain;
3834 init_wait_data (&user_data.wait);
3835 /* This shouldn't take any locks */
3836 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3837 mono_threads_unlock ();
3839 if (user_data.wait.num > 0) {
3840 /* Abort the threads outside the threads lock */
3841 for (i = 0; i < user_data.wait.num; ++i)
3842 mono_thread_internal_abort (user_data.wait.threads [i]);
3845 * We should wait for the threads either to abort, or to leave the
3846 * domain. We can't do the latter, so we wait with a timeout.
3848 wait_for_tids (&user_data.wait, 100, FALSE);
3851 /* Update remaining time */
3852 timeout -= mono_msec_ticks () - start_time;
3853 start_time = mono_msec_ticks ();
3855 if (orig_timeout != -1 && timeout < 0)
3858 while (user_data.wait.num > 0);
3860 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3866 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3868 MonoInternalThread *thread = (MonoInternalThread*)value;
3869 MonoDomain *domain = (MonoDomain*)user_data;
3872 /* No locking needed here */
3873 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3875 if (thread->cached_culture_info) {
3876 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3877 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3878 if (obj && obj->vtable->domain == domain)
3879 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3885 * mono_threads_clear_cached_culture:
3887 * Clear the cached_current_culture from all threads if it is in the
3891 mono_threads_clear_cached_culture (MonoDomain *domain)
3893 mono_threads_lock ();
3894 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3895 mono_threads_unlock ();
3899 * mono_thread_get_undeniable_exception:
3901 * Return an exception which needs to be raised when leaving a catch clause.
3902 * This is used for undeniable exception propagation.
3905 mono_thread_get_undeniable_exception (void)
3907 MonoInternalThread *thread = mono_thread_internal_current ();
3909 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3911 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3912 * exception if the thread no longer references a dying appdomain.
3914 thread->abort_exc->trace_ips = NULL;
3915 thread->abort_exc->stack_trace = NULL;
3916 return thread->abort_exc;
3922 #if MONO_SMALL_CONFIG
3923 #define NUM_STATIC_DATA_IDX 4
3924 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3928 #define NUM_STATIC_DATA_IDX 8
3929 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3930 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3934 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3935 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3938 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3940 gpointer *static_data = (gpointer *)addr;
3942 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3943 void **ptr = (void **)static_data [i];
3948 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3949 void **p = ptr + idx;
3952 mark_func ((MonoObject**)p, gc_data);
3958 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3960 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3964 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3966 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3970 * mono_alloc_static_data
3972 * Allocate memory blocks for storing threads or context static data
3975 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3977 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3980 gpointer* static_data = *static_data_ptr;
3982 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3983 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3985 if (mono_gc_user_markers_supported ()) {
3986 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3987 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3989 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3990 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3993 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3994 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3995 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3996 *static_data_ptr = static_data;
3997 static_data [0] = static_data;
4000 for (i = 1; i <= idx; ++i) {
4001 if (static_data [i])
4004 if (mono_gc_user_markers_supported ())
4005 static_data [i] = g_malloc0 (static_data_size [i]);
4007 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4008 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4009 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4014 mono_free_static_data (gpointer* static_data)
4017 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4018 gpointer p = static_data [i];
4022 * At this point, the static data pointer array is still registered with the
4023 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4024 * data. Freeing the individual arrays without first nulling their slots
4025 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4026 * such an already freed array. See bug #13813.
4028 static_data [i] = NULL;
4029 mono_memory_write_barrier ();
4030 if (mono_gc_user_markers_supported ())
4033 mono_gc_free_fixed (p);
4035 mono_gc_free_fixed (static_data);
4039 * mono_init_static_data_info
4041 * Initializes static data counters
4043 static void mono_init_static_data_info (StaticDataInfo *static_data)
4045 static_data->idx = 0;
4046 static_data->offset = 0;
4047 static_data->freelist = NULL;
4051 * mono_alloc_static_data_slot
4053 * Generates an offset for static data. static_data contains the counters
4054 * used to generate it.
4057 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4059 if (!static_data->idx && !static_data->offset) {
4061 * we use the first chunk of the first allocation also as
4062 * an array for the rest of the data
4064 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4066 static_data->offset += align - 1;
4067 static_data->offset &= ~(align - 1);
4068 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4069 static_data->idx ++;
4070 g_assert (size <= static_data_size [static_data->idx]);
4071 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4072 static_data->offset = 0;
4074 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4075 static_data->offset += size;
4080 * LOCKING: requires that threads_mutex is held
4083 context_adjust_static_data (MonoAppContext *ctx)
4085 if (context_static_info.offset || context_static_info.idx > 0) {
4086 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4087 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4088 ctx->data->static_data = ctx->static_data;
4093 * LOCKING: requires that threads_mutex is held
4096 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4098 MonoInternalThread *thread = (MonoInternalThread *)value;
4099 guint32 offset = GPOINTER_TO_UINT (user);
4101 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4105 * LOCKING: requires that threads_mutex is held
4108 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4110 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4115 guint32 offset = GPOINTER_TO_UINT (user);
4116 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4117 ctx->data->static_data = ctx->static_data;
4120 static StaticDataFreeList*
4121 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4123 StaticDataFreeList* prev = NULL;
4124 StaticDataFreeList* tmp = static_data->freelist;
4126 if (tmp->size == size) {
4128 prev->next = tmp->next;
4130 static_data->freelist = tmp->next;
4139 #if SIZEOF_VOID_P == 4
4146 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4148 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4150 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4151 MonoBitSet *rb = sets [idx];
4152 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4153 offset /= sizeof (uintptr_t);
4154 /* offset is now the bitmap offset */
4155 for (int i = 0; i < numbits; ++i) {
4156 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4157 mono_bitset_set_fast (rb, offset + i);
4162 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4164 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4165 MonoBitSet *rb = sets [idx];
4166 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4167 offset /= sizeof (uintptr_t);
4168 /* offset is now the bitmap offset */
4169 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4170 mono_bitset_clear_fast (rb, offset + i);
4174 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4176 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4178 StaticDataInfo *info;
4181 if (static_type == SPECIAL_STATIC_THREAD) {
4182 info = &thread_static_info;
4183 sets = thread_reference_bitmaps;
4185 info = &context_static_info;
4186 sets = context_reference_bitmaps;
4189 mono_threads_lock ();
4191 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4195 offset = item->offset;
4198 offset = mono_alloc_static_data_slot (info, size, align);
4201 update_reference_bitmap (sets, offset, bitmap, numbits);
4203 if (static_type == SPECIAL_STATIC_THREAD) {
4204 /* This can be called during startup */
4205 if (threads != NULL)
4206 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4208 if (contexts != NULL)
4209 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4211 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4214 mono_threads_unlock ();
4220 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4222 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4224 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4225 return get_thread_static_data (thread, offset);
4227 return get_context_static_data (thread->current_appcontext, offset);
4232 mono_get_special_static_data (guint32 offset)
4234 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4243 * LOCKING: requires that threads_mutex is held
4246 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4248 MonoInternalThread *thread = (MonoInternalThread *)value;
4249 OffsetSize *data = (OffsetSize *)user;
4250 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4251 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4254 if (!thread->static_data || !thread->static_data [idx])
4256 ptr = ((char*) thread->static_data [idx]) + off;
4257 mono_gc_bzero_atomic (ptr, data->size);
4261 * LOCKING: requires that threads_mutex is held
4264 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4266 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4271 OffsetSize *data = (OffsetSize *)user;
4272 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4273 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4276 if (!ctx->static_data || !ctx->static_data [idx])
4279 ptr = ((char*) ctx->static_data [idx]) + off;
4280 mono_gc_bzero_atomic (ptr, data->size);
4284 do_free_special_slot (guint32 offset, guint32 size)
4286 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4288 StaticDataInfo *info;
4290 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4291 info = &thread_static_info;
4292 sets = thread_reference_bitmaps;
4294 info = &context_static_info;
4295 sets = context_reference_bitmaps;
4298 guint32 data_offset = offset;
4299 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4300 OffsetSize data = { data_offset, size };
4302 clear_reference_bitmap (sets, data.offset, data.size);
4304 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4305 if (threads != NULL)
4306 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4308 if (contexts != NULL)
4309 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4312 if (!mono_runtime_is_shutting_down ()) {
4313 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4315 item->offset = offset;
4318 item->next = info->freelist;
4319 info->freelist = item;
4324 do_free_special (gpointer key, gpointer value, gpointer data)
4326 MonoClassField *field = (MonoClassField *)key;
4327 guint32 offset = GPOINTER_TO_UINT (value);
4330 size = mono_type_size (field->type, &align);
4331 do_free_special_slot (offset, size);
4335 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4337 mono_threads_lock ();
4339 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4341 mono_threads_unlock ();
4345 static void CALLBACK dummy_apc (ULONG_PTR param)
4351 * mono_thread_execute_interruption
4353 * Performs the operation that the requested thread state requires (abort,
4356 static MonoException*
4357 mono_thread_execute_interruption (void)
4359 MonoInternalThread *thread = mono_thread_internal_current ();
4360 MonoThread *sys_thread = mono_thread_current ();
4362 LOCK_THREAD (thread);
4364 /* MonoThread::interruption_requested can only be changed with atomics */
4365 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4366 /* this will consume pending APC calls */
4368 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4370 InterlockedDecrement (&thread_interruption_requested);
4372 /* Clear the interrupted flag of the thread so it can wait again */
4373 mono_thread_info_clear_self_interrupt ();
4376 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4377 if (sys_thread->pending_exception) {
4380 exc = sys_thread->pending_exception;
4381 sys_thread->pending_exception = NULL;
4383 UNLOCK_THREAD (thread);
4385 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4386 UNLOCK_THREAD (thread);
4387 g_assert (sys_thread->pending_exception == NULL);
4388 if (thread->abort_exc == NULL) {
4390 * This might be racy, but it has to be called outside the lock
4391 * since it calls managed code.
4393 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4395 return thread->abort_exc;
4397 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4398 /* calls UNLOCK_THREAD (thread) */
4399 self_suspend_internal ();
4402 else if ((thread->state & ThreadState_StopRequested) != 0) {
4403 /* FIXME: do this through the JIT? */
4405 UNLOCK_THREAD (thread);
4407 mono_thread_exit ();
4409 } else if (thread->thread_interrupt_requested) {
4411 thread->thread_interrupt_requested = FALSE;
4412 UNLOCK_THREAD (thread);
4414 return(mono_get_exception_thread_interrupted ());
4417 UNLOCK_THREAD (thread);
4423 * mono_thread_request_interruption
4425 * A signal handler can call this method to request the interruption of a
4426 * thread. The result of the interruption will depend on the current state of
4427 * the thread. If the result is an exception that needs to be throw, it is
4428 * provided as return value.
4431 mono_thread_request_interruption (gboolean running_managed)
4433 MonoInternalThread *thread = mono_thread_internal_current ();
4435 /* The thread may already be stopping */
4440 if (thread->interrupt_on_stop &&
4441 thread->state & ThreadState_StopRequested &&
4442 thread->state & ThreadState_Background)
4445 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4447 InterlockedIncrement (&thread_interruption_requested);
4449 if (!running_managed || is_running_protected_wrapper ()) {
4450 /* Can't stop while in unmanaged code. Increase the global interruption
4451 request count. When exiting the unmanaged method the count will be
4452 checked and the thread will be interrupted. */
4454 /* this will awake the thread if it is in WaitForSingleObject
4456 /* Our implementation of this function ignores the func argument */
4458 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
4460 mono_thread_info_self_interrupt ();
4465 return mono_thread_execute_interruption ();
4469 /*This function should be called by a thread after it has exited all of
4470 * its handle blocks at interruption time.*/
4472 mono_thread_resume_interruption (void)
4474 MonoInternalThread *thread = mono_thread_internal_current ();
4475 gboolean still_aborting;
4477 /* The thread may already be stopping */
4481 LOCK_THREAD (thread);
4482 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4483 UNLOCK_THREAD (thread);
4485 /*This can happen if the protected block called Thread::ResetAbort*/
4486 if (!still_aborting)
4489 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4491 InterlockedIncrement (&thread_interruption_requested);
4493 mono_thread_info_self_interrupt ();
4495 return mono_thread_execute_interruption ();
4498 gboolean mono_thread_interruption_requested ()
4500 if (thread_interruption_requested) {
4501 MonoInternalThread *thread = mono_thread_internal_current ();
4502 /* The thread may already be stopping */
4504 return (thread->interruption_requested);
4509 static MonoException*
4510 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4512 MonoInternalThread *thread = mono_thread_internal_current ();
4514 /* The thread may already be stopping */
4518 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4519 MonoException* exc = mono_thread_execute_interruption ();
4527 * Performs the interruption of the current thread, if one has been requested,
4528 * and the thread is not running a protected wrapper.
4529 * Return the exception which needs to be thrown, if any.
4532 mono_thread_interruption_checkpoint (void)
4534 return mono_thread_interruption_checkpoint_request (FALSE);
4538 * Performs the interruption of the current thread, if one has been requested.
4539 * Return the exception which needs to be thrown, if any.
4542 mono_thread_force_interruption_checkpoint_noraise (void)
4544 return mono_thread_interruption_checkpoint_request (TRUE);
4548 * mono_set_pending_exception:
4550 * Set the pending exception of the current thread to EXC.
4551 * The exception will be thrown when execution returns to managed code.
4554 mono_set_pending_exception (MonoException *exc)
4556 MonoThread *thread = mono_thread_current ();
4558 /* The thread may already be stopping */
4562 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4564 mono_thread_request_interruption (FALSE);
4568 * mono_thread_interruption_request_flag:
4570 * Returns the address of a flag that will be non-zero if an interruption has
4571 * been requested for a thread. The thread to interrupt may not be the current
4572 * thread, so an additional call to mono_thread_interruption_requested() or
4573 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4576 gint32* mono_thread_interruption_request_flag ()
4578 return &thread_interruption_requested;
4582 mono_thread_init_apartment_state (void)
4585 MonoInternalThread* thread = mono_thread_internal_current ();
4587 /* Positive return value indicates success, either
4588 * S_OK if this is first CoInitialize call, or
4589 * S_FALSE if CoInitialize already called, but with same
4590 * threading model. A negative value indicates failure,
4591 * probably due to trying to change the threading model.
4593 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4594 ? COINIT_APARTMENTTHREADED
4595 : COINIT_MULTITHREADED) < 0) {
4596 thread->apartment_state = ThreadApartmentState_Unknown;
4602 mono_thread_cleanup_apartment_state (void)
4605 MonoInternalThread* thread = mono_thread_internal_current ();
4607 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4614 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4616 LOCK_THREAD (thread);
4617 thread->state |= state;
4618 UNLOCK_THREAD (thread);
4622 * mono_thread_test_and_set_state:
4624 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4626 * Returns TRUE is @set was OR'd in.
4629 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4631 LOCK_THREAD (thread);
4633 if ((thread->state & test) != 0) {
4634 UNLOCK_THREAD (thread);
4638 thread->state |= set;
4639 UNLOCK_THREAD (thread);
4645 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4647 LOCK_THREAD (thread);
4648 thread->state &= ~state;
4649 UNLOCK_THREAD (thread);
4653 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4655 gboolean ret = FALSE;
4657 LOCK_THREAD (thread);
4659 if ((thread->state & test) != 0) {
4663 UNLOCK_THREAD (thread);
4668 static gboolean has_tls_get = FALSE;
4671 mono_runtime_set_has_tls_get (gboolean val)
4677 mono_runtime_has_tls_get (void)
4683 self_interrupt_thread (void *_unused)
4686 MonoThreadInfo *info;
4688 exc = mono_thread_execute_interruption ();
4690 if (mono_threads_is_coop_enabled ()) {
4691 /* We can return from an async call in coop, as
4692 * it's simply called when exiting the safepoint */
4696 g_error ("%s: we can't resume from an async call", __func__);
4699 info = mono_thread_info_current ();
4701 /* We must use _with_context since we didn't trampoline into the runtime */
4702 mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
4706 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4710 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4714 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4716 MonoJitInfo **dest = (MonoJitInfo **)data;
4722 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4724 MonoJitInfo *ji = NULL;
4729 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4730 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4731 * where we hold runtime locks.
4733 if (!mono_threads_is_coop_enabled ())
4734 mono_thread_info_set_is_async_context (TRUE);
4735 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4736 if (!mono_threads_is_coop_enabled ())
4737 mono_thread_info_set_is_async_context (FALSE);
4742 MonoInternalThread *thread;
4743 gboolean install_async_abort;
4744 MonoThreadInfoInterruptToken *interrupt_token;
4747 static SuspendThreadResult
4748 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4750 AbortThreadData *data = (AbortThreadData *)ud;
4751 MonoInternalThread *thread = data->thread;
4752 MonoJitInfo *ji = NULL;
4753 gboolean protected_wrapper;
4754 gboolean running_managed;
4756 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4757 return MonoResumeThread;
4760 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4761 The protected block code will give them a chance when appropriate.
4763 if (thread->abort_protected_block_count)
4764 return MonoResumeThread;
4766 /*someone is already interrupting it*/
4767 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4768 return MonoResumeThread;
4770 InterlockedIncrement (&thread_interruption_requested);
4772 ji = mono_thread_info_get_last_managed (info);
4773 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4774 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4776 if (!protected_wrapper && running_managed) {
4777 /*We are in managed code*/
4778 /*Set the thread to call */
4779 if (data->install_async_abort)
4780 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4781 return MonoResumeThread;
4784 * This will cause waits to be broken.
4785 * It will also prevent the thread from entering a wait, so if the thread returns
4786 * from the wait before it receives the abort signal, it will just spin in the wait
4787 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4790 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4792 return MonoResumeThread;
4797 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4799 AbortThreadData data;
4801 g_assert (thread != mono_thread_internal_current ());
4803 data.thread = thread;
4804 data.install_async_abort = install_async_abort;
4805 data.interrupt_token = NULL;
4807 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4808 if (data.interrupt_token)
4809 mono_thread_info_finish_interrupt (data.interrupt_token);
4810 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4814 self_abort_internal (MonoError *error)
4818 mono_error_init (error);
4820 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4821 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4824 Self aborts ignore the protected block logic and raise the TAE regardless. This is verified by one of the tests in mono/tests/abort-cctor.cs.
4826 exc = mono_thread_request_interruption (TRUE);
4828 mono_error_set_exception_instance (error, exc);
4830 mono_thread_info_self_interrupt ();
4834 MonoInternalThread *thread;
4836 MonoThreadInfoInterruptToken *interrupt_token;
4837 } SuspendThreadData;
4839 static SuspendThreadResult
4840 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4842 SuspendThreadData *data = (SuspendThreadData *)ud;
4843 MonoInternalThread *thread = data->thread;
4844 MonoJitInfo *ji = NULL;
4845 gboolean protected_wrapper;
4846 gboolean running_managed;
4848 ji = mono_thread_info_get_last_managed (info);
4849 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4850 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4852 if (running_managed && !protected_wrapper) {
4853 if (mono_threads_is_coop_enabled ()) {
4854 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4855 return MonoResumeThread;
4857 thread->state &= ~ThreadState_SuspendRequested;
4858 thread->state |= ThreadState_Suspended;
4859 return KeepSuspended;
4862 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4863 InterlockedIncrement (&thread_interruption_requested);
4864 if (data->interrupt)
4865 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4867 return MonoResumeThread;
4871 /* LOCKING: called with @thread synch_cs held, and releases it */
4873 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4875 SuspendThreadData data;
4877 g_assert (thread != mono_thread_internal_current ());
4879 // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4881 thread->self_suspended = FALSE;
4883 data.thread = thread;
4884 data.interrupt = interrupt;
4885 data.interrupt_token = NULL;
4887 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4888 if (data.interrupt_token)
4889 mono_thread_info_finish_interrupt (data.interrupt_token);
4891 UNLOCK_THREAD (thread);
4894 /* LOCKING: called with @thread synch_cs held, and releases it */
4896 self_suspend_internal (void)
4898 MonoInternalThread *thread;
4900 MonoOSEventWaitRet res;
4902 thread = mono_thread_internal_current ();
4904 // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4906 thread->self_suspended = TRUE;
4908 thread->state &= ~ThreadState_SuspendRequested;
4909 thread->state |= ThreadState_Suspended;
4911 UNLOCK_THREAD (thread);
4913 event = thread->suspended;
4916 res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT);
4917 g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
4922 * mono_thread_is_foreign:
4923 * @thread: the thread to query
4925 * This function allows one to determine if a thread was created by the mono runtime and has
4926 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4928 * Returns: TRUE if @thread was not created by the runtime.
4931 mono_thread_is_foreign (MonoThread *thread)
4933 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4934 return info->runtime_thread == FALSE;
4938 * mono_add_joinable_thread:
4940 * Add TID to the list of joinable threads.
4941 * LOCKING: Acquires the threads lock.
4944 mono_threads_add_joinable_thread (gpointer tid)
4948 * We cannot detach from threads because it causes problems like
4949 * 2fd16f60/r114307. So we collect them and join them when
4950 * we have time (in he finalizer thread).
4952 joinable_threads_lock ();
4953 if (!joinable_threads)
4954 joinable_threads = g_hash_table_new (NULL, NULL);
4955 g_hash_table_insert (joinable_threads, tid, tid);
4956 joinable_thread_count ++;
4957 joinable_threads_unlock ();
4959 mono_gc_finalize_notify ();
4964 * mono_threads_join_threads:
4966 * Join all joinable threads. This is called from the finalizer thread.
4967 * LOCKING: Acquires the threads lock.
4970 mono_threads_join_threads (void)
4973 GHashTableIter iter;
4980 if (!joinable_thread_count)
4984 joinable_threads_lock ();
4986 if (g_hash_table_size (joinable_threads)) {
4987 g_hash_table_iter_init (&iter, joinable_threads);
4988 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4989 thread = (pthread_t)tid;
4990 g_hash_table_remove (joinable_threads, key);
4991 joinable_thread_count --;
4994 joinable_threads_unlock ();
4996 if (thread != pthread_self ()) {
4998 /* This shouldn't block */
4999 mono_native_thread_join (thread);
5001 thread_wait_lock ();
5003 mono_os_cond_signal (&thread_wait_cond);
5004 thread_wait_unlock ();
5016 * Wait for thread TID to exit.
5017 * LOCKING: Acquires the threads lock.
5020 mono_thread_join (gpointer tid)
5024 gboolean found = FALSE;
5026 joinable_threads_lock ();
5027 if (!joinable_threads)
5028 joinable_threads = g_hash_table_new (NULL, NULL);
5029 if (g_hash_table_lookup (joinable_threads, tid)) {
5030 g_hash_table_remove (joinable_threads, tid);
5031 joinable_thread_count --;
5034 joinable_threads_unlock ();
5037 thread = (pthread_t)tid;
5039 mono_native_thread_join (thread);
5045 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
5047 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
5048 mono_thread_interruption_checkpoint ();
5052 mono_thread_internal_unhandled_exception (MonoObject* exc)
5054 MonoClass *klass = exc->vtable->klass;
5055 if (is_threadabort_exception (klass)) {
5056 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5057 } else if (!is_appdomainunloaded_exception (klass)
5058 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5059 mono_unhandled_exception (exc);
5060 if (mono_environment_exitcode_get () == 1) {
5061 mono_environment_exitcode_set (255);
5062 mono_invoke_unhandled_exception_hook (exc);
5063 g_assert_not_reached ();
5069 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5072 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5073 mono_error_set_pending_exception (&error);
5077 * mono_threads_attach_coop: called by native->managed wrappers
5081 * - @return: the original domain which needs to be restored, or NULL.
5084 * - @dummy: contains the original domain
5085 * - @return: a cookie containing current MonoThreadInfo*.
5088 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5091 gboolean fresh_thread = FALSE;
5094 /* Happens when called from AOTed code which is only used in the root domain. */
5095 domain = mono_get_root_domain ();
5100 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5101 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5102 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5103 * we're only responsible for making the cookie. */
5104 if (mono_threads_is_coop_enabled ()) {
5105 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5106 fresh_thread = !info || !mono_thread_info_is_live (info);
5109 if (!mono_thread_internal_current ()) {
5110 mono_thread_attach_full (domain, FALSE);
5113 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5116 orig = mono_domain_get ();
5118 mono_domain_set (domain, TRUE);
5120 if (!mono_threads_is_coop_enabled ())
5121 return orig != domain ? orig : NULL;
5125 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5126 * return the right cookie. */
5127 return mono_threads_enter_gc_unsafe_region_cookie ();
5130 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5131 return mono_threads_enter_gc_unsafe_region (dummy);
5136 * mono_threads_detach_coop: called by native->managed wrappers
5139 * - @cookie: the original domain which needs to be restored, or NULL.
5143 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5144 * - @dummy: contains the original domain
5147 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5149 MonoDomain *domain, *orig;
5151 if (!mono_threads_is_coop_enabled ()) {
5152 orig = (MonoDomain*) cookie;
5154 mono_domain_set (orig, TRUE);
5156 orig = (MonoDomain*) *dummy;
5158 domain = mono_domain_get ();
5161 /* it won't do anything if cookie is NULL
5162 * thread state RUNNING -> (RUNNING|BLOCKING) */
5163 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5165 if (orig != domain) {
5167 mono_domain_unset ();
5169 mono_domain_set (orig, TRUE);
5175 mono_threads_begin_abort_protected_block (void)
5177 MonoInternalThread *thread;
5179 thread = mono_thread_internal_current ();
5180 ++thread->abort_protected_block_count;
5181 mono_memory_barrier ();
5185 mono_threads_end_abort_protected_block (void)
5187 MonoInternalThread *thread;
5189 thread = mono_thread_internal_current ();
5191 mono_memory_barrier ();
5192 --thread->abort_protected_block_count;
5196 mono_thread_try_resume_interruption (void)
5198 MonoInternalThread *thread;
5200 thread = mono_thread_internal_current ();
5201 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5204 return mono_thread_resume_interruption ();
5208 /* Returns TRUE if the current thread is ready to be interrupted. */
5210 mono_threads_is_ready_to_be_interrupted (void)
5212 MonoInternalThread *thread;
5214 thread = mono_thread_internal_current ();
5215 LOCK_THREAD (thread);
5216 if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5217 UNLOCK_THREAD (thread);
5221 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5222 UNLOCK_THREAD (thread);
5226 UNLOCK_THREAD (thread);
5232 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5234 g_string_append_printf (text, ", thread handle : %p", internal->handle);
5236 if (internal->thread_info) {
5237 g_string_append (text, ", state : ");
5238 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5241 if (internal->owned_mutexes) {
5244 g_string_append (text, ", owns : [");
5245 for (i = 0; i < internal->owned_mutexes->len; i++)
5246 g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5247 g_string_append (text, "]");
5252 mono_thread_internal_is_current (MonoInternalThread *internal)
5254 g_assert (internal);
5255 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));