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/metadata/object-internals.h>
32 #include <mono/metadata/debug-internals.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/mono-threads-coop.h>
40 #include <mono/utils/hazard-pointer.h>
41 #include <mono/utils/mono-tls.h>
42 #include <mono/utils/atomic.h>
43 #include <mono/utils/mono-memory-model.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/os-event.h>
46 #include <mono/utils/mono-threads-debug.h>
47 #include <mono/metadata/w32handle.h>
48 #include <mono/metadata/w32event.h>
49 #include <mono/metadata/w32mutex.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/abi-details.h>
53 #include <mono/metadata/w32error.h>
54 #include <mono/utils/w32api.h>
60 #if defined(HOST_WIN32)
64 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
65 #define USE_TKILL_ON_ANDROID 1
68 #ifdef PLATFORM_ANDROID
71 #ifdef USE_TKILL_ON_ANDROID
72 extern int tkill (pid_t tid, int signal);
76 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
77 #define THREAD_DEBUG(a)
78 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
79 #define THREAD_WAIT_DEBUG(a)
80 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
81 #define LIBGC_DEBUG(a)
83 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
84 #define SPIN_LOCK(i) do { \
85 if (SPIN_TRYLOCK (i)) \
89 #define SPIN_UNLOCK(i) i = 0
91 #define LOCK_THREAD(thread) lock_thread((thread))
92 #define UNLOCK_THREAD(thread) unlock_thread((thread))
104 typedef struct _StaticDataFreeList StaticDataFreeList;
105 struct _StaticDataFreeList {
106 StaticDataFreeList *next;
114 StaticDataFreeList *freelist;
117 /* Controls access to the 'threads' hash table */
118 static void mono_threads_lock (void);
119 static void mono_threads_unlock (void);
120 static MonoCoopMutex threads_mutex;
122 /* Controls access to the 'joinable_threads' hash table */
123 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
124 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
125 static mono_mutex_t joinable_threads_mutex;
127 /* Holds current status of static data heap */
128 static StaticDataInfo thread_static_info;
129 static StaticDataInfo context_static_info;
131 /* The hash of existing threads (key is thread ID, value is
132 * MonoInternalThread*) that need joining before exit
134 static MonoGHashTable *threads=NULL;
136 /* List of app context GC handles.
137 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
139 static GHashTable *contexts = NULL;
141 /* Cleanup queue for contexts. */
142 static MonoReferenceQueue *context_queue;
145 * Threads which are starting up and they are not in the 'threads' hash yet.
146 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
147 * Protected by mono_threads_lock ().
149 static MonoGHashTable *threads_starting_up = NULL;
152 /* Protected by the threads lock */
153 static GHashTable *joinable_threads;
154 static int joinable_thread_count;
156 #define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
157 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
159 /* function called at thread start */
160 static MonoThreadStartCB mono_thread_start_cb = NULL;
162 /* function called at thread attach */
163 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
165 /* function called at thread cleanup */
166 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
168 /* The default stack size for each thread */
169 static guint32 default_stacksize = 0;
170 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
172 static void context_adjust_static_data (MonoAppContext *ctx);
173 static void mono_free_static_data (gpointer* static_data);
174 static void mono_init_static_data_info (StaticDataInfo *static_data);
175 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
176 static gboolean mono_thread_resume (MonoInternalThread* thread);
177 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
178 static void self_abort_internal (MonoError *error);
179 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
180 static void self_suspend_internal (void);
182 static MonoException* mono_thread_execute_interruption (void);
183 static void ref_stack_destroy (gpointer rs);
185 /* Spin lock for InterlockedXXX 64 bit functions */
186 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
187 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
188 static mono_mutex_t interlocked_mutex;
190 /* global count of thread interruptions requested */
191 static gint32 thread_interruption_requested = 0;
193 /* Event signaled when a thread changes its background mode */
194 static MonoOSEvent background_change_event;
196 static gboolean shutting_down = FALSE;
198 static gint32 managed_thread_id_counter = 0;
200 /* Class lazy loading functions */
201 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, "System", "AppDomainUnloadedException")
204 mono_threads_lock (void)
206 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
210 mono_threads_unlock (void)
212 mono_locks_coop_release (&threads_mutex, ThreadsLock);
217 get_next_managed_thread_id (void)
219 return InterlockedIncrement (&managed_thread_id_counter);
223 * We separate interruptions/exceptions into either sync (they can be processed anytime,
224 * normally as soon as they are set, and are set by the same thread) and async (they can't
225 * be processed inside abort protected blocks and are normally set by other threads). We
226 * can have both a pending sync and async interruption. In this case, the sync exception is
227 * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
228 * also handle all sync type exceptions before the async type exceptions.
231 INTERRUPT_SYNC_REQUESTED_BIT = 0x1,
232 INTERRUPT_ASYNC_REQUESTED_BIT = 0x2,
233 INTERRUPT_REQUESTED_MASK = 0x3,
234 ABORT_PROT_BLOCK_SHIFT = 2,
235 ABORT_PROT_BLOCK_BITS = 8,
236 ABORT_PROT_BLOCK_MASK = (((1 << ABORT_PROT_BLOCK_BITS) - 1) << ABORT_PROT_BLOCK_SHIFT)
240 mono_thread_get_abort_prot_block_count (MonoInternalThread *thread)
242 gsize state = thread->thread_state;
243 return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
247 mono_threads_begin_abort_protected_block (void)
249 MonoInternalThread *thread = mono_thread_internal_current ();
250 gsize old_state, new_state;
253 old_state = thread->thread_state;
255 new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) + 1;
256 //bounds check abort_prot_count
257 g_assert (new_val > 0);
258 g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
260 new_state = old_state + (1 << ABORT_PROT_BLOCK_SHIFT);
261 } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
263 /* Defer async request since we won't be able to process until exiting the block */
264 if (new_val == 1 && (new_state & INTERRUPT_ASYNC_REQUESTED_BIT)) {
265 InterlockedDecrement (&thread_interruption_requested);
266 THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, defer tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
267 if (thread_interruption_requested < 0)
268 g_warning ("bad thread_interruption_requested state");
270 THREADS_INTERRUPT_DEBUG ("[%d] begin abort protected block old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
275 mono_thread_state_has_interruption (gsize state)
277 /* pending exception, self abort */
278 if (state & INTERRUPT_SYNC_REQUESTED_BIT)
281 /* abort, interruption, suspend */
282 if ((state & INTERRUPT_ASYNC_REQUESTED_BIT) && !(state & ABORT_PROT_BLOCK_MASK))
289 mono_threads_end_abort_protected_block (void)
291 MonoInternalThread *thread = mono_thread_internal_current ();
292 gsize old_state, new_state;
295 old_state = thread->thread_state;
297 //bounds check abort_prot_count
298 new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
299 g_assert (new_val >= 0);
300 g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
302 new_state = old_state - (1 << ABORT_PROT_BLOCK_SHIFT);
303 } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
305 if (new_val == 0 && (new_state & INTERRUPT_ASYNC_REQUESTED_BIT)) {
306 InterlockedIncrement (&thread_interruption_requested);
307 THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, restore tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
309 THREADS_INTERRUPT_DEBUG ("[%d] end abort protected block old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
312 return mono_thread_state_has_interruption (new_state);
316 mono_thread_get_interruption_requested (MonoInternalThread *thread)
318 gsize state = thread->thread_state;
320 return mono_thread_state_has_interruption (state);
324 * Returns TRUE is there was a state change
325 * We clear a single interruption request, sync has priority.
328 mono_thread_clear_interruption_requested (MonoInternalThread *thread)
330 gsize old_state, new_state;
332 old_state = thread->thread_state;
334 // no interruption to process
335 if (!(old_state & INTERRUPT_SYNC_REQUESTED_BIT) &&
336 (!(old_state & INTERRUPT_ASYNC_REQUESTED_BIT) || (old_state & ABORT_PROT_BLOCK_MASK)))
339 if (old_state & INTERRUPT_SYNC_REQUESTED_BIT)
340 new_state = old_state & ~INTERRUPT_SYNC_REQUESTED_BIT;
342 new_state = old_state & ~INTERRUPT_ASYNC_REQUESTED_BIT;
343 } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
345 InterlockedDecrement (&thread_interruption_requested);
346 THREADS_INTERRUPT_DEBUG ("[%d] clear interruption old_state %ld new_state %ld, tir %d\n", thread->small_id, old_state, new_state, thread_interruption_requested);
347 if (thread_interruption_requested < 0)
348 g_warning ("bad thread_interruption_requested state");
352 /* Returns TRUE is there was a state change and the interruption can be processed */
354 mono_thread_set_interruption_requested (MonoInternalThread *thread)
356 //always force when the current thread is doing it to itself.
357 gboolean sync = thread == mono_thread_internal_current ();
358 gsize old_state, new_state;
360 old_state = thread->thread_state;
363 if ((sync && (old_state & INTERRUPT_SYNC_REQUESTED_BIT)) ||
364 (!sync && (old_state & INTERRUPT_ASYNC_REQUESTED_BIT)))
368 new_state = old_state | INTERRUPT_SYNC_REQUESTED_BIT;
370 new_state = old_state | INTERRUPT_ASYNC_REQUESTED_BIT;
371 } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
373 if (sync || !(new_state & ABORT_PROT_BLOCK_MASK)) {
374 InterlockedIncrement (&thread_interruption_requested);
375 THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir %d\n", mono_thread_internal_current ()->small_id, thread->small_id, old_state, new_state, thread_interruption_requested);
377 THREADS_INTERRUPT_DEBUG ("[%d] set interruption on [%d] old_state %ld new_state %ld, tir deferred %d\n", mono_thread_internal_current ()->small_id, thread->small_id, old_state, new_state, thread_interruption_requested);
380 return sync || !(new_state & ABORT_PROT_BLOCK_MASK);
383 static inline MonoNativeThreadId
384 thread_get_tid (MonoInternalThread *thread)
386 /* We store the tid as a guint64 to keep the object layout constant between platforms */
387 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
390 static void ensure_synch_cs_set (MonoInternalThread *thread)
392 MonoCoopMutex *synch_cs;
394 if (thread->synch_cs != NULL) {
398 synch_cs = g_new0 (MonoCoopMutex, 1);
399 mono_coop_mutex_init_recursive (synch_cs);
401 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
402 synch_cs, NULL) != NULL) {
403 /* Another thread must have installed this CS */
404 mono_coop_mutex_destroy (synch_cs);
410 lock_thread (MonoInternalThread *thread)
412 if (!thread->synch_cs)
413 ensure_synch_cs_set (thread);
415 g_assert (thread->synch_cs);
417 mono_coop_mutex_lock (thread->synch_cs);
421 unlock_thread (MonoInternalThread *thread)
423 mono_coop_mutex_unlock (thread->synch_cs);
426 static inline gboolean
427 is_appdomainunloaded_exception (MonoClass *klass)
429 return klass == mono_class_get_appdomain_unloaded_exception_class ();
432 static inline gboolean
433 is_threadabort_exception (MonoClass *klass)
435 return klass == mono_defaults.threadabortexception_class;
439 * A special static data offset (guint32) consists of 3 parts:
441 * [0] 6-bit index into the array of chunks.
442 * [6] 25-bit offset into the array.
443 * [31] Bit indicating thread or context static.
448 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
459 } SpecialStaticOffset;
461 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
462 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
464 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
465 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
466 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
467 (((SpecialStaticOffset *) &(x))->fields.f)
470 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
472 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
474 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
475 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
477 return ((char *) thread->static_data [idx]) + off;
481 get_context_static_data (MonoAppContext *ctx, guint32 offset)
483 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
485 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
486 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
488 return ((char *) ctx->static_data [idx]) + off;
492 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
494 static MonoClassField *current_thread_field = NULL;
498 if (!current_thread_field) {
499 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
500 g_assert (current_thread_field);
503 mono_class_vtable (domain, mono_defaults.thread_class);
504 mono_domain_lock (domain);
505 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
506 mono_domain_unlock (domain);
509 return (MonoThread **)get_thread_static_data (thread, offset);
513 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
515 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
517 g_assert (current->obj.vtable->domain == domain);
519 g_assert (!*current_thread_ptr);
520 *current_thread_ptr = current;
524 create_thread_object (MonoDomain *domain, MonoInternalThread *internal)
530 vtable = mono_class_vtable (domain, mono_defaults.thread_class);
533 thread = (MonoThread*)mono_object_new_mature (vtable, &error);
534 /* only possible failure mode is OOM, from which we don't expect to recover. */
535 mono_error_assert_ok (&error);
537 MONO_OBJECT_SETREF (thread, internal_thread, internal);
542 static MonoInternalThread*
543 create_internal_thread_object (void)
546 MonoInternalThread *thread;
549 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
550 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
551 /* only possible failure mode is OOM, from which we don't exect to recover */
552 mono_error_assert_ok (&error);
554 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
555 mono_coop_mutex_init_recursive (thread->synch_cs);
557 thread->apartment_state = ThreadApartmentState_Unknown;
558 thread->managed_id = get_next_managed_thread_id ();
559 if (mono_gc_is_moving ()) {
560 thread->thread_pinning_ref = thread;
561 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
564 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
566 thread->suspended = g_new0 (MonoOSEvent, 1);
567 mono_os_event_init (thread->suspended, TRUE);
573 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
577 g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
578 g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
579 g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
584 g_assert (internal->native_handle);
586 res = SetThreadPriority (internal->native_handle, priority - 2);
588 g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
589 #else /* HOST_WIN32 */
592 struct sched_param param;
595 tid = thread_get_tid (internal);
597 res = pthread_getschedparam (tid, &policy, ¶m);
599 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
601 #ifdef _POSIX_PRIORITY_SCHEDULING
604 /* Necessary to get valid priority range */
606 min = sched_get_priority_min (policy);
607 max = sched_get_priority_max (policy);
609 if (max > 0 && min >= 0 && max > min) {
610 double srange, drange, sposition, dposition;
611 srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
613 sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
614 dposition = (sposition / srange) * drange;
615 param.sched_priority = (int)(dposition + min);
622 param.sched_priority = 50;
628 param.sched_priority = 0;
631 g_warning ("%s: unknown policy %d", __func__, policy);
636 res = pthread_setschedparam (tid, policy, ¶m);
639 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
642 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
644 #endif /* HOST_WIN32 */
648 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
651 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain)
653 MonoThreadInfo *info;
654 MonoInternalThread *internal;
655 MonoDomain *domain, *root_domain;
659 info = mono_thread_info_current ();
661 internal = thread->internal_thread;
662 internal->handle = mono_threads_open_thread_handle (info->handle);
664 internal->native_handle = OpenThread (THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId ());
666 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
667 internal->thread_info = info;
668 internal->small_id = info->small_id;
670 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
672 SET_CURRENT_OBJECT (internal);
674 domain = mono_object_domain (thread);
676 mono_thread_push_appdomain_ref (domain);
677 if (!mono_domain_set (domain, force_domain)) {
678 mono_thread_pop_appdomain_ref ();
682 mono_threads_lock ();
684 if (threads_starting_up)
685 mono_g_hash_table_remove (threads_starting_up, thread);
687 if (shutting_down && !force_attach) {
688 mono_threads_unlock ();
689 mono_thread_pop_appdomain_ref ();
694 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
697 /* We don't need to duplicate thread->handle, because it is
698 * only closed when the thread object is finalized by the GC. */
699 mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
701 /* We have to do this here because mono_thread_start_cb
702 * requires that root_domain_thread is set up. */
703 if (thread_static_info.offset || thread_static_info.idx > 0) {
704 /* get the current allocated size */
705 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
706 mono_alloc_static_data (&internal->static_data, offset, TRUE);
709 mono_threads_unlock ();
711 root_domain = mono_get_root_domain ();
713 g_assert (!internal->root_domain_thread);
714 if (domain != root_domain)
715 MONO_OBJECT_SETREF (internal, root_domain_thread, create_thread_object (root_domain, internal));
717 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
719 if (domain != root_domain)
720 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
722 set_current_thread_for_domain (domain, internal, thread);
724 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
732 MonoObject *start_delegate;
733 MonoObject *start_delegate_arg;
734 MonoThreadStart start_func;
735 gpointer start_func_arg;
736 gboolean force_attach;
738 MonoCoopSem registered;
741 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
744 MonoThreadStart start_func;
745 void *start_func_arg;
748 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
752 MonoInternalThread *internal;
753 MonoObject *start_delegate;
754 MonoObject *start_delegate_arg;
757 thread = start_info->thread;
758 internal = thread->internal_thread;
759 domain = mono_object_domain (start_info->thread);
761 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
763 if (!mono_thread_attach_internal (thread, start_info->force_attach, FALSE)) {
764 start_info->failed = TRUE;
766 mono_coop_sem_post (&start_info->registered);
768 if (InterlockedDecrement (&start_info->ref) == 0) {
769 mono_coop_sem_destroy (&start_info->registered);
776 mono_thread_internal_set_priority (internal, internal->priority);
780 start_delegate = start_info->start_delegate;
781 start_delegate_arg = start_info->start_delegate_arg;
782 start_func = start_info->start_func;
783 start_func_arg = start_info->start_func_arg;
785 /* This MUST be called before any managed code can be
786 * executed, as it calls the callback function that (for the
787 * jit) sets the lmf marker.
790 if (mono_thread_start_cb)
791 mono_thread_start_cb (tid, stack_ptr, start_func);
793 /* On 2.0 profile (and higher), set explicitly since state might have been
795 if (internal->apartment_state == ThreadApartmentState_Unknown)
796 internal->apartment_state = ThreadApartmentState_MTA;
798 mono_thread_init_apartment_state ();
800 /* Let the thread that called Start() know we're ready */
801 mono_coop_sem_post (&start_info->registered);
803 if (InterlockedDecrement (&start_info->ref) == 0) {
804 mono_coop_sem_destroy (&start_info->registered);
808 /* start_info is not valid anymore */
812 * Call this after calling start_notify, since the profiler callback might want
813 * to lock the thread, and the lock is held by thread_start () which waits for
816 mono_profiler_thread_start (tid);
818 /* if the name was set before starting, we didn't invoke the profiler callback */
819 if (internal->name) {
820 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
821 mono_profiler_thread_name (internal->tid, tname);
822 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
826 /* start_func is set only for unmanaged start functions */
828 start_func (start_func_arg);
832 g_assert (start_delegate != NULL);
834 /* we may want to handle the exception here. See comment below on unhandled exceptions */
835 args [0] = (gpointer) start_delegate_arg;
836 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
838 if (!mono_error_ok (&error)) {
839 MonoException *ex = mono_error_convert_to_exception (&error);
841 g_assert (ex != NULL);
842 MonoClass *klass = mono_object_get_class (&ex->object);
843 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
844 !is_threadabort_exception (klass)) {
845 mono_unhandled_exception (&ex->object);
846 mono_invoke_unhandled_exception_hook (&ex->object);
847 g_assert_not_reached ();
850 mono_error_cleanup (&error);
854 /* If the thread calls ExitThread at all, this remaining code
855 * will not be executed, but the main thread will eventually
856 * call mono_thread_detach_internal() on this thread's behalf.
859 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
861 /* Do any cleanup needed for apartment state. This
862 * cannot be done in mono_thread_detach_internal since
863 * mono_thread_detach_internal could be called for a
864 * thread other than the current thread.
865 * mono_thread_cleanup_apartment_state cleans up apartment
866 * for the current thead */
867 mono_thread_cleanup_apartment_state ();
869 mono_thread_detach_internal (internal);
877 start_wrapper (gpointer data)
879 StartInfo *start_info;
880 MonoThreadInfo *info;
883 start_info = (StartInfo*) data;
884 g_assert (start_info);
886 info = mono_thread_info_attach (&res);
887 info->runtime_thread = TRUE;
889 /* Run the actual main function of the thread */
890 res = start_wrapper_internal (start_info, &res);
892 mono_thread_info_exit (res);
894 g_assert_not_reached ();
900 * Common thread creation code.
901 * LOCKING: Acquires the threads lock.
904 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
905 MonoThreadCreateFlags flags, MonoError *error)
907 StartInfo *start_info = NULL;
908 MonoNativeThreadId tid;
910 gsize stack_set_size;
913 g_assert (!start_func && !start_func_arg);
915 g_assert (!start_delegate);
917 if (flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL) {
918 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER));
919 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
921 if (flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER) {
922 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL));
923 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
927 * Join joinable threads to prevent running out of threads since the finalizer
928 * thread might be blocked/backlogged.
930 mono_threads_join_threads ();
934 mono_threads_lock ();
935 if (shutting_down && !(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE)) {
936 mono_threads_unlock ();
939 if (threads_starting_up == NULL) {
940 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
942 mono_g_hash_table_insert (threads_starting_up, thread, thread);
943 mono_threads_unlock ();
945 internal->threadpool_thread = flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL;
946 if (internal->threadpool_thread)
947 mono_thread_set_state (internal, ThreadState_Background);
949 internal->debugger_thread = flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER;
951 start_info = g_new0 (StartInfo, 1);
953 start_info->thread = thread;
954 start_info->start_delegate = start_delegate;
955 start_info->start_delegate_arg = thread->start_obj;
956 start_info->start_func = start_func;
957 start_info->start_func_arg = start_func_arg;
958 start_info->force_attach = flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE;
959 start_info->failed = FALSE;
960 mono_coop_sem_init (&start_info->registered, 0);
962 if (flags != MONO_THREAD_CREATE_FLAGS_SMALL_STACK)
963 stack_set_size = default_stacksize_for_thread (internal);
967 if (!mono_thread_platform_create_thread (start_wrapper, start_info, &stack_set_size, &tid)) {
968 /* The thread couldn't be created, so set an exception */
969 mono_threads_lock ();
970 mono_g_hash_table_remove (threads_starting_up, thread);
971 mono_threads_unlock ();
972 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
973 /* ref is not going to be decremented in start_wrapper_internal */
974 InterlockedDecrement (&start_info->ref);
979 internal->stack_size = (int) stack_set_size;
981 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
984 * Wait for the thread to set up its TLS data etc, so
985 * theres no potential race condition if someone tries
986 * to look up the data believing the thread has
990 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
992 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));
994 ret = !start_info->failed;
997 if (InterlockedDecrement (&start_info->ref) == 0) {
998 mono_coop_sem_destroy (&start_info->registered);
1005 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
1007 if (mono_thread_start_cb) {
1008 mono_thread_start_cb (tid, stack_start, func);
1012 void mono_threads_set_default_stacksize (guint32 stacksize)
1014 default_stacksize = stacksize;
1017 guint32 mono_threads_get_default_stacksize (void)
1019 return default_stacksize;
1023 * mono_thread_create_internal:
1025 * ARG should not be a GC reference.
1028 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, MonoThreadCreateFlags flags, MonoError *error)
1031 MonoInternalThread *internal;
1036 internal = create_internal_thread_object ();
1038 thread = create_thread_object (domain, internal);
1040 LOCK_THREAD (internal);
1042 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, flags, error);
1044 UNLOCK_THREAD (internal);
1046 return_val_if_nok (error, NULL);
1051 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1054 if (!mono_thread_create_checked (domain, func, arg, &error))
1055 mono_error_cleanup (&error);
1059 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1061 return (NULL != mono_thread_create_internal (domain, func, arg, MONO_THREAD_CREATE_FLAGS_NONE, error));
1065 mono_thread_attach (MonoDomain *domain)
1067 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1073 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1075 MonoInternalThread *internal;
1077 MonoThreadInfo *info;
1078 MonoNativeThreadId tid;
1081 if (mono_thread_internal_current_is_attached ()) {
1082 if (domain != mono_domain_get ())
1083 mono_domain_set (domain, TRUE);
1084 /* Already attached */
1085 return mono_thread_current ();
1088 info = mono_thread_info_attach (&stack_ptr);
1091 tid=mono_native_thread_id_get ();
1093 internal = create_internal_thread_object ();
1095 thread = create_thread_object (domain, internal);
1097 if (!mono_thread_attach_internal (thread, force_attach, TRUE)) {
1098 /* Mono is shutting down, so just wait for the end */
1100 mono_thread_info_sleep (10000, NULL);
1103 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1105 if (mono_thread_attach_cb) {
1109 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1112 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1114 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1117 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1118 if (!mono_thread_info_current ()->tools_thread)
1119 // FIXME: Need a separate callback
1120 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1126 mono_thread_detach_internal (MonoInternalThread *thread)
1130 g_assert (thread != NULL);
1132 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1135 mono_w32mutex_abandon ();
1138 if (thread->abort_state_handle) {
1139 mono_gchandle_free (thread->abort_state_handle);
1140 thread->abort_state_handle = 0;
1143 thread->abort_exc = NULL;
1144 thread->current_appcontext = NULL;
1147 * thread->synch_cs can be NULL if this was called after
1148 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
1149 * This can happen only during shutdown.
1150 * The shutting_down flag is not always set, so we can't assert on it.
1152 if (thread->synch_cs)
1153 LOCK_THREAD (thread);
1155 thread->state |= ThreadState_Stopped;
1156 thread->state &= ~ThreadState_Background;
1158 if (thread->synch_cs)
1159 UNLOCK_THREAD (thread);
1162 An interruption request has leaked to cleanup. Adjust the global counter.
1164 This can happen is the abort source thread finds the abortee (this) thread
1165 in unmanaged code. If this thread never trips back to managed code or check
1166 the local flag it will be left set and positively unbalance the global counter.
1168 Leaving the counter unbalanced will cause a performance degradation since all threads
1169 will now keep checking their local flags all the time.
1171 mono_thread_clear_interruption_requested (thread);
1173 mono_threads_lock ();
1177 } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
1178 /* We have to check whether the thread object for the
1179 * tid is still the same in the table because the
1180 * thread might have been destroyed and the tid reused
1181 * in the meantime, in which case the tid would be in
1182 * the table, but with another thread object.
1186 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
1190 mono_threads_unlock ();
1192 /* Don't close the handle here, wait for the object finalizer
1193 * to do it. Otherwise, the following race condition applies:
1195 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
1197 * 2) Some other handle is reassigned the same slot
1199 * 3) Another thread tries to join the first thread, and
1200 * blocks waiting for the reassigned handle to be signalled
1201 * (which might never happen). This is possible, because the
1202 * thread calling Join() still has a reference to the first
1206 /* if the thread is not in the hash it has been removed already */
1208 mono_domain_unset ();
1209 mono_memory_barrier ();
1211 if (mono_thread_cleanup_fn)
1212 mono_thread_cleanup_fn (thread_get_tid (thread));
1217 mono_release_type_locks (thread);
1219 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1220 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
1221 mono_profiler_thread_end (thread->tid);
1223 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1226 * This will signal async signal handlers that the thread has exited.
1227 * The profiler callback needs this to be set, so it cannot be done earlier.
1229 mono_domain_unset ();
1230 mono_memory_barrier ();
1232 if (thread == mono_thread_internal_current ())
1233 mono_thread_pop_appdomain_ref ();
1235 mono_free_static_data (thread->static_data);
1236 thread->static_data = NULL;
1237 ref_stack_destroy (thread->appdomain_refs);
1238 thread->appdomain_refs = NULL;
1240 g_assert (thread->suspended);
1241 mono_os_event_destroy (thread->suspended);
1242 g_free (thread->suspended);
1243 thread->suspended = NULL;
1245 if (mono_thread_cleanup_fn)
1246 mono_thread_cleanup_fn (thread_get_tid (thread));
1248 mono_memory_barrier ();
1250 if (mono_gc_is_moving ()) {
1251 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
1252 thread->thread_pinning_ref = NULL;
1256 SET_CURRENT_OBJECT (NULL);
1257 mono_domain_unset ();
1259 /* Don't need to close the handle to this thread, even though we took a
1260 * reference in mono_thread_attach (), because the GC will do it
1261 * when the Thread object is finalised.
1266 mono_thread_detach (MonoThread *thread)
1269 mono_thread_detach_internal (thread->internal_thread);
1273 * mono_thread_detach_if_exiting:
1275 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1276 * This should be used at the end of embedding code which calls into managed code, and which
1277 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1280 mono_thread_detach_if_exiting (void)
1282 if (mono_thread_info_is_exiting ()) {
1283 MonoInternalThread *thread;
1285 thread = mono_thread_internal_current ();
1287 mono_thread_detach_internal (thread);
1288 mono_thread_info_detach ();
1296 mono_thread_internal_current_is_attached (void)
1298 MonoInternalThread *internal;
1300 internal = GET_CURRENT_OBJECT ();
1308 mono_thread_exit (void)
1310 MonoInternalThread *thread = mono_thread_internal_current ();
1312 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1314 mono_thread_detach_internal (thread);
1316 /* we could add a callback here for embedders to use. */
1317 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1318 exit (mono_environment_exitcode_get ());
1320 mono_thread_info_exit (0);
1324 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1326 MonoInternalThread *internal;
1328 internal = create_internal_thread_object ();
1330 internal->state = ThreadState_Unstarted;
1332 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1336 ves_icall_System_Threading_Thread_GetCurrentThread (void)
1338 return mono_thread_current ();
1342 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1346 MonoInternalThread *internal;
1349 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1351 if (!this_obj->internal_thread)
1352 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1353 internal = this_obj->internal_thread;
1355 LOCK_THREAD (internal);
1357 if ((internal->state & ThreadState_Unstarted) == 0) {
1358 UNLOCK_THREAD (internal);
1359 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1363 if ((internal->state & ThreadState_Aborted) != 0) {
1364 UNLOCK_THREAD (internal);
1368 res = create_thread (this_obj, internal, start, NULL, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error);
1370 mono_error_cleanup (&error);
1371 UNLOCK_THREAD (internal);
1375 internal->state &= ~ThreadState_Unstarted;
1377 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1379 UNLOCK_THREAD (internal);
1380 return internal->handle;
1384 * This is called from the finalizer of the internal thread object.
1387 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj)
1389 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle));
1392 * Since threads keep a reference to their thread object while running, by
1393 * the time this function is called, the thread has already exited/detached,
1394 * i.e. mono_thread_detach_internal () has ran. The exception is during
1395 * shutdown, when mono_thread_detach_internal () can be called after this.
1397 if (this_obj->handle) {
1398 mono_threads_close_thread_handle (this_obj->handle);
1399 this_obj->handle = NULL;
1403 CloseHandle (this_obj->native_handle);
1406 if (this_obj->synch_cs) {
1407 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1408 this_obj->synch_cs = NULL;
1409 mono_coop_mutex_destroy (synch_cs);
1413 if (this_obj->name) {
1414 void *name = this_obj->name;
1415 this_obj->name = NULL;
1421 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1424 MonoInternalThread *thread = mono_thread_internal_current ();
1426 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1428 if (mono_thread_current_check_pending_interrupt ())
1432 gboolean alerted = FALSE;
1434 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1436 res = mono_thread_info_sleep (ms, &alerted);
1438 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1441 MonoException* exc = mono_thread_execute_interruption ();
1443 mono_raise_exception (exc);
1445 // FIXME: !MONO_INFINITE_WAIT
1446 if (ms != MONO_INFINITE_WAIT)
1455 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1460 ves_icall_System_Threading_Thread_GetDomainID (void)
1462 return mono_domain_get()->domain_id;
1466 ves_icall_System_Threading_Thread_Yield (void)
1468 return mono_thread_info_yield ();
1472 * mono_thread_get_name:
1474 * Return the name of the thread. NAME_LEN is set to the length of the name.
1475 * Return NULL if the thread has no name. The returned memory is owned by the
1479 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1483 LOCK_THREAD (this_obj);
1485 if (!this_obj->name) {
1489 *name_len = this_obj->name_len;
1490 res = g_new (gunichar2, this_obj->name_len);
1491 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1494 UNLOCK_THREAD (this_obj);
1500 * mono_thread_get_name_utf8:
1502 * Return the name of the thread in UTF-8.
1503 * Return NULL if the thread has no name.
1504 * The returned memory is owned by the caller.
1507 mono_thread_get_name_utf8 (MonoThread *thread)
1512 MonoInternalThread *internal = thread->internal_thread;
1513 if (internal == NULL)
1516 LOCK_THREAD (internal);
1518 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1520 UNLOCK_THREAD (internal);
1526 * mono_thread_get_managed_id:
1528 * Return the Thread.ManagedThreadId value of `thread`.
1529 * Returns -1 if `thread` is NULL.
1532 mono_thread_get_managed_id (MonoThread *thread)
1537 MonoInternalThread *internal = thread->internal_thread;
1538 if (internal == NULL)
1541 int32_t id = internal->managed_id;
1547 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1552 error_init (&error);
1554 LOCK_THREAD (this_obj);
1556 if (!this_obj->name)
1559 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1561 UNLOCK_THREAD (this_obj);
1563 if (mono_error_set_pending_exception (&error))
1570 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, gboolean reset, MonoError *error)
1572 LOCK_THREAD (this_obj);
1577 this_obj->flags &= ~MONO_THREAD_FLAG_NAME_SET;
1578 } else if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1579 UNLOCK_THREAD (this_obj);
1581 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1584 if (this_obj->name) {
1585 g_free (this_obj->name);
1586 this_obj->name_len = 0;
1589 this_obj->name = g_memdup (mono_string_chars (name), mono_string_length (name) * sizeof (gunichar2));
1590 this_obj->name_len = mono_string_length (name);
1593 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1596 this_obj->name = NULL;
1599 UNLOCK_THREAD (this_obj);
1601 if (this_obj->name && this_obj->tid) {
1602 char *tname = mono_string_to_utf8_checked (name, error);
1603 return_if_nok (error);
1604 mono_profiler_thread_name (this_obj->tid, tname);
1605 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1611 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1614 mono_thread_set_name_internal (this_obj, name, TRUE, FALSE, &error);
1615 mono_error_set_pending_exception (&error);
1619 * ves_icall_System_Threading_Thread_GetPriority_internal:
1620 * @param this_obj: The MonoInternalThread on which to operate.
1622 * Gets the priority of the given thread.
1623 * @return: The priority of the given thread.
1626 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1629 MonoInternalThread *internal = this_obj->internal_thread;
1631 LOCK_THREAD (internal);
1632 priority = internal->priority;
1633 UNLOCK_THREAD (internal);
1639 * ves_icall_System_Threading_Thread_SetPriority_internal:
1640 * @param this_obj: The MonoInternalThread on which to operate.
1641 * @param priority: The priority to set.
1643 * Sets the priority of the given thread.
1646 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1648 MonoInternalThread *internal = this_obj->internal_thread;
1650 LOCK_THREAD (internal);
1651 internal->priority = priority;
1652 if (internal->thread_info != NULL)
1653 mono_thread_internal_set_priority (internal, priority);
1654 UNLOCK_THREAD (internal);
1657 /* If the array is already in the requested domain, we just return it,
1658 otherwise we return a copy in that domain. */
1660 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1668 if (mono_object_domain (arr) == domain)
1671 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1672 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1677 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1680 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1681 mono_error_set_pending_exception (&error);
1686 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1689 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1690 mono_error_set_pending_exception (&error);
1695 mono_thread_current (void)
1697 MonoDomain *domain = mono_domain_get ();
1698 MonoInternalThread *internal = mono_thread_internal_current ();
1699 MonoThread **current_thread_ptr;
1701 g_assert (internal);
1702 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1704 if (!*current_thread_ptr) {
1705 g_assert (domain != mono_get_root_domain ());
1706 *current_thread_ptr = create_thread_object (domain, internal);
1708 return *current_thread_ptr;
1711 /* Return the thread object belonging to INTERNAL in the current domain */
1713 mono_thread_current_for_thread (MonoInternalThread *internal)
1715 MonoDomain *domain = mono_domain_get ();
1716 MonoThread **current_thread_ptr;
1718 g_assert (internal);
1719 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1721 if (!*current_thread_ptr) {
1722 g_assert (domain != mono_get_root_domain ());
1723 *current_thread_ptr = create_thread_object (domain, internal);
1725 return *current_thread_ptr;
1729 mono_thread_internal_current (void)
1731 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1732 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1736 static MonoThreadInfoWaitRet
1737 mono_join_uninterrupted (MonoThreadHandle* thread_to_join, gint32 ms, MonoError *error)
1740 MonoThreadInfoWaitRet ret;
1747 start = (ms == -1) ? 0 : mono_msec_ticks ();
1750 ret = mono_thread_info_wait_one_handle (thread_to_join, ms, TRUE);
1753 if (ret != MONO_THREAD_INFO_WAIT_RET_ALERTED)
1756 exc = mono_thread_execute_interruption ();
1758 mono_error_set_exception_instance (error, exc);
1765 /* Re-calculate ms according to the time passed */
1766 diff_ms = (gint32)(mono_msec_ticks () - start);
1767 if (diff_ms >= ms) {
1768 ret = MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1771 wait = ms - diff_ms;
1778 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1780 MonoInternalThread *thread = this_obj->internal_thread;
1781 MonoThreadHandle *handle = thread->handle;
1782 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1786 if (mono_thread_current_check_pending_interrupt ())
1789 LOCK_THREAD (thread);
1791 if ((thread->state & ThreadState_Unstarted) != 0) {
1792 UNLOCK_THREAD (thread);
1794 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1798 UNLOCK_THREAD (thread);
1801 ms=MONO_INFINITE_WAIT;
1803 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1805 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1807 ret=mono_join_uninterrupted (handle, ms, &error);
1809 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1811 mono_error_set_pending_exception (&error);
1813 if(ret==MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
1814 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1819 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1824 #define MANAGED_WAIT_FAILED 0x7fffffff
1827 map_native_wait_result_to_managed (MonoW32HandleWaitRet val, gsize numobjects)
1829 if (val >= MONO_W32HANDLE_WAIT_RET_SUCCESS_0 && val < MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + numobjects) {
1830 return WAIT_OBJECT_0 + (val - MONO_W32HANDLE_WAIT_RET_SUCCESS_0);
1831 } else if (val >= MONO_W32HANDLE_WAIT_RET_ABANDONED_0 && val < MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + numobjects) {
1832 return WAIT_ABANDONED_0 + (val - MONO_W32HANDLE_WAIT_RET_ABANDONED_0);
1833 } else if (val == MONO_W32HANDLE_WAIT_RET_ALERTED) {
1834 return WAIT_IO_COMPLETION;
1835 } else if (val == MONO_W32HANDLE_WAIT_RET_TIMEOUT) {
1836 return WAIT_TIMEOUT;
1837 } else if (val == MONO_W32HANDLE_WAIT_RET_FAILED) {
1838 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1839 return MANAGED_WAIT_FAILED;
1841 g_error ("%s: unknown val value %d", __func__, val);
1845 static MonoW32HandleWaitRet
1846 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1849 MonoW32HandleWaitRet ret;
1856 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1860 if (numhandles != 1)
1861 ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE), numhandles);
1863 ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], ms, TRUE), 1);
1865 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
1866 ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, wait, TRUE);
1867 #endif /* HOST_WIN32 */
1870 if (ret != MONO_W32HANDLE_WAIT_RET_ALERTED)
1873 exc = mono_thread_execute_interruption ();
1875 mono_error_set_exception_instance (error, exc);
1882 /* Re-calculate ms according to the time passed */
1883 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1884 if (diff_ms >= ms) {
1885 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1888 wait = ms - diff_ms;
1894 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1899 MonoW32HandleWaitRet ret;
1901 MonoObject *waitHandle;
1902 MonoInternalThread *thread = mono_thread_internal_current ();
1904 /* Do this WaitSleepJoin check before creating objects */
1905 if (mono_thread_current_check_pending_interrupt ())
1906 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1908 /* We fail in managed if the array has more than 64 elements */
1909 numhandles = (guint32)mono_array_length(mono_handles);
1910 handles = g_new0(HANDLE, numhandles);
1912 for(i = 0; i < numhandles; i++) {
1913 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1914 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1918 ms=MONO_INFINITE_WAIT;
1921 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1923 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1925 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1929 mono_error_set_pending_exception (&error);
1931 return map_native_wait_result_to_managed (ret, numhandles);
1934 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1937 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1938 uintptr_t numhandles;
1939 MonoW32HandleWaitRet ret;
1941 MonoObject *waitHandle;
1942 MonoInternalThread *thread = mono_thread_internal_current ();
1944 /* Do this WaitSleepJoin check before creating objects */
1945 if (mono_thread_current_check_pending_interrupt ())
1946 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1948 numhandles = mono_array_length(mono_handles);
1949 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1950 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1952 for(i = 0; i < numhandles; i++) {
1953 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1954 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1958 ms=MONO_INFINITE_WAIT;
1961 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1963 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1965 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1967 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1969 mono_error_set_pending_exception (&error);
1971 return map_native_wait_result_to_managed (ret, numhandles);
1974 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1977 MonoW32HandleWaitRet ret;
1978 MonoInternalThread *thread = mono_thread_internal_current ();
1980 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1983 ms=MONO_INFINITE_WAIT;
1986 if (mono_thread_current_check_pending_interrupt ())
1987 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1989 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1991 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1993 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1995 mono_error_set_pending_exception (&error);
1996 return map_native_wait_result_to_managed (ret, 1);
2000 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
2002 MonoW32HandleWaitRet ret;
2003 MonoInternalThread *thread = mono_thread_internal_current ();
2006 ms = MONO_INFINITE_WAIT;
2008 if (mono_thread_current_check_pending_interrupt ())
2009 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
2011 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
2015 ret = mono_w32handle_convert_wait_ret (SignalObjectAndWait (toSignal, toWait, ms, TRUE), 1);
2017 ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE);
2021 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
2023 return map_native_wait_result_to_managed (ret, 1);
2026 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
2028 return InterlockedIncrement (location);
2031 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
2033 #if SIZEOF_VOID_P == 4
2034 if (G_UNLIKELY ((size_t)location & 0x7)) {
2036 mono_interlocked_lock ();
2039 mono_interlocked_unlock ();
2043 return InterlockedIncrement64 (location);
2046 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
2048 return InterlockedDecrement(location);
2051 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
2053 #if SIZEOF_VOID_P == 4
2054 if (G_UNLIKELY ((size_t)location & 0x7)) {
2056 mono_interlocked_lock ();
2059 mono_interlocked_unlock ();
2063 return InterlockedDecrement64 (location);
2066 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
2068 return InterlockedExchange(location, value);
2071 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
2074 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
2075 mono_gc_wbarrier_generic_nostore (location);
2079 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
2081 return InterlockedExchangePointer(location, value);
2084 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
2086 IntFloatUnion val, ret;
2089 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
2095 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
2097 #if SIZEOF_VOID_P == 4
2098 if (G_UNLIKELY ((size_t)location & 0x7)) {
2100 mono_interlocked_lock ();
2103 mono_interlocked_unlock ();
2107 return InterlockedExchange64 (location, value);
2111 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
2113 LongDoubleUnion val, ret;
2116 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
2121 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
2123 return InterlockedCompareExchange(location, value, comparand);
2126 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
2128 gint32 r = InterlockedCompareExchange(location, value, comparand);
2129 *success = r == comparand;
2133 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
2136 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
2137 mono_gc_wbarrier_generic_nostore (location);
2141 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
2143 return InterlockedCompareExchangePointer(location, value, comparand);
2146 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2148 IntFloatUnion val, ret, cmp;
2151 cmp.fval = comparand;
2152 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2158 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2160 #if SIZEOF_VOID_P == 8
2161 LongDoubleUnion val, comp, ret;
2164 comp.fval = comparand;
2165 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2171 mono_interlocked_lock ();
2173 if (old == comparand)
2175 mono_interlocked_unlock ();
2182 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2184 #if SIZEOF_VOID_P == 4
2185 if (G_UNLIKELY ((size_t)location & 0x7)) {
2187 mono_interlocked_lock ();
2189 if (old == comparand)
2191 mono_interlocked_unlock ();
2195 return InterlockedCompareExchange64 (location, value, comparand);
2199 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2202 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2203 mono_gc_wbarrier_generic_nostore (location);
2208 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2211 MONO_CHECK_NULL (location, NULL);
2212 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2213 mono_gc_wbarrier_generic_nostore (location);
2218 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2220 return InterlockedAdd (location, value);
2224 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2226 #if SIZEOF_VOID_P == 4
2227 if (G_UNLIKELY ((size_t)location & 0x7)) {
2229 mono_interlocked_lock ();
2232 mono_interlocked_unlock ();
2236 return InterlockedAdd64 (location, value);
2240 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2242 #if SIZEOF_VOID_P == 4
2243 if (G_UNLIKELY ((size_t)location & 0x7)) {
2245 mono_interlocked_lock ();
2247 mono_interlocked_unlock ();
2251 return InterlockedRead64 (location);
2255 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2257 mono_memory_barrier ();
2261 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2263 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2265 if (state & ThreadState_Background) {
2266 /* If the thread changes the background mode, the main thread has to
2267 * be notified, since it has to rebuild the list of threads to
2270 mono_os_event_set (&background_change_event);
2275 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2277 mono_thread_set_state (this_obj, (MonoThreadState)state);
2279 if (state & ThreadState_Background) {
2280 /* If the thread changes the background mode, the main thread has to
2281 * be notified, since it has to rebuild the list of threads to
2284 mono_os_event_set (&background_change_event);
2289 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2293 LOCK_THREAD (this_obj);
2295 state = this_obj->state;
2297 UNLOCK_THREAD (this_obj);
2302 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2304 MonoInternalThread *current;
2306 MonoInternalThread *thread = this_obj->internal_thread;
2308 LOCK_THREAD (thread);
2310 current = mono_thread_internal_current ();
2312 thread->thread_interrupt_requested = TRUE;
2313 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2315 UNLOCK_THREAD (thread);
2318 async_abort_internal (thread, FALSE);
2323 * mono_thread_current_check_pending_interrupt:
2325 * Checks if there's a interruption request and set the pending exception if so.
2327 * @returns true if a pending exception was set
2330 mono_thread_current_check_pending_interrupt (void)
2332 MonoInternalThread *thread = mono_thread_internal_current ();
2333 gboolean throw_ = FALSE;
2335 LOCK_THREAD (thread);
2337 if (thread->thread_interrupt_requested) {
2339 thread->thread_interrupt_requested = FALSE;
2342 UNLOCK_THREAD (thread);
2345 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2350 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2352 LOCK_THREAD (thread);
2354 if (thread->state & (ThreadState_AbortRequested | ThreadState_Stopped))
2356 UNLOCK_THREAD (thread);
2360 if ((thread->state & ThreadState_Unstarted) != 0) {
2361 thread->state |= ThreadState_Aborted;
2362 UNLOCK_THREAD (thread);
2366 thread->state |= ThreadState_AbortRequested;
2367 if (thread->abort_state_handle)
2368 mono_gchandle_free (thread->abort_state_handle);
2370 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2371 g_assert (thread->abort_state_handle);
2373 thread->abort_state_handle = 0;
2375 thread->abort_exc = NULL;
2377 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));
2379 /* During shutdown, we can't wait for other threads */
2381 /* Make sure the thread is awake */
2382 mono_thread_resume (thread);
2384 UNLOCK_THREAD (thread);
2389 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2391 if (!request_thread_abort (thread, state))
2394 if (thread == mono_thread_internal_current ()) {
2396 self_abort_internal (&error);
2397 mono_error_set_pending_exception (&error);
2399 async_abort_internal (thread, TRUE);
2404 * mono_thread_internal_abort:
2406 * Request thread @thread to be aborted.
2408 * @thread MUST NOT be the current thread.
2411 mono_thread_internal_abort (MonoInternalThread *thread)
2413 g_assert (thread != mono_thread_internal_current ());
2415 if (!request_thread_abort (thread, NULL))
2417 async_abort_internal (thread, TRUE);
2421 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2423 MonoInternalThread *thread = mono_thread_internal_current ();
2424 gboolean was_aborting;
2426 LOCK_THREAD (thread);
2427 was_aborting = thread->state & ThreadState_AbortRequested;
2428 thread->state &= ~ThreadState_AbortRequested;
2429 UNLOCK_THREAD (thread);
2431 if (!was_aborting) {
2432 const char *msg = "Unable to reset abort because no abort was requested";
2433 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2437 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2438 thread->abort_exc = NULL;
2439 if (thread->abort_state_handle) {
2440 mono_gchandle_free (thread->abort_state_handle);
2441 /* This is actually not necessary - the handle
2442 only counts if the exception is set */
2443 thread->abort_state_handle = 0;
2448 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2450 LOCK_THREAD (thread);
2452 thread->state &= ~ThreadState_AbortRequested;
2454 if (thread->abort_exc) {
2455 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2456 thread->abort_exc = NULL;
2457 if (thread->abort_state_handle) {
2458 mono_gchandle_free (thread->abort_state_handle);
2459 /* This is actually not necessary - the handle
2460 only counts if the exception is set */
2461 thread->abort_state_handle = 0;
2465 UNLOCK_THREAD (thread);
2469 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2472 MonoInternalThread *thread = this_obj->internal_thread;
2473 MonoObject *state, *deserialized = NULL;
2476 if (!thread->abort_state_handle)
2479 state = mono_gchandle_get_target (thread->abort_state_handle);
2482 domain = mono_domain_get ();
2483 if (mono_object_domain (state) == domain)
2486 deserialized = mono_object_xdomain_representation (state, domain, &error);
2488 if (!deserialized) {
2489 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2490 if (!is_ok (&error)) {
2491 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2492 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2494 mono_set_pending_exception (invalid_op_exc);
2498 return deserialized;
2502 mono_thread_suspend (MonoInternalThread *thread)
2504 LOCK_THREAD (thread);
2506 if (thread->state & (ThreadState_Unstarted | ThreadState_Aborted | ThreadState_Stopped))
2508 UNLOCK_THREAD (thread);
2512 if (thread->state & (ThreadState_Suspended | ThreadState_SuspendRequested | ThreadState_AbortRequested))
2514 UNLOCK_THREAD (thread);
2518 thread->state |= ThreadState_SuspendRequested;
2519 mono_os_event_reset (thread->suspended);
2521 if (thread == mono_thread_internal_current ()) {
2522 /* calls UNLOCK_THREAD (thread) */
2523 self_suspend_internal ();
2525 /* calls UNLOCK_THREAD (thread) */
2526 async_suspend_internal (thread, FALSE);
2533 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2535 if (!mono_thread_suspend (this_obj->internal_thread)) {
2536 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2541 /* LOCKING: LOCK_THREAD(thread) must be held */
2543 mono_thread_resume (MonoInternalThread *thread)
2545 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2546 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread));
2547 thread->state &= ~ThreadState_SuspendRequested;
2548 mono_os_event_set (thread->suspended);
2552 if ((thread->state & ThreadState_Suspended) == 0 ||
2553 (thread->state & ThreadState_Unstarted) != 0 ||
2554 (thread->state & ThreadState_Aborted) != 0 ||
2555 (thread->state & ThreadState_Stopped) != 0)
2557 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread));
2561 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread));
2563 mono_os_event_set (thread->suspended);
2565 if (!thread->self_suspended) {
2566 UNLOCK_THREAD (thread);
2568 /* Awake the thread */
2569 if (!mono_thread_info_resume (thread_get_tid (thread)))
2572 LOCK_THREAD (thread);
2575 thread->state &= ~ThreadState_Suspended;
2581 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2583 if (!thread->internal_thread) {
2584 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2586 LOCK_THREAD (thread->internal_thread);
2587 if (!mono_thread_resume (thread->internal_thread))
2588 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2589 UNLOCK_THREAD (thread->internal_thread);
2594 mono_threads_is_critical_method (MonoMethod *method)
2596 switch (method->wrapper_type) {
2597 case MONO_WRAPPER_RUNTIME_INVOKE:
2598 case MONO_WRAPPER_XDOMAIN_INVOKE:
2599 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2606 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2611 if (mono_threads_is_critical_method (m)) {
2612 *((gboolean*)data) = TRUE;
2619 is_running_protected_wrapper (void)
2621 gboolean found = FALSE;
2622 mono_stack_walk (find_wrapper, &found);
2627 mono_thread_stop (MonoThread *thread)
2629 MonoInternalThread *internal = thread->internal_thread;
2631 if (!request_thread_abort (internal, NULL))
2634 if (internal == mono_thread_internal_current ()) {
2636 self_abort_internal (&error);
2638 This function is part of the embeding API and has no way to return the exception
2639 to be thrown. So what we do is keep the old behavior and raise the exception.
2641 mono_error_raise_exception (&error); /* OK to throw, see note */
2643 async_abort_internal (internal, TRUE);
2648 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2650 gint8 tmp = *(volatile gint8 *)ptr;
2651 mono_memory_barrier ();
2656 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2658 gint16 tmp = *(volatile gint16 *)ptr;
2659 mono_memory_barrier ();
2664 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2666 gint32 tmp = *(volatile gint32 *)ptr;
2667 mono_memory_barrier ();
2672 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2674 gint64 tmp = *(volatile gint64 *)ptr;
2675 mono_memory_barrier ();
2680 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2682 volatile void *tmp = *(volatile void **)ptr;
2683 mono_memory_barrier ();
2684 return (void *) tmp;
2688 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2690 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2691 mono_memory_barrier ();
2692 return (MonoObject *) tmp;
2696 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2698 double tmp = *(volatile double *)ptr;
2699 mono_memory_barrier ();
2704 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2706 float tmp = *(volatile float *)ptr;
2707 mono_memory_barrier ();
2712 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2714 return InterlockedRead8 ((volatile gint8 *)ptr);
2718 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2720 return InterlockedRead16 ((volatile gint16 *)ptr);
2724 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2726 return InterlockedRead ((volatile gint32 *)ptr);
2730 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2732 #if SIZEOF_VOID_P == 4
2733 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2735 mono_interlocked_lock ();
2736 val = *(gint64*)ptr;
2737 mono_interlocked_unlock ();
2741 return InterlockedRead64 ((volatile gint64 *)ptr);
2745 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2747 return InterlockedReadPointer ((volatile gpointer *)ptr);
2751 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2755 #if SIZEOF_VOID_P == 4
2756 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2758 mono_interlocked_lock ();
2759 val = *(double*)ptr;
2760 mono_interlocked_unlock ();
2765 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2771 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2775 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2781 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2783 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2787 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2789 mono_memory_barrier ();
2790 *(volatile gint8 *)ptr = value;
2794 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2796 mono_memory_barrier ();
2797 *(volatile gint16 *)ptr = value;
2801 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2803 mono_memory_barrier ();
2804 *(volatile gint32 *)ptr = value;
2808 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2810 mono_memory_barrier ();
2811 *(volatile gint64 *)ptr = value;
2815 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2817 mono_memory_barrier ();
2818 *(volatile void **)ptr = value;
2822 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2824 mono_memory_barrier ();
2825 mono_gc_wbarrier_generic_store (ptr, value);
2829 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2831 mono_memory_barrier ();
2832 *(volatile double *)ptr = value;
2836 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2838 mono_memory_barrier ();
2839 *(volatile float *)ptr = value;
2843 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2845 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2849 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2851 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2855 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2857 InterlockedWrite ((volatile gint32 *)ptr, value);
2861 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2863 #if SIZEOF_VOID_P == 4
2864 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2865 mono_interlocked_lock ();
2866 *(gint64*)ptr = value;
2867 mono_interlocked_unlock ();
2872 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2876 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2878 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2882 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2886 #if SIZEOF_VOID_P == 4
2887 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2888 mono_interlocked_lock ();
2889 *(double*)ptr = value;
2890 mono_interlocked_unlock ();
2897 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2901 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2907 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2911 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2913 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2917 free_context (void *user_data)
2919 ContextStaticData *data = user_data;
2921 mono_threads_lock ();
2924 * There is no guarantee that, by the point this reference queue callback
2925 * has been invoked, the GC handle associated with the object will fail to
2926 * resolve as one might expect. So if we don't free and remove the GC
2927 * handle here, free_context_static_data_helper () could end up resolving
2928 * a GC handle to an actually-dead context which would contain a pointer
2929 * to an already-freed static data segment, resulting in a crash when
2932 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2934 mono_threads_unlock ();
2936 mono_gchandle_free (data->gc_handle);
2937 mono_free_static_data (data->static_data);
2942 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2944 mono_threads_lock ();
2946 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2949 contexts = g_hash_table_new (NULL, NULL);
2952 context_queue = mono_gc_reference_queue_new (free_context);
2954 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2955 g_hash_table_insert (contexts, gch, gch);
2958 * We use this intermediate structure to contain a duplicate pointer to
2959 * the static data because we can't rely on being able to resolve the GC
2960 * handle in the reference queue callback.
2962 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2963 data->gc_handle = GPOINTER_TO_UINT (gch);
2966 context_adjust_static_data (ctx);
2967 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2969 mono_threads_unlock ();
2971 mono_profiler_context_loaded (ctx);
2975 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2978 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2979 * cleanup in exceptional circumstances, we don't actually do any
2980 * cleanup work here. We instead do this via a reference queue.
2983 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2985 mono_profiler_context_unloaded (ctx);
2988 void mono_thread_init (MonoThreadStartCB start_cb,
2989 MonoThreadAttachCB attach_cb)
2991 mono_coop_mutex_init_recursive (&threads_mutex);
2993 mono_os_mutex_init_recursive(&interlocked_mutex);
2994 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2996 mono_os_event_init (&background_change_event, FALSE);
2998 mono_init_static_data_info (&thread_static_info);
2999 mono_init_static_data_info (&context_static_info);
3001 mono_thread_start_cb = start_cb;
3002 mono_thread_attach_cb = attach_cb;
3005 void mono_thread_cleanup (void)
3007 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
3008 /* The main thread must abandon any held mutexes (particularly
3009 * important for named mutexes as they are shared across
3010 * processes, see bug 74680.) This will happen when the
3011 * thread exits, but if it's not running in a subthread it
3012 * won't exit in time.
3014 mono_w32mutex_abandon ();
3018 /* This stuff needs more testing, it seems one of these
3019 * critical sections can be locked when mono_thread_cleanup is
3022 mono_coop_mutex_destroy (&threads_mutex);
3023 mono_os_mutex_destroy (&interlocked_mutex);
3024 mono_os_mutex_destroy (&delayed_free_table_mutex);
3025 mono_os_mutex_destroy (&small_id_mutex);
3026 mono_os_event_destroy (&background_change_event);
3031 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
3033 mono_thread_cleanup_fn = func;
3037 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
3039 thread->internal_thread->manage_callback = func;
3043 static void print_tids (gpointer key, gpointer value, gpointer user)
3045 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
3046 * sizeof(uint) and a cast to uint would overflow
3048 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
3049 * print this as a pointer.
3051 g_message ("Waiting for: %p", key);
3056 MonoThreadHandle *handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
3057 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
3062 wait_for_tids (struct wait_data *wait, guint32 timeout, gboolean check_state_change)
3065 MonoThreadInfoWaitRet ret;
3067 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3069 /* Add the thread state change event, so it wakes
3070 * up if a thread changes to background mode. */
3073 if (check_state_change)
3074 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, &background_change_event, FALSE, timeout, TRUE);
3076 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, NULL, TRUE, timeout, TRUE);
3079 if (ret == MONO_THREAD_INFO_WAIT_RET_FAILED) {
3080 /* See the comment in build_wait_tids() */
3081 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3085 for( i = 0; i < wait->num; i++)
3086 mono_threads_close_thread_handle (wait->handles [i]);
3088 if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT)
3091 if (ret < wait->num) {
3092 MonoInternalThread *internal;
3094 internal = wait->threads [ret];
3096 mono_threads_lock ();
3097 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
3098 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
3099 mono_threads_unlock ();
3103 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3105 struct wait_data *wait=(struct wait_data *)user;
3107 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS - 1) {
3108 MonoInternalThread *thread=(MonoInternalThread *)value;
3110 /* Ignore background threads, we abort them later */
3111 /* Do not lock here since it is not needed and the caller holds threads_lock */
3112 if (thread->state & ThreadState_Background) {
3113 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3114 return; /* just leave, ignore */
3117 if (mono_gc_is_finalizer_internal_thread (thread)) {
3118 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3122 if (thread == mono_thread_internal_current ()) {
3123 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3127 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3128 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3132 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3133 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3137 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3138 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3139 wait->handles[wait->num]=mono_threads_open_thread_handle (thread->handle);
3140 wait->threads[wait->num]=thread;
3143 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3145 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3150 /* Just ignore the rest, we can't do anything with
3157 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3159 struct wait_data *wait=(struct wait_data *)user;
3160 MonoNativeThreadId self = mono_native_thread_id_get ();
3161 MonoInternalThread *thread = (MonoInternalThread *)value;
3163 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3166 if (mono_native_thread_id_equals (thread_get_tid (thread), self))
3168 if (mono_gc_is_finalizer_internal_thread (thread))
3171 if ((thread->state & ThreadState_Background) && !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3172 wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
3173 wait->threads[wait->num] = thread;
3176 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3177 mono_thread_internal_abort (thread);
3184 * mono_threads_set_shutting_down:
3186 * Is called by a thread that wants to shut down Mono. If the runtime is already
3187 * shutting down, the calling thread is suspended/stopped, and this function never
3191 mono_threads_set_shutting_down (void)
3193 MonoInternalThread *current_thread = mono_thread_internal_current ();
3195 mono_threads_lock ();
3197 if (shutting_down) {
3198 mono_threads_unlock ();
3200 /* Make sure we're properly suspended/stopped */
3202 LOCK_THREAD (current_thread);
3204 if (current_thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
3205 UNLOCK_THREAD (current_thread);
3206 mono_thread_execute_interruption ();
3208 UNLOCK_THREAD (current_thread);
3211 /*since we're killing the thread, detach it.*/
3212 mono_thread_detach_internal (current_thread);
3214 /* Wake up other threads potentially waiting for us */
3215 mono_thread_info_exit (0);
3217 shutting_down = TRUE;
3219 /* Not really a background state change, but this will
3220 * interrupt the main thread if it is waiting for all
3221 * the other threads.
3223 mono_os_event_set (&background_change_event);
3225 mono_threads_unlock ();
3229 void mono_thread_manage (void)
3231 struct wait_data wait_data;
3232 struct wait_data *wait = &wait_data;
3234 memset (wait, 0, sizeof (struct wait_data));
3235 /* join each thread that's still running */
3236 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3238 mono_threads_lock ();
3240 THREAD_DEBUG (g_message("%s: No threads", __func__));
3241 mono_threads_unlock ();
3244 mono_threads_unlock ();
3247 mono_threads_lock ();
3248 if (shutting_down) {
3249 /* somebody else is shutting down */
3250 mono_threads_unlock ();
3253 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3254 mono_g_hash_table_foreach (threads, print_tids, NULL));
3256 mono_os_event_reset (&background_change_event);
3258 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3259 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3260 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3261 mono_threads_unlock ();
3263 /* Something to wait for */
3264 wait_for_tids (wait, MONO_INFINITE_WAIT, TRUE);
3265 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3266 } while(wait->num>0);
3268 /* Mono is shutting down, so just wait for the end */
3269 if (!mono_runtime_try_shutdown ()) {
3270 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3271 mono_thread_suspend (mono_thread_internal_current ());
3272 mono_thread_execute_interruption ();
3276 * Remove everything but the finalizer thread and self.
3277 * Also abort all the background threads
3280 mono_threads_lock ();
3283 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3284 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3285 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3287 mono_threads_unlock ();
3289 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3290 if (wait->num > 0) {
3291 /* Something to wait for */
3292 wait_for_tids (wait, MONO_INFINITE_WAIT, FALSE);
3294 } while (wait->num > 0);
3297 * give the subthreads a chance to really quit (this is mainly needed
3298 * to get correct user and system times from getrusage/wait/time(1)).
3299 * This could be removed if we avoid pthread_detach() and use pthread_join().
3301 mono_thread_info_yield ();
3305 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3307 MonoInternalThread *thread = (MonoInternalThread*)value;
3308 struct wait_data *wait = (struct wait_data*)user_data;
3311 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3313 * This needs no locking.
3315 if ((thread->state & ThreadState_Suspended) != 0 ||
3316 (thread->state & ThreadState_Stopped) != 0)
3319 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3320 wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle);
3321 wait->threads [wait->num] = thread;
3327 * mono_thread_suspend_all_other_threads:
3329 * Suspend all managed threads except the finalizer thread and this thread. It is
3330 * not possible to resume them later.
3332 void mono_thread_suspend_all_other_threads (void)
3334 struct wait_data wait_data;
3335 struct wait_data *wait = &wait_data;
3337 MonoNativeThreadId self = mono_native_thread_id_get ();
3338 guint32 eventidx = 0;
3339 gboolean starting, finished;
3341 memset (wait, 0, sizeof (struct wait_data));
3343 * The other threads could be in an arbitrary state at this point, i.e.
3344 * they could be starting up, shutting down etc. This means that there could be
3345 * threads which are not even in the threads hash table yet.
3349 * First we set a barrier which will be checked by all threads before they
3350 * are added to the threads hash table, and they will exit if the flag is set.
3351 * This ensures that no threads could be added to the hash later.
3352 * We will use shutting_down as the barrier for now.
3354 g_assert (shutting_down);
3357 * We make multiple calls to WaitForMultipleObjects since:
3358 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3359 * - some threads could exit without becoming suspended
3364 * Make a copy of the hashtable since we can't do anything with
3365 * threads while threads_mutex is held.
3368 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3369 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3370 mono_threads_lock ();
3371 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3372 mono_threads_unlock ();
3375 /* Get the suspended events that we'll be waiting for */
3376 for (i = 0; i < wait->num; ++i) {
3377 MonoInternalThread *thread = wait->threads [i];
3379 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3380 || mono_gc_is_finalizer_internal_thread (thread)
3381 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3383 mono_threads_close_thread_handle (wait->handles [i]);
3384 wait->threads [i] = NULL;
3388 LOCK_THREAD (thread);
3390 if (thread->state & (ThreadState_Suspended | ThreadState_Stopped)) {
3391 UNLOCK_THREAD (thread);
3392 mono_threads_close_thread_handle (wait->handles [i]);
3393 wait->threads [i] = NULL;
3399 /* Convert abort requests into suspend requests */
3400 if ((thread->state & ThreadState_AbortRequested) != 0)
3401 thread->state &= ~ThreadState_AbortRequested;
3403 thread->state |= ThreadState_SuspendRequested;
3404 mono_os_event_reset (thread->suspended);
3406 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3407 async_suspend_internal (thread, TRUE);
3409 mono_threads_close_thread_handle (wait->handles [i]);
3410 wait->threads [i] = NULL;
3412 if (eventidx <= 0) {
3414 * If there are threads which are starting up, we wait until they
3415 * are suspended when they try to register in the threads hash.
3416 * This is guaranteed to finish, since the threads which can create new
3417 * threads get suspended after a while.
3418 * FIXME: The finalizer thread can still create new threads.
3420 mono_threads_lock ();
3421 if (threads_starting_up)
3422 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3425 mono_threads_unlock ();
3427 mono_thread_info_sleep (100, NULL);
3435 MonoInternalThread *thread;
3436 MonoStackFrameInfo *frames;
3437 int nframes, max_frames;
3438 int nthreads, max_threads;
3439 MonoInternalThread **threads;
3440 } ThreadDumpUserData;
3442 static gboolean thread_dump_requested;
3444 /* This needs to be async safe */
3446 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3448 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3450 if (ud->nframes < ud->max_frames) {
3451 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3458 /* This needs to be async safe */
3459 static SuspendThreadResult
3460 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3462 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3463 MonoInternalThread *thread = user_data->thread;
3466 /* This no longer works with remote unwinding */
3467 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3468 mono_thread_internal_describe (thread, text);
3469 g_string_append (text, "\n");
3472 if (thread == mono_thread_internal_current ())
3473 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3475 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3477 return MonoResumeThread;
3481 int nthreads, max_threads;
3482 MonoInternalThread **threads;
3483 } CollectThreadsUserData;
3486 collect_thread (gpointer key, gpointer value, gpointer user)
3488 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3489 MonoInternalThread *thread = (MonoInternalThread *)value;
3491 if (ud->nthreads < ud->max_threads)
3492 ud->threads [ud->nthreads ++] = thread;
3496 * Collect running threads into the THREADS array.
3497 * THREADS should be an array allocated on the stack.
3500 collect_threads (MonoInternalThread **thread_array, int max_threads)
3502 CollectThreadsUserData ud;
3504 memset (&ud, 0, sizeof (ud));
3505 /* This array contains refs, but its on the stack, so its ok */
3506 ud.threads = thread_array;
3507 ud.max_threads = max_threads;
3509 mono_threads_lock ();
3510 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3511 mono_threads_unlock ();
3517 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3519 GString* text = g_string_new (0);
3521 GError *error = NULL;
3524 ud->thread = thread;
3527 /* Collect frames for the thread */
3528 if (thread == mono_thread_internal_current ()) {
3529 get_thread_dump (mono_thread_info_current (), ud);
3531 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3535 * Do all the non async-safe work outside of get_thread_dump.
3538 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3540 g_string_append_printf (text, "\n\"%s\"", name);
3543 else if (thread->threadpool_thread) {
3544 g_string_append (text, "\n\"<threadpool thread>\"");
3546 g_string_append (text, "\n\"<unnamed thread>\"");
3549 for (i = 0; i < ud->nframes; ++i) {
3550 MonoStackFrameInfo *frame = &ud->frames [i];
3551 MonoMethod *method = NULL;
3553 if (frame->type == FRAME_TYPE_MANAGED)
3554 method = mono_jit_info_get_method (frame->ji);
3557 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3558 g_string_append_printf (text, " %s\n", location);
3561 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3565 fprintf (stdout, "%s", text->str);
3567 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3568 OutputDebugStringA(text->str);
3571 g_string_free (text, TRUE);
3576 mono_threads_perform_thread_dump (void)
3578 ThreadDumpUserData ud;
3579 MonoInternalThread *thread_array [128];
3580 int tindex, nthreads;
3582 if (!thread_dump_requested)
3585 printf ("Full thread dump:\n");
3587 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3588 nthreads = collect_threads (thread_array, 128);
3590 memset (&ud, 0, sizeof (ud));
3591 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3592 ud.max_frames = 256;
3594 for (tindex = 0; tindex < nthreads; ++tindex)
3595 dump_thread (thread_array [tindex], &ud);
3599 thread_dump_requested = FALSE;
3602 /* Obtain the thread dump of all threads */
3604 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3607 ThreadDumpUserData ud;
3608 MonoInternalThread *thread_array [128];
3609 MonoDomain *domain = mono_domain_get ();
3610 MonoDebugSourceLocation *location;
3611 int tindex, nthreads;
3615 *out_threads = NULL;
3616 *out_stack_frames = NULL;
3618 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3619 nthreads = collect_threads (thread_array, 128);
3621 memset (&ud, 0, sizeof (ud));
3622 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3623 ud.max_frames = 256;
3625 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3628 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3632 for (tindex = 0; tindex < nthreads; ++tindex) {
3633 MonoInternalThread *thread = thread_array [tindex];
3634 MonoArray *thread_frames;
3640 /* Collect frames for the thread */
3641 if (thread == mono_thread_internal_current ()) {
3642 get_thread_dump (mono_thread_info_current (), &ud);
3644 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3647 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3649 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3652 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3654 for (i = 0; i < ud.nframes; ++i) {
3655 MonoStackFrameInfo *frame = &ud.frames [i];
3656 MonoMethod *method = NULL;
3657 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3661 sf->native_offset = frame->native_offset;
3663 if (frame->type == FRAME_TYPE_MANAGED)
3664 method = mono_jit_info_get_method (frame->ji);
3667 sf->method_address = (gsize) frame->ji->code_start;
3669 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3672 MONO_OBJECT_SETREF (sf, method, rm);
3674 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3676 sf->il_offset = location->il_offset;
3678 if (location && location->source_file) {
3679 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3680 sf->line = location->row;
3681 sf->column = location->column;
3683 mono_debug_free_source_location (location);
3688 mono_array_setref (thread_frames, i, sf);
3694 return is_ok (error);
3698 * mono_threads_request_thread_dump:
3700 * Ask all threads except the current to print their stacktrace to stdout.
3703 mono_threads_request_thread_dump (void)
3705 /*The new thread dump code runs out of the finalizer thread. */
3706 thread_dump_requested = TRUE;
3707 mono_gc_finalize_notify ();
3712 gint allocated; /* +1 so that refs [allocated] == NULL */
3716 typedef struct ref_stack RefStack;
3719 ref_stack_new (gint initial_size)
3723 initial_size = MAX (initial_size, 16) + 1;
3724 rs = g_new0 (RefStack, 1);
3725 rs->refs = g_new0 (gpointer, initial_size);
3726 rs->allocated = initial_size;
3731 ref_stack_destroy (gpointer ptr)
3733 RefStack *rs = (RefStack *)ptr;
3742 ref_stack_push (RefStack *rs, gpointer ptr)
3744 g_assert (rs != NULL);
3746 if (rs->bottom >= rs->allocated) {
3747 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3748 rs->allocated <<= 1;
3749 rs->refs [rs->allocated] = NULL;
3751 rs->refs [rs->bottom++] = ptr;
3755 ref_stack_pop (RefStack *rs)
3757 if (rs == NULL || rs->bottom == 0)
3761 rs->refs [rs->bottom] = NULL;
3765 ref_stack_find (RefStack *rs, gpointer ptr)
3772 for (refs = rs->refs; refs && *refs; refs++) {
3780 * mono_thread_push_appdomain_ref:
3782 * Register that the current thread may have references to objects in domain
3783 * @domain on its stack. Each call to this function should be paired with a
3784 * call to pop_appdomain_ref.
3787 mono_thread_push_appdomain_ref (MonoDomain *domain)
3789 MonoInternalThread *thread = mono_thread_internal_current ();
3792 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3793 SPIN_LOCK (thread->lock_thread_id);
3794 if (thread->appdomain_refs == NULL)
3795 thread->appdomain_refs = ref_stack_new (16);
3796 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3797 SPIN_UNLOCK (thread->lock_thread_id);
3802 mono_thread_pop_appdomain_ref (void)
3804 MonoInternalThread *thread = mono_thread_internal_current ();
3807 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3808 SPIN_LOCK (thread->lock_thread_id);
3809 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3810 SPIN_UNLOCK (thread->lock_thread_id);
3815 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3818 SPIN_LOCK (thread->lock_thread_id);
3819 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3820 SPIN_UNLOCK (thread->lock_thread_id);
3825 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3827 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3830 typedef struct abort_appdomain_data {
3831 struct wait_data wait;
3833 } abort_appdomain_data;
3836 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3838 MonoInternalThread *thread = (MonoInternalThread*)value;
3839 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3840 MonoDomain *domain = data->domain;
3842 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3843 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3845 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3846 data->wait.handles [data->wait.num] = mono_threads_open_thread_handle (thread->handle);
3847 data->wait.threads [data->wait.num] = thread;
3850 /* Just ignore the rest, we can't do anything with
3858 * mono_threads_abort_appdomain_threads:
3860 * Abort threads which has references to the given appdomain.
3863 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3865 #ifdef __native_client__
3869 abort_appdomain_data user_data;
3871 int orig_timeout = timeout;
3874 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3876 start_time = mono_msec_ticks ();
3878 mono_threads_lock ();
3880 user_data.domain = domain;
3881 user_data.wait.num = 0;
3882 /* This shouldn't take any locks */
3883 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3884 mono_threads_unlock ();
3886 if (user_data.wait.num > 0) {
3887 /* Abort the threads outside the threads lock */
3888 for (i = 0; i < user_data.wait.num; ++i)
3889 mono_thread_internal_abort (user_data.wait.threads [i]);
3892 * We should wait for the threads either to abort, or to leave the
3893 * domain. We can't do the latter, so we wait with a timeout.
3895 wait_for_tids (&user_data.wait, 100, FALSE);
3898 /* Update remaining time */
3899 timeout -= mono_msec_ticks () - start_time;
3900 start_time = mono_msec_ticks ();
3902 if (orig_timeout != -1 && timeout < 0)
3905 while (user_data.wait.num > 0);
3907 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3913 * mono_thread_get_undeniable_exception:
3915 * Return an exception which needs to be raised when leaving a catch clause.
3916 * This is used for undeniable exception propagation.
3919 mono_thread_get_undeniable_exception (void)
3921 MonoInternalThread *thread = mono_thread_internal_current ();
3923 if (!(thread && thread->abort_exc && !is_running_protected_wrapper ()))
3926 // We don't want to have our exception effect calls made by
3927 // the catching block
3929 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
3933 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3934 * exception if the thread no longer references a dying appdomain.
3936 thread->abort_exc->trace_ips = NULL;
3937 thread->abort_exc->stack_trace = NULL;
3938 return thread->abort_exc;
3941 #if MONO_SMALL_CONFIG
3942 #define NUM_STATIC_DATA_IDX 4
3943 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3947 #define NUM_STATIC_DATA_IDX 8
3948 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3949 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3953 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3954 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3957 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3959 gpointer *static_data = (gpointer *)addr;
3961 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3962 void **ptr = (void **)static_data [i];
3967 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3968 void **p = ptr + idx;
3971 mark_func ((MonoObject**)p, gc_data);
3977 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3979 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3983 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3985 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3989 * mono_alloc_static_data
3991 * Allocate memory blocks for storing threads or context static data
3994 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3996 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3999 gpointer* static_data = *static_data_ptr;
4001 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4002 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4004 if (mono_gc_user_markers_supported ()) {
4005 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4006 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4008 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4009 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4012 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4013 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4014 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4015 *static_data_ptr = static_data;
4016 static_data [0] = static_data;
4019 for (i = 1; i <= idx; ++i) {
4020 if (static_data [i])
4023 if (mono_gc_user_markers_supported ())
4024 static_data [i] = g_malloc0 (static_data_size [i]);
4026 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4027 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4028 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4033 mono_free_static_data (gpointer* static_data)
4036 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4037 gpointer p = static_data [i];
4041 * At this point, the static data pointer array is still registered with the
4042 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4043 * data. Freeing the individual arrays without first nulling their slots
4044 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4045 * such an already freed array. See bug #13813.
4047 static_data [i] = NULL;
4048 mono_memory_write_barrier ();
4049 if (mono_gc_user_markers_supported ())
4052 mono_gc_free_fixed (p);
4054 mono_gc_free_fixed (static_data);
4058 * mono_init_static_data_info
4060 * Initializes static data counters
4062 static void mono_init_static_data_info (StaticDataInfo *static_data)
4064 static_data->idx = 0;
4065 static_data->offset = 0;
4066 static_data->freelist = NULL;
4070 * mono_alloc_static_data_slot
4072 * Generates an offset for static data. static_data contains the counters
4073 * used to generate it.
4076 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4078 if (!static_data->idx && !static_data->offset) {
4080 * we use the first chunk of the first allocation also as
4081 * an array for the rest of the data
4083 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4085 static_data->offset += align - 1;
4086 static_data->offset &= ~(align - 1);
4087 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4088 static_data->idx ++;
4089 g_assert (size <= static_data_size [static_data->idx]);
4090 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4091 static_data->offset = 0;
4093 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4094 static_data->offset += size;
4099 * LOCKING: requires that threads_mutex is held
4102 context_adjust_static_data (MonoAppContext *ctx)
4104 if (context_static_info.offset || context_static_info.idx > 0) {
4105 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4106 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4107 ctx->data->static_data = ctx->static_data;
4112 * LOCKING: requires that threads_mutex is held
4115 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4117 MonoInternalThread *thread = (MonoInternalThread *)value;
4118 guint32 offset = GPOINTER_TO_UINT (user);
4120 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4124 * LOCKING: requires that threads_mutex is held
4127 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4129 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4134 guint32 offset = GPOINTER_TO_UINT (user);
4135 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4136 ctx->data->static_data = ctx->static_data;
4139 static StaticDataFreeList*
4140 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4142 StaticDataFreeList* prev = NULL;
4143 StaticDataFreeList* tmp = static_data->freelist;
4145 if (tmp->size == size) {
4147 prev->next = tmp->next;
4149 static_data->freelist = tmp->next;
4158 #if SIZEOF_VOID_P == 4
4165 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4167 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4169 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4170 MonoBitSet *rb = sets [idx];
4171 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4172 offset /= sizeof (uintptr_t);
4173 /* offset is now the bitmap offset */
4174 for (int i = 0; i < numbits; ++i) {
4175 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4176 mono_bitset_set_fast (rb, offset + i);
4181 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4183 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4184 MonoBitSet *rb = sets [idx];
4185 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4186 offset /= sizeof (uintptr_t);
4187 /* offset is now the bitmap offset */
4188 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4189 mono_bitset_clear_fast (rb, offset + i);
4193 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4195 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4197 StaticDataInfo *info;
4200 if (static_type == SPECIAL_STATIC_THREAD) {
4201 info = &thread_static_info;
4202 sets = thread_reference_bitmaps;
4204 info = &context_static_info;
4205 sets = context_reference_bitmaps;
4208 mono_threads_lock ();
4210 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4214 offset = item->offset;
4217 offset = mono_alloc_static_data_slot (info, size, align);
4220 update_reference_bitmap (sets, offset, bitmap, numbits);
4222 if (static_type == SPECIAL_STATIC_THREAD) {
4223 /* This can be called during startup */
4224 if (threads != NULL)
4225 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4227 if (contexts != NULL)
4228 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4230 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4233 mono_threads_unlock ();
4239 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4241 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4243 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4244 return get_thread_static_data (thread, offset);
4246 return get_context_static_data (thread->current_appcontext, offset);
4251 mono_get_special_static_data (guint32 offset)
4253 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4262 * LOCKING: requires that threads_mutex is held
4265 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4267 MonoInternalThread *thread = (MonoInternalThread *)value;
4268 OffsetSize *data = (OffsetSize *)user;
4269 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4270 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4273 if (!thread->static_data || !thread->static_data [idx])
4275 ptr = ((char*) thread->static_data [idx]) + off;
4276 mono_gc_bzero_atomic (ptr, data->size);
4280 * LOCKING: requires that threads_mutex is held
4283 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4285 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4290 OffsetSize *data = (OffsetSize *)user;
4291 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4292 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4295 if (!ctx->static_data || !ctx->static_data [idx])
4298 ptr = ((char*) ctx->static_data [idx]) + off;
4299 mono_gc_bzero_atomic (ptr, data->size);
4303 do_free_special_slot (guint32 offset, guint32 size)
4305 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4307 StaticDataInfo *info;
4309 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4310 info = &thread_static_info;
4311 sets = thread_reference_bitmaps;
4313 info = &context_static_info;
4314 sets = context_reference_bitmaps;
4317 guint32 data_offset = offset;
4318 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4319 OffsetSize data = { data_offset, size };
4321 clear_reference_bitmap (sets, data.offset, data.size);
4323 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4324 if (threads != NULL)
4325 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4327 if (contexts != NULL)
4328 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4331 if (!mono_runtime_is_shutting_down ()) {
4332 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4334 item->offset = offset;
4337 item->next = info->freelist;
4338 info->freelist = item;
4343 do_free_special (gpointer key, gpointer value, gpointer data)
4345 MonoClassField *field = (MonoClassField *)key;
4346 guint32 offset = GPOINTER_TO_UINT (value);
4349 size = mono_type_size (field->type, &align);
4350 do_free_special_slot (offset, size);
4354 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4356 mono_threads_lock ();
4358 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4360 mono_threads_unlock ();
4364 static void CALLBACK dummy_apc (ULONG_PTR param)
4370 * mono_thread_execute_interruption
4372 * Performs the operation that the requested thread state requires (abort,
4375 static MonoException*
4376 mono_thread_execute_interruption (void)
4378 MonoInternalThread *thread = mono_thread_internal_current ();
4379 MonoThread *sys_thread = mono_thread_current ();
4381 LOCK_THREAD (thread);
4383 /* MonoThread::interruption_requested can only be changed with atomics */
4384 if (mono_thread_clear_interruption_requested (thread)) {
4385 /* this will consume pending APC calls */
4387 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4389 /* Clear the interrupted flag of the thread so it can wait again */
4390 mono_thread_info_clear_self_interrupt ();
4393 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4394 if (sys_thread->pending_exception) {
4397 exc = sys_thread->pending_exception;
4398 sys_thread->pending_exception = NULL;
4400 UNLOCK_THREAD (thread);
4402 } else if (thread->state & (ThreadState_AbortRequested)) {
4403 UNLOCK_THREAD (thread);
4404 g_assert (sys_thread->pending_exception == NULL);
4405 if (thread->abort_exc == NULL) {
4407 * This might be racy, but it has to be called outside the lock
4408 * since it calls managed code.
4410 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4412 return thread->abort_exc;
4413 } else if (thread->state & (ThreadState_SuspendRequested)) {
4414 /* calls UNLOCK_THREAD (thread) */
4415 self_suspend_internal ();
4417 } else if (thread->thread_interrupt_requested) {
4419 thread->thread_interrupt_requested = FALSE;
4420 UNLOCK_THREAD (thread);
4422 return(mono_get_exception_thread_interrupted ());
4425 UNLOCK_THREAD (thread);
4431 * mono_thread_request_interruption
4433 * A signal handler can call this method to request the interruption of a
4434 * thread. The result of the interruption will depend on the current state of
4435 * the thread. If the result is an exception that needs to be throw, it is
4436 * provided as return value.
4439 mono_thread_request_interruption (gboolean running_managed)
4441 MonoInternalThread *thread = mono_thread_internal_current ();
4443 /* The thread may already be stopping */
4447 if (!mono_thread_set_interruption_requested (thread))
4450 if (!running_managed || is_running_protected_wrapper ()) {
4451 /* Can't stop while in unmanaged code. Increase the global interruption
4452 request count. When exiting the unmanaged method the count will be
4453 checked and the thread will be interrupted. */
4455 /* this will awake the thread if it is in WaitForSingleObject
4457 /* Our implementation of this function ignores the func argument */
4459 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
4461 mono_thread_info_self_interrupt ();
4466 return mono_thread_execute_interruption ();
4470 /*This function should be called by a thread after it has exited all of
4471 * its handle blocks at interruption time.*/
4473 mono_thread_resume_interruption (gboolean exec)
4475 MonoInternalThread *thread = mono_thread_internal_current ();
4476 gboolean still_aborting;
4478 /* The thread may already be stopping */
4482 LOCK_THREAD (thread);
4483 still_aborting = (thread->state & (ThreadState_AbortRequested)) != 0;
4484 UNLOCK_THREAD (thread);
4486 /*This can happen if the protected block called Thread::ResetAbort*/
4487 if (!still_aborting)
4490 if (!mono_thread_set_interruption_requested (thread))
4493 mono_thread_info_self_interrupt ();
4496 return mono_thread_execute_interruption ();
4501 gboolean mono_thread_interruption_requested ()
4503 if (thread_interruption_requested) {
4504 MonoInternalThread *thread = mono_thread_internal_current ();
4505 /* The thread may already be stopping */
4507 return mono_thread_get_interruption_requested (thread);
4512 static MonoException*
4513 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4515 MonoInternalThread *thread = mono_thread_internal_current ();
4517 /* The thread may already be stopping */
4520 if (!mono_thread_get_interruption_requested (thread))
4522 if (!bypass_abort_protection && is_running_protected_wrapper ())
4525 return mono_thread_execute_interruption ();
4529 * Performs the interruption of the current thread, if one has been requested,
4530 * and the thread is not running a protected wrapper.
4531 * Return the exception which needs to be thrown, if any.
4534 mono_thread_interruption_checkpoint (void)
4536 return mono_thread_interruption_checkpoint_request (FALSE);
4540 * Performs the interruption of the current thread, if one has been requested.
4541 * Return the exception which needs to be thrown, if any.
4544 mono_thread_force_interruption_checkpoint_noraise (void)
4546 return mono_thread_interruption_checkpoint_request (TRUE);
4550 * mono_set_pending_exception:
4552 * Set the pending exception of the current thread to EXC.
4553 * The exception will be thrown when execution returns to managed code.
4556 mono_set_pending_exception (MonoException *exc)
4558 MonoThread *thread = mono_thread_current ();
4560 /* The thread may already be stopping */
4564 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4566 mono_thread_request_interruption (FALSE);
4570 * mono_thread_interruption_request_flag:
4572 * Returns the address of a flag that will be non-zero if an interruption has
4573 * been requested for a thread. The thread to interrupt may not be the current
4574 * thread, so an additional call to mono_thread_interruption_requested() or
4575 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4578 gint32* mono_thread_interruption_request_flag ()
4580 return &thread_interruption_requested;
4584 mono_thread_init_apartment_state (void)
4587 MonoInternalThread* thread = mono_thread_internal_current ();
4589 /* Positive return value indicates success, either
4590 * S_OK if this is first CoInitialize call, or
4591 * S_FALSE if CoInitialize already called, but with same
4592 * threading model. A negative value indicates failure,
4593 * probably due to trying to change the threading model.
4595 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4596 ? COINIT_APARTMENTTHREADED
4597 : COINIT_MULTITHREADED) < 0) {
4598 thread->apartment_state = ThreadApartmentState_Unknown;
4604 mono_thread_cleanup_apartment_state (void)
4607 MonoInternalThread* thread = mono_thread_internal_current ();
4609 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4616 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4618 LOCK_THREAD (thread);
4619 thread->state |= state;
4620 UNLOCK_THREAD (thread);
4624 * mono_thread_test_and_set_state:
4626 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4628 * Returns TRUE is @set was OR'd in.
4631 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4633 LOCK_THREAD (thread);
4635 if ((thread->state & test) != 0) {
4636 UNLOCK_THREAD (thread);
4640 thread->state |= set;
4641 UNLOCK_THREAD (thread);
4647 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4649 LOCK_THREAD (thread);
4650 thread->state &= ~state;
4651 UNLOCK_THREAD (thread);
4655 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4657 gboolean ret = FALSE;
4659 LOCK_THREAD (thread);
4661 if ((thread->state & test) != 0) {
4665 UNLOCK_THREAD (thread);
4671 self_interrupt_thread (void *_unused)
4674 MonoThreadInfo *info;
4676 exc = mono_thread_execute_interruption ();
4678 if (mono_threads_is_coop_enabled ()) {
4679 /* We can return from an async call in coop, as
4680 * it's simply called when exiting the safepoint */
4684 g_error ("%s: we can't resume from an async call", __func__);
4687 info = mono_thread_info_current ();
4689 /* We must use _with_context since we didn't trampoline into the runtime */
4690 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. */
4694 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4698 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4702 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4704 MonoJitInfo **dest = (MonoJitInfo **)data;
4710 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4712 MonoJitInfo *ji = NULL;
4717 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4718 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4719 * where we hold runtime locks.
4721 if (!mono_threads_is_coop_enabled ())
4722 mono_thread_info_set_is_async_context (TRUE);
4723 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4724 if (!mono_threads_is_coop_enabled ())
4725 mono_thread_info_set_is_async_context (FALSE);
4730 MonoInternalThread *thread;
4731 gboolean install_async_abort;
4732 MonoThreadInfoInterruptToken *interrupt_token;
4735 static SuspendThreadResult
4736 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4738 AbortThreadData *data = (AbortThreadData *)ud;
4739 MonoInternalThread *thread = data->thread;
4740 MonoJitInfo *ji = NULL;
4741 gboolean protected_wrapper;
4742 gboolean running_managed;
4744 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4745 return MonoResumeThread;
4747 /*someone is already interrupting it*/
4748 if (!mono_thread_set_interruption_requested (thread))
4749 return MonoResumeThread;
4751 ji = mono_thread_info_get_last_managed (info);
4752 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4753 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4755 if (!protected_wrapper && running_managed) {
4756 /*We are in managed code*/
4757 /*Set the thread to call */
4758 if (data->install_async_abort)
4759 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4760 return MonoResumeThread;
4763 * This will cause waits to be broken.
4764 * It will also prevent the thread from entering a wait, so if the thread returns
4765 * from the wait before it receives the abort signal, it will just spin in the wait
4766 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4769 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4771 return MonoResumeThread;
4776 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4778 AbortThreadData data;
4780 g_assert (thread != mono_thread_internal_current ());
4782 data.thread = thread;
4783 data.install_async_abort = install_async_abort;
4784 data.interrupt_token = NULL;
4786 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4787 if (data.interrupt_token)
4788 mono_thread_info_finish_interrupt (data.interrupt_token);
4789 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4793 self_abort_internal (MonoError *error)
4799 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4800 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4803 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.
4805 exc = mono_thread_request_interruption (TRUE);
4807 mono_error_set_exception_instance (error, exc);
4809 mono_thread_info_self_interrupt ();
4813 MonoInternalThread *thread;
4815 MonoThreadInfoInterruptToken *interrupt_token;
4816 } SuspendThreadData;
4818 static SuspendThreadResult
4819 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4821 SuspendThreadData *data = (SuspendThreadData *)ud;
4822 MonoInternalThread *thread = data->thread;
4823 MonoJitInfo *ji = NULL;
4824 gboolean protected_wrapper;
4825 gboolean running_managed;
4827 ji = mono_thread_info_get_last_managed (info);
4828 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4829 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4831 if (running_managed && !protected_wrapper) {
4832 if (mono_threads_is_coop_enabled ()) {
4833 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4834 return MonoResumeThread;
4836 thread->state &= ~ThreadState_SuspendRequested;
4837 thread->state |= ThreadState_Suspended;
4838 return KeepSuspended;
4841 mono_thread_set_interruption_requested (thread);
4842 if (data->interrupt)
4843 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4845 return MonoResumeThread;
4849 /* LOCKING: called with @thread synch_cs held, and releases it */
4851 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4853 SuspendThreadData data;
4855 g_assert (thread != mono_thread_internal_current ());
4857 // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4859 thread->self_suspended = FALSE;
4861 data.thread = thread;
4862 data.interrupt = interrupt;
4863 data.interrupt_token = NULL;
4865 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4866 if (data.interrupt_token)
4867 mono_thread_info_finish_interrupt (data.interrupt_token);
4869 UNLOCK_THREAD (thread);
4872 /* LOCKING: called with @thread synch_cs held, and releases it */
4874 self_suspend_internal (void)
4876 MonoInternalThread *thread;
4878 MonoOSEventWaitRet res;
4880 thread = mono_thread_internal_current ();
4882 // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4884 thread->self_suspended = TRUE;
4886 thread->state &= ~ThreadState_SuspendRequested;
4887 thread->state |= ThreadState_Suspended;
4889 UNLOCK_THREAD (thread);
4891 event = thread->suspended;
4894 res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT, TRUE);
4895 g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
4900 suspend_for_shutdown_async_call (gpointer unused)
4903 mono_thread_info_yield ();
4906 static SuspendThreadResult
4907 suspend_for_shutdown_critical (MonoThreadInfo *info, gpointer unused)
4909 mono_thread_info_setup_async_call (info, suspend_for_shutdown_async_call, NULL);
4910 return MonoResumeThread;
4914 mono_thread_internal_suspend_for_shutdown (MonoInternalThread *thread)
4916 g_assert (thread != mono_thread_internal_current ());
4918 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, suspend_for_shutdown_critical, NULL);
4922 * mono_thread_is_foreign:
4923 * @thread: the thread to query
4925 * This function allows one to determine if a thread was created by the mono runtime and has
4926 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4928 * Returns: TRUE if @thread was not created by the runtime.
4931 mono_thread_is_foreign (MonoThread *thread)
4933 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4934 return info->runtime_thread == FALSE;
4938 * mono_add_joinable_thread:
4940 * Add TID to the list of joinable threads.
4941 * LOCKING: Acquires the threads lock.
4944 mono_threads_add_joinable_thread (gpointer tid)
4948 * We cannot detach from threads because it causes problems like
4949 * 2fd16f60/r114307. So we collect them and join them when
4950 * we have time (in he finalizer thread).
4952 joinable_threads_lock ();
4953 if (!joinable_threads)
4954 joinable_threads = g_hash_table_new (NULL, NULL);
4955 g_hash_table_insert (joinable_threads, tid, tid);
4956 joinable_thread_count ++;
4957 joinable_threads_unlock ();
4959 mono_gc_finalize_notify ();
4964 * mono_threads_join_threads:
4966 * Join all joinable threads. This is called from the finalizer thread.
4967 * LOCKING: Acquires the threads lock.
4970 mono_threads_join_threads (void)
4973 GHashTableIter iter;
4980 if (!joinable_thread_count)
4984 joinable_threads_lock ();
4986 if (g_hash_table_size (joinable_threads)) {
4987 g_hash_table_iter_init (&iter, joinable_threads);
4988 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4989 thread = (pthread_t)tid;
4990 g_hash_table_remove (joinable_threads, key);
4991 joinable_thread_count --;
4994 joinable_threads_unlock ();
4996 if (thread != pthread_self ()) {
4998 /* This shouldn't block */
4999 mono_threads_join_lock ();
5000 mono_native_thread_join (thread);
5001 mono_threads_join_unlock ();
5014 * Wait for thread TID to exit.
5015 * LOCKING: Acquires the threads lock.
5018 mono_thread_join (gpointer tid)
5022 gboolean found = FALSE;
5024 joinable_threads_lock ();
5025 if (!joinable_threads)
5026 joinable_threads = g_hash_table_new (NULL, NULL);
5027 if (g_hash_table_lookup (joinable_threads, tid)) {
5028 g_hash_table_remove (joinable_threads, tid);
5029 joinable_thread_count --;
5032 joinable_threads_unlock ();
5035 thread = (pthread_t)tid;
5037 mono_native_thread_join (thread);
5043 mono_thread_internal_unhandled_exception (MonoObject* exc)
5045 MonoClass *klass = exc->vtable->klass;
5046 if (is_threadabort_exception (klass)) {
5047 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5048 } else if (!is_appdomainunloaded_exception (klass)
5049 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5050 mono_unhandled_exception (exc);
5051 if (mono_environment_exitcode_get () == 1) {
5052 mono_environment_exitcode_set (255);
5053 mono_invoke_unhandled_exception_hook (exc);
5054 g_assert_not_reached ();
5060 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5063 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5064 mono_error_set_pending_exception (&error);
5068 * mono_threads_attach_coop: called by native->managed wrappers
5072 * - @return: the original domain which needs to be restored, or NULL.
5075 * - @dummy: contains the original domain
5076 * - @return: a cookie containing current MonoThreadInfo*.
5079 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5082 gboolean fresh_thread = FALSE;
5085 /* Happens when called from AOTed code which is only used in the root domain. */
5086 domain = mono_get_root_domain ();
5091 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5092 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5093 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5094 * we're only responsible for making the cookie. */
5095 if (mono_threads_is_coop_enabled ()) {
5096 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5097 fresh_thread = !info || !mono_thread_info_is_live (info);
5100 if (!mono_thread_internal_current ()) {
5101 mono_thread_attach_full (domain, FALSE);
5104 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5107 orig = mono_domain_get ();
5109 mono_domain_set (domain, TRUE);
5111 if (!mono_threads_is_coop_enabled ())
5112 return orig != domain ? orig : NULL;
5116 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5117 * return the right cookie. */
5118 return mono_threads_enter_gc_unsafe_region_cookie ();
5121 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5122 return mono_threads_enter_gc_unsafe_region (dummy);
5127 * mono_threads_detach_coop: called by native->managed wrappers
5130 * - @cookie: the original domain which needs to be restored, or NULL.
5134 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5135 * - @dummy: contains the original domain
5138 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5140 MonoDomain *domain, *orig;
5142 if (!mono_threads_is_coop_enabled ()) {
5143 orig = (MonoDomain*) cookie;
5145 mono_domain_set (orig, TRUE);
5147 orig = (MonoDomain*) *dummy;
5149 domain = mono_domain_get ();
5152 /* it won't do anything if cookie is NULL
5153 * thread state RUNNING -> (RUNNING|BLOCKING) */
5154 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5156 if (orig != domain) {
5158 mono_domain_unset ();
5160 mono_domain_set (orig, TRUE);
5166 /* Returns TRUE if the current thread is ready to be interrupted. */
5168 mono_threads_is_ready_to_be_interrupted (void)
5170 MonoInternalThread *thread;
5172 thread = mono_thread_internal_current ();
5173 LOCK_THREAD (thread);
5174 if (thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5175 UNLOCK_THREAD (thread);
5179 if (mono_thread_get_abort_prot_block_count (thread) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5180 UNLOCK_THREAD (thread);
5184 UNLOCK_THREAD (thread);
5190 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5192 g_string_append_printf (text, ", thread handle : %p", internal->handle);
5194 if (internal->thread_info) {
5195 g_string_append (text, ", state : ");
5196 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5199 if (internal->owned_mutexes) {
5202 g_string_append (text, ", owns : [");
5203 for (i = 0; i < internal->owned_mutexes->len; i++)
5204 g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5205 g_string_append (text, "]");
5210 mono_thread_internal_is_current (MonoInternalThread *internal)
5212 g_assert (internal);
5213 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));