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;
915 g_assert (!start_func && !start_func_arg);
917 g_assert (!start_delegate);
920 * Join joinable threads to prevent running out of threads since the finalizer
921 * thread might be blocked/backlogged.
923 mono_threads_join_threads ();
925 mono_error_init (error);
927 mono_threads_lock ();
929 mono_threads_unlock ();
932 if (threads_starting_up == NULL) {
933 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
934 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
936 mono_g_hash_table_insert (threads_starting_up, thread, thread);
937 mono_threads_unlock ();
939 internal->threadpool_thread = threadpool_thread;
940 if (threadpool_thread)
941 mono_thread_set_state (internal, ThreadState_Background);
943 start_info = g_new0 (StartInfo, 1);
945 start_info->thread = thread;
946 start_info->start_delegate = start_delegate;
947 start_info->start_delegate_arg = thread->start_obj;
948 start_info->start_func = start_func;
949 start_info->start_func_arg = start_func_arg;
950 start_info->failed = FALSE;
951 mono_coop_sem_init (&start_info->registered, 0);
954 stack_size = default_stacksize_for_thread (internal);
956 thread_handle = mono_threads_create_thread (start_wrapper, start_info, stack_size, &tid);
958 if (thread_handle == NULL) {
959 /* The thread couldn't be created, so set an exception */
960 mono_threads_lock ();
961 mono_g_hash_table_remove (threads_starting_up, thread);
962 mono_threads_unlock ();
963 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
964 /* ref is not going to be decremented in start_wrapper_internal */
965 InterlockedDecrement (&start_info->ref);
970 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
973 * Wait for the thread to set up its TLS data etc, so
974 * theres no potential race condition if someone tries
975 * to look up the data believing the thread has
979 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
981 mono_threads_close_thread_handle (thread_handle);
983 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));
985 ret = !start_info->failed;
988 if (InterlockedDecrement (&start_info->ref) == 0) {
989 mono_coop_sem_destroy (&start_info->registered);
996 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
998 if (mono_thread_start_cb) {
999 mono_thread_start_cb (tid, stack_start, func);
1003 void mono_threads_set_default_stacksize (guint32 stacksize)
1005 default_stacksize = stacksize;
1008 guint32 mono_threads_get_default_stacksize (void)
1010 return default_stacksize;
1014 * mono_thread_create_internal:
1016 * ARG should not be a GC reference.
1019 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
1022 MonoInternalThread *internal;
1025 mono_error_init (error);
1027 thread = create_thread_object (domain);
1029 internal = create_internal_thread ();
1031 MONO_OBJECT_SETREF (thread, internal_thread, internal);
1033 LOCK_THREAD (internal);
1035 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
1036 return_val_if_nok (error, NULL);
1038 UNLOCK_THREAD (internal);
1044 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1047 if (!mono_thread_create_checked (domain, func, arg, &error))
1048 mono_error_cleanup (&error);
1052 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1054 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
1058 mono_thread_attach (MonoDomain *domain)
1060 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1066 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1068 MonoInternalThread *internal;
1070 MonoNativeThreadId tid;
1073 if (mono_thread_internal_current_is_attached ()) {
1074 if (domain != mono_domain_get ())
1075 mono_domain_set (domain, TRUE);
1076 /* Already attached */
1077 return mono_thread_current ();
1080 if (!mono_gc_register_thread (&domain)) {
1081 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 ());
1084 tid=mono_native_thread_id_get ();
1086 internal = create_internal_thread ();
1088 thread = new_thread_with_internal (domain, internal);
1090 if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
1091 /* Mono is shutting down, so just wait for the end */
1093 mono_thread_info_sleep (10000, NULL);
1096 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1098 if (mono_thread_attach_cb) {
1102 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1105 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1107 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1110 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1111 if (!mono_thread_info_current ()->tools_thread)
1112 // FIXME: Need a separate callback
1113 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1119 mono_thread_detach_internal (MonoInternalThread *thread)
1121 g_return_if_fail (thread != NULL);
1123 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1126 mono_w32mutex_abandon ();
1129 thread_cleanup (thread);
1131 SET_CURRENT_OBJECT (NULL);
1132 mono_domain_unset ();
1134 /* Don't need to close the handle to this thread, even though we took a
1135 * reference in mono_thread_attach (), because the GC will do it
1136 * when the Thread object is finalised.
1141 mono_thread_detach (MonoThread *thread)
1144 mono_thread_detach_internal (thread->internal_thread);
1148 * mono_thread_detach_if_exiting:
1150 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1151 * This should be used at the end of embedding code which calls into managed code, and which
1152 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1155 mono_thread_detach_if_exiting (void)
1157 if (mono_thread_info_is_exiting ()) {
1158 MonoInternalThread *thread;
1160 thread = mono_thread_internal_current ();
1162 mono_thread_detach_internal (thread);
1163 mono_thread_info_detach ();
1171 mono_thread_internal_current_is_attached (void)
1173 MonoInternalThread *internal;
1175 internal = GET_CURRENT_OBJECT ();
1183 mono_thread_exit (void)
1185 MonoInternalThread *thread = mono_thread_internal_current ();
1187 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1189 mono_thread_detach_internal (thread);
1191 /* we could add a callback here for embedders to use. */
1192 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1193 exit (mono_environment_exitcode_get ());
1195 mono_thread_info_exit ();
1199 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1201 MonoInternalThread *internal;
1203 internal = create_internal_thread ();
1205 internal->state = ThreadState_Unstarted;
1207 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1211 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1215 MonoInternalThread *internal;
1218 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1220 if (!this_obj->internal_thread)
1221 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1222 internal = this_obj->internal_thread;
1224 LOCK_THREAD (internal);
1226 if ((internal->state & ThreadState_Unstarted) == 0) {
1227 UNLOCK_THREAD (internal);
1228 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1232 if ((internal->state & ThreadState_Aborted) != 0) {
1233 UNLOCK_THREAD (internal);
1237 res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1239 mono_error_cleanup (&error);
1240 UNLOCK_THREAD (internal);
1244 internal->state &= ~ThreadState_Unstarted;
1246 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1248 UNLOCK_THREAD (internal);
1249 return internal->handle;
1253 * This is called from the finalizer of the internal thread object.
1256 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1258 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1261 * Since threads keep a reference to their thread object while running, by the time this function is called,
1262 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1263 * when thread_cleanup () can be called after this.
1266 mono_threads_close_thread_handle (thread);
1268 if (this_obj->synch_cs) {
1269 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1270 this_obj->synch_cs = NULL;
1271 mono_coop_mutex_destroy (synch_cs);
1275 if (this_obj->name) {
1276 void *name = this_obj->name;
1277 this_obj->name = NULL;
1283 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1286 MonoInternalThread *thread = mono_thread_internal_current ();
1288 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1290 if (mono_thread_current_check_pending_interrupt ())
1294 gboolean alerted = FALSE;
1296 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1298 res = mono_thread_info_sleep (ms, &alerted);
1300 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1303 MonoException* exc = mono_thread_execute_interruption ();
1305 mono_raise_exception (exc);
1317 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1322 ves_icall_System_Threading_Thread_GetDomainID (void)
1324 return mono_domain_get()->domain_id;
1328 ves_icall_System_Threading_Thread_Yield (void)
1330 return mono_thread_info_yield ();
1334 * mono_thread_get_name:
1336 * Return the name of the thread. NAME_LEN is set to the length of the name.
1337 * Return NULL if the thread has no name. The returned memory is owned by the
1341 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1345 LOCK_THREAD (this_obj);
1347 if (!this_obj->name) {
1351 *name_len = this_obj->name_len;
1352 res = g_new (gunichar2, this_obj->name_len);
1353 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1356 UNLOCK_THREAD (this_obj);
1362 * mono_thread_get_name_utf8:
1364 * Return the name of the thread in UTF-8.
1365 * Return NULL if the thread has no name.
1366 * The returned memory is owned by the caller.
1369 mono_thread_get_name_utf8 (MonoThread *thread)
1374 MonoInternalThread *internal = thread->internal_thread;
1375 if (internal == NULL)
1378 LOCK_THREAD (internal);
1380 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1382 UNLOCK_THREAD (internal);
1388 * mono_thread_get_managed_id:
1390 * Return the Thread.ManagedThreadId value of `thread`.
1391 * Returns -1 if `thread` is NULL.
1394 mono_thread_get_managed_id (MonoThread *thread)
1399 MonoInternalThread *internal = thread->internal_thread;
1400 if (internal == NULL)
1403 int32_t id = internal->managed_id;
1409 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1414 mono_error_init (&error);
1416 LOCK_THREAD (this_obj);
1418 if (!this_obj->name)
1421 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1423 UNLOCK_THREAD (this_obj);
1425 if (mono_error_set_pending_exception (&error))
1432 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1434 LOCK_THREAD (this_obj);
1436 mono_error_init (error);
1438 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1439 UNLOCK_THREAD (this_obj);
1441 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1444 if (this_obj->name) {
1445 g_free (this_obj->name);
1446 this_obj->name_len = 0;
1449 this_obj->name = g_new (gunichar2, mono_string_length (name));
1450 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1451 this_obj->name_len = mono_string_length (name);
1454 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1457 this_obj->name = NULL;
1460 UNLOCK_THREAD (this_obj);
1462 if (this_obj->name && this_obj->tid) {
1463 char *tname = mono_string_to_utf8_checked (name, error);
1464 return_if_nok (error);
1465 mono_profiler_thread_name (this_obj->tid, tname);
1466 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1472 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1475 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1476 mono_error_set_pending_exception (&error);
1480 * ves_icall_System_Threading_Thread_GetPriority_internal:
1481 * @param this_obj: The MonoInternalThread on which to operate.
1483 * Gets the priority of the given thread.
1484 * @return: The priority of the given thread.
1487 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1490 MonoInternalThread *internal = this_obj->internal_thread;
1492 LOCK_THREAD (internal);
1493 priority = internal->priority;
1494 UNLOCK_THREAD (internal);
1500 * ves_icall_System_Threading_Thread_SetPriority_internal:
1501 * @param this_obj: The MonoInternalThread on which to operate.
1502 * @param priority: The priority to set.
1504 * Sets the priority of the given thread.
1507 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1509 MonoInternalThread *internal = this_obj->internal_thread;
1511 LOCK_THREAD (internal);
1512 internal->priority = priority;
1513 if (internal->handle != NULL)
1514 mono_thread_internal_set_priority (internal, priority);
1515 UNLOCK_THREAD (internal);
1518 /* If the array is already in the requested domain, we just return it,
1519 otherwise we return a copy in that domain. */
1521 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1525 mono_error_init (error);
1529 if (mono_object_domain (arr) == domain)
1532 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1533 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1538 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1541 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1542 mono_error_set_pending_exception (&error);
1547 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1550 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1551 mono_error_set_pending_exception (&error);
1556 mono_thread_current (void)
1558 MonoDomain *domain = mono_domain_get ();
1559 MonoInternalThread *internal = mono_thread_internal_current ();
1560 MonoThread **current_thread_ptr;
1562 g_assert (internal);
1563 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1565 if (!*current_thread_ptr) {
1566 g_assert (domain != mono_get_root_domain ());
1567 *current_thread_ptr = new_thread_with_internal (domain, internal);
1569 return *current_thread_ptr;
1572 /* Return the thread object belonging to INTERNAL in the current domain */
1574 mono_thread_current_for_thread (MonoInternalThread *internal)
1576 MonoDomain *domain = mono_domain_get ();
1577 MonoThread **current_thread_ptr;
1579 g_assert (internal);
1580 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1582 if (!*current_thread_ptr) {
1583 g_assert (domain != mono_get_root_domain ());
1584 *current_thread_ptr = new_thread_with_internal (domain, internal);
1586 return *current_thread_ptr;
1590 mono_thread_internal_current (void)
1592 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1593 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1598 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1600 MonoInternalThread *thread = this_obj->internal_thread;
1601 HANDLE handle = thread->handle;
1602 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1605 if (mono_thread_current_check_pending_interrupt ())
1608 LOCK_THREAD (thread);
1610 if ((thread->state & ThreadState_Unstarted) != 0) {
1611 UNLOCK_THREAD (thread);
1613 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1617 UNLOCK_THREAD (thread);
1622 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1624 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1627 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1630 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1632 if(ret==WAIT_OBJECT_0) {
1633 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1638 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1643 #define MANAGED_WAIT_FAILED 0x7fffffff
1646 map_native_wait_result_to_managed (gint32 val)
1648 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1649 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1653 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1661 mono_error_init (error);
1663 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1666 if (numhandles != 1)
1667 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1669 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1672 if (ret != WAIT_IO_COMPLETION)
1675 exc = mono_thread_execute_interruption ();
1677 mono_error_set_exception_instance (error, exc);
1684 /* Re-calculate ms according to the time passed */
1685 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1686 if (diff_ms >= ms) {
1690 wait = ms - diff_ms;
1696 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1703 MonoObject *waitHandle;
1704 MonoInternalThread *thread = mono_thread_internal_current ();
1706 /* Do this WaitSleepJoin check before creating objects */
1707 if (mono_thread_current_check_pending_interrupt ())
1708 return map_native_wait_result_to_managed (WAIT_FAILED);
1710 /* We fail in managed if the array has more than 64 elements */
1711 numhandles = (guint32)mono_array_length(mono_handles);
1712 handles = g_new0(HANDLE, numhandles);
1714 for(i = 0; i < numhandles; i++) {
1715 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1716 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1723 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1725 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1727 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1731 mono_error_set_pending_exception (&error);
1733 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1734 return map_native_wait_result_to_managed (ret);
1737 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1740 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1741 uintptr_t numhandles;
1744 MonoObject *waitHandle;
1745 MonoInternalThread *thread = mono_thread_internal_current ();
1747 /* Do this WaitSleepJoin check before creating objects */
1748 if (mono_thread_current_check_pending_interrupt ())
1749 return map_native_wait_result_to_managed (WAIT_FAILED);
1751 numhandles = mono_array_length(mono_handles);
1752 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1753 return map_native_wait_result_to_managed (WAIT_FAILED);
1755 for(i = 0; i < numhandles; i++) {
1756 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1757 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1764 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1766 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1768 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1770 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1772 mono_error_set_pending_exception (&error);
1774 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1775 return map_native_wait_result_to_managed (ret);
1778 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1782 MonoInternalThread *thread = mono_thread_internal_current ();
1784 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1790 if (mono_thread_current_check_pending_interrupt ())
1791 return map_native_wait_result_to_managed (WAIT_FAILED);
1793 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1795 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1797 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1799 mono_error_set_pending_exception (&error);
1800 return map_native_wait_result_to_managed (ret);
1804 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1807 MonoInternalThread *thread = mono_thread_internal_current ();
1812 if (mono_thread_current_check_pending_interrupt ())
1813 return map_native_wait_result_to_managed (WAIT_FAILED);
1815 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1818 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1821 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1823 return map_native_wait_result_to_managed (ret);
1826 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1828 return InterlockedIncrement (location);
1831 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1833 #if SIZEOF_VOID_P == 4
1834 if (G_UNLIKELY ((size_t)location & 0x7)) {
1836 mono_interlocked_lock ();
1839 mono_interlocked_unlock ();
1843 return InterlockedIncrement64 (location);
1846 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1848 return InterlockedDecrement(location);
1851 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1853 #if SIZEOF_VOID_P == 4
1854 if (G_UNLIKELY ((size_t)location & 0x7)) {
1856 mono_interlocked_lock ();
1859 mono_interlocked_unlock ();
1863 return InterlockedDecrement64 (location);
1866 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1868 return InterlockedExchange(location, value);
1871 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1874 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1875 mono_gc_wbarrier_generic_nostore (location);
1879 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1881 return InterlockedExchangePointer(location, value);
1884 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1886 IntFloatUnion val, ret;
1889 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1895 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1897 #if SIZEOF_VOID_P == 4
1898 if (G_UNLIKELY ((size_t)location & 0x7)) {
1900 mono_interlocked_lock ();
1903 mono_interlocked_unlock ();
1907 return InterlockedExchange64 (location, value);
1911 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1913 LongDoubleUnion val, ret;
1916 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1921 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1923 return InterlockedCompareExchange(location, value, comparand);
1926 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1928 gint32 r = InterlockedCompareExchange(location, value, comparand);
1929 *success = r == comparand;
1933 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1936 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1937 mono_gc_wbarrier_generic_nostore (location);
1941 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1943 return InterlockedCompareExchangePointer(location, value, comparand);
1946 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1948 IntFloatUnion val, ret, cmp;
1951 cmp.fval = comparand;
1952 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1958 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1960 #if SIZEOF_VOID_P == 8
1961 LongDoubleUnion val, comp, ret;
1964 comp.fval = comparand;
1965 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1971 mono_interlocked_lock ();
1973 if (old == comparand)
1975 mono_interlocked_unlock ();
1982 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1984 #if SIZEOF_VOID_P == 4
1985 if (G_UNLIKELY ((size_t)location & 0x7)) {
1987 mono_interlocked_lock ();
1989 if (old == comparand)
1991 mono_interlocked_unlock ();
1995 return InterlockedCompareExchange64 (location, value, comparand);
1999 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2002 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2003 mono_gc_wbarrier_generic_nostore (location);
2008 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2011 MONO_CHECK_NULL (location, NULL);
2012 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2013 mono_gc_wbarrier_generic_nostore (location);
2018 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2020 return InterlockedAdd (location, value);
2024 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2026 #if SIZEOF_VOID_P == 4
2027 if (G_UNLIKELY ((size_t)location & 0x7)) {
2029 mono_interlocked_lock ();
2032 mono_interlocked_unlock ();
2036 return InterlockedAdd64 (location, value);
2040 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2042 #if SIZEOF_VOID_P == 4
2043 if (G_UNLIKELY ((size_t)location & 0x7)) {
2045 mono_interlocked_lock ();
2047 mono_interlocked_unlock ();
2051 return InterlockedRead64 (location);
2055 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2057 mono_memory_barrier ();
2061 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2063 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2065 if (state & ThreadState_Background) {
2066 /* If the thread changes the background mode, the main thread has to
2067 * be notified, since it has to rebuild the list of threads to
2070 mono_w32event_set (background_change_event);
2075 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2077 mono_thread_set_state (this_obj, (MonoThreadState)state);
2079 if (state & ThreadState_Background) {
2080 /* If the thread changes the background mode, the main thread has to
2081 * be notified, since it has to rebuild the list of threads to
2084 mono_w32event_set (background_change_event);
2089 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2093 LOCK_THREAD (this_obj);
2095 state = this_obj->state;
2097 UNLOCK_THREAD (this_obj);
2102 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2104 MonoInternalThread *current;
2106 MonoInternalThread *thread = this_obj->internal_thread;
2108 LOCK_THREAD (thread);
2110 current = mono_thread_internal_current ();
2112 thread->thread_interrupt_requested = TRUE;
2113 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2115 UNLOCK_THREAD (thread);
2118 async_abort_internal (thread, FALSE);
2123 * mono_thread_current_check_pending_interrupt:
2125 * Checks if there's a interruption request and set the pending exception if so.
2127 * @returns true if a pending exception was set
2130 mono_thread_current_check_pending_interrupt (void)
2132 MonoInternalThread *thread = mono_thread_internal_current ();
2133 gboolean throw_ = FALSE;
2135 LOCK_THREAD (thread);
2137 if (thread->thread_interrupt_requested) {
2139 thread->thread_interrupt_requested = FALSE;
2142 UNLOCK_THREAD (thread);
2145 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2150 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2152 LOCK_THREAD (thread);
2154 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2155 (thread->state & ThreadState_StopRequested) != 0 ||
2156 (thread->state & ThreadState_Stopped) != 0)
2158 UNLOCK_THREAD (thread);
2162 if ((thread->state & ThreadState_Unstarted) != 0) {
2163 thread->state |= ThreadState_Aborted;
2164 UNLOCK_THREAD (thread);
2168 thread->state |= ThreadState_AbortRequested;
2169 if (thread->abort_state_handle)
2170 mono_gchandle_free (thread->abort_state_handle);
2172 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2173 g_assert (thread->abort_state_handle);
2175 thread->abort_state_handle = 0;
2177 thread->abort_exc = NULL;
2179 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));
2181 /* During shutdown, we can't wait for other threads */
2183 /* Make sure the thread is awake */
2184 mono_thread_resume (thread);
2186 UNLOCK_THREAD (thread);
2191 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2193 if (!request_thread_abort (thread, state))
2196 if (thread == mono_thread_internal_current ()) {
2198 self_abort_internal (&error);
2199 mono_error_set_pending_exception (&error);
2201 async_abort_internal (thread, TRUE);
2206 * mono_thread_internal_abort:
2208 * Request thread @thread to be aborted.
2210 * @thread MUST NOT be the current thread.
2213 mono_thread_internal_abort (MonoInternalThread *thread)
2215 g_assert (thread != mono_thread_internal_current ());
2217 if (!request_thread_abort (thread, NULL))
2219 async_abort_internal (thread, TRUE);
2223 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2225 MonoInternalThread *thread = mono_thread_internal_current ();
2226 gboolean was_aborting;
2228 LOCK_THREAD (thread);
2229 was_aborting = thread->state & ThreadState_AbortRequested;
2230 thread->state &= ~ThreadState_AbortRequested;
2231 UNLOCK_THREAD (thread);
2233 if (!was_aborting) {
2234 const char *msg = "Unable to reset abort because no abort was requested";
2235 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2238 thread->abort_exc = NULL;
2239 if (thread->abort_state_handle) {
2240 mono_gchandle_free (thread->abort_state_handle);
2241 /* This is actually not necessary - the handle
2242 only counts if the exception is set */
2243 thread->abort_state_handle = 0;
2248 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2250 LOCK_THREAD (thread);
2252 thread->state &= ~ThreadState_AbortRequested;
2254 if (thread->abort_exc) {
2255 thread->abort_exc = NULL;
2256 if (thread->abort_state_handle) {
2257 mono_gchandle_free (thread->abort_state_handle);
2258 /* This is actually not necessary - the handle
2259 only counts if the exception is set */
2260 thread->abort_state_handle = 0;
2264 UNLOCK_THREAD (thread);
2268 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2271 MonoInternalThread *thread = this_obj->internal_thread;
2272 MonoObject *state, *deserialized = NULL;
2275 if (!thread->abort_state_handle)
2278 state = mono_gchandle_get_target (thread->abort_state_handle);
2281 domain = mono_domain_get ();
2282 if (mono_object_domain (state) == domain)
2285 deserialized = mono_object_xdomain_representation (state, domain, &error);
2287 if (!deserialized) {
2288 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2289 if (!is_ok (&error)) {
2290 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2291 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2293 mono_set_pending_exception (invalid_op_exc);
2297 return deserialized;
2301 mono_thread_suspend (MonoInternalThread *thread)
2303 LOCK_THREAD (thread);
2305 if ((thread->state & ThreadState_Unstarted) != 0 ||
2306 (thread->state & ThreadState_Aborted) != 0 ||
2307 (thread->state & ThreadState_Stopped) != 0)
2309 UNLOCK_THREAD (thread);
2313 if ((thread->state & ThreadState_Suspended) != 0 ||
2314 (thread->state & ThreadState_SuspendRequested) != 0 ||
2315 (thread->state & ThreadState_StopRequested) != 0)
2317 UNLOCK_THREAD (thread);
2321 thread->state |= ThreadState_SuspendRequested;
2323 if (thread == mono_thread_internal_current ()) {
2324 /* calls UNLOCK_THREAD (thread) */
2325 self_suspend_internal ();
2327 /* calls UNLOCK_THREAD (thread) */
2328 async_suspend_internal (thread, FALSE);
2335 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2337 if (!mono_thread_suspend (this_obj->internal_thread)) {
2338 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2343 /* LOCKING: LOCK_THREAD(thread) must be held */
2345 mono_thread_resume (MonoInternalThread *thread)
2347 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2348 thread->state &= ~ThreadState_SuspendRequested;
2352 if ((thread->state & ThreadState_Suspended) == 0 ||
2353 (thread->state & ThreadState_Unstarted) != 0 ||
2354 (thread->state & ThreadState_Aborted) != 0 ||
2355 (thread->state & ThreadState_Stopped) != 0)
2360 UNLOCK_THREAD (thread);
2362 /* Awake the thread */
2363 if (!mono_thread_info_resume (thread_get_tid (thread)))
2366 LOCK_THREAD (thread);
2368 thread->state &= ~ThreadState_Suspended;
2374 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2376 if (!thread->internal_thread) {
2377 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2379 LOCK_THREAD (thread->internal_thread);
2380 if (!mono_thread_resume (thread->internal_thread))
2381 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2382 UNLOCK_THREAD (thread->internal_thread);
2387 mono_threads_is_critical_method (MonoMethod *method)
2389 switch (method->wrapper_type) {
2390 case MONO_WRAPPER_RUNTIME_INVOKE:
2391 case MONO_WRAPPER_XDOMAIN_INVOKE:
2392 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2399 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2404 if (mono_threads_is_critical_method (m)) {
2405 *((gboolean*)data) = TRUE;
2412 is_running_protected_wrapper (void)
2414 gboolean found = FALSE;
2415 mono_stack_walk (find_wrapper, &found);
2420 request_thread_stop (MonoInternalThread *thread)
2422 LOCK_THREAD (thread);
2424 if ((thread->state & ThreadState_StopRequested) != 0 ||
2425 (thread->state & ThreadState_Stopped) != 0)
2427 UNLOCK_THREAD (thread);
2431 /* Make sure the thread is awake */
2432 mono_thread_resume (thread);
2434 thread->state |= ThreadState_StopRequested;
2435 thread->state &= ~ThreadState_AbortRequested;
2437 UNLOCK_THREAD (thread);
2442 * mono_thread_internal_stop:
2444 * Request thread @thread to stop.
2446 * @thread MUST NOT be the current thread.
2449 mono_thread_internal_stop (MonoInternalThread *thread)
2451 g_assert (thread != mono_thread_internal_current ());
2453 if (!request_thread_stop (thread))
2456 async_abort_internal (thread, TRUE);
2459 void mono_thread_stop (MonoThread *thread)
2461 MonoInternalThread *internal = thread->internal_thread;
2463 if (!request_thread_stop (internal))
2466 if (internal == mono_thread_internal_current ()) {
2468 self_abort_internal (&error);
2470 This function is part of the embeding API and has no way to return the exception
2471 to be thrown. So what we do is keep the old behavior and raise the exception.
2473 mono_error_raise_exception (&error); /* OK to throw, see note */
2475 async_abort_internal (internal, TRUE);
2480 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2482 gint8 tmp = *(volatile gint8 *)ptr;
2483 mono_memory_barrier ();
2488 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2490 gint16 tmp = *(volatile gint16 *)ptr;
2491 mono_memory_barrier ();
2496 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2498 gint32 tmp = *(volatile gint32 *)ptr;
2499 mono_memory_barrier ();
2504 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2506 gint64 tmp = *(volatile gint64 *)ptr;
2507 mono_memory_barrier ();
2512 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2514 volatile void *tmp = *(volatile void **)ptr;
2515 mono_memory_barrier ();
2516 return (void *) tmp;
2520 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2522 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2523 mono_memory_barrier ();
2524 return (MonoObject *) tmp;
2528 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2530 double tmp = *(volatile double *)ptr;
2531 mono_memory_barrier ();
2536 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2538 float tmp = *(volatile float *)ptr;
2539 mono_memory_barrier ();
2544 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2546 return InterlockedRead8 ((volatile gint8 *)ptr);
2550 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2552 return InterlockedRead16 ((volatile gint16 *)ptr);
2556 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2558 return InterlockedRead ((volatile gint32 *)ptr);
2562 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2564 #if SIZEOF_VOID_P == 4
2565 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2567 mono_interlocked_lock ();
2568 val = *(gint64*)ptr;
2569 mono_interlocked_unlock ();
2573 return InterlockedRead64 ((volatile gint64 *)ptr);
2577 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2579 return InterlockedReadPointer ((volatile gpointer *)ptr);
2583 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2587 #if SIZEOF_VOID_P == 4
2588 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2590 mono_interlocked_lock ();
2591 val = *(double*)ptr;
2592 mono_interlocked_unlock ();
2597 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2603 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2607 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2613 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2615 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2619 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2621 mono_memory_barrier ();
2622 *(volatile gint8 *)ptr = value;
2626 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2628 mono_memory_barrier ();
2629 *(volatile gint16 *)ptr = value;
2633 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2635 mono_memory_barrier ();
2636 *(volatile gint32 *)ptr = value;
2640 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2642 mono_memory_barrier ();
2643 *(volatile gint64 *)ptr = value;
2647 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2649 mono_memory_barrier ();
2650 *(volatile void **)ptr = value;
2654 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2656 mono_memory_barrier ();
2657 mono_gc_wbarrier_generic_store (ptr, value);
2661 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2663 mono_memory_barrier ();
2664 *(volatile double *)ptr = value;
2668 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2670 mono_memory_barrier ();
2671 *(volatile float *)ptr = value;
2675 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2677 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2681 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2683 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2687 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2689 InterlockedWrite ((volatile gint32 *)ptr, value);
2693 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2695 #if SIZEOF_VOID_P == 4
2696 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2697 mono_interlocked_lock ();
2698 *(gint64*)ptr = value;
2699 mono_interlocked_unlock ();
2704 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2708 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2710 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2714 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2718 #if SIZEOF_VOID_P == 4
2719 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2720 mono_interlocked_lock ();
2721 *(double*)ptr = value;
2722 mono_interlocked_unlock ();
2729 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2733 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2739 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2743 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2745 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2749 free_context (void *user_data)
2751 ContextStaticData *data = user_data;
2753 mono_threads_lock ();
2756 * There is no guarantee that, by the point this reference queue callback
2757 * has been invoked, the GC handle associated with the object will fail to
2758 * resolve as one might expect. So if we don't free and remove the GC
2759 * handle here, free_context_static_data_helper () could end up resolving
2760 * a GC handle to an actually-dead context which would contain a pointer
2761 * to an already-freed static data segment, resulting in a crash when
2764 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2766 mono_threads_unlock ();
2768 mono_gchandle_free (data->gc_handle);
2769 mono_free_static_data (data->static_data);
2774 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2776 mono_threads_lock ();
2778 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2781 contexts = g_hash_table_new (NULL, NULL);
2784 context_queue = mono_gc_reference_queue_new (free_context);
2786 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2787 g_hash_table_insert (contexts, gch, gch);
2790 * We use this intermediate structure to contain a duplicate pointer to
2791 * the static data because we can't rely on being able to resolve the GC
2792 * handle in the reference queue callback.
2794 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2795 data->gc_handle = GPOINTER_TO_UINT (gch);
2798 context_adjust_static_data (ctx);
2799 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2801 mono_threads_unlock ();
2803 mono_profiler_context_loaded (ctx);
2807 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2810 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2811 * cleanup in exceptional circumstances, we don't actually do any
2812 * cleanup work here. We instead do this via a reference queue.
2815 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2817 mono_profiler_context_unloaded (ctx);
2821 mono_thread_init_tls (void)
2823 MONO_FAST_TLS_INIT (tls_current_object);
2824 mono_native_tls_alloc (¤t_object_key, NULL);
2827 void mono_thread_init (MonoThreadStartCB start_cb,
2828 MonoThreadAttachCB attach_cb)
2830 mono_coop_mutex_init_recursive (&threads_mutex);
2832 mono_os_mutex_init_recursive(&interlocked_mutex);
2833 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2835 background_change_event = mono_w32event_create (TRUE, FALSE);
2836 g_assert(background_change_event != NULL);
2838 mono_init_static_data_info (&thread_static_info);
2839 mono_init_static_data_info (&context_static_info);
2841 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2843 mono_thread_start_cb = start_cb;
2844 mono_thread_attach_cb = attach_cb;
2846 /* Get a pseudo handle to the current process. This is just a
2847 * kludge so that wapi can build a process handle if needed.
2848 * As a pseudo handle is returned, we don't need to clean
2851 GetCurrentProcess ();
2854 void mono_thread_cleanup (void)
2856 #if !defined(RUN_IN_SUBTHREAD)
2857 /* The main thread must abandon any held mutexes (particularly
2858 * important for named mutexes as they are shared across
2859 * processes, see bug 74680.) This will happen when the
2860 * thread exits, but if it's not running in a subthread it
2861 * won't exit in time.
2863 mono_thread_info_set_exited (mono_thread_info_current ());
2867 /* This stuff needs more testing, it seems one of these
2868 * critical sections can be locked when mono_thread_cleanup is
2871 mono_coop_mutex_destroy (&threads_mutex);
2872 mono_os_mutex_destroy (&interlocked_mutex);
2873 mono_os_mutex_destroy (&delayed_free_table_mutex);
2874 mono_os_mutex_destroy (&small_id_mutex);
2875 CloseHandle (background_change_event);
2878 mono_native_tls_free (current_object_key);
2882 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2884 mono_thread_cleanup_fn = func;
2888 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2890 thread->internal_thread->manage_callback = func;
2894 static void print_tids (gpointer key, gpointer value, gpointer user)
2896 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2897 * sizeof(uint) and a cast to uint would overflow
2899 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2900 * print this as a pointer.
2902 g_message ("Waiting for: %p", key);
2907 HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2908 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2913 wait_for_tids (struct wait_data *wait, guint32 timeout)
2917 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2920 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2923 if(ret==WAIT_FAILED) {
2924 /* See the comment in build_wait_tids() */
2925 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2929 for(i=0; i<wait->num; i++)
2930 mono_threads_close_thread_handle (wait->handles [i]);
2932 if (ret == WAIT_TIMEOUT)
2935 for(i=0; i<wait->num; i++) {
2936 MonoInternalThread *internal;
2938 internal = wait->threads [i];
2940 mono_threads_lock ();
2941 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
2942 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
2943 mono_threads_unlock ();
2947 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2949 guint32 i, ret, count;
2951 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2953 /* Add the thread state change event, so it wakes up if a thread changes
2954 * to background mode.
2957 if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
2958 wait->handles [count] = background_change_event;
2963 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2966 if(ret==WAIT_FAILED) {
2967 /* See the comment in build_wait_tids() */
2968 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2972 for(i=0; i<wait->num; i++)
2973 mono_threads_close_thread_handle (wait->handles [i]);
2975 if (ret == WAIT_TIMEOUT)
2978 if (ret < wait->num) {
2979 MonoInternalThread *internal;
2981 internal = wait->threads [ret];
2983 mono_threads_lock ();
2984 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
2985 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
2986 mono_threads_unlock ();
2990 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2992 struct wait_data *wait=(struct wait_data *)user;
2994 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
2996 MonoInternalThread *thread=(MonoInternalThread *)value;
2998 /* Ignore background threads, we abort them later */
2999 /* Do not lock here since it is not needed and the caller holds threads_lock */
3000 if (thread->state & ThreadState_Background) {
3001 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3002 return; /* just leave, ignore */
3005 if (mono_gc_is_finalizer_internal_thread (thread)) {
3006 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3010 if (thread == mono_thread_internal_current ()) {
3011 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3015 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3016 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3020 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3021 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3025 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3026 if (handle == NULL) {
3027 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3031 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3032 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3033 wait->handles[wait->num]=handle;
3034 wait->threads[wait->num]=thread;
3037 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3039 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3044 /* Just ignore the rest, we can't do anything with
3051 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3053 struct wait_data *wait=(struct wait_data *)user;
3054 MonoNativeThreadId self = mono_native_thread_id_get ();
3055 MonoInternalThread *thread = (MonoInternalThread *)value;
3058 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3061 /* The finalizer thread is not a background thread */
3062 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3063 && (thread->state & ThreadState_Background) != 0
3064 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3066 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3070 wait->handles[wait->num] = handle;
3071 wait->threads[wait->num] = thread;
3074 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3075 mono_thread_internal_abort (thread);
3079 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3080 && !mono_gc_is_finalizer_internal_thread (thread);
3084 * mono_threads_set_shutting_down:
3086 * Is called by a thread that wants to shut down Mono. If the runtime is already
3087 * shutting down, the calling thread is suspended/stopped, and this function never
3091 mono_threads_set_shutting_down (void)
3093 MonoInternalThread *current_thread = mono_thread_internal_current ();
3095 mono_threads_lock ();
3097 if (shutting_down) {
3098 mono_threads_unlock ();
3100 /* Make sure we're properly suspended/stopped */
3102 LOCK_THREAD (current_thread);
3104 if ((current_thread->state & ThreadState_SuspendRequested) ||
3105 (current_thread->state & ThreadState_AbortRequested) ||
3106 (current_thread->state & ThreadState_StopRequested)) {
3107 UNLOCK_THREAD (current_thread);
3108 mono_thread_execute_interruption ();
3110 current_thread->state |= ThreadState_Stopped;
3111 UNLOCK_THREAD (current_thread);
3114 /*since we're killing the thread, detach it.*/
3115 mono_thread_detach_internal (current_thread);
3117 /* Wake up other threads potentially waiting for us */
3118 mono_thread_info_exit ();
3120 shutting_down = TRUE;
3122 /* Not really a background state change, but this will
3123 * interrupt the main thread if it is waiting for all
3124 * the other threads.
3126 mono_w32event_set (background_change_event);
3128 mono_threads_unlock ();
3132 void mono_thread_manage (void)
3134 struct wait_data wait_data;
3135 struct wait_data *wait = &wait_data;
3137 memset (wait, 0, sizeof (struct wait_data));
3138 /* join each thread that's still running */
3139 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3141 mono_threads_lock ();
3143 THREAD_DEBUG (g_message("%s: No threads", __func__));
3144 mono_threads_unlock ();
3147 mono_threads_unlock ();
3150 mono_threads_lock ();
3151 if (shutting_down) {
3152 /* somebody else is shutting down */
3153 mono_threads_unlock ();
3156 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3157 mono_g_hash_table_foreach (threads, print_tids, NULL));
3159 mono_w32event_reset (background_change_event);
3161 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3162 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3163 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3164 mono_threads_unlock ();
3166 /* Something to wait for */
3167 wait_for_tids_or_state_change (wait, INFINITE);
3169 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3170 } while(wait->num>0);
3172 /* Mono is shutting down, so just wait for the end */
3173 if (!mono_runtime_try_shutdown ()) {
3174 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3175 mono_thread_suspend (mono_thread_internal_current ());
3176 mono_thread_execute_interruption ();
3180 * Remove everything but the finalizer thread and self.
3181 * Also abort all the background threads
3184 mono_threads_lock ();
3187 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3188 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3189 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3191 mono_threads_unlock ();
3193 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3195 /* Something to wait for */
3196 wait_for_tids (wait, INFINITE);
3198 } while (wait->num > 0);
3201 * give the subthreads a chance to really quit (this is mainly needed
3202 * to get correct user and system times from getrusage/wait/time(1)).
3203 * This could be removed if we avoid pthread_detach() and use pthread_join().
3205 mono_thread_info_yield ();
3209 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3211 MonoInternalThread *thread = (MonoInternalThread*)value;
3212 struct wait_data *wait = (struct wait_data*)user_data;
3216 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3218 * This needs no locking.
3220 if ((thread->state & ThreadState_Suspended) != 0 ||
3221 (thread->state & ThreadState_Stopped) != 0)
3224 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3225 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3229 wait->handles [wait->num] = handle;
3230 wait->threads [wait->num] = thread;
3236 * mono_thread_suspend_all_other_threads:
3238 * Suspend all managed threads except the finalizer thread and this thread. It is
3239 * not possible to resume them later.
3241 void mono_thread_suspend_all_other_threads (void)
3243 struct wait_data wait_data;
3244 struct wait_data *wait = &wait_data;
3246 MonoNativeThreadId self = mono_native_thread_id_get ();
3247 guint32 eventidx = 0;
3248 gboolean starting, finished;
3250 memset (wait, 0, sizeof (struct wait_data));
3252 * The other threads could be in an arbitrary state at this point, i.e.
3253 * they could be starting up, shutting down etc. This means that there could be
3254 * threads which are not even in the threads hash table yet.
3258 * First we set a barrier which will be checked by all threads before they
3259 * are added to the threads hash table, and they will exit if the flag is set.
3260 * This ensures that no threads could be added to the hash later.
3261 * We will use shutting_down as the barrier for now.
3263 g_assert (shutting_down);
3266 * We make multiple calls to WaitForMultipleObjects since:
3267 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3268 * - some threads could exit without becoming suspended
3273 * Make a copy of the hashtable since we can't do anything with
3274 * threads while threads_mutex is held.
3277 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3278 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3279 mono_threads_lock ();
3280 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3281 mono_threads_unlock ();
3284 /* Get the suspended events that we'll be waiting for */
3285 for (i = 0; i < wait->num; ++i) {
3286 MonoInternalThread *thread = wait->threads [i];
3288 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3289 || mono_gc_is_finalizer_internal_thread (thread)
3290 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3292 //mono_threads_close_thread_handle (wait->handles [i]);
3293 wait->threads [i] = NULL; /* ignore this thread in next loop */
3297 LOCK_THREAD (thread);
3299 if ((thread->state & ThreadState_Suspended) != 0 ||
3300 (thread->state & ThreadState_StopRequested) != 0 ||
3301 (thread->state & ThreadState_Stopped) != 0) {
3302 UNLOCK_THREAD (thread);
3303 mono_threads_close_thread_handle (wait->handles [i]);
3304 wait->threads [i] = NULL; /* ignore this thread in next loop */
3310 /* Convert abort requests into suspend requests */
3311 if ((thread->state & ThreadState_AbortRequested) != 0)
3312 thread->state &= ~ThreadState_AbortRequested;
3314 thread->state |= ThreadState_SuspendRequested;
3316 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3317 async_suspend_internal (thread, TRUE);
3319 if (eventidx <= 0) {
3321 * If there are threads which are starting up, we wait until they
3322 * are suspended when they try to register in the threads hash.
3323 * This is guaranteed to finish, since the threads which can create new
3324 * threads get suspended after a while.
3325 * FIXME: The finalizer thread can still create new threads.
3327 mono_threads_lock ();
3328 if (threads_starting_up)
3329 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3332 mono_threads_unlock ();
3334 mono_thread_info_sleep (100, NULL);
3342 MonoInternalThread *thread;
3343 MonoStackFrameInfo *frames;
3344 int nframes, max_frames;
3345 int nthreads, max_threads;
3346 MonoInternalThread **threads;
3347 } ThreadDumpUserData;
3349 static gboolean thread_dump_requested;
3351 /* This needs to be async safe */
3353 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3355 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3357 if (ud->nframes < ud->max_frames) {
3358 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3365 /* This needs to be async safe */
3366 static SuspendThreadResult
3367 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3369 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3370 MonoInternalThread *thread = user_data->thread;
3373 /* This no longer works with remote unwinding */
3374 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3375 mono_thread_internal_describe (thread, text);
3376 g_string_append (text, "\n");
3379 if (thread == mono_thread_internal_current ())
3380 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3382 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3384 return MonoResumeThread;
3388 int nthreads, max_threads;
3389 MonoInternalThread **threads;
3390 } CollectThreadsUserData;
3393 collect_thread (gpointer key, gpointer value, gpointer user)
3395 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3396 MonoInternalThread *thread = (MonoInternalThread *)value;
3398 if (ud->nthreads < ud->max_threads)
3399 ud->threads [ud->nthreads ++] = thread;
3403 * Collect running threads into the THREADS array.
3404 * THREADS should be an array allocated on the stack.
3407 collect_threads (MonoInternalThread **thread_array, int max_threads)
3409 CollectThreadsUserData ud;
3411 memset (&ud, 0, sizeof (ud));
3412 /* This array contains refs, but its on the stack, so its ok */
3413 ud.threads = thread_array;
3414 ud.max_threads = max_threads;
3416 mono_threads_lock ();
3417 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3418 mono_threads_unlock ();
3424 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3426 GString* text = g_string_new (0);
3428 GError *error = NULL;
3431 ud->thread = thread;
3434 /* Collect frames for the thread */
3435 if (thread == mono_thread_internal_current ()) {
3436 get_thread_dump (mono_thread_info_current (), ud);
3438 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3442 * Do all the non async-safe work outside of get_thread_dump.
3445 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3447 g_string_append_printf (text, "\n\"%s\"", name);
3450 else if (thread->threadpool_thread) {
3451 g_string_append (text, "\n\"<threadpool thread>\"");
3453 g_string_append (text, "\n\"<unnamed thread>\"");
3456 for (i = 0; i < ud->nframes; ++i) {
3457 MonoStackFrameInfo *frame = &ud->frames [i];
3458 MonoMethod *method = NULL;
3460 if (frame->type == FRAME_TYPE_MANAGED)
3461 method = mono_jit_info_get_method (frame->ji);
3464 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3465 g_string_append_printf (text, " %s\n", location);
3468 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3472 fprintf (stdout, "%s", text->str);
3474 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3475 OutputDebugStringA(text->str);
3478 g_string_free (text, TRUE);
3483 mono_threads_perform_thread_dump (void)
3485 ThreadDumpUserData ud;
3486 MonoInternalThread *thread_array [128];
3487 int tindex, nthreads;
3489 if (!thread_dump_requested)
3492 printf ("Full thread dump:\n");
3494 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3495 nthreads = collect_threads (thread_array, 128);
3497 memset (&ud, 0, sizeof (ud));
3498 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3499 ud.max_frames = 256;
3501 for (tindex = 0; tindex < nthreads; ++tindex)
3502 dump_thread (thread_array [tindex], &ud);
3506 thread_dump_requested = FALSE;
3509 /* Obtain the thread dump of all threads */
3511 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3514 ThreadDumpUserData ud;
3515 MonoInternalThread *thread_array [128];
3516 MonoDomain *domain = mono_domain_get ();
3517 MonoDebugSourceLocation *location;
3518 int tindex, nthreads;
3520 mono_error_init (error);
3522 *out_threads = NULL;
3523 *out_stack_frames = NULL;
3525 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3526 nthreads = collect_threads (thread_array, 128);
3528 memset (&ud, 0, sizeof (ud));
3529 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3530 ud.max_frames = 256;
3532 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3535 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3539 for (tindex = 0; tindex < nthreads; ++tindex) {
3540 MonoInternalThread *thread = thread_array [tindex];
3541 MonoArray *thread_frames;
3547 /* Collect frames for the thread */
3548 if (thread == mono_thread_internal_current ()) {
3549 get_thread_dump (mono_thread_info_current (), &ud);
3551 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3554 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3556 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3559 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3561 for (i = 0; i < ud.nframes; ++i) {
3562 MonoStackFrameInfo *frame = &ud.frames [i];
3563 MonoMethod *method = NULL;
3564 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3568 sf->native_offset = frame->native_offset;
3570 if (frame->type == FRAME_TYPE_MANAGED)
3571 method = mono_jit_info_get_method (frame->ji);
3574 sf->method_address = (gsize) frame->ji->code_start;
3576 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3579 MONO_OBJECT_SETREF (sf, method, rm);
3581 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3583 sf->il_offset = location->il_offset;
3585 if (location && location->source_file) {
3586 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3587 sf->line = location->row;
3588 sf->column = location->column;
3590 mono_debug_free_source_location (location);
3595 mono_array_setref (thread_frames, i, sf);
3601 return is_ok (error);
3605 * mono_threads_request_thread_dump:
3607 * Ask all threads except the current to print their stacktrace to stdout.
3610 mono_threads_request_thread_dump (void)
3612 /*The new thread dump code runs out of the finalizer thread. */
3613 thread_dump_requested = TRUE;
3614 mono_gc_finalize_notify ();
3619 gint allocated; /* +1 so that refs [allocated] == NULL */
3623 typedef struct ref_stack RefStack;
3626 ref_stack_new (gint initial_size)
3630 initial_size = MAX (initial_size, 16) + 1;
3631 rs = g_new0 (RefStack, 1);
3632 rs->refs = g_new0 (gpointer, initial_size);
3633 rs->allocated = initial_size;
3638 ref_stack_destroy (gpointer ptr)
3640 RefStack *rs = (RefStack *)ptr;
3649 ref_stack_push (RefStack *rs, gpointer ptr)
3651 g_assert (rs != NULL);
3653 if (rs->bottom >= rs->allocated) {
3654 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3655 rs->allocated <<= 1;
3656 rs->refs [rs->allocated] = NULL;
3658 rs->refs [rs->bottom++] = ptr;
3662 ref_stack_pop (RefStack *rs)
3664 if (rs == NULL || rs->bottom == 0)
3668 rs->refs [rs->bottom] = NULL;
3672 ref_stack_find (RefStack *rs, gpointer ptr)
3679 for (refs = rs->refs; refs && *refs; refs++) {
3687 * mono_thread_push_appdomain_ref:
3689 * Register that the current thread may have references to objects in domain
3690 * @domain on its stack. Each call to this function should be paired with a
3691 * call to pop_appdomain_ref.
3694 mono_thread_push_appdomain_ref (MonoDomain *domain)
3696 MonoInternalThread *thread = mono_thread_internal_current ();
3699 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3700 SPIN_LOCK (thread->lock_thread_id);
3701 if (thread->appdomain_refs == NULL)
3702 thread->appdomain_refs = ref_stack_new (16);
3703 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3704 SPIN_UNLOCK (thread->lock_thread_id);
3709 mono_thread_pop_appdomain_ref (void)
3711 MonoInternalThread *thread = mono_thread_internal_current ();
3714 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3715 SPIN_LOCK (thread->lock_thread_id);
3716 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3717 SPIN_UNLOCK (thread->lock_thread_id);
3722 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3725 SPIN_LOCK (thread->lock_thread_id);
3726 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3727 SPIN_UNLOCK (thread->lock_thread_id);
3732 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3734 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3737 typedef struct abort_appdomain_data {
3738 struct wait_data wait;
3740 } abort_appdomain_data;
3743 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3745 MonoInternalThread *thread = (MonoInternalThread*)value;
3746 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3747 MonoDomain *domain = data->domain;
3749 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3750 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3752 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3753 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3756 data->wait.handles [data->wait.num] = handle;
3757 data->wait.threads [data->wait.num] = thread;
3760 /* Just ignore the rest, we can't do anything with
3768 * mono_threads_abort_appdomain_threads:
3770 * Abort threads which has references to the given appdomain.
3773 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3775 #ifdef __native_client__
3779 abort_appdomain_data user_data;
3781 int orig_timeout = timeout;
3784 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3786 start_time = mono_msec_ticks ();
3788 mono_threads_lock ();
3790 user_data.domain = domain;
3791 user_data.wait.num = 0;
3792 /* This shouldn't take any locks */
3793 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3794 mono_threads_unlock ();
3796 if (user_data.wait.num > 0) {
3797 /* Abort the threads outside the threads lock */
3798 for (i = 0; i < user_data.wait.num; ++i)
3799 mono_thread_internal_abort (user_data.wait.threads [i]);
3802 * We should wait for the threads either to abort, or to leave the
3803 * domain. We can't do the latter, so we wait with a timeout.
3805 wait_for_tids (&user_data.wait, 100);
3808 /* Update remaining time */
3809 timeout -= mono_msec_ticks () - start_time;
3810 start_time = mono_msec_ticks ();
3812 if (orig_timeout != -1 && timeout < 0)
3815 while (user_data.wait.num > 0);
3817 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3823 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3825 MonoInternalThread *thread = (MonoInternalThread*)value;
3826 MonoDomain *domain = (MonoDomain*)user_data;
3829 /* No locking needed here */
3830 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3832 if (thread->cached_culture_info) {
3833 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3834 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3835 if (obj && obj->vtable->domain == domain)
3836 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3842 * mono_threads_clear_cached_culture:
3844 * Clear the cached_current_culture from all threads if it is in the
3848 mono_threads_clear_cached_culture (MonoDomain *domain)
3850 mono_threads_lock ();
3851 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3852 mono_threads_unlock ();
3856 * mono_thread_get_undeniable_exception:
3858 * Return an exception which needs to be raised when leaving a catch clause.
3859 * This is used for undeniable exception propagation.
3862 mono_thread_get_undeniable_exception (void)
3864 MonoInternalThread *thread = mono_thread_internal_current ();
3866 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3868 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3869 * exception if the thread no longer references a dying appdomain.
3871 thread->abort_exc->trace_ips = NULL;
3872 thread->abort_exc->stack_trace = NULL;
3873 return thread->abort_exc;
3879 #if MONO_SMALL_CONFIG
3880 #define NUM_STATIC_DATA_IDX 4
3881 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3885 #define NUM_STATIC_DATA_IDX 8
3886 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3887 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3891 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3892 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3895 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3897 gpointer *static_data = (gpointer *)addr;
3899 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3900 void **ptr = (void **)static_data [i];
3905 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3906 void **p = ptr + idx;
3909 mark_func ((MonoObject**)p, gc_data);
3915 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3917 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3921 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3923 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3927 * mono_alloc_static_data
3929 * Allocate memory blocks for storing threads or context static data
3932 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3934 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3937 gpointer* static_data = *static_data_ptr;
3939 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3940 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3942 if (mono_gc_user_markers_supported ()) {
3943 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3944 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3946 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3947 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3950 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3951 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3952 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3953 *static_data_ptr = static_data;
3954 static_data [0] = static_data;
3957 for (i = 1; i <= idx; ++i) {
3958 if (static_data [i])
3961 if (mono_gc_user_markers_supported ())
3962 static_data [i] = g_malloc0 (static_data_size [i]);
3964 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3965 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3966 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3971 mono_free_static_data (gpointer* static_data)
3974 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3975 gpointer p = static_data [i];
3979 * At this point, the static data pointer array is still registered with the
3980 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3981 * data. Freeing the individual arrays without first nulling their slots
3982 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3983 * such an already freed array. See bug #13813.
3985 static_data [i] = NULL;
3986 mono_memory_write_barrier ();
3987 if (mono_gc_user_markers_supported ())
3990 mono_gc_free_fixed (p);
3992 mono_gc_free_fixed (static_data);
3996 * mono_init_static_data_info
3998 * Initializes static data counters
4000 static void mono_init_static_data_info (StaticDataInfo *static_data)
4002 static_data->idx = 0;
4003 static_data->offset = 0;
4004 static_data->freelist = NULL;
4008 * mono_alloc_static_data_slot
4010 * Generates an offset for static data. static_data contains the counters
4011 * used to generate it.
4014 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4016 if (!static_data->idx && !static_data->offset) {
4018 * we use the first chunk of the first allocation also as
4019 * an array for the rest of the data
4021 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4023 static_data->offset += align - 1;
4024 static_data->offset &= ~(align - 1);
4025 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4026 static_data->idx ++;
4027 g_assert (size <= static_data_size [static_data->idx]);
4028 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4029 static_data->offset = 0;
4031 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4032 static_data->offset += size;
4037 * LOCKING: requires that threads_mutex is held
4040 context_adjust_static_data (MonoAppContext *ctx)
4042 if (context_static_info.offset || context_static_info.idx > 0) {
4043 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4044 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4045 ctx->data->static_data = ctx->static_data;
4050 * LOCKING: requires that threads_mutex is held
4053 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4055 MonoInternalThread *thread = (MonoInternalThread *)value;
4056 guint32 offset = GPOINTER_TO_UINT (user);
4058 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4062 * LOCKING: requires that threads_mutex is held
4065 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4067 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4072 guint32 offset = GPOINTER_TO_UINT (user);
4073 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4074 ctx->data->static_data = ctx->static_data;
4077 static StaticDataFreeList*
4078 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4080 StaticDataFreeList* prev = NULL;
4081 StaticDataFreeList* tmp = static_data->freelist;
4083 if (tmp->size == size) {
4085 prev->next = tmp->next;
4087 static_data->freelist = tmp->next;
4096 #if SIZEOF_VOID_P == 4
4103 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4105 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4107 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4108 MonoBitSet *rb = sets [idx];
4109 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4110 offset /= sizeof (uintptr_t);
4111 /* offset is now the bitmap offset */
4112 for (int i = 0; i < numbits; ++i) {
4113 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4114 mono_bitset_set_fast (rb, offset + i);
4119 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4121 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4122 MonoBitSet *rb = sets [idx];
4123 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4124 offset /= sizeof (uintptr_t);
4125 /* offset is now the bitmap offset */
4126 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4127 mono_bitset_clear_fast (rb, offset + i);
4131 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4133 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4135 StaticDataInfo *info;
4138 if (static_type == SPECIAL_STATIC_THREAD) {
4139 info = &thread_static_info;
4140 sets = thread_reference_bitmaps;
4142 info = &context_static_info;
4143 sets = context_reference_bitmaps;
4146 mono_threads_lock ();
4148 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4152 offset = item->offset;
4155 offset = mono_alloc_static_data_slot (info, size, align);
4158 update_reference_bitmap (sets, offset, bitmap, numbits);
4160 if (static_type == SPECIAL_STATIC_THREAD) {
4161 /* This can be called during startup */
4162 if (threads != NULL)
4163 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4165 if (contexts != NULL)
4166 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4168 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4171 mono_threads_unlock ();
4177 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4179 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4181 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4182 return get_thread_static_data (thread, offset);
4184 return get_context_static_data (thread->current_appcontext, offset);
4189 mono_get_special_static_data (guint32 offset)
4191 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4200 * LOCKING: requires that threads_mutex is held
4203 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4205 MonoInternalThread *thread = (MonoInternalThread *)value;
4206 OffsetSize *data = (OffsetSize *)user;
4207 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4208 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4211 if (!thread->static_data || !thread->static_data [idx])
4213 ptr = ((char*) thread->static_data [idx]) + off;
4214 mono_gc_bzero_atomic (ptr, data->size);
4218 * LOCKING: requires that threads_mutex is held
4221 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4223 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4228 OffsetSize *data = (OffsetSize *)user;
4229 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4230 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4233 if (!ctx->static_data || !ctx->static_data [idx])
4236 ptr = ((char*) ctx->static_data [idx]) + off;
4237 mono_gc_bzero_atomic (ptr, data->size);
4241 do_free_special_slot (guint32 offset, guint32 size)
4243 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4245 StaticDataInfo *info;
4247 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4248 info = &thread_static_info;
4249 sets = thread_reference_bitmaps;
4251 info = &context_static_info;
4252 sets = context_reference_bitmaps;
4255 guint32 data_offset = offset;
4256 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4257 OffsetSize data = { data_offset, size };
4259 clear_reference_bitmap (sets, data.offset, data.size);
4261 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4262 if (threads != NULL)
4263 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4265 if (contexts != NULL)
4266 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4269 if (!mono_runtime_is_shutting_down ()) {
4270 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4272 item->offset = offset;
4275 item->next = info->freelist;
4276 info->freelist = item;
4281 do_free_special (gpointer key, gpointer value, gpointer data)
4283 MonoClassField *field = (MonoClassField *)key;
4284 guint32 offset = GPOINTER_TO_UINT (value);
4287 size = mono_type_size (field->type, &align);
4288 do_free_special_slot (offset, size);
4292 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4294 mono_threads_lock ();
4296 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4298 mono_threads_unlock ();
4302 static void CALLBACK dummy_apc (ULONG_PTR param)
4308 * mono_thread_execute_interruption
4310 * Performs the operation that the requested thread state requires (abort,
4313 static MonoException*
4314 mono_thread_execute_interruption (void)
4316 MonoInternalThread *thread = mono_thread_internal_current ();
4317 MonoThread *sys_thread = mono_thread_current ();
4319 LOCK_THREAD (thread);
4321 /* MonoThread::interruption_requested can only be changed with atomics */
4322 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4323 /* this will consume pending APC calls */
4325 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4327 InterlockedDecrement (&thread_interruption_requested);
4329 /* Clear the interrupted flag of the thread so it can wait again */
4330 mono_thread_info_clear_self_interrupt ();
4333 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4334 if (sys_thread->pending_exception) {
4337 exc = sys_thread->pending_exception;
4338 sys_thread->pending_exception = NULL;
4340 UNLOCK_THREAD (thread);
4342 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4343 UNLOCK_THREAD (thread);
4344 g_assert (sys_thread->pending_exception == NULL);
4345 if (thread->abort_exc == NULL) {
4347 * This might be racy, but it has to be called outside the lock
4348 * since it calls managed code.
4350 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4352 return thread->abort_exc;
4354 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4355 /* calls UNLOCK_THREAD (thread) */
4356 self_suspend_internal ();
4359 else if ((thread->state & ThreadState_StopRequested) != 0) {
4360 /* FIXME: do this through the JIT? */
4362 UNLOCK_THREAD (thread);
4364 mono_thread_exit ();
4366 } else if (thread->thread_interrupt_requested) {
4368 thread->thread_interrupt_requested = FALSE;
4369 UNLOCK_THREAD (thread);
4371 return(mono_get_exception_thread_interrupted ());
4374 UNLOCK_THREAD (thread);
4380 * mono_thread_request_interruption
4382 * A signal handler can call this method to request the interruption of a
4383 * thread. The result of the interruption will depend on the current state of
4384 * the thread. If the result is an exception that needs to be throw, it is
4385 * provided as return value.
4388 mono_thread_request_interruption (gboolean running_managed)
4390 MonoInternalThread *thread = mono_thread_internal_current ();
4392 /* The thread may already be stopping */
4397 if (thread->interrupt_on_stop &&
4398 thread->state & ThreadState_StopRequested &&
4399 thread->state & ThreadState_Background)
4402 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4404 InterlockedIncrement (&thread_interruption_requested);
4406 if (!running_managed || is_running_protected_wrapper ()) {
4407 /* Can't stop while in unmanaged code. Increase the global interruption
4408 request count. When exiting the unmanaged method the count will be
4409 checked and the thread will be interrupted. */
4411 /* this will awake the thread if it is in WaitForSingleObject
4413 /* Our implementation of this function ignores the func argument */
4415 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4417 mono_thread_info_self_interrupt ();
4422 return mono_thread_execute_interruption ();
4426 /*This function should be called by a thread after it has exited all of
4427 * its handle blocks at interruption time.*/
4429 mono_thread_resume_interruption (void)
4431 MonoInternalThread *thread = mono_thread_internal_current ();
4432 gboolean still_aborting;
4434 /* The thread may already be stopping */
4438 LOCK_THREAD (thread);
4439 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4440 UNLOCK_THREAD (thread);
4442 /*This can happen if the protected block called Thread::ResetAbort*/
4443 if (!still_aborting)
4446 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4448 InterlockedIncrement (&thread_interruption_requested);
4450 mono_thread_info_self_interrupt ();
4452 return mono_thread_execute_interruption ();
4455 gboolean mono_thread_interruption_requested ()
4457 if (thread_interruption_requested) {
4458 MonoInternalThread *thread = mono_thread_internal_current ();
4459 /* The thread may already be stopping */
4461 return (thread->interruption_requested);
4466 static MonoException*
4467 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4469 MonoInternalThread *thread = mono_thread_internal_current ();
4471 /* The thread may already be stopping */
4475 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4476 MonoException* exc = mono_thread_execute_interruption ();
4484 * Performs the interruption of the current thread, if one has been requested,
4485 * and the thread is not running a protected wrapper.
4486 * Return the exception which needs to be thrown, if any.
4489 mono_thread_interruption_checkpoint (void)
4491 return mono_thread_interruption_checkpoint_request (FALSE);
4495 * Performs the interruption of the current thread, if one has been requested.
4496 * Return the exception which needs to be thrown, if any.
4499 mono_thread_force_interruption_checkpoint_noraise (void)
4501 return mono_thread_interruption_checkpoint_request (TRUE);
4505 * mono_set_pending_exception:
4507 * Set the pending exception of the current thread to EXC.
4508 * The exception will be thrown when execution returns to managed code.
4511 mono_set_pending_exception (MonoException *exc)
4513 MonoThread *thread = mono_thread_current ();
4515 /* The thread may already be stopping */
4519 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4521 mono_thread_request_interruption (FALSE);
4525 * mono_thread_interruption_request_flag:
4527 * Returns the address of a flag that will be non-zero if an interruption has
4528 * been requested for a thread. The thread to interrupt may not be the current
4529 * thread, so an additional call to mono_thread_interruption_requested() or
4530 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4533 gint32* mono_thread_interruption_request_flag ()
4535 return &thread_interruption_requested;
4539 mono_thread_init_apartment_state (void)
4542 MonoInternalThread* thread = mono_thread_internal_current ();
4544 /* Positive return value indicates success, either
4545 * S_OK if this is first CoInitialize call, or
4546 * S_FALSE if CoInitialize already called, but with same
4547 * threading model. A negative value indicates failure,
4548 * probably due to trying to change the threading model.
4550 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4551 ? COINIT_APARTMENTTHREADED
4552 : COINIT_MULTITHREADED) < 0) {
4553 thread->apartment_state = ThreadApartmentState_Unknown;
4559 mono_thread_cleanup_apartment_state (void)
4562 MonoInternalThread* thread = mono_thread_internal_current ();
4564 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4571 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4573 LOCK_THREAD (thread);
4574 thread->state |= state;
4575 UNLOCK_THREAD (thread);
4579 * mono_thread_test_and_set_state:
4581 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4583 * Returns TRUE is @set was OR'd in.
4586 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4588 LOCK_THREAD (thread);
4590 if ((thread->state & test) != 0) {
4591 UNLOCK_THREAD (thread);
4595 thread->state |= set;
4596 UNLOCK_THREAD (thread);
4602 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4604 LOCK_THREAD (thread);
4605 thread->state &= ~state;
4606 UNLOCK_THREAD (thread);
4610 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4612 gboolean ret = FALSE;
4614 LOCK_THREAD (thread);
4616 if ((thread->state & test) != 0) {
4620 UNLOCK_THREAD (thread);
4625 static gboolean has_tls_get = FALSE;
4628 mono_runtime_set_has_tls_get (gboolean val)
4634 mono_runtime_has_tls_get (void)
4640 self_interrupt_thread (void *_unused)
4642 MonoThreadInfo *info = mono_thread_info_current ();
4643 MonoException *exc = mono_thread_execute_interruption ();
4644 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4645 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. */
4646 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4650 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4654 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4658 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4660 MonoJitInfo **dest = (MonoJitInfo **)data;
4666 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4668 MonoJitInfo *ji = NULL;
4673 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4674 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4675 * where we hold runtime locks.
4677 if (!mono_threads_is_coop_enabled ())
4678 mono_thread_info_set_is_async_context (TRUE);
4679 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4680 if (!mono_threads_is_coop_enabled ())
4681 mono_thread_info_set_is_async_context (FALSE);
4686 MonoInternalThread *thread;
4687 gboolean install_async_abort;
4688 MonoThreadInfoInterruptToken *interrupt_token;
4691 static SuspendThreadResult
4692 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4694 AbortThreadData *data = (AbortThreadData *)ud;
4695 MonoInternalThread *thread = data->thread;
4696 MonoJitInfo *ji = NULL;
4697 gboolean protected_wrapper;
4698 gboolean running_managed;
4700 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4701 return MonoResumeThread;
4704 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4705 The protected block code will give them a chance when appropriate.
4707 if (thread->abort_protected_block_count)
4708 return MonoResumeThread;
4710 /*someone is already interrupting it*/
4711 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4712 return MonoResumeThread;
4714 InterlockedIncrement (&thread_interruption_requested);
4716 ji = mono_thread_info_get_last_managed (info);
4717 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4718 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4720 if (!protected_wrapper && running_managed) {
4721 /*We are in managed code*/
4722 /*Set the thread to call */
4723 if (data->install_async_abort)
4724 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4725 return MonoResumeThread;
4728 * This will cause waits to be broken.
4729 * It will also prevent the thread from entering a wait, so if the thread returns
4730 * from the wait before it receives the abort signal, it will just spin in the wait
4731 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4734 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4736 return MonoResumeThread;
4741 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4743 AbortThreadData data;
4745 g_assert (thread != mono_thread_internal_current ());
4747 data.thread = thread;
4748 data.install_async_abort = install_async_abort;
4749 data.interrupt_token = NULL;
4751 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4752 if (data.interrupt_token)
4753 mono_thread_info_finish_interrupt (data.interrupt_token);
4754 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4758 self_abort_internal (MonoError *error)
4762 mono_error_init (error);
4764 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4765 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4768 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.
4770 exc = mono_thread_request_interruption (TRUE);
4772 mono_error_set_exception_instance (error, exc);
4774 mono_thread_info_self_interrupt ();
4778 MonoInternalThread *thread;
4780 MonoThreadInfoInterruptToken *interrupt_token;
4781 } SuspendThreadData;
4783 static SuspendThreadResult
4784 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4786 SuspendThreadData *data = (SuspendThreadData *)ud;
4787 MonoInternalThread *thread = data->thread;
4788 MonoJitInfo *ji = NULL;
4789 gboolean protected_wrapper;
4790 gboolean running_managed;
4792 ji = mono_thread_info_get_last_managed (info);
4793 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4794 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4796 if (running_managed && !protected_wrapper) {
4797 thread->state &= ~ThreadState_SuspendRequested;
4798 thread->state |= ThreadState_Suspended;
4799 return KeepSuspended;
4801 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4802 InterlockedIncrement (&thread_interruption_requested);
4803 if (data->interrupt)
4804 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4806 return MonoResumeThread;
4810 /* LOCKING: called with @thread synch_cs held, and releases it */
4812 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4814 SuspendThreadData data;
4816 g_assert (thread != mono_thread_internal_current ());
4818 data.thread = thread;
4819 data.interrupt = interrupt;
4820 data.interrupt_token = NULL;
4822 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4823 if (data.interrupt_token)
4824 mono_thread_info_finish_interrupt (data.interrupt_token);
4826 UNLOCK_THREAD (thread);
4829 /* LOCKING: called with @thread synch_cs held, and releases it */
4831 self_suspend_internal (void)
4833 MonoInternalThread *thread;
4835 thread = mono_thread_internal_current ();
4837 mono_thread_info_begin_self_suspend ();
4838 thread->state &= ~ThreadState_SuspendRequested;
4839 thread->state |= ThreadState_Suspended;
4841 UNLOCK_THREAD (thread);
4843 mono_thread_info_end_self_suspend ();
4847 * mono_thread_is_foreign:
4848 * @thread: the thread to query
4850 * This function allows one to determine if a thread was created by the mono runtime and has
4851 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4853 * Returns: TRUE if @thread was not created by the runtime.
4856 mono_thread_is_foreign (MonoThread *thread)
4858 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4859 return info->runtime_thread == FALSE;
4863 * mono_add_joinable_thread:
4865 * Add TID to the list of joinable threads.
4866 * LOCKING: Acquires the threads lock.
4869 mono_threads_add_joinable_thread (gpointer tid)
4873 * We cannot detach from threads because it causes problems like
4874 * 2fd16f60/r114307. So we collect them and join them when
4875 * we have time (in he finalizer thread).
4877 joinable_threads_lock ();
4878 if (!joinable_threads)
4879 joinable_threads = g_hash_table_new (NULL, NULL);
4880 g_hash_table_insert (joinable_threads, tid, tid);
4881 joinable_thread_count ++;
4882 joinable_threads_unlock ();
4884 mono_gc_finalize_notify ();
4889 * mono_threads_join_threads:
4891 * Join all joinable threads. This is called from the finalizer thread.
4892 * LOCKING: Acquires the threads lock.
4895 mono_threads_join_threads (void)
4898 GHashTableIter iter;
4905 if (!joinable_thread_count)
4909 joinable_threads_lock ();
4911 if (g_hash_table_size (joinable_threads)) {
4912 g_hash_table_iter_init (&iter, joinable_threads);
4913 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4914 thread = (pthread_t)tid;
4915 g_hash_table_remove (joinable_threads, key);
4916 joinable_thread_count --;
4919 joinable_threads_unlock ();
4921 if (thread != pthread_self ()) {
4923 /* This shouldn't block */
4924 pthread_join (thread, NULL);
4937 * Wait for thread TID to exit.
4938 * LOCKING: Acquires the threads lock.
4941 mono_thread_join (gpointer tid)
4945 gboolean found = FALSE;
4947 joinable_threads_lock ();
4948 if (!joinable_threads)
4949 joinable_threads = g_hash_table_new (NULL, NULL);
4950 if (g_hash_table_lookup (joinable_threads, tid)) {
4951 g_hash_table_remove (joinable_threads, tid);
4952 joinable_thread_count --;
4955 joinable_threads_unlock ();
4958 thread = (pthread_t)tid;
4960 pthread_join (thread, NULL);
4966 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4968 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4969 mono_thread_interruption_checkpoint ();
4973 mono_thread_internal_unhandled_exception (MonoObject* exc)
4975 MonoClass *klass = exc->vtable->klass;
4976 if (is_threadabort_exception (klass)) {
4977 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4978 } else if (!is_appdomainunloaded_exception (klass)
4979 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4980 mono_unhandled_exception (exc);
4981 if (mono_environment_exitcode_get () == 1) {
4982 mono_environment_exitcode_set (255);
4983 mono_invoke_unhandled_exception_hook (exc);
4984 g_assert_not_reached ();
4990 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
4993 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
4994 mono_error_set_pending_exception (&error);
4998 * mono_threads_attach_coop: called by native->managed wrappers
5002 * - @return: the original domain which needs to be restored, or NULL.
5005 * - @dummy: contains the original domain
5006 * - @return: a cookie containing current MonoThreadInfo*.
5009 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5012 gboolean fresh_thread = FALSE;
5015 /* Happens when called from AOTed code which is only used in the root domain. */
5016 domain = mono_get_root_domain ();
5021 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5022 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5023 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5024 * we're only responsible for making the cookie. */
5025 if (mono_threads_is_coop_enabled ()) {
5026 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5027 fresh_thread = !info || !mono_thread_info_is_live (info);
5030 if (!mono_thread_internal_current ()) {
5031 mono_thread_attach_full (domain, FALSE);
5034 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5037 orig = mono_domain_get ();
5039 mono_domain_set (domain, TRUE);
5041 if (!mono_threads_is_coop_enabled ())
5042 return orig != domain ? orig : NULL;
5046 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5047 * return the right cookie. */
5048 return mono_threads_enter_gc_unsafe_region_cookie ();
5051 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5052 return mono_threads_enter_gc_unsafe_region (dummy);
5057 * mono_threads_detach_coop: called by native->managed wrappers
5060 * - @cookie: the original domain which needs to be restored, or NULL.
5064 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5065 * - @dummy: contains the original domain
5068 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5070 MonoDomain *domain, *orig;
5072 if (!mono_threads_is_coop_enabled ()) {
5073 orig = (MonoDomain*) cookie;
5075 mono_domain_set (orig, TRUE);
5077 orig = (MonoDomain*) *dummy;
5079 domain = mono_domain_get ();
5082 /* it won't do anything if cookie is NULL
5083 * thread state RUNNING -> (RUNNING|BLOCKING) */
5084 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5086 if (orig != domain) {
5088 mono_domain_unset ();
5090 mono_domain_set (orig, TRUE);
5096 mono_threads_begin_abort_protected_block (void)
5098 MonoInternalThread *thread;
5100 thread = mono_thread_internal_current ();
5101 ++thread->abort_protected_block_count;
5102 mono_memory_barrier ();
5106 mono_threads_end_abort_protected_block (void)
5108 MonoInternalThread *thread;
5110 thread = mono_thread_internal_current ();
5112 mono_memory_barrier ();
5113 --thread->abort_protected_block_count;
5117 mono_thread_try_resume_interruption (void)
5119 MonoInternalThread *thread;
5121 thread = mono_thread_internal_current ();
5122 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5125 return mono_thread_resume_interruption ();
5128 /* Returns TRUE if the current thread is ready to be interrupted. */
5130 mono_threads_is_ready_to_be_interrupted (void)
5132 MonoInternalThread *thread;
5134 thread = mono_thread_internal_current ();
5135 LOCK_THREAD (thread);
5136 if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5137 UNLOCK_THREAD (thread);
5141 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5142 UNLOCK_THREAD (thread);
5146 UNLOCK_THREAD (thread);
5151 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5153 g_string_append_printf (text, ", thread handle : %p", internal->handle);
5155 if (internal->thread_info) {
5156 g_string_append (text, ", state : ");
5157 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5160 if (internal->owned_mutexes) {
5163 g_string_append (text, ", owns : [");
5164 for (i = 0; i < internal->owned_mutexes->len; i++)
5165 g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5166 g_string_append (text, "]");
5171 mono_thread_internal_is_current (MonoInternalThread *internal)
5173 g_assert (internal);
5174 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));