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/w32handle.h>
48 #include <mono/metadata/w32event.h>
49 #include <mono/metadata/w32mutex.h>
51 #include <mono/metadata/gc-internals.h>
52 #include <mono/metadata/reflection-internals.h>
53 #include <mono/metadata/abi-details.h>
59 #if defined(HOST_WIN32)
63 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
64 #define USE_TKILL_ON_ANDROID 1
67 #ifdef PLATFORM_ANDROID
70 #ifdef USE_TKILL_ON_ANDROID
71 extern int tkill (pid_t tid, int signal);
75 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
76 #define THREAD_DEBUG(a)
77 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
78 #define THREAD_WAIT_DEBUG(a)
79 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
80 #define LIBGC_DEBUG(a)
82 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
83 #define SPIN_LOCK(i) do { \
84 if (SPIN_TRYLOCK (i)) \
88 #define SPIN_UNLOCK(i) i = 0
90 #define LOCK_THREAD(thread) lock_thread((thread))
91 #define UNLOCK_THREAD(thread) unlock_thread((thread))
103 typedef struct _StaticDataFreeList StaticDataFreeList;
104 struct _StaticDataFreeList {
105 StaticDataFreeList *next;
113 StaticDataFreeList *freelist;
116 /* Number of cached culture objects in the MonoThread->cached_culture_info array
117 * (per-type): we use the first NUM entries for CultureInfo and the last for
118 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
120 #define NUM_CACHED_CULTURES 4
121 #define CULTURES_START_IDX 0
122 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
124 /* Controls access to the 'threads' hash table */
125 static void mono_threads_lock (void);
126 static void mono_threads_unlock (void);
127 static MonoCoopMutex threads_mutex;
129 /* Controls access to the 'joinable_threads' hash table */
130 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
131 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
132 static mono_mutex_t joinable_threads_mutex;
134 /* Holds current status of static data heap */
135 static StaticDataInfo thread_static_info;
136 static StaticDataInfo context_static_info;
138 /* The hash of existing threads (key is thread ID, value is
139 * MonoInternalThread*) that need joining before exit
141 static MonoGHashTable *threads=NULL;
143 /* List of app context GC handles.
144 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
146 static GHashTable *contexts = NULL;
148 /* Cleanup queue for contexts. */
149 static MonoReferenceQueue *context_queue;
152 * Threads which are starting up and they are not in the 'threads' hash yet.
153 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
154 * Protected by mono_threads_lock ().
156 static MonoGHashTable *threads_starting_up = NULL;
158 /* The TLS key that holds the MonoObject assigned to each thread */
159 static MonoNativeTlsKey current_object_key;
162 /* Protected by the threads lock */
163 static GHashTable *joinable_threads;
164 static int joinable_thread_count;
166 #ifdef MONO_HAVE_FAST_TLS
167 /* we need to use both the Tls* functions and __thread because
168 * the gc needs to see all the threads
170 MONO_FAST_TLS_DECLARE(tls_current_object);
171 #define SET_CURRENT_OBJECT(x) do { \
172 MONO_FAST_TLS_SET (tls_current_object, x); \
173 mono_native_tls_set_value (current_object_key, x); \
175 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
177 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
178 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
181 /* function called at thread start */
182 static MonoThreadStartCB mono_thread_start_cb = NULL;
184 /* function called at thread attach */
185 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
187 /* function called at thread cleanup */
188 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
190 /* The default stack size for each thread */
191 static guint32 default_stacksize = 0;
192 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
194 static void context_adjust_static_data (MonoAppContext *ctx);
195 static void mono_free_static_data (gpointer* static_data);
196 static void mono_init_static_data_info (StaticDataInfo *static_data);
197 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
198 static gboolean mono_thread_resume (MonoInternalThread* thread);
199 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
200 static void self_abort_internal (MonoError *error);
201 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
202 static void self_suspend_internal (void);
204 static MonoException* mono_thread_execute_interruption (void);
205 static void ref_stack_destroy (gpointer rs);
207 /* Spin lock for InterlockedXXX 64 bit functions */
208 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
209 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
210 static mono_mutex_t interlocked_mutex;
212 /* global count of thread interruptions requested */
213 static gint32 thread_interruption_requested = 0;
215 /* Event signaled when a thread changes its background mode */
216 static HANDLE background_change_event;
218 static gboolean shutting_down = FALSE;
220 static gint32 managed_thread_id_counter = 0;
222 /* Class lazy loading functions */
223 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
226 mono_threads_lock (void)
228 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
232 mono_threads_unlock (void)
234 mono_locks_coop_release (&threads_mutex, ThreadsLock);
239 get_next_managed_thread_id (void)
241 return InterlockedIncrement (&managed_thread_id_counter);
245 mono_thread_get_tls_key (void)
247 return current_object_key;
251 mono_thread_get_tls_offset (void)
256 if (current_object_key)
257 offset = current_object_key;
259 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
264 static inline MonoNativeThreadId
265 thread_get_tid (MonoInternalThread *thread)
267 /* We store the tid as a guint64 to keep the object layout constant between platforms */
268 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
271 static void ensure_synch_cs_set (MonoInternalThread *thread)
273 MonoCoopMutex *synch_cs;
275 if (thread->synch_cs != NULL) {
279 synch_cs = g_new0 (MonoCoopMutex, 1);
280 mono_coop_mutex_init_recursive (synch_cs);
282 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
283 synch_cs, NULL) != NULL) {
284 /* Another thread must have installed this CS */
285 mono_coop_mutex_destroy (synch_cs);
291 lock_thread (MonoInternalThread *thread)
293 if (!thread->synch_cs)
294 ensure_synch_cs_set (thread);
296 g_assert (thread->synch_cs);
298 mono_coop_mutex_lock (thread->synch_cs);
302 unlock_thread (MonoInternalThread *thread)
304 mono_coop_mutex_unlock (thread->synch_cs);
307 static inline gboolean
308 is_appdomainunloaded_exception (MonoClass *klass)
310 return klass == mono_class_get_appdomain_unloaded_exception_class ();
313 static inline gboolean
314 is_threadabort_exception (MonoClass *klass)
316 return klass == mono_defaults.threadabortexception_class;
320 * NOTE: this function can be called also for threads different from the current one:
321 * make sure no code called from it will ever assume it is run on the thread that is
322 * getting cleaned up.
324 static void thread_cleanup (MonoInternalThread *thread)
328 g_assert (thread != NULL);
330 if (thread->abort_state_handle) {
331 mono_gchandle_free (thread->abort_state_handle);
332 thread->abort_state_handle = 0;
334 thread->abort_exc = NULL;
335 thread->current_appcontext = NULL;
338 * This is necessary because otherwise we might have
339 * cross-domain references which will not get cleaned up when
340 * the target domain is unloaded.
342 if (thread->cached_culture_info) {
344 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
345 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
349 * thread->synch_cs can be NULL if this was called after
350 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
351 * This can happen only during shutdown.
352 * The shutting_down flag is not always set, so we can't assert on it.
354 if (thread->synch_cs)
355 LOCK_THREAD (thread);
357 thread->state |= ThreadState_Stopped;
358 thread->state &= ~ThreadState_Background;
360 if (thread->synch_cs)
361 UNLOCK_THREAD (thread);
364 An interruption request has leaked to cleanup. Adjust the global counter.
366 This can happen is the abort source thread finds the abortee (this) thread
367 in unmanaged code. If this thread never trips back to managed code or check
368 the local flag it will be left set and positively unbalance the global counter.
370 Leaving the counter unbalanced will cause a performance degradation since all threads
371 will now keep checking their local flags all the time.
373 if (InterlockedExchange (&thread->interruption_requested, 0))
374 InterlockedDecrement (&thread_interruption_requested);
376 mono_threads_lock ();
380 } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
381 /* We have to check whether the thread object for the
382 * tid is still the same in the table because the
383 * thread might have been destroyed and the tid reused
384 * in the meantime, in which case the tid would be in
385 * the table, but with another thread object.
389 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
393 mono_threads_unlock ();
395 /* Don't close the handle here, wait for the object finalizer
396 * to do it. Otherwise, the following race condition applies:
398 * 1) Thread exits (and thread_cleanup() closes the handle)
400 * 2) Some other handle is reassigned the same slot
402 * 3) Another thread tries to join the first thread, and
403 * blocks waiting for the reassigned handle to be signalled
404 * (which might never happen). This is possible, because the
405 * thread calling Join() still has a reference to the first
409 /* if the thread is not in the hash it has been removed already */
411 if (thread == mono_thread_internal_current ()) {
412 mono_domain_unset ();
413 mono_memory_barrier ();
415 if (mono_thread_cleanup_fn)
416 mono_thread_cleanup_fn (thread_get_tid (thread));
419 mono_release_type_locks (thread);
421 /* Can happen when we attach the profiler helper thread in order to heapshot. */
422 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
423 mono_profiler_thread_end (thread->tid);
425 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
427 if (thread == mono_thread_internal_current ()) {
429 * This will signal async signal handlers that the thread has exited.
430 * The profiler callback needs this to be set, so it cannot be done earlier.
432 mono_domain_unset ();
433 mono_memory_barrier ();
436 if (thread == mono_thread_internal_current ())
437 mono_thread_pop_appdomain_ref ();
439 thread->cached_culture_info = NULL;
441 mono_free_static_data (thread->static_data);
442 thread->static_data = NULL;
443 ref_stack_destroy (thread->appdomain_refs);
444 thread->appdomain_refs = NULL;
446 if (mono_thread_cleanup_fn)
447 mono_thread_cleanup_fn (thread_get_tid (thread));
449 if (mono_gc_is_moving ()) {
450 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
451 thread->thread_pinning_ref = NULL;
457 * A special static data offset (guint32) consists of 3 parts:
459 * [0] 6-bit index into the array of chunks.
460 * [6] 25-bit offset into the array.
461 * [31] Bit indicating thread or context static.
466 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
477 } SpecialStaticOffset;
479 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
480 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
482 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
483 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
484 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
485 (((SpecialStaticOffset *) &(x))->fields.f)
488 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
490 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
492 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
493 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
495 return ((char *) thread->static_data [idx]) + off;
499 get_context_static_data (MonoAppContext *ctx, guint32 offset)
501 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
503 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
504 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
506 return ((char *) ctx->static_data [idx]) + off;
510 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
512 static MonoClassField *current_thread_field = NULL;
516 if (!current_thread_field) {
517 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
518 g_assert (current_thread_field);
521 mono_class_vtable (domain, mono_defaults.thread_class);
522 mono_domain_lock (domain);
523 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
524 mono_domain_unlock (domain);
527 return (MonoThread **)get_thread_static_data (thread, offset);
531 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
533 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
535 g_assert (current->obj.vtable->domain == domain);
537 g_assert (!*current_thread_ptr);
538 *current_thread_ptr = current;
542 create_thread_object (MonoDomain *domain)
545 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
546 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, &error);
547 /* only possible failure mode is OOM, from which we don't expect to recover. */
548 mono_error_assert_ok (&error);
553 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
557 thread = create_thread_object (domain);
559 MONO_OBJECT_SETREF (thread, internal_thread, internal);
564 static MonoInternalThread*
565 create_internal_thread (void)
568 MonoInternalThread *thread;
571 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
572 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
573 /* only possible failure mode is OOM, from which we don't exect to recover */
574 mono_error_assert_ok (&error);
576 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
577 mono_coop_mutex_init_recursive (thread->synch_cs);
579 thread->apartment_state = ThreadApartmentState_Unknown;
580 thread->managed_id = get_next_managed_thread_id ();
581 if (mono_gc_is_moving ()) {
582 thread->thread_pinning_ref = thread;
583 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
586 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
592 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
595 g_assert (internal->handle);
597 g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
598 g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
599 g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
604 res = SetThreadPriority (internal->handle, priority - 2);
606 g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
607 #else /* HOST_WIN32 */
610 struct sched_param param;
613 tid = thread_get_tid (internal);
615 res = pthread_getschedparam (tid, &policy, ¶m);
617 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
619 #ifdef _POSIX_PRIORITY_SCHEDULING
622 /* Necessary to get valid priority range */
624 min = sched_get_priority_min (policy);
625 max = sched_get_priority_max (policy);
627 if (max > 0 && min >= 0 && max > min) {
628 double srange, drange, sposition, dposition;
629 srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
631 sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
632 dposition = (sposition / srange) * drange;
633 param.sched_priority = (int)(dposition + min);
640 param.sched_priority = 50;
646 param.sched_priority = 0;
649 g_error ("%s: unknown policy %d", __func__, policy);
653 res = pthread_setschedparam (tid, policy, ¶m);
656 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
659 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
661 #endif /* HOST_WIN32 */
665 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
668 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
670 MonoThreadInfo *info;
671 MonoInternalThread *internal;
672 MonoDomain *domain, *root_domain;
676 info = mono_thread_info_current ();
678 internal = thread->internal_thread;
679 internal->handle = mono_thread_info_duplicate_handle (info);
680 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
681 internal->thread_info = info;
682 internal->small_id = info->small_id;
683 internal->stack_ptr = stack_ptr;
685 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
687 SET_CURRENT_OBJECT (internal);
689 domain = mono_object_domain (thread);
691 mono_thread_push_appdomain_ref (domain);
692 if (!mono_domain_set (domain, force_domain)) {
693 mono_thread_pop_appdomain_ref ();
697 mono_threads_lock ();
699 if (threads_starting_up)
700 mono_g_hash_table_remove (threads_starting_up, thread);
702 if (shutting_down && !force_attach) {
703 mono_threads_unlock ();
708 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
709 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
712 /* We don't need to duplicate thread->handle, because it is
713 * only closed when the thread object is finalized by the GC. */
714 mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
716 /* We have to do this here because mono_thread_start_cb
717 * requires that root_domain_thread is set up. */
718 if (thread_static_info.offset || thread_static_info.idx > 0) {
719 /* get the current allocated size */
720 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
721 mono_alloc_static_data (&internal->static_data, offset, TRUE);
724 mono_threads_unlock ();
726 root_domain = mono_get_root_domain ();
728 g_assert (!internal->root_domain_thread);
729 if (domain != root_domain)
730 MONO_OBJECT_SETREF (internal, root_domain_thread, new_thread_with_internal (root_domain, internal));
732 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
734 if (domain != root_domain)
735 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
737 set_current_thread_for_domain (domain, internal, thread);
739 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
747 MonoObject *start_delegate;
748 MonoObject *start_delegate_arg;
749 MonoThreadStart start_func;
750 gpointer start_func_arg;
752 MonoCoopSem registered;
755 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
758 MonoThreadStart start_func;
759 void *start_func_arg;
762 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
766 MonoInternalThread *internal;
767 MonoObject *start_delegate;
768 MonoObject *start_delegate_arg;
771 thread = start_info->thread;
772 internal = thread->internal_thread;
773 domain = mono_object_domain (start_info->thread);
775 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
777 if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
778 start_info->failed = TRUE;
780 mono_coop_sem_post (&start_info->registered);
782 if (InterlockedDecrement (&start_info->ref) == 0) {
783 mono_coop_sem_destroy (&start_info->registered);
790 mono_thread_internal_set_priority (internal, internal->priority);
794 start_delegate = start_info->start_delegate;
795 start_delegate_arg = start_info->start_delegate_arg;
796 start_func = start_info->start_func;
797 start_func_arg = start_info->start_func_arg;
799 /* This MUST be called before any managed code can be
800 * executed, as it calls the callback function that (for the
801 * jit) sets the lmf marker.
804 if (mono_thread_start_cb)
805 mono_thread_start_cb (tid, stack_ptr, start_func);
807 /* On 2.0 profile (and higher), set explicitly since state might have been
809 if (internal->apartment_state == ThreadApartmentState_Unknown)
810 internal->apartment_state = ThreadApartmentState_MTA;
812 mono_thread_init_apartment_state ();
814 /* Let the thread that called Start() know we're ready */
815 mono_coop_sem_post (&start_info->registered);
817 if (InterlockedDecrement (&start_info->ref) == 0) {
818 mono_coop_sem_destroy (&start_info->registered);
822 /* start_info is not valid anymore */
826 * Call this after calling start_notify, since the profiler callback might want
827 * to lock the thread, and the lock is held by thread_start () which waits for
830 mono_profiler_thread_start (tid);
832 /* if the name was set before starting, we didn't invoke the profiler callback */
833 if (internal->name) {
834 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
835 mono_profiler_thread_name (internal->tid, tname);
836 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
840 /* start_func is set only for unmanaged start functions */
842 start_func (start_func_arg);
846 g_assert (start_delegate != NULL);
848 /* we may want to handle the exception here. See comment below on unhandled exceptions */
849 args [0] = (gpointer) start_delegate_arg;
850 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
852 if (!mono_error_ok (&error)) {
853 MonoException *ex = mono_error_convert_to_exception (&error);
855 g_assert (ex != NULL);
856 MonoClass *klass = mono_object_get_class (&ex->object);
857 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
858 !is_threadabort_exception (klass)) {
859 mono_unhandled_exception (&ex->object);
860 mono_invoke_unhandled_exception_hook (&ex->object);
861 g_assert_not_reached ();
864 mono_error_cleanup (&error);
868 /* If the thread calls ExitThread at all, this remaining code
869 * will not be executed, but the main thread will eventually
870 * call thread_cleanup() on this thread's behalf.
873 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
875 /* Do any cleanup needed for apartment state. This
876 * cannot be done in thread_cleanup since thread_cleanup could be
877 * called for a thread other than the current thread.
878 * mono_thread_cleanup_apartment_state cleans up apartment
879 * for the current thead */
880 mono_thread_cleanup_apartment_state ();
882 mono_thread_detach_internal (internal);
889 static gsize WINAPI start_wrapper(void *data)
891 volatile gsize dummy;
893 /* Avoid scanning the frames above this frame during a GC */
894 mono_gc_set_stack_end ((void*)&dummy);
896 return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
902 * Common thread creation code.
903 * LOCKING: Acquires the threads lock.
906 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
907 gboolean threadpool_thread, guint32 stack_size, MonoError *error)
909 StartInfo *start_info = NULL;
910 HANDLE thread_handle;
911 MonoNativeThreadId tid;
913 gsize stack_set_size;
916 g_assert (!start_func && !start_func_arg);
918 g_assert (!start_delegate);
921 * Join joinable threads to prevent running out of threads since the finalizer
922 * thread might be blocked/backlogged.
924 mono_threads_join_threads ();
926 mono_error_init (error);
928 mono_threads_lock ();
930 mono_threads_unlock ();
933 if (threads_starting_up == NULL) {
934 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
935 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
937 mono_g_hash_table_insert (threads_starting_up, thread, thread);
938 mono_threads_unlock ();
940 internal->threadpool_thread = threadpool_thread;
941 if (threadpool_thread)
942 mono_thread_set_state (internal, ThreadState_Background);
944 start_info = g_new0 (StartInfo, 1);
946 start_info->thread = thread;
947 start_info->start_delegate = start_delegate;
948 start_info->start_delegate_arg = thread->start_obj;
949 start_info->start_func = start_func;
950 start_info->start_func_arg = start_func_arg;
951 start_info->failed = FALSE;
952 mono_coop_sem_init (&start_info->registered, 0);
955 stack_set_size = default_stacksize_for_thread (internal);
959 thread_handle = mono_threads_create_thread (start_wrapper, start_info, &stack_set_size, &tid);
961 if (thread_handle == NULL) {
962 /* The thread couldn't be created, so set an exception */
963 mono_threads_lock ();
964 mono_g_hash_table_remove (threads_starting_up, thread);
965 mono_threads_unlock ();
966 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
967 /* ref is not going to be decremented in start_wrapper_internal */
968 InterlockedDecrement (&start_info->ref);
973 internal->stack_size = (int) stack_set_size;
975 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
978 * Wait for the thread to set up its TLS data etc, so
979 * theres no potential race condition if someone tries
980 * to look up the data believing the thread has
984 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
986 mono_threads_close_thread_handle (thread_handle);
988 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));
990 ret = !start_info->failed;
993 if (InterlockedDecrement (&start_info->ref) == 0) {
994 mono_coop_sem_destroy (&start_info->registered);
1001 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
1003 if (mono_thread_start_cb) {
1004 mono_thread_start_cb (tid, stack_start, func);
1008 void mono_threads_set_default_stacksize (guint32 stacksize)
1010 default_stacksize = stacksize;
1013 guint32 mono_threads_get_default_stacksize (void)
1015 return default_stacksize;
1019 * mono_thread_create_internal:
1021 * ARG should not be a GC reference.
1024 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
1027 MonoInternalThread *internal;
1030 mono_error_init (error);
1032 thread = create_thread_object (domain);
1034 internal = create_internal_thread ();
1036 MONO_OBJECT_SETREF (thread, internal_thread, internal);
1038 LOCK_THREAD (internal);
1040 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
1041 return_val_if_nok (error, NULL);
1043 UNLOCK_THREAD (internal);
1049 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1052 if (!mono_thread_create_checked (domain, func, arg, &error))
1053 mono_error_cleanup (&error);
1057 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1059 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
1063 mono_thread_attach (MonoDomain *domain)
1065 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1071 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1073 MonoInternalThread *internal;
1075 MonoNativeThreadId tid;
1078 if (mono_thread_internal_current_is_attached ()) {
1079 if (domain != mono_domain_get ())
1080 mono_domain_set (domain, TRUE);
1081 /* Already attached */
1082 return mono_thread_current ();
1085 if (!mono_gc_register_thread (&domain)) {
1086 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 ());
1089 tid=mono_native_thread_id_get ();
1091 internal = create_internal_thread ();
1093 thread = new_thread_with_internal (domain, internal);
1095 if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
1096 /* Mono is shutting down, so just wait for the end */
1098 mono_thread_info_sleep (10000, NULL);
1101 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1103 if (mono_thread_attach_cb) {
1107 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1110 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1112 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1115 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1116 if (!mono_thread_info_current ()->tools_thread)
1117 // FIXME: Need a separate callback
1118 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1124 mono_thread_detach_internal (MonoInternalThread *thread)
1126 g_return_if_fail (thread != NULL);
1128 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1131 mono_w32mutex_abandon ();
1134 thread_cleanup (thread);
1136 SET_CURRENT_OBJECT (NULL);
1137 mono_domain_unset ();
1139 /* Don't need to close the handle to this thread, even though we took a
1140 * reference in mono_thread_attach (), because the GC will do it
1141 * when the Thread object is finalised.
1146 mono_thread_detach (MonoThread *thread)
1149 mono_thread_detach_internal (thread->internal_thread);
1153 * mono_thread_detach_if_exiting:
1155 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1156 * This should be used at the end of embedding code which calls into managed code, and which
1157 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1160 mono_thread_detach_if_exiting (void)
1162 if (mono_thread_info_is_exiting ()) {
1163 MonoInternalThread *thread;
1165 thread = mono_thread_internal_current ();
1167 mono_thread_detach_internal (thread);
1168 mono_thread_info_detach ();
1176 mono_thread_internal_current_is_attached (void)
1178 MonoInternalThread *internal;
1180 internal = GET_CURRENT_OBJECT ();
1188 mono_thread_exit (void)
1190 MonoInternalThread *thread = mono_thread_internal_current ();
1192 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1194 mono_thread_detach_internal (thread);
1196 /* we could add a callback here for embedders to use. */
1197 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1198 exit (mono_environment_exitcode_get ());
1200 mono_thread_info_exit ();
1204 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1206 MonoInternalThread *internal;
1208 internal = create_internal_thread ();
1210 internal->state = ThreadState_Unstarted;
1212 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1216 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1220 MonoInternalThread *internal;
1223 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1225 if (!this_obj->internal_thread)
1226 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1227 internal = this_obj->internal_thread;
1229 LOCK_THREAD (internal);
1231 if ((internal->state & ThreadState_Unstarted) == 0) {
1232 UNLOCK_THREAD (internal);
1233 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1237 if ((internal->state & ThreadState_Aborted) != 0) {
1238 UNLOCK_THREAD (internal);
1242 res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1244 mono_error_cleanup (&error);
1245 UNLOCK_THREAD (internal);
1249 internal->state &= ~ThreadState_Unstarted;
1251 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1253 UNLOCK_THREAD (internal);
1254 return internal->handle;
1258 * This is called from the finalizer of the internal thread object.
1261 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1263 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1266 * Since threads keep a reference to their thread object while running, by the time this function is called,
1267 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1268 * when thread_cleanup () can be called after this.
1271 mono_threads_close_thread_handle (thread);
1273 if (this_obj->synch_cs) {
1274 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1275 this_obj->synch_cs = NULL;
1276 mono_coop_mutex_destroy (synch_cs);
1280 if (this_obj->name) {
1281 void *name = this_obj->name;
1282 this_obj->name = NULL;
1288 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1291 MonoInternalThread *thread = mono_thread_internal_current ();
1293 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1295 if (mono_thread_current_check_pending_interrupt ())
1299 gboolean alerted = FALSE;
1301 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1303 res = mono_thread_info_sleep (ms, &alerted);
1305 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1308 MonoException* exc = mono_thread_execute_interruption ();
1310 mono_raise_exception (exc);
1322 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1327 ves_icall_System_Threading_Thread_GetDomainID (void)
1329 return mono_domain_get()->domain_id;
1333 ves_icall_System_Threading_Thread_Yield (void)
1335 return mono_thread_info_yield ();
1339 * mono_thread_get_name:
1341 * Return the name of the thread. NAME_LEN is set to the length of the name.
1342 * Return NULL if the thread has no name. The returned memory is owned by the
1346 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1350 LOCK_THREAD (this_obj);
1352 if (!this_obj->name) {
1356 *name_len = this_obj->name_len;
1357 res = g_new (gunichar2, this_obj->name_len);
1358 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1361 UNLOCK_THREAD (this_obj);
1367 * mono_thread_get_name_utf8:
1369 * Return the name of the thread in UTF-8.
1370 * Return NULL if the thread has no name.
1371 * The returned memory is owned by the caller.
1374 mono_thread_get_name_utf8 (MonoThread *thread)
1379 MonoInternalThread *internal = thread->internal_thread;
1380 if (internal == NULL)
1383 LOCK_THREAD (internal);
1385 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1387 UNLOCK_THREAD (internal);
1393 * mono_thread_get_managed_id:
1395 * Return the Thread.ManagedThreadId value of `thread`.
1396 * Returns -1 if `thread` is NULL.
1399 mono_thread_get_managed_id (MonoThread *thread)
1404 MonoInternalThread *internal = thread->internal_thread;
1405 if (internal == NULL)
1408 int32_t id = internal->managed_id;
1414 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1419 mono_error_init (&error);
1421 LOCK_THREAD (this_obj);
1423 if (!this_obj->name)
1426 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1428 UNLOCK_THREAD (this_obj);
1430 if (mono_error_set_pending_exception (&error))
1437 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1439 LOCK_THREAD (this_obj);
1441 mono_error_init (error);
1443 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1444 UNLOCK_THREAD (this_obj);
1446 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1449 if (this_obj->name) {
1450 g_free (this_obj->name);
1451 this_obj->name_len = 0;
1454 this_obj->name = g_new (gunichar2, mono_string_length (name));
1455 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1456 this_obj->name_len = mono_string_length (name);
1459 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1462 this_obj->name = NULL;
1465 UNLOCK_THREAD (this_obj);
1467 if (this_obj->name && this_obj->tid) {
1468 char *tname = mono_string_to_utf8_checked (name, error);
1469 return_if_nok (error);
1470 mono_profiler_thread_name (this_obj->tid, tname);
1471 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1477 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1480 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1481 mono_error_set_pending_exception (&error);
1485 * ves_icall_System_Threading_Thread_GetPriority_internal:
1486 * @param this_obj: The MonoInternalThread on which to operate.
1488 * Gets the priority of the given thread.
1489 * @return: The priority of the given thread.
1492 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1495 MonoInternalThread *internal = this_obj->internal_thread;
1497 LOCK_THREAD (internal);
1498 priority = internal->priority;
1499 UNLOCK_THREAD (internal);
1505 * ves_icall_System_Threading_Thread_SetPriority_internal:
1506 * @param this_obj: The MonoInternalThread on which to operate.
1507 * @param priority: The priority to set.
1509 * Sets the priority of the given thread.
1512 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1514 MonoInternalThread *internal = this_obj->internal_thread;
1516 LOCK_THREAD (internal);
1517 internal->priority = priority;
1518 if (internal->handle != NULL)
1519 mono_thread_internal_set_priority (internal, priority);
1520 UNLOCK_THREAD (internal);
1523 /* If the array is already in the requested domain, we just return it,
1524 otherwise we return a copy in that domain. */
1526 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1530 mono_error_init (error);
1534 if (mono_object_domain (arr) == domain)
1537 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1538 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1543 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1546 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1547 mono_error_set_pending_exception (&error);
1552 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1555 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1556 mono_error_set_pending_exception (&error);
1561 mono_thread_current (void)
1563 MonoDomain *domain = mono_domain_get ();
1564 MonoInternalThread *internal = mono_thread_internal_current ();
1565 MonoThread **current_thread_ptr;
1567 g_assert (internal);
1568 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1570 if (!*current_thread_ptr) {
1571 g_assert (domain != mono_get_root_domain ());
1572 *current_thread_ptr = new_thread_with_internal (domain, internal);
1574 return *current_thread_ptr;
1577 /* Return the thread object belonging to INTERNAL in the current domain */
1579 mono_thread_current_for_thread (MonoInternalThread *internal)
1581 MonoDomain *domain = mono_domain_get ();
1582 MonoThread **current_thread_ptr;
1584 g_assert (internal);
1585 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1587 if (!*current_thread_ptr) {
1588 g_assert (domain != mono_get_root_domain ());
1589 *current_thread_ptr = new_thread_with_internal (domain, internal);
1591 return *current_thread_ptr;
1595 mono_thread_internal_current (void)
1597 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1598 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1603 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1605 MonoInternalThread *thread = this_obj->internal_thread;
1606 HANDLE handle = thread->handle;
1607 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1610 if (mono_thread_current_check_pending_interrupt ())
1613 LOCK_THREAD (thread);
1615 if ((thread->state & ThreadState_Unstarted) != 0) {
1616 UNLOCK_THREAD (thread);
1618 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1622 UNLOCK_THREAD (thread);
1627 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1629 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1632 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1635 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1637 if(ret==WAIT_OBJECT_0) {
1638 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1643 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1648 #define MANAGED_WAIT_FAILED 0x7fffffff
1651 map_native_wait_result_to_managed (gint32 val)
1653 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1654 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1658 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1666 mono_error_init (error);
1668 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1671 if (numhandles != 1)
1672 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1674 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1677 if (ret != WAIT_IO_COMPLETION)
1680 exc = mono_thread_execute_interruption ();
1682 mono_error_set_exception_instance (error, exc);
1689 /* Re-calculate ms according to the time passed */
1690 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1691 if (diff_ms >= ms) {
1695 wait = ms - diff_ms;
1701 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1708 MonoObject *waitHandle;
1709 MonoInternalThread *thread = mono_thread_internal_current ();
1711 /* Do this WaitSleepJoin check before creating objects */
1712 if (mono_thread_current_check_pending_interrupt ())
1713 return map_native_wait_result_to_managed (WAIT_FAILED);
1715 /* We fail in managed if the array has more than 64 elements */
1716 numhandles = (guint32)mono_array_length(mono_handles);
1717 handles = g_new0(HANDLE, numhandles);
1719 for(i = 0; i < numhandles; i++) {
1720 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1721 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1728 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1730 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1732 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1736 mono_error_set_pending_exception (&error);
1738 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1739 return map_native_wait_result_to_managed (ret);
1742 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1745 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1746 uintptr_t numhandles;
1749 MonoObject *waitHandle;
1750 MonoInternalThread *thread = mono_thread_internal_current ();
1752 /* Do this WaitSleepJoin check before creating objects */
1753 if (mono_thread_current_check_pending_interrupt ())
1754 return map_native_wait_result_to_managed (WAIT_FAILED);
1756 numhandles = mono_array_length(mono_handles);
1757 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1758 return map_native_wait_result_to_managed (WAIT_FAILED);
1760 for(i = 0; i < numhandles; i++) {
1761 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1762 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1769 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1771 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1773 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1775 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1777 mono_error_set_pending_exception (&error);
1779 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1780 return map_native_wait_result_to_managed (ret);
1783 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1787 MonoInternalThread *thread = mono_thread_internal_current ();
1789 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1795 if (mono_thread_current_check_pending_interrupt ())
1796 return map_native_wait_result_to_managed (WAIT_FAILED);
1798 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1800 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1802 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1804 mono_error_set_pending_exception (&error);
1805 return map_native_wait_result_to_managed (ret);
1809 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1812 MonoInternalThread *thread = mono_thread_internal_current ();
1817 if (mono_thread_current_check_pending_interrupt ())
1818 return map_native_wait_result_to_managed (WAIT_FAILED);
1820 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1823 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1826 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1828 return map_native_wait_result_to_managed (ret);
1831 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1833 return InterlockedIncrement (location);
1836 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1838 #if SIZEOF_VOID_P == 4
1839 if (G_UNLIKELY ((size_t)location & 0x7)) {
1841 mono_interlocked_lock ();
1844 mono_interlocked_unlock ();
1848 return InterlockedIncrement64 (location);
1851 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1853 return InterlockedDecrement(location);
1856 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1858 #if SIZEOF_VOID_P == 4
1859 if (G_UNLIKELY ((size_t)location & 0x7)) {
1861 mono_interlocked_lock ();
1864 mono_interlocked_unlock ();
1868 return InterlockedDecrement64 (location);
1871 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1873 return InterlockedExchange(location, value);
1876 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1879 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1880 mono_gc_wbarrier_generic_nostore (location);
1884 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1886 return InterlockedExchangePointer(location, value);
1889 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1891 IntFloatUnion val, ret;
1894 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1900 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1902 #if SIZEOF_VOID_P == 4
1903 if (G_UNLIKELY ((size_t)location & 0x7)) {
1905 mono_interlocked_lock ();
1908 mono_interlocked_unlock ();
1912 return InterlockedExchange64 (location, value);
1916 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1918 LongDoubleUnion val, ret;
1921 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1926 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1928 return InterlockedCompareExchange(location, value, comparand);
1931 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1933 gint32 r = InterlockedCompareExchange(location, value, comparand);
1934 *success = r == comparand;
1938 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1941 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1942 mono_gc_wbarrier_generic_nostore (location);
1946 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1948 return InterlockedCompareExchangePointer(location, value, comparand);
1951 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1953 IntFloatUnion val, ret, cmp;
1956 cmp.fval = comparand;
1957 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1963 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1965 #if SIZEOF_VOID_P == 8
1966 LongDoubleUnion val, comp, ret;
1969 comp.fval = comparand;
1970 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1976 mono_interlocked_lock ();
1978 if (old == comparand)
1980 mono_interlocked_unlock ();
1987 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1989 #if SIZEOF_VOID_P == 4
1990 if (G_UNLIKELY ((size_t)location & 0x7)) {
1992 mono_interlocked_lock ();
1994 if (old == comparand)
1996 mono_interlocked_unlock ();
2000 return InterlockedCompareExchange64 (location, value, comparand);
2004 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2007 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2008 mono_gc_wbarrier_generic_nostore (location);
2013 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2016 MONO_CHECK_NULL (location, NULL);
2017 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2018 mono_gc_wbarrier_generic_nostore (location);
2023 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2025 return InterlockedAdd (location, value);
2029 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2031 #if SIZEOF_VOID_P == 4
2032 if (G_UNLIKELY ((size_t)location & 0x7)) {
2034 mono_interlocked_lock ();
2037 mono_interlocked_unlock ();
2041 return InterlockedAdd64 (location, value);
2045 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2047 #if SIZEOF_VOID_P == 4
2048 if (G_UNLIKELY ((size_t)location & 0x7)) {
2050 mono_interlocked_lock ();
2052 mono_interlocked_unlock ();
2056 return InterlockedRead64 (location);
2060 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2062 mono_memory_barrier ();
2066 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2068 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2070 if (state & ThreadState_Background) {
2071 /* If the thread changes the background mode, the main thread has to
2072 * be notified, since it has to rebuild the list of threads to
2075 mono_w32event_set (background_change_event);
2080 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2082 mono_thread_set_state (this_obj, (MonoThreadState)state);
2084 if (state & ThreadState_Background) {
2085 /* If the thread changes the background mode, the main thread has to
2086 * be notified, since it has to rebuild the list of threads to
2089 mono_w32event_set (background_change_event);
2094 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2098 LOCK_THREAD (this_obj);
2100 state = this_obj->state;
2102 UNLOCK_THREAD (this_obj);
2107 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2109 MonoInternalThread *current;
2111 MonoInternalThread *thread = this_obj->internal_thread;
2113 LOCK_THREAD (thread);
2115 current = mono_thread_internal_current ();
2117 thread->thread_interrupt_requested = TRUE;
2118 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2120 UNLOCK_THREAD (thread);
2123 async_abort_internal (thread, FALSE);
2128 * mono_thread_current_check_pending_interrupt:
2130 * Checks if there's a interruption request and set the pending exception if so.
2132 * @returns true if a pending exception was set
2135 mono_thread_current_check_pending_interrupt (void)
2137 MonoInternalThread *thread = mono_thread_internal_current ();
2138 gboolean throw_ = FALSE;
2140 LOCK_THREAD (thread);
2142 if (thread->thread_interrupt_requested) {
2144 thread->thread_interrupt_requested = FALSE;
2147 UNLOCK_THREAD (thread);
2150 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2155 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2157 LOCK_THREAD (thread);
2159 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2160 (thread->state & ThreadState_StopRequested) != 0 ||
2161 (thread->state & ThreadState_Stopped) != 0)
2163 UNLOCK_THREAD (thread);
2167 if ((thread->state & ThreadState_Unstarted) != 0) {
2168 thread->state |= ThreadState_Aborted;
2169 UNLOCK_THREAD (thread);
2173 thread->state |= ThreadState_AbortRequested;
2174 if (thread->abort_state_handle)
2175 mono_gchandle_free (thread->abort_state_handle);
2177 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2178 g_assert (thread->abort_state_handle);
2180 thread->abort_state_handle = 0;
2182 thread->abort_exc = NULL;
2184 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));
2186 /* During shutdown, we can't wait for other threads */
2188 /* Make sure the thread is awake */
2189 mono_thread_resume (thread);
2191 UNLOCK_THREAD (thread);
2196 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2198 if (!request_thread_abort (thread, state))
2201 if (thread == mono_thread_internal_current ()) {
2203 self_abort_internal (&error);
2204 mono_error_set_pending_exception (&error);
2206 async_abort_internal (thread, TRUE);
2211 * mono_thread_internal_abort:
2213 * Request thread @thread to be aborted.
2215 * @thread MUST NOT be the current thread.
2218 mono_thread_internal_abort (MonoInternalThread *thread)
2220 g_assert (thread != mono_thread_internal_current ());
2222 if (!request_thread_abort (thread, NULL))
2224 async_abort_internal (thread, TRUE);
2228 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2230 MonoInternalThread *thread = mono_thread_internal_current ();
2231 gboolean was_aborting;
2233 LOCK_THREAD (thread);
2234 was_aborting = thread->state & ThreadState_AbortRequested;
2235 thread->state &= ~ThreadState_AbortRequested;
2236 UNLOCK_THREAD (thread);
2238 if (!was_aborting) {
2239 const char *msg = "Unable to reset abort because no abort was requested";
2240 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2243 thread->abort_exc = NULL;
2244 if (thread->abort_state_handle) {
2245 mono_gchandle_free (thread->abort_state_handle);
2246 /* This is actually not necessary - the handle
2247 only counts if the exception is set */
2248 thread->abort_state_handle = 0;
2253 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2255 LOCK_THREAD (thread);
2257 thread->state &= ~ThreadState_AbortRequested;
2259 if (thread->abort_exc) {
2260 thread->abort_exc = NULL;
2261 if (thread->abort_state_handle) {
2262 mono_gchandle_free (thread->abort_state_handle);
2263 /* This is actually not necessary - the handle
2264 only counts if the exception is set */
2265 thread->abort_state_handle = 0;
2269 UNLOCK_THREAD (thread);
2273 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2276 MonoInternalThread *thread = this_obj->internal_thread;
2277 MonoObject *state, *deserialized = NULL;
2280 if (!thread->abort_state_handle)
2283 state = mono_gchandle_get_target (thread->abort_state_handle);
2286 domain = mono_domain_get ();
2287 if (mono_object_domain (state) == domain)
2290 deserialized = mono_object_xdomain_representation (state, domain, &error);
2292 if (!deserialized) {
2293 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2294 if (!is_ok (&error)) {
2295 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2296 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2298 mono_set_pending_exception (invalid_op_exc);
2302 return deserialized;
2306 mono_thread_suspend (MonoInternalThread *thread)
2308 LOCK_THREAD (thread);
2310 if ((thread->state & ThreadState_Unstarted) != 0 ||
2311 (thread->state & ThreadState_Aborted) != 0 ||
2312 (thread->state & ThreadState_Stopped) != 0)
2314 UNLOCK_THREAD (thread);
2318 if ((thread->state & ThreadState_Suspended) != 0 ||
2319 (thread->state & ThreadState_SuspendRequested) != 0 ||
2320 (thread->state & ThreadState_StopRequested) != 0)
2322 UNLOCK_THREAD (thread);
2326 thread->state |= ThreadState_SuspendRequested;
2328 if (thread == mono_thread_internal_current ()) {
2329 /* calls UNLOCK_THREAD (thread) */
2330 self_suspend_internal ();
2332 /* calls UNLOCK_THREAD (thread) */
2333 async_suspend_internal (thread, FALSE);
2340 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2342 if (!mono_thread_suspend (this_obj->internal_thread)) {
2343 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2348 /* LOCKING: LOCK_THREAD(thread) must be held */
2350 mono_thread_resume (MonoInternalThread *thread)
2352 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2353 thread->state &= ~ThreadState_SuspendRequested;
2357 if ((thread->state & ThreadState_Suspended) == 0 ||
2358 (thread->state & ThreadState_Unstarted) != 0 ||
2359 (thread->state & ThreadState_Aborted) != 0 ||
2360 (thread->state & ThreadState_Stopped) != 0)
2365 UNLOCK_THREAD (thread);
2367 /* Awake the thread */
2368 if (!mono_thread_info_resume (thread_get_tid (thread)))
2371 LOCK_THREAD (thread);
2373 thread->state &= ~ThreadState_Suspended;
2379 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2381 if (!thread->internal_thread) {
2382 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2384 LOCK_THREAD (thread->internal_thread);
2385 if (!mono_thread_resume (thread->internal_thread))
2386 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2387 UNLOCK_THREAD (thread->internal_thread);
2392 mono_threads_is_critical_method (MonoMethod *method)
2394 switch (method->wrapper_type) {
2395 case MONO_WRAPPER_RUNTIME_INVOKE:
2396 case MONO_WRAPPER_XDOMAIN_INVOKE:
2397 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2404 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2409 if (mono_threads_is_critical_method (m)) {
2410 *((gboolean*)data) = TRUE;
2417 is_running_protected_wrapper (void)
2419 gboolean found = FALSE;
2420 mono_stack_walk (find_wrapper, &found);
2425 request_thread_stop (MonoInternalThread *thread)
2427 LOCK_THREAD (thread);
2429 if ((thread->state & ThreadState_StopRequested) != 0 ||
2430 (thread->state & ThreadState_Stopped) != 0)
2432 UNLOCK_THREAD (thread);
2436 /* Make sure the thread is awake */
2437 mono_thread_resume (thread);
2439 thread->state |= ThreadState_StopRequested;
2440 thread->state &= ~ThreadState_AbortRequested;
2442 UNLOCK_THREAD (thread);
2447 * mono_thread_internal_stop:
2449 * Request thread @thread to stop.
2451 * @thread MUST NOT be the current thread.
2454 mono_thread_internal_stop (MonoInternalThread *thread)
2456 g_assert (thread != mono_thread_internal_current ());
2458 if (!request_thread_stop (thread))
2461 async_abort_internal (thread, TRUE);
2464 void mono_thread_stop (MonoThread *thread)
2466 MonoInternalThread *internal = thread->internal_thread;
2468 if (!request_thread_stop (internal))
2471 if (internal == mono_thread_internal_current ()) {
2473 self_abort_internal (&error);
2475 This function is part of the embeding API and has no way to return the exception
2476 to be thrown. So what we do is keep the old behavior and raise the exception.
2478 mono_error_raise_exception (&error); /* OK to throw, see note */
2480 async_abort_internal (internal, TRUE);
2485 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2487 gint8 tmp = *(volatile gint8 *)ptr;
2488 mono_memory_barrier ();
2493 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2495 gint16 tmp = *(volatile gint16 *)ptr;
2496 mono_memory_barrier ();
2501 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2503 gint32 tmp = *(volatile gint32 *)ptr;
2504 mono_memory_barrier ();
2509 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2511 gint64 tmp = *(volatile gint64 *)ptr;
2512 mono_memory_barrier ();
2517 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2519 volatile void *tmp = *(volatile void **)ptr;
2520 mono_memory_barrier ();
2521 return (void *) tmp;
2525 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2527 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2528 mono_memory_barrier ();
2529 return (MonoObject *) tmp;
2533 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2535 double tmp = *(volatile double *)ptr;
2536 mono_memory_barrier ();
2541 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2543 float tmp = *(volatile float *)ptr;
2544 mono_memory_barrier ();
2549 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2551 return InterlockedRead8 ((volatile gint8 *)ptr);
2555 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2557 return InterlockedRead16 ((volatile gint16 *)ptr);
2561 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2563 return InterlockedRead ((volatile gint32 *)ptr);
2567 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2569 #if SIZEOF_VOID_P == 4
2570 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2572 mono_interlocked_lock ();
2573 val = *(gint64*)ptr;
2574 mono_interlocked_unlock ();
2578 return InterlockedRead64 ((volatile gint64 *)ptr);
2582 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2584 return InterlockedReadPointer ((volatile gpointer *)ptr);
2588 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2592 #if SIZEOF_VOID_P == 4
2593 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2595 mono_interlocked_lock ();
2596 val = *(double*)ptr;
2597 mono_interlocked_unlock ();
2602 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2608 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2612 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2618 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2620 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2624 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2626 mono_memory_barrier ();
2627 *(volatile gint8 *)ptr = value;
2631 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2633 mono_memory_barrier ();
2634 *(volatile gint16 *)ptr = value;
2638 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2640 mono_memory_barrier ();
2641 *(volatile gint32 *)ptr = value;
2645 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2647 mono_memory_barrier ();
2648 *(volatile gint64 *)ptr = value;
2652 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2654 mono_memory_barrier ();
2655 *(volatile void **)ptr = value;
2659 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2661 mono_memory_barrier ();
2662 mono_gc_wbarrier_generic_store (ptr, value);
2666 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2668 mono_memory_barrier ();
2669 *(volatile double *)ptr = value;
2673 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2675 mono_memory_barrier ();
2676 *(volatile float *)ptr = value;
2680 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2682 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2686 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2688 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2692 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2694 InterlockedWrite ((volatile gint32 *)ptr, value);
2698 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2700 #if SIZEOF_VOID_P == 4
2701 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2702 mono_interlocked_lock ();
2703 *(gint64*)ptr = value;
2704 mono_interlocked_unlock ();
2709 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2713 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2715 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2719 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2723 #if SIZEOF_VOID_P == 4
2724 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2725 mono_interlocked_lock ();
2726 *(double*)ptr = value;
2727 mono_interlocked_unlock ();
2734 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2738 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2744 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2748 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2750 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2754 free_context (void *user_data)
2756 ContextStaticData *data = user_data;
2758 mono_threads_lock ();
2761 * There is no guarantee that, by the point this reference queue callback
2762 * has been invoked, the GC handle associated with the object will fail to
2763 * resolve as one might expect. So if we don't free and remove the GC
2764 * handle here, free_context_static_data_helper () could end up resolving
2765 * a GC handle to an actually-dead context which would contain a pointer
2766 * to an already-freed static data segment, resulting in a crash when
2769 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2771 mono_threads_unlock ();
2773 mono_gchandle_free (data->gc_handle);
2774 mono_free_static_data (data->static_data);
2779 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2781 mono_threads_lock ();
2783 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2786 contexts = g_hash_table_new (NULL, NULL);
2789 context_queue = mono_gc_reference_queue_new (free_context);
2791 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2792 g_hash_table_insert (contexts, gch, gch);
2795 * We use this intermediate structure to contain a duplicate pointer to
2796 * the static data because we can't rely on being able to resolve the GC
2797 * handle in the reference queue callback.
2799 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2800 data->gc_handle = GPOINTER_TO_UINT (gch);
2803 context_adjust_static_data (ctx);
2804 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2806 mono_threads_unlock ();
2808 mono_profiler_context_loaded (ctx);
2812 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2815 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2816 * cleanup in exceptional circumstances, we don't actually do any
2817 * cleanup work here. We instead do this via a reference queue.
2820 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2822 mono_profiler_context_unloaded (ctx);
2826 mono_thread_init_tls (void)
2828 MONO_FAST_TLS_INIT (tls_current_object);
2829 mono_native_tls_alloc (¤t_object_key, NULL);
2832 void mono_thread_init (MonoThreadStartCB start_cb,
2833 MonoThreadAttachCB attach_cb)
2835 mono_coop_mutex_init_recursive (&threads_mutex);
2837 mono_os_mutex_init_recursive(&interlocked_mutex);
2838 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2840 background_change_event = mono_w32event_create (TRUE, FALSE);
2841 g_assert(background_change_event != NULL);
2843 mono_init_static_data_info (&thread_static_info);
2844 mono_init_static_data_info (&context_static_info);
2846 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2848 mono_thread_start_cb = start_cb;
2849 mono_thread_attach_cb = attach_cb;
2851 /* Get a pseudo handle to the current process. This is just a
2852 * kludge so that wapi can build a process handle if needed.
2853 * As a pseudo handle is returned, we don't need to clean
2856 GetCurrentProcess ();
2859 void mono_thread_cleanup (void)
2861 #if !defined(RUN_IN_SUBTHREAD)
2862 /* The main thread must abandon any held mutexes (particularly
2863 * important for named mutexes as they are shared across
2864 * processes, see bug 74680.) This will happen when the
2865 * thread exits, but if it's not running in a subthread it
2866 * won't exit in time.
2868 mono_thread_info_set_exited (mono_thread_info_current ());
2872 /* This stuff needs more testing, it seems one of these
2873 * critical sections can be locked when mono_thread_cleanup is
2876 mono_coop_mutex_destroy (&threads_mutex);
2877 mono_os_mutex_destroy (&interlocked_mutex);
2878 mono_os_mutex_destroy (&delayed_free_table_mutex);
2879 mono_os_mutex_destroy (&small_id_mutex);
2880 CloseHandle (background_change_event);
2883 mono_native_tls_free (current_object_key);
2887 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2889 mono_thread_cleanup_fn = func;
2893 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2895 thread->internal_thread->manage_callback = func;
2899 static void print_tids (gpointer key, gpointer value, gpointer user)
2901 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2902 * sizeof(uint) and a cast to uint would overflow
2904 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2905 * print this as a pointer.
2907 g_message ("Waiting for: %p", key);
2912 HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2913 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2918 wait_for_tids (struct wait_data *wait, guint32 timeout)
2922 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2925 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2928 if(ret==WAIT_FAILED) {
2929 /* See the comment in build_wait_tids() */
2930 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2934 for(i=0; i<wait->num; i++)
2935 mono_threads_close_thread_handle (wait->handles [i]);
2937 if (ret == WAIT_TIMEOUT)
2940 for(i=0; i<wait->num; i++) {
2941 MonoInternalThread *internal;
2943 internal = wait->threads [i];
2945 mono_threads_lock ();
2946 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
2947 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
2948 mono_threads_unlock ();
2952 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2954 guint32 i, ret, count;
2956 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2958 /* Add the thread state change event, so it wakes up if a thread changes
2959 * to background mode.
2962 if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
2963 wait->handles [count] = background_change_event;
2968 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2971 if(ret==WAIT_FAILED) {
2972 /* See the comment in build_wait_tids() */
2973 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2977 for(i=0; i<wait->num; i++)
2978 mono_threads_close_thread_handle (wait->handles [i]);
2980 if (ret == WAIT_TIMEOUT)
2983 if (ret < wait->num) {
2984 MonoInternalThread *internal;
2986 internal = wait->threads [ret];
2988 mono_threads_lock ();
2989 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
2990 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
2991 mono_threads_unlock ();
2995 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2997 struct wait_data *wait=(struct wait_data *)user;
2999 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3001 MonoInternalThread *thread=(MonoInternalThread *)value;
3003 /* Ignore background threads, we abort them later */
3004 /* Do not lock here since it is not needed and the caller holds threads_lock */
3005 if (thread->state & ThreadState_Background) {
3006 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3007 return; /* just leave, ignore */
3010 if (mono_gc_is_finalizer_internal_thread (thread)) {
3011 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3015 if (thread == mono_thread_internal_current ()) {
3016 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3020 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3021 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3025 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3026 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3030 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3031 if (handle == NULL) {
3032 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3036 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3037 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3038 wait->handles[wait->num]=handle;
3039 wait->threads[wait->num]=thread;
3042 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3044 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3049 /* Just ignore the rest, we can't do anything with
3056 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3058 struct wait_data *wait=(struct wait_data *)user;
3059 MonoNativeThreadId self = mono_native_thread_id_get ();
3060 MonoInternalThread *thread = (MonoInternalThread *)value;
3063 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3066 /* The finalizer thread is not a background thread */
3067 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3068 && (thread->state & ThreadState_Background) != 0
3069 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3071 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3075 wait->handles[wait->num] = handle;
3076 wait->threads[wait->num] = thread;
3079 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3080 mono_thread_internal_abort (thread);
3084 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3085 && !mono_gc_is_finalizer_internal_thread (thread);
3089 * mono_threads_set_shutting_down:
3091 * Is called by a thread that wants to shut down Mono. If the runtime is already
3092 * shutting down, the calling thread is suspended/stopped, and this function never
3096 mono_threads_set_shutting_down (void)
3098 MonoInternalThread *current_thread = mono_thread_internal_current ();
3100 mono_threads_lock ();
3102 if (shutting_down) {
3103 mono_threads_unlock ();
3105 /* Make sure we're properly suspended/stopped */
3107 LOCK_THREAD (current_thread);
3109 if ((current_thread->state & ThreadState_SuspendRequested) ||
3110 (current_thread->state & ThreadState_AbortRequested) ||
3111 (current_thread->state & ThreadState_StopRequested)) {
3112 UNLOCK_THREAD (current_thread);
3113 mono_thread_execute_interruption ();
3115 current_thread->state |= ThreadState_Stopped;
3116 UNLOCK_THREAD (current_thread);
3119 /*since we're killing the thread, detach it.*/
3120 mono_thread_detach_internal (current_thread);
3122 /* Wake up other threads potentially waiting for us */
3123 mono_thread_info_exit ();
3125 shutting_down = TRUE;
3127 /* Not really a background state change, but this will
3128 * interrupt the main thread if it is waiting for all
3129 * the other threads.
3131 mono_w32event_set (background_change_event);
3133 mono_threads_unlock ();
3137 void mono_thread_manage (void)
3139 struct wait_data wait_data;
3140 struct wait_data *wait = &wait_data;
3142 memset (wait, 0, sizeof (struct wait_data));
3143 /* join each thread that's still running */
3144 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3146 mono_threads_lock ();
3148 THREAD_DEBUG (g_message("%s: No threads", __func__));
3149 mono_threads_unlock ();
3152 mono_threads_unlock ();
3155 mono_threads_lock ();
3156 if (shutting_down) {
3157 /* somebody else is shutting down */
3158 mono_threads_unlock ();
3161 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3162 mono_g_hash_table_foreach (threads, print_tids, NULL));
3164 mono_w32event_reset (background_change_event);
3166 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3167 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3168 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3169 mono_threads_unlock ();
3171 /* Something to wait for */
3172 wait_for_tids_or_state_change (wait, INFINITE);
3174 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3175 } while(wait->num>0);
3177 /* Mono is shutting down, so just wait for the end */
3178 if (!mono_runtime_try_shutdown ()) {
3179 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3180 mono_thread_suspend (mono_thread_internal_current ());
3181 mono_thread_execute_interruption ();
3185 * Remove everything but the finalizer thread and self.
3186 * Also abort all the background threads
3189 mono_threads_lock ();
3192 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3193 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3194 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3196 mono_threads_unlock ();
3198 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3200 /* Something to wait for */
3201 wait_for_tids (wait, INFINITE);
3203 } while (wait->num > 0);
3206 * give the subthreads a chance to really quit (this is mainly needed
3207 * to get correct user and system times from getrusage/wait/time(1)).
3208 * This could be removed if we avoid pthread_detach() and use pthread_join().
3210 mono_thread_info_yield ();
3214 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3216 MonoInternalThread *thread = (MonoInternalThread*)value;
3217 struct wait_data *wait = (struct wait_data*)user_data;
3221 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3223 * This needs no locking.
3225 if ((thread->state & ThreadState_Suspended) != 0 ||
3226 (thread->state & ThreadState_Stopped) != 0)
3229 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3230 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3234 wait->handles [wait->num] = handle;
3235 wait->threads [wait->num] = thread;
3241 * mono_thread_suspend_all_other_threads:
3243 * Suspend all managed threads except the finalizer thread and this thread. It is
3244 * not possible to resume them later.
3246 void mono_thread_suspend_all_other_threads (void)
3248 struct wait_data wait_data;
3249 struct wait_data *wait = &wait_data;
3251 MonoNativeThreadId self = mono_native_thread_id_get ();
3252 guint32 eventidx = 0;
3253 gboolean starting, finished;
3255 memset (wait, 0, sizeof (struct wait_data));
3257 * The other threads could be in an arbitrary state at this point, i.e.
3258 * they could be starting up, shutting down etc. This means that there could be
3259 * threads which are not even in the threads hash table yet.
3263 * First we set a barrier which will be checked by all threads before they
3264 * are added to the threads hash table, and they will exit if the flag is set.
3265 * This ensures that no threads could be added to the hash later.
3266 * We will use shutting_down as the barrier for now.
3268 g_assert (shutting_down);
3271 * We make multiple calls to WaitForMultipleObjects since:
3272 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3273 * - some threads could exit without becoming suspended
3278 * Make a copy of the hashtable since we can't do anything with
3279 * threads while threads_mutex is held.
3282 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3283 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3284 mono_threads_lock ();
3285 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3286 mono_threads_unlock ();
3289 /* Get the suspended events that we'll be waiting for */
3290 for (i = 0; i < wait->num; ++i) {
3291 MonoInternalThread *thread = wait->threads [i];
3293 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3294 || mono_gc_is_finalizer_internal_thread (thread)
3295 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3297 //mono_threads_close_thread_handle (wait->handles [i]);
3298 wait->threads [i] = NULL; /* ignore this thread in next loop */
3302 LOCK_THREAD (thread);
3304 if ((thread->state & ThreadState_Suspended) != 0 ||
3305 (thread->state & ThreadState_StopRequested) != 0 ||
3306 (thread->state & ThreadState_Stopped) != 0) {
3307 UNLOCK_THREAD (thread);
3308 mono_threads_close_thread_handle (wait->handles [i]);
3309 wait->threads [i] = NULL; /* ignore this thread in next loop */
3315 /* Convert abort requests into suspend requests */
3316 if ((thread->state & ThreadState_AbortRequested) != 0)
3317 thread->state &= ~ThreadState_AbortRequested;
3319 thread->state |= ThreadState_SuspendRequested;
3321 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3322 async_suspend_internal (thread, TRUE);
3324 if (eventidx <= 0) {
3326 * If there are threads which are starting up, we wait until they
3327 * are suspended when they try to register in the threads hash.
3328 * This is guaranteed to finish, since the threads which can create new
3329 * threads get suspended after a while.
3330 * FIXME: The finalizer thread can still create new threads.
3332 mono_threads_lock ();
3333 if (threads_starting_up)
3334 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3337 mono_threads_unlock ();
3339 mono_thread_info_sleep (100, NULL);
3347 MonoInternalThread *thread;
3348 MonoStackFrameInfo *frames;
3349 int nframes, max_frames;
3350 int nthreads, max_threads;
3351 MonoInternalThread **threads;
3352 } ThreadDumpUserData;
3354 static gboolean thread_dump_requested;
3356 /* This needs to be async safe */
3358 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3360 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3362 if (ud->nframes < ud->max_frames) {
3363 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3370 /* This needs to be async safe */
3371 static SuspendThreadResult
3372 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3374 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3375 MonoInternalThread *thread = user_data->thread;
3378 /* This no longer works with remote unwinding */
3379 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3380 mono_thread_internal_describe (thread, text);
3381 g_string_append (text, "\n");
3384 if (thread == mono_thread_internal_current ())
3385 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3387 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3389 return MonoResumeThread;
3393 int nthreads, max_threads;
3394 MonoInternalThread **threads;
3395 } CollectThreadsUserData;
3398 collect_thread (gpointer key, gpointer value, gpointer user)
3400 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3401 MonoInternalThread *thread = (MonoInternalThread *)value;
3403 if (ud->nthreads < ud->max_threads)
3404 ud->threads [ud->nthreads ++] = thread;
3408 * Collect running threads into the THREADS array.
3409 * THREADS should be an array allocated on the stack.
3412 collect_threads (MonoInternalThread **thread_array, int max_threads)
3414 CollectThreadsUserData ud;
3416 memset (&ud, 0, sizeof (ud));
3417 /* This array contains refs, but its on the stack, so its ok */
3418 ud.threads = thread_array;
3419 ud.max_threads = max_threads;
3421 mono_threads_lock ();
3422 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3423 mono_threads_unlock ();
3429 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3431 GString* text = g_string_new (0);
3433 GError *error = NULL;
3436 ud->thread = thread;
3439 /* Collect frames for the thread */
3440 if (thread == mono_thread_internal_current ()) {
3441 get_thread_dump (mono_thread_info_current (), ud);
3443 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3447 * Do all the non async-safe work outside of get_thread_dump.
3450 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3452 g_string_append_printf (text, "\n\"%s\"", name);
3455 else if (thread->threadpool_thread) {
3456 g_string_append (text, "\n\"<threadpool thread>\"");
3458 g_string_append (text, "\n\"<unnamed thread>\"");
3461 for (i = 0; i < ud->nframes; ++i) {
3462 MonoStackFrameInfo *frame = &ud->frames [i];
3463 MonoMethod *method = NULL;
3465 if (frame->type == FRAME_TYPE_MANAGED)
3466 method = mono_jit_info_get_method (frame->ji);
3469 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3470 g_string_append_printf (text, " %s\n", location);
3473 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3477 fprintf (stdout, "%s", text->str);
3479 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3480 OutputDebugStringA(text->str);
3483 g_string_free (text, TRUE);
3488 mono_threads_perform_thread_dump (void)
3490 ThreadDumpUserData ud;
3491 MonoInternalThread *thread_array [128];
3492 int tindex, nthreads;
3494 if (!thread_dump_requested)
3497 printf ("Full thread dump:\n");
3499 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3500 nthreads = collect_threads (thread_array, 128);
3502 memset (&ud, 0, sizeof (ud));
3503 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3504 ud.max_frames = 256;
3506 for (tindex = 0; tindex < nthreads; ++tindex)
3507 dump_thread (thread_array [tindex], &ud);
3511 thread_dump_requested = FALSE;
3514 /* Obtain the thread dump of all threads */
3516 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3519 ThreadDumpUserData ud;
3520 MonoInternalThread *thread_array [128];
3521 MonoDomain *domain = mono_domain_get ();
3522 MonoDebugSourceLocation *location;
3523 int tindex, nthreads;
3525 mono_error_init (error);
3527 *out_threads = NULL;
3528 *out_stack_frames = NULL;
3530 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3531 nthreads = collect_threads (thread_array, 128);
3533 memset (&ud, 0, sizeof (ud));
3534 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3535 ud.max_frames = 256;
3537 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3540 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3544 for (tindex = 0; tindex < nthreads; ++tindex) {
3545 MonoInternalThread *thread = thread_array [tindex];
3546 MonoArray *thread_frames;
3552 /* Collect frames for the thread */
3553 if (thread == mono_thread_internal_current ()) {
3554 get_thread_dump (mono_thread_info_current (), &ud);
3556 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3559 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3561 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3564 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3566 for (i = 0; i < ud.nframes; ++i) {
3567 MonoStackFrameInfo *frame = &ud.frames [i];
3568 MonoMethod *method = NULL;
3569 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3573 sf->native_offset = frame->native_offset;
3575 if (frame->type == FRAME_TYPE_MANAGED)
3576 method = mono_jit_info_get_method (frame->ji);
3579 sf->method_address = (gsize) frame->ji->code_start;
3581 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3584 MONO_OBJECT_SETREF (sf, method, rm);
3586 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3588 sf->il_offset = location->il_offset;
3590 if (location && location->source_file) {
3591 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3592 sf->line = location->row;
3593 sf->column = location->column;
3595 mono_debug_free_source_location (location);
3600 mono_array_setref (thread_frames, i, sf);
3606 return is_ok (error);
3610 * mono_threads_request_thread_dump:
3612 * Ask all threads except the current to print their stacktrace to stdout.
3615 mono_threads_request_thread_dump (void)
3617 /*The new thread dump code runs out of the finalizer thread. */
3618 thread_dump_requested = TRUE;
3619 mono_gc_finalize_notify ();
3624 gint allocated; /* +1 so that refs [allocated] == NULL */
3628 typedef struct ref_stack RefStack;
3631 ref_stack_new (gint initial_size)
3635 initial_size = MAX (initial_size, 16) + 1;
3636 rs = g_new0 (RefStack, 1);
3637 rs->refs = g_new0 (gpointer, initial_size);
3638 rs->allocated = initial_size;
3643 ref_stack_destroy (gpointer ptr)
3645 RefStack *rs = (RefStack *)ptr;
3654 ref_stack_push (RefStack *rs, gpointer ptr)
3656 g_assert (rs != NULL);
3658 if (rs->bottom >= rs->allocated) {
3659 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3660 rs->allocated <<= 1;
3661 rs->refs [rs->allocated] = NULL;
3663 rs->refs [rs->bottom++] = ptr;
3667 ref_stack_pop (RefStack *rs)
3669 if (rs == NULL || rs->bottom == 0)
3673 rs->refs [rs->bottom] = NULL;
3677 ref_stack_find (RefStack *rs, gpointer ptr)
3684 for (refs = rs->refs; refs && *refs; refs++) {
3692 * mono_thread_push_appdomain_ref:
3694 * Register that the current thread may have references to objects in domain
3695 * @domain on its stack. Each call to this function should be paired with a
3696 * call to pop_appdomain_ref.
3699 mono_thread_push_appdomain_ref (MonoDomain *domain)
3701 MonoInternalThread *thread = mono_thread_internal_current ();
3704 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3705 SPIN_LOCK (thread->lock_thread_id);
3706 if (thread->appdomain_refs == NULL)
3707 thread->appdomain_refs = ref_stack_new (16);
3708 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3709 SPIN_UNLOCK (thread->lock_thread_id);
3714 mono_thread_pop_appdomain_ref (void)
3716 MonoInternalThread *thread = mono_thread_internal_current ();
3719 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3720 SPIN_LOCK (thread->lock_thread_id);
3721 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3722 SPIN_UNLOCK (thread->lock_thread_id);
3727 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3730 SPIN_LOCK (thread->lock_thread_id);
3731 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3732 SPIN_UNLOCK (thread->lock_thread_id);
3737 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3739 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3742 typedef struct abort_appdomain_data {
3743 struct wait_data wait;
3745 } abort_appdomain_data;
3748 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3750 MonoInternalThread *thread = (MonoInternalThread*)value;
3751 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3752 MonoDomain *domain = data->domain;
3754 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3755 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3757 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3758 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3761 data->wait.handles [data->wait.num] = handle;
3762 data->wait.threads [data->wait.num] = thread;
3765 /* Just ignore the rest, we can't do anything with
3773 * mono_threads_abort_appdomain_threads:
3775 * Abort threads which has references to the given appdomain.
3778 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3780 #ifdef __native_client__
3784 abort_appdomain_data user_data;
3786 int orig_timeout = timeout;
3789 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3791 start_time = mono_msec_ticks ();
3793 mono_threads_lock ();
3795 user_data.domain = domain;
3796 user_data.wait.num = 0;
3797 /* This shouldn't take any locks */
3798 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3799 mono_threads_unlock ();
3801 if (user_data.wait.num > 0) {
3802 /* Abort the threads outside the threads lock */
3803 for (i = 0; i < user_data.wait.num; ++i)
3804 mono_thread_internal_abort (user_data.wait.threads [i]);
3807 * We should wait for the threads either to abort, or to leave the
3808 * domain. We can't do the latter, so we wait with a timeout.
3810 wait_for_tids (&user_data.wait, 100);
3813 /* Update remaining time */
3814 timeout -= mono_msec_ticks () - start_time;
3815 start_time = mono_msec_ticks ();
3817 if (orig_timeout != -1 && timeout < 0)
3820 while (user_data.wait.num > 0);
3822 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3828 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3830 MonoInternalThread *thread = (MonoInternalThread*)value;
3831 MonoDomain *domain = (MonoDomain*)user_data;
3834 /* No locking needed here */
3835 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3837 if (thread->cached_culture_info) {
3838 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3839 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3840 if (obj && obj->vtable->domain == domain)
3841 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3847 * mono_threads_clear_cached_culture:
3849 * Clear the cached_current_culture from all threads if it is in the
3853 mono_threads_clear_cached_culture (MonoDomain *domain)
3855 mono_threads_lock ();
3856 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3857 mono_threads_unlock ();
3861 * mono_thread_get_undeniable_exception:
3863 * Return an exception which needs to be raised when leaving a catch clause.
3864 * This is used for undeniable exception propagation.
3867 mono_thread_get_undeniable_exception (void)
3869 MonoInternalThread *thread = mono_thread_internal_current ();
3871 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3873 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3874 * exception if the thread no longer references a dying appdomain.
3876 thread->abort_exc->trace_ips = NULL;
3877 thread->abort_exc->stack_trace = NULL;
3878 return thread->abort_exc;
3884 #if MONO_SMALL_CONFIG
3885 #define NUM_STATIC_DATA_IDX 4
3886 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3890 #define NUM_STATIC_DATA_IDX 8
3891 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3892 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3896 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3897 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3900 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3902 gpointer *static_data = (gpointer *)addr;
3904 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3905 void **ptr = (void **)static_data [i];
3910 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3911 void **p = ptr + idx;
3914 mark_func ((MonoObject**)p, gc_data);
3920 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3922 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3926 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3928 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3932 * mono_alloc_static_data
3934 * Allocate memory blocks for storing threads or context static data
3937 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3939 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3942 gpointer* static_data = *static_data_ptr;
3944 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3945 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3947 if (mono_gc_user_markers_supported ()) {
3948 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3949 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3951 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3952 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3955 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3956 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3957 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3958 *static_data_ptr = static_data;
3959 static_data [0] = static_data;
3962 for (i = 1; i <= idx; ++i) {
3963 if (static_data [i])
3966 if (mono_gc_user_markers_supported ())
3967 static_data [i] = g_malloc0 (static_data_size [i]);
3969 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3970 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3971 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3976 mono_free_static_data (gpointer* static_data)
3979 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3980 gpointer p = static_data [i];
3984 * At this point, the static data pointer array is still registered with the
3985 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3986 * data. Freeing the individual arrays without first nulling their slots
3987 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3988 * such an already freed array. See bug #13813.
3990 static_data [i] = NULL;
3991 mono_memory_write_barrier ();
3992 if (mono_gc_user_markers_supported ())
3995 mono_gc_free_fixed (p);
3997 mono_gc_free_fixed (static_data);
4001 * mono_init_static_data_info
4003 * Initializes static data counters
4005 static void mono_init_static_data_info (StaticDataInfo *static_data)
4007 static_data->idx = 0;
4008 static_data->offset = 0;
4009 static_data->freelist = NULL;
4013 * mono_alloc_static_data_slot
4015 * Generates an offset for static data. static_data contains the counters
4016 * used to generate it.
4019 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4021 if (!static_data->idx && !static_data->offset) {
4023 * we use the first chunk of the first allocation also as
4024 * an array for the rest of the data
4026 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4028 static_data->offset += align - 1;
4029 static_data->offset &= ~(align - 1);
4030 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4031 static_data->idx ++;
4032 g_assert (size <= static_data_size [static_data->idx]);
4033 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4034 static_data->offset = 0;
4036 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4037 static_data->offset += size;
4042 * LOCKING: requires that threads_mutex is held
4045 context_adjust_static_data (MonoAppContext *ctx)
4047 if (context_static_info.offset || context_static_info.idx > 0) {
4048 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4049 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4050 ctx->data->static_data = ctx->static_data;
4055 * LOCKING: requires that threads_mutex is held
4058 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4060 MonoInternalThread *thread = (MonoInternalThread *)value;
4061 guint32 offset = GPOINTER_TO_UINT (user);
4063 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4067 * LOCKING: requires that threads_mutex is held
4070 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4072 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4077 guint32 offset = GPOINTER_TO_UINT (user);
4078 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4079 ctx->data->static_data = ctx->static_data;
4082 static StaticDataFreeList*
4083 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4085 StaticDataFreeList* prev = NULL;
4086 StaticDataFreeList* tmp = static_data->freelist;
4088 if (tmp->size == size) {
4090 prev->next = tmp->next;
4092 static_data->freelist = tmp->next;
4101 #if SIZEOF_VOID_P == 4
4108 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4110 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4112 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4113 MonoBitSet *rb = sets [idx];
4114 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4115 offset /= sizeof (uintptr_t);
4116 /* offset is now the bitmap offset */
4117 for (int i = 0; i < numbits; ++i) {
4118 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4119 mono_bitset_set_fast (rb, offset + i);
4124 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4126 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4127 MonoBitSet *rb = sets [idx];
4128 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4129 offset /= sizeof (uintptr_t);
4130 /* offset is now the bitmap offset */
4131 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4132 mono_bitset_clear_fast (rb, offset + i);
4136 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4138 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4140 StaticDataInfo *info;
4143 if (static_type == SPECIAL_STATIC_THREAD) {
4144 info = &thread_static_info;
4145 sets = thread_reference_bitmaps;
4147 info = &context_static_info;
4148 sets = context_reference_bitmaps;
4151 mono_threads_lock ();
4153 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4157 offset = item->offset;
4160 offset = mono_alloc_static_data_slot (info, size, align);
4163 update_reference_bitmap (sets, offset, bitmap, numbits);
4165 if (static_type == SPECIAL_STATIC_THREAD) {
4166 /* This can be called during startup */
4167 if (threads != NULL)
4168 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4170 if (contexts != NULL)
4171 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4173 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4176 mono_threads_unlock ();
4182 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4184 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4186 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4187 return get_thread_static_data (thread, offset);
4189 return get_context_static_data (thread->current_appcontext, offset);
4194 mono_get_special_static_data (guint32 offset)
4196 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4205 * LOCKING: requires that threads_mutex is held
4208 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4210 MonoInternalThread *thread = (MonoInternalThread *)value;
4211 OffsetSize *data = (OffsetSize *)user;
4212 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4213 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4216 if (!thread->static_data || !thread->static_data [idx])
4218 ptr = ((char*) thread->static_data [idx]) + off;
4219 mono_gc_bzero_atomic (ptr, data->size);
4223 * LOCKING: requires that threads_mutex is held
4226 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4228 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4233 OffsetSize *data = (OffsetSize *)user;
4234 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4235 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4238 if (!ctx->static_data || !ctx->static_data [idx])
4241 ptr = ((char*) ctx->static_data [idx]) + off;
4242 mono_gc_bzero_atomic (ptr, data->size);
4246 do_free_special_slot (guint32 offset, guint32 size)
4248 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4250 StaticDataInfo *info;
4252 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4253 info = &thread_static_info;
4254 sets = thread_reference_bitmaps;
4256 info = &context_static_info;
4257 sets = context_reference_bitmaps;
4260 guint32 data_offset = offset;
4261 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4262 OffsetSize data = { data_offset, size };
4264 clear_reference_bitmap (sets, data.offset, data.size);
4266 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4267 if (threads != NULL)
4268 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4270 if (contexts != NULL)
4271 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4274 if (!mono_runtime_is_shutting_down ()) {
4275 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4277 item->offset = offset;
4280 item->next = info->freelist;
4281 info->freelist = item;
4286 do_free_special (gpointer key, gpointer value, gpointer data)
4288 MonoClassField *field = (MonoClassField *)key;
4289 guint32 offset = GPOINTER_TO_UINT (value);
4292 size = mono_type_size (field->type, &align);
4293 do_free_special_slot (offset, size);
4297 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4299 mono_threads_lock ();
4301 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4303 mono_threads_unlock ();
4307 static void CALLBACK dummy_apc (ULONG_PTR param)
4313 * mono_thread_execute_interruption
4315 * Performs the operation that the requested thread state requires (abort,
4318 static MonoException*
4319 mono_thread_execute_interruption (void)
4321 MonoInternalThread *thread = mono_thread_internal_current ();
4322 MonoThread *sys_thread = mono_thread_current ();
4324 LOCK_THREAD (thread);
4326 /* MonoThread::interruption_requested can only be changed with atomics */
4327 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4328 /* this will consume pending APC calls */
4330 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4332 InterlockedDecrement (&thread_interruption_requested);
4334 /* Clear the interrupted flag of the thread so it can wait again */
4335 mono_thread_info_clear_self_interrupt ();
4338 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4339 if (sys_thread->pending_exception) {
4342 exc = sys_thread->pending_exception;
4343 sys_thread->pending_exception = NULL;
4345 UNLOCK_THREAD (thread);
4347 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4348 UNLOCK_THREAD (thread);
4349 g_assert (sys_thread->pending_exception == NULL);
4350 if (thread->abort_exc == NULL) {
4352 * This might be racy, but it has to be called outside the lock
4353 * since it calls managed code.
4355 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4357 return thread->abort_exc;
4359 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4360 /* calls UNLOCK_THREAD (thread) */
4361 self_suspend_internal ();
4364 else if ((thread->state & ThreadState_StopRequested) != 0) {
4365 /* FIXME: do this through the JIT? */
4367 UNLOCK_THREAD (thread);
4369 mono_thread_exit ();
4371 } else if (thread->thread_interrupt_requested) {
4373 thread->thread_interrupt_requested = FALSE;
4374 UNLOCK_THREAD (thread);
4376 return(mono_get_exception_thread_interrupted ());
4379 UNLOCK_THREAD (thread);
4385 * mono_thread_request_interruption
4387 * A signal handler can call this method to request the interruption of a
4388 * thread. The result of the interruption will depend on the current state of
4389 * the thread. If the result is an exception that needs to be throw, it is
4390 * provided as return value.
4393 mono_thread_request_interruption (gboolean running_managed)
4395 MonoInternalThread *thread = mono_thread_internal_current ();
4397 /* The thread may already be stopping */
4402 if (thread->interrupt_on_stop &&
4403 thread->state & ThreadState_StopRequested &&
4404 thread->state & ThreadState_Background)
4407 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4409 InterlockedIncrement (&thread_interruption_requested);
4411 if (!running_managed || is_running_protected_wrapper ()) {
4412 /* Can't stop while in unmanaged code. Increase the global interruption
4413 request count. When exiting the unmanaged method the count will be
4414 checked and the thread will be interrupted. */
4416 /* this will awake the thread if it is in WaitForSingleObject
4418 /* Our implementation of this function ignores the func argument */
4420 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4422 mono_thread_info_self_interrupt ();
4427 return mono_thread_execute_interruption ();
4431 /*This function should be called by a thread after it has exited all of
4432 * its handle blocks at interruption time.*/
4434 mono_thread_resume_interruption (void)
4436 MonoInternalThread *thread = mono_thread_internal_current ();
4437 gboolean still_aborting;
4439 /* The thread may already be stopping */
4443 LOCK_THREAD (thread);
4444 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4445 UNLOCK_THREAD (thread);
4447 /*This can happen if the protected block called Thread::ResetAbort*/
4448 if (!still_aborting)
4451 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4453 InterlockedIncrement (&thread_interruption_requested);
4455 mono_thread_info_self_interrupt ();
4457 return mono_thread_execute_interruption ();
4460 gboolean mono_thread_interruption_requested ()
4462 if (thread_interruption_requested) {
4463 MonoInternalThread *thread = mono_thread_internal_current ();
4464 /* The thread may already be stopping */
4466 return (thread->interruption_requested);
4471 static MonoException*
4472 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4474 MonoInternalThread *thread = mono_thread_internal_current ();
4476 /* The thread may already be stopping */
4480 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4481 MonoException* exc = mono_thread_execute_interruption ();
4489 * Performs the interruption of the current thread, if one has been requested,
4490 * and the thread is not running a protected wrapper.
4491 * Return the exception which needs to be thrown, if any.
4494 mono_thread_interruption_checkpoint (void)
4496 return mono_thread_interruption_checkpoint_request (FALSE);
4500 * Performs the interruption of the current thread, if one has been requested.
4501 * Return the exception which needs to be thrown, if any.
4504 mono_thread_force_interruption_checkpoint_noraise (void)
4506 return mono_thread_interruption_checkpoint_request (TRUE);
4510 * mono_set_pending_exception:
4512 * Set the pending exception of the current thread to EXC.
4513 * The exception will be thrown when execution returns to managed code.
4516 mono_set_pending_exception (MonoException *exc)
4518 MonoThread *thread = mono_thread_current ();
4520 /* The thread may already be stopping */
4524 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4526 mono_thread_request_interruption (FALSE);
4530 * mono_thread_interruption_request_flag:
4532 * Returns the address of a flag that will be non-zero if an interruption has
4533 * been requested for a thread. The thread to interrupt may not be the current
4534 * thread, so an additional call to mono_thread_interruption_requested() or
4535 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4538 gint32* mono_thread_interruption_request_flag ()
4540 return &thread_interruption_requested;
4544 mono_thread_init_apartment_state (void)
4547 MonoInternalThread* thread = mono_thread_internal_current ();
4549 /* Positive return value indicates success, either
4550 * S_OK if this is first CoInitialize call, or
4551 * S_FALSE if CoInitialize already called, but with same
4552 * threading model. A negative value indicates failure,
4553 * probably due to trying to change the threading model.
4555 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4556 ? COINIT_APARTMENTTHREADED
4557 : COINIT_MULTITHREADED) < 0) {
4558 thread->apartment_state = ThreadApartmentState_Unknown;
4564 mono_thread_cleanup_apartment_state (void)
4567 MonoInternalThread* thread = mono_thread_internal_current ();
4569 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4576 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4578 LOCK_THREAD (thread);
4579 thread->state |= state;
4580 UNLOCK_THREAD (thread);
4584 * mono_thread_test_and_set_state:
4586 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4588 * Returns TRUE is @set was OR'd in.
4591 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4593 LOCK_THREAD (thread);
4595 if ((thread->state & test) != 0) {
4596 UNLOCK_THREAD (thread);
4600 thread->state |= set;
4601 UNLOCK_THREAD (thread);
4607 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4609 LOCK_THREAD (thread);
4610 thread->state &= ~state;
4611 UNLOCK_THREAD (thread);
4615 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4617 gboolean ret = FALSE;
4619 LOCK_THREAD (thread);
4621 if ((thread->state & test) != 0) {
4625 UNLOCK_THREAD (thread);
4630 static gboolean has_tls_get = FALSE;
4633 mono_runtime_set_has_tls_get (gboolean val)
4639 mono_runtime_has_tls_get (void)
4645 self_interrupt_thread (void *_unused)
4647 MonoThreadInfo *info = mono_thread_info_current ();
4648 MonoException *exc = mono_thread_execute_interruption ();
4649 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4650 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. */
4651 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4655 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4659 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4663 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4665 MonoJitInfo **dest = (MonoJitInfo **)data;
4671 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4673 MonoJitInfo *ji = NULL;
4678 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4679 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4680 * where we hold runtime locks.
4682 if (!mono_threads_is_coop_enabled ())
4683 mono_thread_info_set_is_async_context (TRUE);
4684 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4685 if (!mono_threads_is_coop_enabled ())
4686 mono_thread_info_set_is_async_context (FALSE);
4691 MonoInternalThread *thread;
4692 gboolean install_async_abort;
4693 MonoThreadInfoInterruptToken *interrupt_token;
4696 static SuspendThreadResult
4697 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4699 AbortThreadData *data = (AbortThreadData *)ud;
4700 MonoInternalThread *thread = data->thread;
4701 MonoJitInfo *ji = NULL;
4702 gboolean protected_wrapper;
4703 gboolean running_managed;
4705 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4706 return MonoResumeThread;
4709 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4710 The protected block code will give them a chance when appropriate.
4712 if (thread->abort_protected_block_count)
4713 return MonoResumeThread;
4715 /*someone is already interrupting it*/
4716 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4717 return MonoResumeThread;
4719 InterlockedIncrement (&thread_interruption_requested);
4721 ji = mono_thread_info_get_last_managed (info);
4722 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4723 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4725 if (!protected_wrapper && running_managed) {
4726 /*We are in managed code*/
4727 /*Set the thread to call */
4728 if (data->install_async_abort)
4729 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4730 return MonoResumeThread;
4733 * This will cause waits to be broken.
4734 * It will also prevent the thread from entering a wait, so if the thread returns
4735 * from the wait before it receives the abort signal, it will just spin in the wait
4736 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4739 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4741 return MonoResumeThread;
4746 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4748 AbortThreadData data;
4750 g_assert (thread != mono_thread_internal_current ());
4752 data.thread = thread;
4753 data.install_async_abort = install_async_abort;
4754 data.interrupt_token = NULL;
4756 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4757 if (data.interrupt_token)
4758 mono_thread_info_finish_interrupt (data.interrupt_token);
4759 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4763 self_abort_internal (MonoError *error)
4767 mono_error_init (error);
4769 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4770 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4773 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.
4775 exc = mono_thread_request_interruption (TRUE);
4777 mono_error_set_exception_instance (error, exc);
4779 mono_thread_info_self_interrupt ();
4783 MonoInternalThread *thread;
4785 MonoThreadInfoInterruptToken *interrupt_token;
4786 } SuspendThreadData;
4788 static SuspendThreadResult
4789 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4791 SuspendThreadData *data = (SuspendThreadData *)ud;
4792 MonoInternalThread *thread = data->thread;
4793 MonoJitInfo *ji = NULL;
4794 gboolean protected_wrapper;
4795 gboolean running_managed;
4797 ji = mono_thread_info_get_last_managed (info);
4798 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4799 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4801 if (running_managed && !protected_wrapper) {
4802 thread->state &= ~ThreadState_SuspendRequested;
4803 thread->state |= ThreadState_Suspended;
4804 return KeepSuspended;
4806 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4807 InterlockedIncrement (&thread_interruption_requested);
4808 if (data->interrupt)
4809 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4811 return MonoResumeThread;
4815 /* LOCKING: called with @thread synch_cs held, and releases it */
4817 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4819 SuspendThreadData data;
4821 g_assert (thread != mono_thread_internal_current ());
4823 data.thread = thread;
4824 data.interrupt = interrupt;
4825 data.interrupt_token = NULL;
4827 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4828 if (data.interrupt_token)
4829 mono_thread_info_finish_interrupt (data.interrupt_token);
4831 UNLOCK_THREAD (thread);
4834 /* LOCKING: called with @thread synch_cs held, and releases it */
4836 self_suspend_internal (void)
4838 MonoInternalThread *thread;
4840 thread = mono_thread_internal_current ();
4842 mono_thread_info_begin_self_suspend ();
4843 thread->state &= ~ThreadState_SuspendRequested;
4844 thread->state |= ThreadState_Suspended;
4846 UNLOCK_THREAD (thread);
4848 mono_thread_info_end_self_suspend ();
4852 * mono_thread_is_foreign:
4853 * @thread: the thread to query
4855 * This function allows one to determine if a thread was created by the mono runtime and has
4856 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4858 * Returns: TRUE if @thread was not created by the runtime.
4861 mono_thread_is_foreign (MonoThread *thread)
4863 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4864 return info->runtime_thread == FALSE;
4868 * mono_add_joinable_thread:
4870 * Add TID to the list of joinable threads.
4871 * LOCKING: Acquires the threads lock.
4874 mono_threads_add_joinable_thread (gpointer tid)
4878 * We cannot detach from threads because it causes problems like
4879 * 2fd16f60/r114307. So we collect them and join them when
4880 * we have time (in he finalizer thread).
4882 joinable_threads_lock ();
4883 if (!joinable_threads)
4884 joinable_threads = g_hash_table_new (NULL, NULL);
4885 g_hash_table_insert (joinable_threads, tid, tid);
4886 joinable_thread_count ++;
4887 joinable_threads_unlock ();
4889 mono_gc_finalize_notify ();
4894 * mono_threads_join_threads:
4896 * Join all joinable threads. This is called from the finalizer thread.
4897 * LOCKING: Acquires the threads lock.
4900 mono_threads_join_threads (void)
4903 GHashTableIter iter;
4910 if (!joinable_thread_count)
4914 joinable_threads_lock ();
4916 if (g_hash_table_size (joinable_threads)) {
4917 g_hash_table_iter_init (&iter, joinable_threads);
4918 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4919 thread = (pthread_t)tid;
4920 g_hash_table_remove (joinable_threads, key);
4921 joinable_thread_count --;
4924 joinable_threads_unlock ();
4926 if (thread != pthread_self ()) {
4928 /* This shouldn't block */
4929 mono_native_thread_join (thread);
4942 * Wait for thread TID to exit.
4943 * LOCKING: Acquires the threads lock.
4946 mono_thread_join (gpointer tid)
4950 gboolean found = FALSE;
4952 joinable_threads_lock ();
4953 if (!joinable_threads)
4954 joinable_threads = g_hash_table_new (NULL, NULL);
4955 if (g_hash_table_lookup (joinable_threads, tid)) {
4956 g_hash_table_remove (joinable_threads, tid);
4957 joinable_thread_count --;
4960 joinable_threads_unlock ();
4963 thread = (pthread_t)tid;
4965 mono_native_thread_join (thread);
4971 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4973 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4974 mono_thread_interruption_checkpoint ();
4978 mono_thread_internal_unhandled_exception (MonoObject* exc)
4980 MonoClass *klass = exc->vtable->klass;
4981 if (is_threadabort_exception (klass)) {
4982 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4983 } else if (!is_appdomainunloaded_exception (klass)
4984 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4985 mono_unhandled_exception (exc);
4986 if (mono_environment_exitcode_get () == 1) {
4987 mono_environment_exitcode_set (255);
4988 mono_invoke_unhandled_exception_hook (exc);
4989 g_assert_not_reached ();
4995 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
4998 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
4999 mono_error_set_pending_exception (&error);
5003 * mono_threads_attach_coop: called by native->managed wrappers
5007 * - @return: the original domain which needs to be restored, or NULL.
5010 * - @dummy: contains the original domain
5011 * - @return: a cookie containing current MonoThreadInfo*.
5014 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5017 gboolean fresh_thread = FALSE;
5020 /* Happens when called from AOTed code which is only used in the root domain. */
5021 domain = mono_get_root_domain ();
5026 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5027 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5028 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5029 * we're only responsible for making the cookie. */
5030 if (mono_threads_is_coop_enabled ()) {
5031 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5032 fresh_thread = !info || !mono_thread_info_is_live (info);
5035 if (!mono_thread_internal_current ()) {
5036 mono_thread_attach_full (domain, FALSE);
5039 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5042 orig = mono_domain_get ();
5044 mono_domain_set (domain, TRUE);
5046 if (!mono_threads_is_coop_enabled ())
5047 return orig != domain ? orig : NULL;
5051 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5052 * return the right cookie. */
5053 return mono_threads_enter_gc_unsafe_region_cookie ();
5056 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5057 return mono_threads_enter_gc_unsafe_region (dummy);
5062 * mono_threads_detach_coop: called by native->managed wrappers
5065 * - @cookie: the original domain which needs to be restored, or NULL.
5069 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5070 * - @dummy: contains the original domain
5073 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5075 MonoDomain *domain, *orig;
5077 if (!mono_threads_is_coop_enabled ()) {
5078 orig = (MonoDomain*) cookie;
5080 mono_domain_set (orig, TRUE);
5082 orig = (MonoDomain*) *dummy;
5084 domain = mono_domain_get ();
5087 /* it won't do anything if cookie is NULL
5088 * thread state RUNNING -> (RUNNING|BLOCKING) */
5089 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5091 if (orig != domain) {
5093 mono_domain_unset ();
5095 mono_domain_set (orig, TRUE);
5101 mono_threads_begin_abort_protected_block (void)
5103 MonoInternalThread *thread;
5105 thread = mono_thread_internal_current ();
5106 ++thread->abort_protected_block_count;
5107 mono_memory_barrier ();
5111 mono_threads_end_abort_protected_block (void)
5113 MonoInternalThread *thread;
5115 thread = mono_thread_internal_current ();
5117 mono_memory_barrier ();
5118 --thread->abort_protected_block_count;
5122 mono_thread_try_resume_interruption (void)
5124 MonoInternalThread *thread;
5126 thread = mono_thread_internal_current ();
5127 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5130 return mono_thread_resume_interruption ();
5134 /* Returns TRUE if the current thread is ready to be interrupted. */
5136 mono_threads_is_ready_to_be_interrupted (void)
5138 MonoInternalThread *thread;
5140 thread = mono_thread_internal_current ();
5141 LOCK_THREAD (thread);
5142 if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5143 UNLOCK_THREAD (thread);
5147 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5148 UNLOCK_THREAD (thread);
5152 UNLOCK_THREAD (thread);
5158 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5160 g_string_append_printf (text, ", thread handle : %p", internal->handle);
5162 if (internal->thread_info) {
5163 g_string_append (text, ", state : ");
5164 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5167 if (internal->owned_mutexes) {
5170 g_string_append (text, ", owns : [");
5171 for (i = 0; i < internal->owned_mutexes->len; i++)
5172 g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5173 g_string_append (text, "]");
5178 mono_thread_internal_is_current (MonoInternalThread *internal)
5180 g_assert (internal);
5181 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));