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 return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
899 * Common thread creation code.
900 * LOCKING: Acquires the threads lock.
903 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
904 gboolean threadpool_thread, guint32 stack_size, MonoError *error)
906 StartInfo *start_info = NULL;
907 HANDLE thread_handle;
908 MonoNativeThreadId tid;
910 gsize stack_set_size;
913 g_assert (!start_func && !start_func_arg);
915 g_assert (!start_delegate);
918 * Join joinable threads to prevent running out of threads since the finalizer
919 * thread might be blocked/backlogged.
921 mono_threads_join_threads ();
923 mono_error_init (error);
925 mono_threads_lock ();
927 mono_threads_unlock ();
930 if (threads_starting_up == NULL) {
931 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
932 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
934 mono_g_hash_table_insert (threads_starting_up, thread, thread);
935 mono_threads_unlock ();
937 internal->threadpool_thread = threadpool_thread;
938 if (threadpool_thread)
939 mono_thread_set_state (internal, ThreadState_Background);
941 start_info = g_new0 (StartInfo, 1);
943 start_info->thread = thread;
944 start_info->start_delegate = start_delegate;
945 start_info->start_delegate_arg = thread->start_obj;
946 start_info->start_func = start_func;
947 start_info->start_func_arg = start_func_arg;
948 start_info->failed = FALSE;
949 mono_coop_sem_init (&start_info->registered, 0);
952 stack_set_size = default_stacksize_for_thread (internal);
956 thread_handle = mono_threads_create_thread (start_wrapper, start_info, &stack_set_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 internal->stack_size = (int) stack_set_size;
972 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
975 * Wait for the thread to set up its TLS data etc, so
976 * theres no potential race condition if someone tries
977 * to look up the data believing the thread has
981 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
983 mono_threads_close_thread_handle (thread_handle);
985 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));
987 ret = !start_info->failed;
990 if (InterlockedDecrement (&start_info->ref) == 0) {
991 mono_coop_sem_destroy (&start_info->registered);
998 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
1000 if (mono_thread_start_cb) {
1001 mono_thread_start_cb (tid, stack_start, func);
1005 void mono_threads_set_default_stacksize (guint32 stacksize)
1007 default_stacksize = stacksize;
1010 guint32 mono_threads_get_default_stacksize (void)
1012 return default_stacksize;
1016 * mono_thread_create_internal:
1018 * ARG should not be a GC reference.
1021 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
1024 MonoInternalThread *internal;
1027 mono_error_init (error);
1029 thread = create_thread_object (domain);
1031 internal = create_internal_thread ();
1033 MONO_OBJECT_SETREF (thread, internal_thread, internal);
1035 LOCK_THREAD (internal);
1037 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
1038 return_val_if_nok (error, NULL);
1040 UNLOCK_THREAD (internal);
1046 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1049 if (!mono_thread_create_checked (domain, func, arg, &error))
1050 mono_error_cleanup (&error);
1054 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1056 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
1060 mono_thread_attach (MonoDomain *domain)
1062 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1068 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1070 MonoInternalThread *internal;
1072 MonoNativeThreadId tid;
1075 if (mono_thread_internal_current_is_attached ()) {
1076 if (domain != mono_domain_get ())
1077 mono_domain_set (domain, TRUE);
1078 /* Already attached */
1079 return mono_thread_current ();
1082 if (!mono_gc_register_thread (&domain)) {
1083 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 ());
1086 tid=mono_native_thread_id_get ();
1088 internal = create_internal_thread ();
1090 thread = new_thread_with_internal (domain, internal);
1092 if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
1093 /* Mono is shutting down, so just wait for the end */
1095 mono_thread_info_sleep (10000, NULL);
1098 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1100 if (mono_thread_attach_cb) {
1104 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1107 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1109 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1112 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1113 if (!mono_thread_info_current ()->tools_thread)
1114 // FIXME: Need a separate callback
1115 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1121 mono_thread_detach_internal (MonoInternalThread *thread)
1123 g_return_if_fail (thread != NULL);
1125 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1128 mono_w32mutex_abandon ();
1131 thread_cleanup (thread);
1133 SET_CURRENT_OBJECT (NULL);
1134 mono_domain_unset ();
1136 /* Don't need to close the handle to this thread, even though we took a
1137 * reference in mono_thread_attach (), because the GC will do it
1138 * when the Thread object is finalised.
1143 mono_thread_detach (MonoThread *thread)
1146 mono_thread_detach_internal (thread->internal_thread);
1150 * mono_thread_detach_if_exiting:
1152 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1153 * This should be used at the end of embedding code which calls into managed code, and which
1154 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1157 mono_thread_detach_if_exiting (void)
1159 if (mono_thread_info_is_exiting ()) {
1160 MonoInternalThread *thread;
1162 thread = mono_thread_internal_current ();
1164 mono_thread_detach_internal (thread);
1165 mono_thread_info_detach ();
1173 mono_thread_internal_current_is_attached (void)
1175 MonoInternalThread *internal;
1177 internal = GET_CURRENT_OBJECT ();
1185 mono_thread_exit (void)
1187 MonoInternalThread *thread = mono_thread_internal_current ();
1189 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1191 mono_thread_detach_internal (thread);
1193 /* we could add a callback here for embedders to use. */
1194 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1195 exit (mono_environment_exitcode_get ());
1197 mono_thread_info_exit ();
1201 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1203 MonoInternalThread *internal;
1205 internal = create_internal_thread ();
1207 internal->state = ThreadState_Unstarted;
1209 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1213 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1217 MonoInternalThread *internal;
1220 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1222 if (!this_obj->internal_thread)
1223 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1224 internal = this_obj->internal_thread;
1226 LOCK_THREAD (internal);
1228 if ((internal->state & ThreadState_Unstarted) == 0) {
1229 UNLOCK_THREAD (internal);
1230 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1234 if ((internal->state & ThreadState_Aborted) != 0) {
1235 UNLOCK_THREAD (internal);
1239 res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1241 mono_error_cleanup (&error);
1242 UNLOCK_THREAD (internal);
1246 internal->state &= ~ThreadState_Unstarted;
1248 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1250 UNLOCK_THREAD (internal);
1251 return internal->handle;
1255 * This is called from the finalizer of the internal thread object.
1258 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1260 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1263 * Since threads keep a reference to their thread object while running, by the time this function is called,
1264 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1265 * when thread_cleanup () can be called after this.
1268 mono_threads_close_thread_handle (thread);
1270 if (this_obj->synch_cs) {
1271 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1272 this_obj->synch_cs = NULL;
1273 mono_coop_mutex_destroy (synch_cs);
1277 if (this_obj->name) {
1278 void *name = this_obj->name;
1279 this_obj->name = NULL;
1285 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1288 MonoInternalThread *thread = mono_thread_internal_current ();
1290 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1292 if (mono_thread_current_check_pending_interrupt ())
1296 gboolean alerted = FALSE;
1298 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1300 res = mono_thread_info_sleep (ms, &alerted);
1302 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1305 MonoException* exc = mono_thread_execute_interruption ();
1307 mono_raise_exception (exc);
1319 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1324 ves_icall_System_Threading_Thread_GetDomainID (void)
1326 return mono_domain_get()->domain_id;
1330 ves_icall_System_Threading_Thread_Yield (void)
1332 return mono_thread_info_yield ();
1336 * mono_thread_get_name:
1338 * Return the name of the thread. NAME_LEN is set to the length of the name.
1339 * Return NULL if the thread has no name. The returned memory is owned by the
1343 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1347 LOCK_THREAD (this_obj);
1349 if (!this_obj->name) {
1353 *name_len = this_obj->name_len;
1354 res = g_new (gunichar2, this_obj->name_len);
1355 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1358 UNLOCK_THREAD (this_obj);
1364 * mono_thread_get_name_utf8:
1366 * Return the name of the thread in UTF-8.
1367 * Return NULL if the thread has no name.
1368 * The returned memory is owned by the caller.
1371 mono_thread_get_name_utf8 (MonoThread *thread)
1376 MonoInternalThread *internal = thread->internal_thread;
1377 if (internal == NULL)
1380 LOCK_THREAD (internal);
1382 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1384 UNLOCK_THREAD (internal);
1390 * mono_thread_get_managed_id:
1392 * Return the Thread.ManagedThreadId value of `thread`.
1393 * Returns -1 if `thread` is NULL.
1396 mono_thread_get_managed_id (MonoThread *thread)
1401 MonoInternalThread *internal = thread->internal_thread;
1402 if (internal == NULL)
1405 int32_t id = internal->managed_id;
1411 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1416 mono_error_init (&error);
1418 LOCK_THREAD (this_obj);
1420 if (!this_obj->name)
1423 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1425 UNLOCK_THREAD (this_obj);
1427 if (mono_error_set_pending_exception (&error))
1434 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1436 LOCK_THREAD (this_obj);
1438 mono_error_init (error);
1440 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1441 UNLOCK_THREAD (this_obj);
1443 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1446 if (this_obj->name) {
1447 g_free (this_obj->name);
1448 this_obj->name_len = 0;
1451 this_obj->name = g_new (gunichar2, mono_string_length (name));
1452 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1453 this_obj->name_len = mono_string_length (name);
1456 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1459 this_obj->name = NULL;
1462 UNLOCK_THREAD (this_obj);
1464 if (this_obj->name && this_obj->tid) {
1465 char *tname = mono_string_to_utf8_checked (name, error);
1466 return_if_nok (error);
1467 mono_profiler_thread_name (this_obj->tid, tname);
1468 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1474 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1477 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1478 mono_error_set_pending_exception (&error);
1482 * ves_icall_System_Threading_Thread_GetPriority_internal:
1483 * @param this_obj: The MonoInternalThread on which to operate.
1485 * Gets the priority of the given thread.
1486 * @return: The priority of the given thread.
1489 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1492 MonoInternalThread *internal = this_obj->internal_thread;
1494 LOCK_THREAD (internal);
1495 priority = internal->priority;
1496 UNLOCK_THREAD (internal);
1502 * ves_icall_System_Threading_Thread_SetPriority_internal:
1503 * @param this_obj: The MonoInternalThread on which to operate.
1504 * @param priority: The priority to set.
1506 * Sets the priority of the given thread.
1509 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1511 MonoInternalThread *internal = this_obj->internal_thread;
1513 LOCK_THREAD (internal);
1514 internal->priority = priority;
1515 if (internal->handle != NULL)
1516 mono_thread_internal_set_priority (internal, priority);
1517 UNLOCK_THREAD (internal);
1520 /* If the array is already in the requested domain, we just return it,
1521 otherwise we return a copy in that domain. */
1523 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1527 mono_error_init (error);
1531 if (mono_object_domain (arr) == domain)
1534 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1535 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1540 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1543 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1544 mono_error_set_pending_exception (&error);
1549 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1552 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1553 mono_error_set_pending_exception (&error);
1558 mono_thread_current (void)
1560 MonoDomain *domain = mono_domain_get ();
1561 MonoInternalThread *internal = mono_thread_internal_current ();
1562 MonoThread **current_thread_ptr;
1564 g_assert (internal);
1565 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1567 if (!*current_thread_ptr) {
1568 g_assert (domain != mono_get_root_domain ());
1569 *current_thread_ptr = new_thread_with_internal (domain, internal);
1571 return *current_thread_ptr;
1574 /* Return the thread object belonging to INTERNAL in the current domain */
1576 mono_thread_current_for_thread (MonoInternalThread *internal)
1578 MonoDomain *domain = mono_domain_get ();
1579 MonoThread **current_thread_ptr;
1581 g_assert (internal);
1582 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1584 if (!*current_thread_ptr) {
1585 g_assert (domain != mono_get_root_domain ());
1586 *current_thread_ptr = new_thread_with_internal (domain, internal);
1588 return *current_thread_ptr;
1592 mono_thread_internal_current (void)
1594 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1595 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1600 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1602 MonoInternalThread *thread = this_obj->internal_thread;
1603 HANDLE handle = thread->handle;
1604 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1607 if (mono_thread_current_check_pending_interrupt ())
1610 LOCK_THREAD (thread);
1612 if ((thread->state & ThreadState_Unstarted) != 0) {
1613 UNLOCK_THREAD (thread);
1615 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1619 UNLOCK_THREAD (thread);
1624 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1626 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1629 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1632 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1634 if(ret==WAIT_OBJECT_0) {
1635 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1640 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1645 #define MANAGED_WAIT_FAILED 0x7fffffff
1648 map_native_wait_result_to_managed (gint32 val)
1650 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1651 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1655 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1663 mono_error_init (error);
1665 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1668 if (numhandles != 1)
1669 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1671 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1674 if (ret != WAIT_IO_COMPLETION)
1677 exc = mono_thread_execute_interruption ();
1679 mono_error_set_exception_instance (error, exc);
1686 /* Re-calculate ms according to the time passed */
1687 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1688 if (diff_ms >= ms) {
1692 wait = ms - diff_ms;
1698 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1705 MonoObject *waitHandle;
1706 MonoInternalThread *thread = mono_thread_internal_current ();
1708 /* Do this WaitSleepJoin check before creating objects */
1709 if (mono_thread_current_check_pending_interrupt ())
1710 return map_native_wait_result_to_managed (WAIT_FAILED);
1712 /* We fail in managed if the array has more than 64 elements */
1713 numhandles = (guint32)mono_array_length(mono_handles);
1714 handles = g_new0(HANDLE, numhandles);
1716 for(i = 0; i < numhandles; i++) {
1717 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1718 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1725 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1727 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1729 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1733 mono_error_set_pending_exception (&error);
1735 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1736 return map_native_wait_result_to_managed (ret);
1739 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1742 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1743 uintptr_t numhandles;
1746 MonoObject *waitHandle;
1747 MonoInternalThread *thread = mono_thread_internal_current ();
1749 /* Do this WaitSleepJoin check before creating objects */
1750 if (mono_thread_current_check_pending_interrupt ())
1751 return map_native_wait_result_to_managed (WAIT_FAILED);
1753 numhandles = mono_array_length(mono_handles);
1754 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1755 return map_native_wait_result_to_managed (WAIT_FAILED);
1757 for(i = 0; i < numhandles; i++) {
1758 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1759 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1766 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1768 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1770 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1772 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1774 mono_error_set_pending_exception (&error);
1776 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1777 return map_native_wait_result_to_managed (ret);
1780 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1784 MonoInternalThread *thread = mono_thread_internal_current ();
1786 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1792 if (mono_thread_current_check_pending_interrupt ())
1793 return map_native_wait_result_to_managed (WAIT_FAILED);
1795 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1797 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1799 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1801 mono_error_set_pending_exception (&error);
1802 return map_native_wait_result_to_managed (ret);
1806 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1809 MonoInternalThread *thread = mono_thread_internal_current ();
1814 if (mono_thread_current_check_pending_interrupt ())
1815 return map_native_wait_result_to_managed (WAIT_FAILED);
1817 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1820 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1823 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1825 return map_native_wait_result_to_managed (ret);
1828 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1830 return InterlockedIncrement (location);
1833 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1835 #if SIZEOF_VOID_P == 4
1836 if (G_UNLIKELY ((size_t)location & 0x7)) {
1838 mono_interlocked_lock ();
1841 mono_interlocked_unlock ();
1845 return InterlockedIncrement64 (location);
1848 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1850 return InterlockedDecrement(location);
1853 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1855 #if SIZEOF_VOID_P == 4
1856 if (G_UNLIKELY ((size_t)location & 0x7)) {
1858 mono_interlocked_lock ();
1861 mono_interlocked_unlock ();
1865 return InterlockedDecrement64 (location);
1868 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1870 return InterlockedExchange(location, value);
1873 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1876 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1877 mono_gc_wbarrier_generic_nostore (location);
1881 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1883 return InterlockedExchangePointer(location, value);
1886 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1888 IntFloatUnion val, ret;
1891 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1897 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1899 #if SIZEOF_VOID_P == 4
1900 if (G_UNLIKELY ((size_t)location & 0x7)) {
1902 mono_interlocked_lock ();
1905 mono_interlocked_unlock ();
1909 return InterlockedExchange64 (location, value);
1913 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1915 LongDoubleUnion val, ret;
1918 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1923 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1925 return InterlockedCompareExchange(location, value, comparand);
1928 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1930 gint32 r = InterlockedCompareExchange(location, value, comparand);
1931 *success = r == comparand;
1935 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1938 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1939 mono_gc_wbarrier_generic_nostore (location);
1943 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1945 return InterlockedCompareExchangePointer(location, value, comparand);
1948 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1950 IntFloatUnion val, ret, cmp;
1953 cmp.fval = comparand;
1954 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1960 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1962 #if SIZEOF_VOID_P == 8
1963 LongDoubleUnion val, comp, ret;
1966 comp.fval = comparand;
1967 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1973 mono_interlocked_lock ();
1975 if (old == comparand)
1977 mono_interlocked_unlock ();
1984 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1986 #if SIZEOF_VOID_P == 4
1987 if (G_UNLIKELY ((size_t)location & 0x7)) {
1989 mono_interlocked_lock ();
1991 if (old == comparand)
1993 mono_interlocked_unlock ();
1997 return InterlockedCompareExchange64 (location, value, comparand);
2001 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2004 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2005 mono_gc_wbarrier_generic_nostore (location);
2010 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2013 MONO_CHECK_NULL (location, NULL);
2014 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2015 mono_gc_wbarrier_generic_nostore (location);
2020 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2022 return InterlockedAdd (location, value);
2026 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2028 #if SIZEOF_VOID_P == 4
2029 if (G_UNLIKELY ((size_t)location & 0x7)) {
2031 mono_interlocked_lock ();
2034 mono_interlocked_unlock ();
2038 return InterlockedAdd64 (location, value);
2042 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2044 #if SIZEOF_VOID_P == 4
2045 if (G_UNLIKELY ((size_t)location & 0x7)) {
2047 mono_interlocked_lock ();
2049 mono_interlocked_unlock ();
2053 return InterlockedRead64 (location);
2057 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2059 mono_memory_barrier ();
2063 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2065 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2067 if (state & ThreadState_Background) {
2068 /* If the thread changes the background mode, the main thread has to
2069 * be notified, since it has to rebuild the list of threads to
2072 mono_w32event_set (background_change_event);
2077 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2079 mono_thread_set_state (this_obj, (MonoThreadState)state);
2081 if (state & ThreadState_Background) {
2082 /* If the thread changes the background mode, the main thread has to
2083 * be notified, since it has to rebuild the list of threads to
2086 mono_w32event_set (background_change_event);
2091 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2095 LOCK_THREAD (this_obj);
2097 state = this_obj->state;
2099 UNLOCK_THREAD (this_obj);
2104 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2106 MonoInternalThread *current;
2108 MonoInternalThread *thread = this_obj->internal_thread;
2110 LOCK_THREAD (thread);
2112 current = mono_thread_internal_current ();
2114 thread->thread_interrupt_requested = TRUE;
2115 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2117 UNLOCK_THREAD (thread);
2120 async_abort_internal (thread, FALSE);
2125 * mono_thread_current_check_pending_interrupt:
2127 * Checks if there's a interruption request and set the pending exception if so.
2129 * @returns true if a pending exception was set
2132 mono_thread_current_check_pending_interrupt (void)
2134 MonoInternalThread *thread = mono_thread_internal_current ();
2135 gboolean throw_ = FALSE;
2137 LOCK_THREAD (thread);
2139 if (thread->thread_interrupt_requested) {
2141 thread->thread_interrupt_requested = FALSE;
2144 UNLOCK_THREAD (thread);
2147 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2152 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2154 LOCK_THREAD (thread);
2156 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2157 (thread->state & ThreadState_StopRequested) != 0 ||
2158 (thread->state & ThreadState_Stopped) != 0)
2160 UNLOCK_THREAD (thread);
2164 if ((thread->state & ThreadState_Unstarted) != 0) {
2165 thread->state |= ThreadState_Aborted;
2166 UNLOCK_THREAD (thread);
2170 thread->state |= ThreadState_AbortRequested;
2171 if (thread->abort_state_handle)
2172 mono_gchandle_free (thread->abort_state_handle);
2174 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2175 g_assert (thread->abort_state_handle);
2177 thread->abort_state_handle = 0;
2179 thread->abort_exc = NULL;
2181 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));
2183 /* During shutdown, we can't wait for other threads */
2185 /* Make sure the thread is awake */
2186 mono_thread_resume (thread);
2188 UNLOCK_THREAD (thread);
2193 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2195 if (!request_thread_abort (thread, state))
2198 if (thread == mono_thread_internal_current ()) {
2200 self_abort_internal (&error);
2201 mono_error_set_pending_exception (&error);
2203 async_abort_internal (thread, TRUE);
2208 * mono_thread_internal_abort:
2210 * Request thread @thread to be aborted.
2212 * @thread MUST NOT be the current thread.
2215 mono_thread_internal_abort (MonoInternalThread *thread)
2217 g_assert (thread != mono_thread_internal_current ());
2219 if (!request_thread_abort (thread, NULL))
2221 async_abort_internal (thread, TRUE);
2225 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2227 MonoInternalThread *thread = mono_thread_internal_current ();
2228 gboolean was_aborting;
2230 LOCK_THREAD (thread);
2231 was_aborting = thread->state & ThreadState_AbortRequested;
2232 thread->state &= ~ThreadState_AbortRequested;
2233 UNLOCK_THREAD (thread);
2235 if (!was_aborting) {
2236 const char *msg = "Unable to reset abort because no abort was requested";
2237 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2240 thread->abort_exc = NULL;
2241 if (thread->abort_state_handle) {
2242 mono_gchandle_free (thread->abort_state_handle);
2243 /* This is actually not necessary - the handle
2244 only counts if the exception is set */
2245 thread->abort_state_handle = 0;
2250 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2252 LOCK_THREAD (thread);
2254 thread->state &= ~ThreadState_AbortRequested;
2256 if (thread->abort_exc) {
2257 thread->abort_exc = NULL;
2258 if (thread->abort_state_handle) {
2259 mono_gchandle_free (thread->abort_state_handle);
2260 /* This is actually not necessary - the handle
2261 only counts if the exception is set */
2262 thread->abort_state_handle = 0;
2266 UNLOCK_THREAD (thread);
2270 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2273 MonoInternalThread *thread = this_obj->internal_thread;
2274 MonoObject *state, *deserialized = NULL;
2277 if (!thread->abort_state_handle)
2280 state = mono_gchandle_get_target (thread->abort_state_handle);
2283 domain = mono_domain_get ();
2284 if (mono_object_domain (state) == domain)
2287 deserialized = mono_object_xdomain_representation (state, domain, &error);
2289 if (!deserialized) {
2290 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2291 if (!is_ok (&error)) {
2292 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2293 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2295 mono_set_pending_exception (invalid_op_exc);
2299 return deserialized;
2303 mono_thread_suspend (MonoInternalThread *thread)
2305 LOCK_THREAD (thread);
2307 if ((thread->state & ThreadState_Unstarted) != 0 ||
2308 (thread->state & ThreadState_Aborted) != 0 ||
2309 (thread->state & ThreadState_Stopped) != 0)
2311 UNLOCK_THREAD (thread);
2315 if ((thread->state & ThreadState_Suspended) != 0 ||
2316 (thread->state & ThreadState_SuspendRequested) != 0 ||
2317 (thread->state & ThreadState_StopRequested) != 0)
2319 UNLOCK_THREAD (thread);
2323 thread->state |= ThreadState_SuspendRequested;
2325 if (thread == mono_thread_internal_current ()) {
2326 /* calls UNLOCK_THREAD (thread) */
2327 self_suspend_internal ();
2329 /* calls UNLOCK_THREAD (thread) */
2330 async_suspend_internal (thread, FALSE);
2337 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2339 if (!mono_thread_suspend (this_obj->internal_thread)) {
2340 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2345 /* LOCKING: LOCK_THREAD(thread) must be held */
2347 mono_thread_resume (MonoInternalThread *thread)
2349 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2350 thread->state &= ~ThreadState_SuspendRequested;
2354 if ((thread->state & ThreadState_Suspended) == 0 ||
2355 (thread->state & ThreadState_Unstarted) != 0 ||
2356 (thread->state & ThreadState_Aborted) != 0 ||
2357 (thread->state & ThreadState_Stopped) != 0)
2362 UNLOCK_THREAD (thread);
2364 /* Awake the thread */
2365 if (!mono_thread_info_resume (thread_get_tid (thread)))
2368 LOCK_THREAD (thread);
2370 thread->state &= ~ThreadState_Suspended;
2376 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2378 if (!thread->internal_thread) {
2379 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2381 LOCK_THREAD (thread->internal_thread);
2382 if (!mono_thread_resume (thread->internal_thread))
2383 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2384 UNLOCK_THREAD (thread->internal_thread);
2389 mono_threads_is_critical_method (MonoMethod *method)
2391 switch (method->wrapper_type) {
2392 case MONO_WRAPPER_RUNTIME_INVOKE:
2393 case MONO_WRAPPER_XDOMAIN_INVOKE:
2394 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2401 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2406 if (mono_threads_is_critical_method (m)) {
2407 *((gboolean*)data) = TRUE;
2414 is_running_protected_wrapper (void)
2416 gboolean found = FALSE;
2417 mono_stack_walk (find_wrapper, &found);
2422 request_thread_stop (MonoInternalThread *thread)
2424 LOCK_THREAD (thread);
2426 if ((thread->state & ThreadState_StopRequested) != 0 ||
2427 (thread->state & ThreadState_Stopped) != 0)
2429 UNLOCK_THREAD (thread);
2433 /* Make sure the thread is awake */
2434 mono_thread_resume (thread);
2436 thread->state |= ThreadState_StopRequested;
2437 thread->state &= ~ThreadState_AbortRequested;
2439 UNLOCK_THREAD (thread);
2444 * mono_thread_internal_stop:
2446 * Request thread @thread to stop.
2448 * @thread MUST NOT be the current thread.
2451 mono_thread_internal_stop (MonoInternalThread *thread)
2453 g_assert (thread != mono_thread_internal_current ());
2455 if (!request_thread_stop (thread))
2458 async_abort_internal (thread, TRUE);
2461 void mono_thread_stop (MonoThread *thread)
2463 MonoInternalThread *internal = thread->internal_thread;
2465 if (!request_thread_stop (internal))
2468 if (internal == mono_thread_internal_current ()) {
2470 self_abort_internal (&error);
2472 This function is part of the embeding API and has no way to return the exception
2473 to be thrown. So what we do is keep the old behavior and raise the exception.
2475 mono_error_raise_exception (&error); /* OK to throw, see note */
2477 async_abort_internal (internal, TRUE);
2482 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2484 gint8 tmp = *(volatile gint8 *)ptr;
2485 mono_memory_barrier ();
2490 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2492 gint16 tmp = *(volatile gint16 *)ptr;
2493 mono_memory_barrier ();
2498 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2500 gint32 tmp = *(volatile gint32 *)ptr;
2501 mono_memory_barrier ();
2506 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2508 gint64 tmp = *(volatile gint64 *)ptr;
2509 mono_memory_barrier ();
2514 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2516 volatile void *tmp = *(volatile void **)ptr;
2517 mono_memory_barrier ();
2518 return (void *) tmp;
2522 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2524 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2525 mono_memory_barrier ();
2526 return (MonoObject *) tmp;
2530 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2532 double tmp = *(volatile double *)ptr;
2533 mono_memory_barrier ();
2538 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2540 float tmp = *(volatile float *)ptr;
2541 mono_memory_barrier ();
2546 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2548 return InterlockedRead8 ((volatile gint8 *)ptr);
2552 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2554 return InterlockedRead16 ((volatile gint16 *)ptr);
2558 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2560 return InterlockedRead ((volatile gint32 *)ptr);
2564 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2566 #if SIZEOF_VOID_P == 4
2567 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2569 mono_interlocked_lock ();
2570 val = *(gint64*)ptr;
2571 mono_interlocked_unlock ();
2575 return InterlockedRead64 ((volatile gint64 *)ptr);
2579 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2581 return InterlockedReadPointer ((volatile gpointer *)ptr);
2585 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2589 #if SIZEOF_VOID_P == 4
2590 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2592 mono_interlocked_lock ();
2593 val = *(double*)ptr;
2594 mono_interlocked_unlock ();
2599 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2605 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2609 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2615 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2617 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2621 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2623 mono_memory_barrier ();
2624 *(volatile gint8 *)ptr = value;
2628 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2630 mono_memory_barrier ();
2631 *(volatile gint16 *)ptr = value;
2635 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2637 mono_memory_barrier ();
2638 *(volatile gint32 *)ptr = value;
2642 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2644 mono_memory_barrier ();
2645 *(volatile gint64 *)ptr = value;
2649 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2651 mono_memory_barrier ();
2652 *(volatile void **)ptr = value;
2656 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2658 mono_memory_barrier ();
2659 mono_gc_wbarrier_generic_store (ptr, value);
2663 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2665 mono_memory_barrier ();
2666 *(volatile double *)ptr = value;
2670 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2672 mono_memory_barrier ();
2673 *(volatile float *)ptr = value;
2677 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2679 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2683 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2685 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2689 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2691 InterlockedWrite ((volatile gint32 *)ptr, value);
2695 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2697 #if SIZEOF_VOID_P == 4
2698 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2699 mono_interlocked_lock ();
2700 *(gint64*)ptr = value;
2701 mono_interlocked_unlock ();
2706 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2710 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2712 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2716 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2720 #if SIZEOF_VOID_P == 4
2721 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2722 mono_interlocked_lock ();
2723 *(double*)ptr = value;
2724 mono_interlocked_unlock ();
2731 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2735 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2741 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2745 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2747 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2751 free_context (void *user_data)
2753 ContextStaticData *data = user_data;
2755 mono_threads_lock ();
2758 * There is no guarantee that, by the point this reference queue callback
2759 * has been invoked, the GC handle associated with the object will fail to
2760 * resolve as one might expect. So if we don't free and remove the GC
2761 * handle here, free_context_static_data_helper () could end up resolving
2762 * a GC handle to an actually-dead context which would contain a pointer
2763 * to an already-freed static data segment, resulting in a crash when
2766 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2768 mono_threads_unlock ();
2770 mono_gchandle_free (data->gc_handle);
2771 mono_free_static_data (data->static_data);
2776 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2778 mono_threads_lock ();
2780 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2783 contexts = g_hash_table_new (NULL, NULL);
2786 context_queue = mono_gc_reference_queue_new (free_context);
2788 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2789 g_hash_table_insert (contexts, gch, gch);
2792 * We use this intermediate structure to contain a duplicate pointer to
2793 * the static data because we can't rely on being able to resolve the GC
2794 * handle in the reference queue callback.
2796 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2797 data->gc_handle = GPOINTER_TO_UINT (gch);
2800 context_adjust_static_data (ctx);
2801 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2803 mono_threads_unlock ();
2805 mono_profiler_context_loaded (ctx);
2809 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2812 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2813 * cleanup in exceptional circumstances, we don't actually do any
2814 * cleanup work here. We instead do this via a reference queue.
2817 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2819 mono_profiler_context_unloaded (ctx);
2823 mono_thread_init_tls (void)
2825 MONO_FAST_TLS_INIT (tls_current_object);
2826 mono_native_tls_alloc (¤t_object_key, NULL);
2829 void mono_thread_init (MonoThreadStartCB start_cb,
2830 MonoThreadAttachCB attach_cb)
2832 mono_coop_mutex_init_recursive (&threads_mutex);
2834 mono_os_mutex_init_recursive(&interlocked_mutex);
2835 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2837 background_change_event = mono_w32event_create (TRUE, FALSE);
2838 g_assert(background_change_event != NULL);
2840 mono_init_static_data_info (&thread_static_info);
2841 mono_init_static_data_info (&context_static_info);
2843 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2845 mono_thread_start_cb = start_cb;
2846 mono_thread_attach_cb = attach_cb;
2848 /* Get a pseudo handle to the current process. This is just a
2849 * kludge so that wapi can build a process handle if needed.
2850 * As a pseudo handle is returned, we don't need to clean
2853 GetCurrentProcess ();
2856 void mono_thread_cleanup (void)
2858 #if !defined(RUN_IN_SUBTHREAD)
2859 /* The main thread must abandon any held mutexes (particularly
2860 * important for named mutexes as they are shared across
2861 * processes, see bug 74680.) This will happen when the
2862 * thread exits, but if it's not running in a subthread it
2863 * won't exit in time.
2865 mono_thread_info_set_exited (mono_thread_info_current ());
2869 /* This stuff needs more testing, it seems one of these
2870 * critical sections can be locked when mono_thread_cleanup is
2873 mono_coop_mutex_destroy (&threads_mutex);
2874 mono_os_mutex_destroy (&interlocked_mutex);
2875 mono_os_mutex_destroy (&delayed_free_table_mutex);
2876 mono_os_mutex_destroy (&small_id_mutex);
2877 CloseHandle (background_change_event);
2880 mono_native_tls_free (current_object_key);
2884 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2886 mono_thread_cleanup_fn = func;
2890 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2892 thread->internal_thread->manage_callback = func;
2896 static void print_tids (gpointer key, gpointer value, gpointer user)
2898 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2899 * sizeof(uint) and a cast to uint would overflow
2901 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2902 * print this as a pointer.
2904 g_message ("Waiting for: %p", key);
2909 HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2910 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2915 wait_for_tids (struct wait_data *wait, guint32 timeout)
2919 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2922 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2925 if(ret==WAIT_FAILED) {
2926 /* See the comment in build_wait_tids() */
2927 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2931 for(i=0; i<wait->num; i++)
2932 mono_threads_close_thread_handle (wait->handles [i]);
2934 if (ret == WAIT_TIMEOUT)
2937 for(i=0; i<wait->num; i++) {
2938 MonoInternalThread *internal;
2940 internal = wait->threads [i];
2942 mono_threads_lock ();
2943 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
2944 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
2945 mono_threads_unlock ();
2949 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2951 guint32 i, ret, count;
2953 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2955 /* Add the thread state change event, so it wakes up if a thread changes
2956 * to background mode.
2959 if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
2960 wait->handles [count] = background_change_event;
2965 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2968 if(ret==WAIT_FAILED) {
2969 /* See the comment in build_wait_tids() */
2970 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2974 for(i=0; i<wait->num; i++)
2975 mono_threads_close_thread_handle (wait->handles [i]);
2977 if (ret == WAIT_TIMEOUT)
2980 if (ret < wait->num) {
2981 MonoInternalThread *internal;
2983 internal = wait->threads [ret];
2985 mono_threads_lock ();
2986 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
2987 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
2988 mono_threads_unlock ();
2992 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2994 struct wait_data *wait=(struct wait_data *)user;
2996 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
2998 MonoInternalThread *thread=(MonoInternalThread *)value;
3000 /* Ignore background threads, we abort them later */
3001 /* Do not lock here since it is not needed and the caller holds threads_lock */
3002 if (thread->state & ThreadState_Background) {
3003 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3004 return; /* just leave, ignore */
3007 if (mono_gc_is_finalizer_internal_thread (thread)) {
3008 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3012 if (thread == mono_thread_internal_current ()) {
3013 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3017 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3018 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3022 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3023 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3027 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3028 if (handle == NULL) {
3029 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3033 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3034 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3035 wait->handles[wait->num]=handle;
3036 wait->threads[wait->num]=thread;
3039 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3041 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3046 /* Just ignore the rest, we can't do anything with
3053 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3055 struct wait_data *wait=(struct wait_data *)user;
3056 MonoNativeThreadId self = mono_native_thread_id_get ();
3057 MonoInternalThread *thread = (MonoInternalThread *)value;
3060 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3063 /* The finalizer thread is not a background thread */
3064 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3065 && (thread->state & ThreadState_Background) != 0
3066 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3068 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3072 wait->handles[wait->num] = handle;
3073 wait->threads[wait->num] = thread;
3076 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3077 mono_thread_internal_abort (thread);
3081 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3082 && !mono_gc_is_finalizer_internal_thread (thread);
3086 * mono_threads_set_shutting_down:
3088 * Is called by a thread that wants to shut down Mono. If the runtime is already
3089 * shutting down, the calling thread is suspended/stopped, and this function never
3093 mono_threads_set_shutting_down (void)
3095 MonoInternalThread *current_thread = mono_thread_internal_current ();
3097 mono_threads_lock ();
3099 if (shutting_down) {
3100 mono_threads_unlock ();
3102 /* Make sure we're properly suspended/stopped */
3104 LOCK_THREAD (current_thread);
3106 if ((current_thread->state & ThreadState_SuspendRequested) ||
3107 (current_thread->state & ThreadState_AbortRequested) ||
3108 (current_thread->state & ThreadState_StopRequested)) {
3109 UNLOCK_THREAD (current_thread);
3110 mono_thread_execute_interruption ();
3112 current_thread->state |= ThreadState_Stopped;
3113 UNLOCK_THREAD (current_thread);
3116 /*since we're killing the thread, detach it.*/
3117 mono_thread_detach_internal (current_thread);
3119 /* Wake up other threads potentially waiting for us */
3120 mono_thread_info_exit ();
3122 shutting_down = TRUE;
3124 /* Not really a background state change, but this will
3125 * interrupt the main thread if it is waiting for all
3126 * the other threads.
3128 mono_w32event_set (background_change_event);
3130 mono_threads_unlock ();
3134 void mono_thread_manage (void)
3136 struct wait_data wait_data;
3137 struct wait_data *wait = &wait_data;
3139 memset (wait, 0, sizeof (struct wait_data));
3140 /* join each thread that's still running */
3141 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3143 mono_threads_lock ();
3145 THREAD_DEBUG (g_message("%s: No threads", __func__));
3146 mono_threads_unlock ();
3149 mono_threads_unlock ();
3152 mono_threads_lock ();
3153 if (shutting_down) {
3154 /* somebody else is shutting down */
3155 mono_threads_unlock ();
3158 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3159 mono_g_hash_table_foreach (threads, print_tids, NULL));
3161 mono_w32event_reset (background_change_event);
3163 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3164 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3165 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3166 mono_threads_unlock ();
3168 /* Something to wait for */
3169 wait_for_tids_or_state_change (wait, INFINITE);
3171 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3172 } while(wait->num>0);
3174 /* Mono is shutting down, so just wait for the end */
3175 if (!mono_runtime_try_shutdown ()) {
3176 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3177 mono_thread_suspend (mono_thread_internal_current ());
3178 mono_thread_execute_interruption ();
3182 * Remove everything but the finalizer thread and self.
3183 * Also abort all the background threads
3186 mono_threads_lock ();
3189 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3190 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3191 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3193 mono_threads_unlock ();
3195 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3197 /* Something to wait for */
3198 wait_for_tids (wait, INFINITE);
3200 } while (wait->num > 0);
3203 * give the subthreads a chance to really quit (this is mainly needed
3204 * to get correct user and system times from getrusage/wait/time(1)).
3205 * This could be removed if we avoid pthread_detach() and use pthread_join().
3207 mono_thread_info_yield ();
3211 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3213 MonoInternalThread *thread = (MonoInternalThread*)value;
3214 struct wait_data *wait = (struct wait_data*)user_data;
3218 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3220 * This needs no locking.
3222 if ((thread->state & ThreadState_Suspended) != 0 ||
3223 (thread->state & ThreadState_Stopped) != 0)
3226 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3227 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3231 wait->handles [wait->num] = handle;
3232 wait->threads [wait->num] = thread;
3238 * mono_thread_suspend_all_other_threads:
3240 * Suspend all managed threads except the finalizer thread and this thread. It is
3241 * not possible to resume them later.
3243 void mono_thread_suspend_all_other_threads (void)
3245 struct wait_data wait_data;
3246 struct wait_data *wait = &wait_data;
3248 MonoNativeThreadId self = mono_native_thread_id_get ();
3249 guint32 eventidx = 0;
3250 gboolean starting, finished;
3252 memset (wait, 0, sizeof (struct wait_data));
3254 * The other threads could be in an arbitrary state at this point, i.e.
3255 * they could be starting up, shutting down etc. This means that there could be
3256 * threads which are not even in the threads hash table yet.
3260 * First we set a barrier which will be checked by all threads before they
3261 * are added to the threads hash table, and they will exit if the flag is set.
3262 * This ensures that no threads could be added to the hash later.
3263 * We will use shutting_down as the barrier for now.
3265 g_assert (shutting_down);
3268 * We make multiple calls to WaitForMultipleObjects since:
3269 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3270 * - some threads could exit without becoming suspended
3275 * Make a copy of the hashtable since we can't do anything with
3276 * threads while threads_mutex is held.
3279 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3280 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3281 mono_threads_lock ();
3282 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3283 mono_threads_unlock ();
3286 /* Get the suspended events that we'll be waiting for */
3287 for (i = 0; i < wait->num; ++i) {
3288 MonoInternalThread *thread = wait->threads [i];
3290 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3291 || mono_gc_is_finalizer_internal_thread (thread)
3292 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3294 //mono_threads_close_thread_handle (wait->handles [i]);
3295 wait->threads [i] = NULL; /* ignore this thread in next loop */
3299 LOCK_THREAD (thread);
3301 if ((thread->state & ThreadState_Suspended) != 0 ||
3302 (thread->state & ThreadState_StopRequested) != 0 ||
3303 (thread->state & ThreadState_Stopped) != 0) {
3304 UNLOCK_THREAD (thread);
3305 mono_threads_close_thread_handle (wait->handles [i]);
3306 wait->threads [i] = NULL; /* ignore this thread in next loop */
3312 /* Convert abort requests into suspend requests */
3313 if ((thread->state & ThreadState_AbortRequested) != 0)
3314 thread->state &= ~ThreadState_AbortRequested;
3316 thread->state |= ThreadState_SuspendRequested;
3318 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3319 async_suspend_internal (thread, TRUE);
3321 if (eventidx <= 0) {
3323 * If there are threads which are starting up, we wait until they
3324 * are suspended when they try to register in the threads hash.
3325 * This is guaranteed to finish, since the threads which can create new
3326 * threads get suspended after a while.
3327 * FIXME: The finalizer thread can still create new threads.
3329 mono_threads_lock ();
3330 if (threads_starting_up)
3331 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3334 mono_threads_unlock ();
3336 mono_thread_info_sleep (100, NULL);
3344 MonoInternalThread *thread;
3345 MonoStackFrameInfo *frames;
3346 int nframes, max_frames;
3347 int nthreads, max_threads;
3348 MonoInternalThread **threads;
3349 } ThreadDumpUserData;
3351 static gboolean thread_dump_requested;
3353 /* This needs to be async safe */
3355 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3357 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3359 if (ud->nframes < ud->max_frames) {
3360 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3367 /* This needs to be async safe */
3368 static SuspendThreadResult
3369 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3371 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3372 MonoInternalThread *thread = user_data->thread;
3375 /* This no longer works with remote unwinding */
3376 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3377 mono_thread_internal_describe (thread, text);
3378 g_string_append (text, "\n");
3381 if (thread == mono_thread_internal_current ())
3382 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3384 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3386 return MonoResumeThread;
3390 int nthreads, max_threads;
3391 MonoInternalThread **threads;
3392 } CollectThreadsUserData;
3395 collect_thread (gpointer key, gpointer value, gpointer user)
3397 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3398 MonoInternalThread *thread = (MonoInternalThread *)value;
3400 if (ud->nthreads < ud->max_threads)
3401 ud->threads [ud->nthreads ++] = thread;
3405 * Collect running threads into the THREADS array.
3406 * THREADS should be an array allocated on the stack.
3409 collect_threads (MonoInternalThread **thread_array, int max_threads)
3411 CollectThreadsUserData ud;
3413 memset (&ud, 0, sizeof (ud));
3414 /* This array contains refs, but its on the stack, so its ok */
3415 ud.threads = thread_array;
3416 ud.max_threads = max_threads;
3418 mono_threads_lock ();
3419 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3420 mono_threads_unlock ();
3426 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3428 GString* text = g_string_new (0);
3430 GError *error = NULL;
3433 ud->thread = thread;
3436 /* Collect frames for the thread */
3437 if (thread == mono_thread_internal_current ()) {
3438 get_thread_dump (mono_thread_info_current (), ud);
3440 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3444 * Do all the non async-safe work outside of get_thread_dump.
3447 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3449 g_string_append_printf (text, "\n\"%s\"", name);
3452 else if (thread->threadpool_thread) {
3453 g_string_append (text, "\n\"<threadpool thread>\"");
3455 g_string_append (text, "\n\"<unnamed thread>\"");
3458 for (i = 0; i < ud->nframes; ++i) {
3459 MonoStackFrameInfo *frame = &ud->frames [i];
3460 MonoMethod *method = NULL;
3462 if (frame->type == FRAME_TYPE_MANAGED)
3463 method = mono_jit_info_get_method (frame->ji);
3466 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3467 g_string_append_printf (text, " %s\n", location);
3470 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3474 fprintf (stdout, "%s", text->str);
3476 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3477 OutputDebugStringA(text->str);
3480 g_string_free (text, TRUE);
3485 mono_threads_perform_thread_dump (void)
3487 ThreadDumpUserData ud;
3488 MonoInternalThread *thread_array [128];
3489 int tindex, nthreads;
3491 if (!thread_dump_requested)
3494 printf ("Full thread dump:\n");
3496 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3497 nthreads = collect_threads (thread_array, 128);
3499 memset (&ud, 0, sizeof (ud));
3500 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3501 ud.max_frames = 256;
3503 for (tindex = 0; tindex < nthreads; ++tindex)
3504 dump_thread (thread_array [tindex], &ud);
3508 thread_dump_requested = FALSE;
3511 /* Obtain the thread dump of all threads */
3513 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3516 ThreadDumpUserData ud;
3517 MonoInternalThread *thread_array [128];
3518 MonoDomain *domain = mono_domain_get ();
3519 MonoDebugSourceLocation *location;
3520 int tindex, nthreads;
3522 mono_error_init (error);
3524 *out_threads = NULL;
3525 *out_stack_frames = NULL;
3527 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3528 nthreads = collect_threads (thread_array, 128);
3530 memset (&ud, 0, sizeof (ud));
3531 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3532 ud.max_frames = 256;
3534 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3537 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3541 for (tindex = 0; tindex < nthreads; ++tindex) {
3542 MonoInternalThread *thread = thread_array [tindex];
3543 MonoArray *thread_frames;
3549 /* Collect frames for the thread */
3550 if (thread == mono_thread_internal_current ()) {
3551 get_thread_dump (mono_thread_info_current (), &ud);
3553 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3556 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3558 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3561 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3563 for (i = 0; i < ud.nframes; ++i) {
3564 MonoStackFrameInfo *frame = &ud.frames [i];
3565 MonoMethod *method = NULL;
3566 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3570 sf->native_offset = frame->native_offset;
3572 if (frame->type == FRAME_TYPE_MANAGED)
3573 method = mono_jit_info_get_method (frame->ji);
3576 sf->method_address = (gsize) frame->ji->code_start;
3578 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3581 MONO_OBJECT_SETREF (sf, method, rm);
3583 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3585 sf->il_offset = location->il_offset;
3587 if (location && location->source_file) {
3588 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3589 sf->line = location->row;
3590 sf->column = location->column;
3592 mono_debug_free_source_location (location);
3597 mono_array_setref (thread_frames, i, sf);
3603 return is_ok (error);
3607 * mono_threads_request_thread_dump:
3609 * Ask all threads except the current to print their stacktrace to stdout.
3612 mono_threads_request_thread_dump (void)
3614 /*The new thread dump code runs out of the finalizer thread. */
3615 thread_dump_requested = TRUE;
3616 mono_gc_finalize_notify ();
3621 gint allocated; /* +1 so that refs [allocated] == NULL */
3625 typedef struct ref_stack RefStack;
3628 ref_stack_new (gint initial_size)
3632 initial_size = MAX (initial_size, 16) + 1;
3633 rs = g_new0 (RefStack, 1);
3634 rs->refs = g_new0 (gpointer, initial_size);
3635 rs->allocated = initial_size;
3640 ref_stack_destroy (gpointer ptr)
3642 RefStack *rs = (RefStack *)ptr;
3651 ref_stack_push (RefStack *rs, gpointer ptr)
3653 g_assert (rs != NULL);
3655 if (rs->bottom >= rs->allocated) {
3656 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3657 rs->allocated <<= 1;
3658 rs->refs [rs->allocated] = NULL;
3660 rs->refs [rs->bottom++] = ptr;
3664 ref_stack_pop (RefStack *rs)
3666 if (rs == NULL || rs->bottom == 0)
3670 rs->refs [rs->bottom] = NULL;
3674 ref_stack_find (RefStack *rs, gpointer ptr)
3681 for (refs = rs->refs; refs && *refs; refs++) {
3689 * mono_thread_push_appdomain_ref:
3691 * Register that the current thread may have references to objects in domain
3692 * @domain on its stack. Each call to this function should be paired with a
3693 * call to pop_appdomain_ref.
3696 mono_thread_push_appdomain_ref (MonoDomain *domain)
3698 MonoInternalThread *thread = mono_thread_internal_current ();
3701 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3702 SPIN_LOCK (thread->lock_thread_id);
3703 if (thread->appdomain_refs == NULL)
3704 thread->appdomain_refs = ref_stack_new (16);
3705 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3706 SPIN_UNLOCK (thread->lock_thread_id);
3711 mono_thread_pop_appdomain_ref (void)
3713 MonoInternalThread *thread = mono_thread_internal_current ();
3716 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3717 SPIN_LOCK (thread->lock_thread_id);
3718 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3719 SPIN_UNLOCK (thread->lock_thread_id);
3724 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3727 SPIN_LOCK (thread->lock_thread_id);
3728 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3729 SPIN_UNLOCK (thread->lock_thread_id);
3734 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3736 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3739 typedef struct abort_appdomain_data {
3740 struct wait_data wait;
3742 } abort_appdomain_data;
3745 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3747 MonoInternalThread *thread = (MonoInternalThread*)value;
3748 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3749 MonoDomain *domain = data->domain;
3751 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3752 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3754 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3755 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3758 data->wait.handles [data->wait.num] = handle;
3759 data->wait.threads [data->wait.num] = thread;
3762 /* Just ignore the rest, we can't do anything with
3770 * mono_threads_abort_appdomain_threads:
3772 * Abort threads which has references to the given appdomain.
3775 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3777 #ifdef __native_client__
3781 abort_appdomain_data user_data;
3783 int orig_timeout = timeout;
3786 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3788 start_time = mono_msec_ticks ();
3790 mono_threads_lock ();
3792 user_data.domain = domain;
3793 user_data.wait.num = 0;
3794 /* This shouldn't take any locks */
3795 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3796 mono_threads_unlock ();
3798 if (user_data.wait.num > 0) {
3799 /* Abort the threads outside the threads lock */
3800 for (i = 0; i < user_data.wait.num; ++i)
3801 mono_thread_internal_abort (user_data.wait.threads [i]);
3804 * We should wait for the threads either to abort, or to leave the
3805 * domain. We can't do the latter, so we wait with a timeout.
3807 wait_for_tids (&user_data.wait, 100);
3810 /* Update remaining time */
3811 timeout -= mono_msec_ticks () - start_time;
3812 start_time = mono_msec_ticks ();
3814 if (orig_timeout != -1 && timeout < 0)
3817 while (user_data.wait.num > 0);
3819 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3825 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3827 MonoInternalThread *thread = (MonoInternalThread*)value;
3828 MonoDomain *domain = (MonoDomain*)user_data;
3831 /* No locking needed here */
3832 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3834 if (thread->cached_culture_info) {
3835 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3836 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3837 if (obj && obj->vtable->domain == domain)
3838 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3844 * mono_threads_clear_cached_culture:
3846 * Clear the cached_current_culture from all threads if it is in the
3850 mono_threads_clear_cached_culture (MonoDomain *domain)
3852 mono_threads_lock ();
3853 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3854 mono_threads_unlock ();
3858 * mono_thread_get_undeniable_exception:
3860 * Return an exception which needs to be raised when leaving a catch clause.
3861 * This is used for undeniable exception propagation.
3864 mono_thread_get_undeniable_exception (void)
3866 MonoInternalThread *thread = mono_thread_internal_current ();
3868 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3870 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3871 * exception if the thread no longer references a dying appdomain.
3873 thread->abort_exc->trace_ips = NULL;
3874 thread->abort_exc->stack_trace = NULL;
3875 return thread->abort_exc;
3881 #if MONO_SMALL_CONFIG
3882 #define NUM_STATIC_DATA_IDX 4
3883 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3887 #define NUM_STATIC_DATA_IDX 8
3888 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3889 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3893 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3894 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3897 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3899 gpointer *static_data = (gpointer *)addr;
3901 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3902 void **ptr = (void **)static_data [i];
3907 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3908 void **p = ptr + idx;
3911 mark_func ((MonoObject**)p, gc_data);
3917 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3919 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3923 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3925 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3929 * mono_alloc_static_data
3931 * Allocate memory blocks for storing threads or context static data
3934 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3936 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3939 gpointer* static_data = *static_data_ptr;
3941 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3942 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3944 if (mono_gc_user_markers_supported ()) {
3945 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3946 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3948 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3949 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3952 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3953 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3954 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3955 *static_data_ptr = static_data;
3956 static_data [0] = static_data;
3959 for (i = 1; i <= idx; ++i) {
3960 if (static_data [i])
3963 if (mono_gc_user_markers_supported ())
3964 static_data [i] = g_malloc0 (static_data_size [i]);
3966 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3967 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3968 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3973 mono_free_static_data (gpointer* static_data)
3976 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3977 gpointer p = static_data [i];
3981 * At this point, the static data pointer array is still registered with the
3982 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3983 * data. Freeing the individual arrays without first nulling their slots
3984 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3985 * such an already freed array. See bug #13813.
3987 static_data [i] = NULL;
3988 mono_memory_write_barrier ();
3989 if (mono_gc_user_markers_supported ())
3992 mono_gc_free_fixed (p);
3994 mono_gc_free_fixed (static_data);
3998 * mono_init_static_data_info
4000 * Initializes static data counters
4002 static void mono_init_static_data_info (StaticDataInfo *static_data)
4004 static_data->idx = 0;
4005 static_data->offset = 0;
4006 static_data->freelist = NULL;
4010 * mono_alloc_static_data_slot
4012 * Generates an offset for static data. static_data contains the counters
4013 * used to generate it.
4016 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4018 if (!static_data->idx && !static_data->offset) {
4020 * we use the first chunk of the first allocation also as
4021 * an array for the rest of the data
4023 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4025 static_data->offset += align - 1;
4026 static_data->offset &= ~(align - 1);
4027 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4028 static_data->idx ++;
4029 g_assert (size <= static_data_size [static_data->idx]);
4030 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4031 static_data->offset = 0;
4033 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4034 static_data->offset += size;
4039 * LOCKING: requires that threads_mutex is held
4042 context_adjust_static_data (MonoAppContext *ctx)
4044 if (context_static_info.offset || context_static_info.idx > 0) {
4045 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4046 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4047 ctx->data->static_data = ctx->static_data;
4052 * LOCKING: requires that threads_mutex is held
4055 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4057 MonoInternalThread *thread = (MonoInternalThread *)value;
4058 guint32 offset = GPOINTER_TO_UINT (user);
4060 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4064 * LOCKING: requires that threads_mutex is held
4067 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4069 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4074 guint32 offset = GPOINTER_TO_UINT (user);
4075 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4076 ctx->data->static_data = ctx->static_data;
4079 static StaticDataFreeList*
4080 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4082 StaticDataFreeList* prev = NULL;
4083 StaticDataFreeList* tmp = static_data->freelist;
4085 if (tmp->size == size) {
4087 prev->next = tmp->next;
4089 static_data->freelist = tmp->next;
4098 #if SIZEOF_VOID_P == 4
4105 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4107 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4109 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4110 MonoBitSet *rb = sets [idx];
4111 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4112 offset /= sizeof (uintptr_t);
4113 /* offset is now the bitmap offset */
4114 for (int i = 0; i < numbits; ++i) {
4115 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4116 mono_bitset_set_fast (rb, offset + i);
4121 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4123 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4124 MonoBitSet *rb = sets [idx];
4125 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4126 offset /= sizeof (uintptr_t);
4127 /* offset is now the bitmap offset */
4128 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4129 mono_bitset_clear_fast (rb, offset + i);
4133 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4135 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4137 StaticDataInfo *info;
4140 if (static_type == SPECIAL_STATIC_THREAD) {
4141 info = &thread_static_info;
4142 sets = thread_reference_bitmaps;
4144 info = &context_static_info;
4145 sets = context_reference_bitmaps;
4148 mono_threads_lock ();
4150 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4154 offset = item->offset;
4157 offset = mono_alloc_static_data_slot (info, size, align);
4160 update_reference_bitmap (sets, offset, bitmap, numbits);
4162 if (static_type == SPECIAL_STATIC_THREAD) {
4163 /* This can be called during startup */
4164 if (threads != NULL)
4165 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4167 if (contexts != NULL)
4168 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4170 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4173 mono_threads_unlock ();
4179 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4181 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4183 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4184 return get_thread_static_data (thread, offset);
4186 return get_context_static_data (thread->current_appcontext, offset);
4191 mono_get_special_static_data (guint32 offset)
4193 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4202 * LOCKING: requires that threads_mutex is held
4205 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4207 MonoInternalThread *thread = (MonoInternalThread *)value;
4208 OffsetSize *data = (OffsetSize *)user;
4209 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4210 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4213 if (!thread->static_data || !thread->static_data [idx])
4215 ptr = ((char*) thread->static_data [idx]) + off;
4216 mono_gc_bzero_atomic (ptr, data->size);
4220 * LOCKING: requires that threads_mutex is held
4223 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4225 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4230 OffsetSize *data = (OffsetSize *)user;
4231 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4232 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4235 if (!ctx->static_data || !ctx->static_data [idx])
4238 ptr = ((char*) ctx->static_data [idx]) + off;
4239 mono_gc_bzero_atomic (ptr, data->size);
4243 do_free_special_slot (guint32 offset, guint32 size)
4245 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4247 StaticDataInfo *info;
4249 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4250 info = &thread_static_info;
4251 sets = thread_reference_bitmaps;
4253 info = &context_static_info;
4254 sets = context_reference_bitmaps;
4257 guint32 data_offset = offset;
4258 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4259 OffsetSize data = { data_offset, size };
4261 clear_reference_bitmap (sets, data.offset, data.size);
4263 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4264 if (threads != NULL)
4265 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4267 if (contexts != NULL)
4268 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4271 if (!mono_runtime_is_shutting_down ()) {
4272 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4274 item->offset = offset;
4277 item->next = info->freelist;
4278 info->freelist = item;
4283 do_free_special (gpointer key, gpointer value, gpointer data)
4285 MonoClassField *field = (MonoClassField *)key;
4286 guint32 offset = GPOINTER_TO_UINT (value);
4289 size = mono_type_size (field->type, &align);
4290 do_free_special_slot (offset, size);
4294 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4296 mono_threads_lock ();
4298 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4300 mono_threads_unlock ();
4304 static void CALLBACK dummy_apc (ULONG_PTR param)
4310 * mono_thread_execute_interruption
4312 * Performs the operation that the requested thread state requires (abort,
4315 static MonoException*
4316 mono_thread_execute_interruption (void)
4318 MonoInternalThread *thread = mono_thread_internal_current ();
4319 MonoThread *sys_thread = mono_thread_current ();
4321 LOCK_THREAD (thread);
4323 /* MonoThread::interruption_requested can only be changed with atomics */
4324 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4325 /* this will consume pending APC calls */
4327 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4329 InterlockedDecrement (&thread_interruption_requested);
4331 /* Clear the interrupted flag of the thread so it can wait again */
4332 mono_thread_info_clear_self_interrupt ();
4335 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4336 if (sys_thread->pending_exception) {
4339 exc = sys_thread->pending_exception;
4340 sys_thread->pending_exception = NULL;
4342 UNLOCK_THREAD (thread);
4344 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4345 UNLOCK_THREAD (thread);
4346 g_assert (sys_thread->pending_exception == NULL);
4347 if (thread->abort_exc == NULL) {
4349 * This might be racy, but it has to be called outside the lock
4350 * since it calls managed code.
4352 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4354 return thread->abort_exc;
4356 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4357 /* calls UNLOCK_THREAD (thread) */
4358 self_suspend_internal ();
4361 else if ((thread->state & ThreadState_StopRequested) != 0) {
4362 /* FIXME: do this through the JIT? */
4364 UNLOCK_THREAD (thread);
4366 mono_thread_exit ();
4368 } else if (thread->thread_interrupt_requested) {
4370 thread->thread_interrupt_requested = FALSE;
4371 UNLOCK_THREAD (thread);
4373 return(mono_get_exception_thread_interrupted ());
4376 UNLOCK_THREAD (thread);
4382 * mono_thread_request_interruption
4384 * A signal handler can call this method to request the interruption of a
4385 * thread. The result of the interruption will depend on the current state of
4386 * the thread. If the result is an exception that needs to be throw, it is
4387 * provided as return value.
4390 mono_thread_request_interruption (gboolean running_managed)
4392 MonoInternalThread *thread = mono_thread_internal_current ();
4394 /* The thread may already be stopping */
4399 if (thread->interrupt_on_stop &&
4400 thread->state & ThreadState_StopRequested &&
4401 thread->state & ThreadState_Background)
4404 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4406 InterlockedIncrement (&thread_interruption_requested);
4408 if (!running_managed || is_running_protected_wrapper ()) {
4409 /* Can't stop while in unmanaged code. Increase the global interruption
4410 request count. When exiting the unmanaged method the count will be
4411 checked and the thread will be interrupted. */
4413 /* this will awake the thread if it is in WaitForSingleObject
4415 /* Our implementation of this function ignores the func argument */
4417 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4419 mono_thread_info_self_interrupt ();
4424 return mono_thread_execute_interruption ();
4428 /*This function should be called by a thread after it has exited all of
4429 * its handle blocks at interruption time.*/
4431 mono_thread_resume_interruption (void)
4433 MonoInternalThread *thread = mono_thread_internal_current ();
4434 gboolean still_aborting;
4436 /* The thread may already be stopping */
4440 LOCK_THREAD (thread);
4441 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4442 UNLOCK_THREAD (thread);
4444 /*This can happen if the protected block called Thread::ResetAbort*/
4445 if (!still_aborting)
4448 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4450 InterlockedIncrement (&thread_interruption_requested);
4452 mono_thread_info_self_interrupt ();
4454 return mono_thread_execute_interruption ();
4457 gboolean mono_thread_interruption_requested ()
4459 if (thread_interruption_requested) {
4460 MonoInternalThread *thread = mono_thread_internal_current ();
4461 /* The thread may already be stopping */
4463 return (thread->interruption_requested);
4468 static MonoException*
4469 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4471 MonoInternalThread *thread = mono_thread_internal_current ();
4473 /* The thread may already be stopping */
4477 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4478 MonoException* exc = mono_thread_execute_interruption ();
4486 * Performs the interruption of the current thread, if one has been requested,
4487 * and the thread is not running a protected wrapper.
4488 * Return the exception which needs to be thrown, if any.
4491 mono_thread_interruption_checkpoint (void)
4493 return mono_thread_interruption_checkpoint_request (FALSE);
4497 * Performs the interruption of the current thread, if one has been requested.
4498 * Return the exception which needs to be thrown, if any.
4501 mono_thread_force_interruption_checkpoint_noraise (void)
4503 return mono_thread_interruption_checkpoint_request (TRUE);
4507 * mono_set_pending_exception:
4509 * Set the pending exception of the current thread to EXC.
4510 * The exception will be thrown when execution returns to managed code.
4513 mono_set_pending_exception (MonoException *exc)
4515 MonoThread *thread = mono_thread_current ();
4517 /* The thread may already be stopping */
4521 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4523 mono_thread_request_interruption (FALSE);
4527 * mono_thread_interruption_request_flag:
4529 * Returns the address of a flag that will be non-zero if an interruption has
4530 * been requested for a thread. The thread to interrupt may not be the current
4531 * thread, so an additional call to mono_thread_interruption_requested() or
4532 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4535 gint32* mono_thread_interruption_request_flag ()
4537 return &thread_interruption_requested;
4541 mono_thread_init_apartment_state (void)
4544 MonoInternalThread* thread = mono_thread_internal_current ();
4546 /* Positive return value indicates success, either
4547 * S_OK if this is first CoInitialize call, or
4548 * S_FALSE if CoInitialize already called, but with same
4549 * threading model. A negative value indicates failure,
4550 * probably due to trying to change the threading model.
4552 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4553 ? COINIT_APARTMENTTHREADED
4554 : COINIT_MULTITHREADED) < 0) {
4555 thread->apartment_state = ThreadApartmentState_Unknown;
4561 mono_thread_cleanup_apartment_state (void)
4564 MonoInternalThread* thread = mono_thread_internal_current ();
4566 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4573 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4575 LOCK_THREAD (thread);
4576 thread->state |= state;
4577 UNLOCK_THREAD (thread);
4581 * mono_thread_test_and_set_state:
4583 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4585 * Returns TRUE is @set was OR'd in.
4588 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4590 LOCK_THREAD (thread);
4592 if ((thread->state & test) != 0) {
4593 UNLOCK_THREAD (thread);
4597 thread->state |= set;
4598 UNLOCK_THREAD (thread);
4604 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4606 LOCK_THREAD (thread);
4607 thread->state &= ~state;
4608 UNLOCK_THREAD (thread);
4612 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4614 gboolean ret = FALSE;
4616 LOCK_THREAD (thread);
4618 if ((thread->state & test) != 0) {
4622 UNLOCK_THREAD (thread);
4627 static gboolean has_tls_get = FALSE;
4630 mono_runtime_set_has_tls_get (gboolean val)
4636 mono_runtime_has_tls_get (void)
4642 self_interrupt_thread (void *_unused)
4644 MonoThreadInfo *info = mono_thread_info_current ();
4645 MonoException *exc = mono_thread_execute_interruption ();
4646 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4647 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. */
4648 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4652 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4656 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4660 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4662 MonoJitInfo **dest = (MonoJitInfo **)data;
4668 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4670 MonoJitInfo *ji = NULL;
4675 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4676 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4677 * where we hold runtime locks.
4679 if (!mono_threads_is_coop_enabled ())
4680 mono_thread_info_set_is_async_context (TRUE);
4681 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4682 if (!mono_threads_is_coop_enabled ())
4683 mono_thread_info_set_is_async_context (FALSE);
4688 MonoInternalThread *thread;
4689 gboolean install_async_abort;
4690 MonoThreadInfoInterruptToken *interrupt_token;
4693 static SuspendThreadResult
4694 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4696 AbortThreadData *data = (AbortThreadData *)ud;
4697 MonoInternalThread *thread = data->thread;
4698 MonoJitInfo *ji = NULL;
4699 gboolean protected_wrapper;
4700 gboolean running_managed;
4702 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4703 return MonoResumeThread;
4706 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4707 The protected block code will give them a chance when appropriate.
4709 if (thread->abort_protected_block_count)
4710 return MonoResumeThread;
4712 /*someone is already interrupting it*/
4713 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4714 return MonoResumeThread;
4716 InterlockedIncrement (&thread_interruption_requested);
4718 ji = mono_thread_info_get_last_managed (info);
4719 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4720 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4722 if (!protected_wrapper && running_managed) {
4723 /*We are in managed code*/
4724 /*Set the thread to call */
4725 if (data->install_async_abort)
4726 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4727 return MonoResumeThread;
4730 * This will cause waits to be broken.
4731 * It will also prevent the thread from entering a wait, so if the thread returns
4732 * from the wait before it receives the abort signal, it will just spin in the wait
4733 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4736 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4738 return MonoResumeThread;
4743 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4745 AbortThreadData data;
4747 g_assert (thread != mono_thread_internal_current ());
4749 data.thread = thread;
4750 data.install_async_abort = install_async_abort;
4751 data.interrupt_token = NULL;
4753 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4754 if (data.interrupt_token)
4755 mono_thread_info_finish_interrupt (data.interrupt_token);
4756 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4760 self_abort_internal (MonoError *error)
4764 mono_error_init (error);
4766 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4767 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4770 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.
4772 exc = mono_thread_request_interruption (TRUE);
4774 mono_error_set_exception_instance (error, exc);
4776 mono_thread_info_self_interrupt ();
4780 MonoInternalThread *thread;
4782 MonoThreadInfoInterruptToken *interrupt_token;
4783 } SuspendThreadData;
4785 static SuspendThreadResult
4786 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4788 SuspendThreadData *data = (SuspendThreadData *)ud;
4789 MonoInternalThread *thread = data->thread;
4790 MonoJitInfo *ji = NULL;
4791 gboolean protected_wrapper;
4792 gboolean running_managed;
4794 ji = mono_thread_info_get_last_managed (info);
4795 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4796 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4798 if (running_managed && !protected_wrapper) {
4799 thread->state &= ~ThreadState_SuspendRequested;
4800 thread->state |= ThreadState_Suspended;
4801 return KeepSuspended;
4803 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4804 InterlockedIncrement (&thread_interruption_requested);
4805 if (data->interrupt)
4806 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4808 return MonoResumeThread;
4812 /* LOCKING: called with @thread synch_cs held, and releases it */
4814 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4816 SuspendThreadData data;
4818 g_assert (thread != mono_thread_internal_current ());
4820 data.thread = thread;
4821 data.interrupt = interrupt;
4822 data.interrupt_token = NULL;
4824 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4825 if (data.interrupt_token)
4826 mono_thread_info_finish_interrupt (data.interrupt_token);
4828 UNLOCK_THREAD (thread);
4831 /* LOCKING: called with @thread synch_cs held, and releases it */
4833 self_suspend_internal (void)
4835 MonoInternalThread *thread;
4837 thread = mono_thread_internal_current ();
4839 mono_thread_info_begin_self_suspend ();
4840 thread->state &= ~ThreadState_SuspendRequested;
4841 thread->state |= ThreadState_Suspended;
4843 UNLOCK_THREAD (thread);
4845 mono_thread_info_end_self_suspend ();
4849 * mono_thread_is_foreign:
4850 * @thread: the thread to query
4852 * This function allows one to determine if a thread was created by the mono runtime and has
4853 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4855 * Returns: TRUE if @thread was not created by the runtime.
4858 mono_thread_is_foreign (MonoThread *thread)
4860 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4861 return info->runtime_thread == FALSE;
4865 * mono_add_joinable_thread:
4867 * Add TID to the list of joinable threads.
4868 * LOCKING: Acquires the threads lock.
4871 mono_threads_add_joinable_thread (gpointer tid)
4875 * We cannot detach from threads because it causes problems like
4876 * 2fd16f60/r114307. So we collect them and join them when
4877 * we have time (in he finalizer thread).
4879 joinable_threads_lock ();
4880 if (!joinable_threads)
4881 joinable_threads = g_hash_table_new (NULL, NULL);
4882 g_hash_table_insert (joinable_threads, tid, tid);
4883 joinable_thread_count ++;
4884 joinable_threads_unlock ();
4886 mono_gc_finalize_notify ();
4891 * mono_threads_join_threads:
4893 * Join all joinable threads. This is called from the finalizer thread.
4894 * LOCKING: Acquires the threads lock.
4897 mono_threads_join_threads (void)
4900 GHashTableIter iter;
4907 if (!joinable_thread_count)
4911 joinable_threads_lock ();
4913 if (g_hash_table_size (joinable_threads)) {
4914 g_hash_table_iter_init (&iter, joinable_threads);
4915 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4916 thread = (pthread_t)tid;
4917 g_hash_table_remove (joinable_threads, key);
4918 joinable_thread_count --;
4921 joinable_threads_unlock ();
4923 if (thread != pthread_self ()) {
4925 /* This shouldn't block */
4926 mono_native_thread_join (thread);
4939 * Wait for thread TID to exit.
4940 * LOCKING: Acquires the threads lock.
4943 mono_thread_join (gpointer tid)
4947 gboolean found = FALSE;
4949 joinable_threads_lock ();
4950 if (!joinable_threads)
4951 joinable_threads = g_hash_table_new (NULL, NULL);
4952 if (g_hash_table_lookup (joinable_threads, tid)) {
4953 g_hash_table_remove (joinable_threads, tid);
4954 joinable_thread_count --;
4957 joinable_threads_unlock ();
4960 thread = (pthread_t)tid;
4962 mono_native_thread_join (thread);
4968 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4970 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4971 mono_thread_interruption_checkpoint ();
4975 mono_thread_internal_unhandled_exception (MonoObject* exc)
4977 MonoClass *klass = exc->vtable->klass;
4978 if (is_threadabort_exception (klass)) {
4979 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4980 } else if (!is_appdomainunloaded_exception (klass)
4981 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4982 mono_unhandled_exception (exc);
4983 if (mono_environment_exitcode_get () == 1) {
4984 mono_environment_exitcode_set (255);
4985 mono_invoke_unhandled_exception_hook (exc);
4986 g_assert_not_reached ();
4992 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
4995 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
4996 mono_error_set_pending_exception (&error);
5000 * mono_threads_attach_coop: called by native->managed wrappers
5004 * - @return: the original domain which needs to be restored, or NULL.
5007 * - @dummy: contains the original domain
5008 * - @return: a cookie containing current MonoThreadInfo*.
5011 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5014 gboolean fresh_thread = FALSE;
5017 /* Happens when called from AOTed code which is only used in the root domain. */
5018 domain = mono_get_root_domain ();
5023 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5024 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5025 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5026 * we're only responsible for making the cookie. */
5027 if (mono_threads_is_coop_enabled ()) {
5028 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5029 fresh_thread = !info || !mono_thread_info_is_live (info);
5032 if (!mono_thread_internal_current ()) {
5033 mono_thread_attach_full (domain, FALSE);
5036 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5039 orig = mono_domain_get ();
5041 mono_domain_set (domain, TRUE);
5043 if (!mono_threads_is_coop_enabled ())
5044 return orig != domain ? orig : NULL;
5048 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5049 * return the right cookie. */
5050 return mono_threads_enter_gc_unsafe_region_cookie ();
5053 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5054 return mono_threads_enter_gc_unsafe_region (dummy);
5059 * mono_threads_detach_coop: called by native->managed wrappers
5062 * - @cookie: the original domain which needs to be restored, or NULL.
5066 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5067 * - @dummy: contains the original domain
5070 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5072 MonoDomain *domain, *orig;
5074 if (!mono_threads_is_coop_enabled ()) {
5075 orig = (MonoDomain*) cookie;
5077 mono_domain_set (orig, TRUE);
5079 orig = (MonoDomain*) *dummy;
5081 domain = mono_domain_get ();
5084 /* it won't do anything if cookie is NULL
5085 * thread state RUNNING -> (RUNNING|BLOCKING) */
5086 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5088 if (orig != domain) {
5090 mono_domain_unset ();
5092 mono_domain_set (orig, TRUE);
5098 mono_threads_begin_abort_protected_block (void)
5100 MonoInternalThread *thread;
5102 thread = mono_thread_internal_current ();
5103 ++thread->abort_protected_block_count;
5104 mono_memory_barrier ();
5108 mono_threads_end_abort_protected_block (void)
5110 MonoInternalThread *thread;
5112 thread = mono_thread_internal_current ();
5114 mono_memory_barrier ();
5115 --thread->abort_protected_block_count;
5119 mono_thread_try_resume_interruption (void)
5121 MonoInternalThread *thread;
5123 thread = mono_thread_internal_current ();
5124 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5127 return mono_thread_resume_interruption ();
5131 /* Returns TRUE if the current thread is ready to be interrupted. */
5133 mono_threads_is_ready_to_be_interrupted (void)
5135 MonoInternalThread *thread;
5137 thread = mono_thread_internal_current ();
5138 LOCK_THREAD (thread);
5139 if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5140 UNLOCK_THREAD (thread);
5144 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5145 UNLOCK_THREAD (thread);
5149 UNLOCK_THREAD (thread);
5155 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5157 g_string_append_printf (text, ", thread handle : %p", internal->handle);
5159 if (internal->thread_info) {
5160 g_string_append (text, ", state : ");
5161 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5164 if (internal->owned_mutexes) {
5167 g_string_append (text, ", owns : [");
5168 for (i = 0; i < internal->owned_mutexes->len; i++)
5169 g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5170 g_string_append (text, "]");
5175 mono_thread_internal_is_current (MonoInternalThread *internal)
5177 g_assert (internal);
5178 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));