3 * Thread support internal calls
6 * Dick Porter (dick@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
8 * Patrik Torstensson (patrik.torstensson@labs2.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/domain-internals.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/threads.h>
25 #include <mono/metadata/threads-types.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/environment.h>
28 #include <mono/metadata/monitor.h>
29 #include <mono/metadata/gc-internals.h>
30 #include <mono/metadata/marshal.h>
31 #include <mono/metadata/runtime.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/debug-internals.h>
34 #include <mono/utils/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/mono-threads-coop.h>
41 #include <mono/utils/hazard-pointer.h>
42 #include <mono/utils/mono-tls.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/os-event.h>
47 #include <mono/utils/mono-threads-debug.h>
48 #include <mono/utils/unlocked.h>
49 #include <mono/metadata/w32handle.h>
50 #include <mono/metadata/w32event.h>
51 #include <mono/metadata/w32mutex.h>
53 #include <mono/metadata/reflection-internals.h>
54 #include <mono/metadata/abi-details.h>
55 #include <mono/metadata/w32error.h>
56 #include <mono/utils/w32api.h>
62 #if defined(HOST_WIN32)
66 #if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
67 #define USE_TKILL_ON_ANDROID 1
73 #ifdef USE_TKILL_ON_ANDROID
74 extern int tkill (pid_t tid, int signal);
78 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
79 #define THREAD_DEBUG(a)
80 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
81 #define THREAD_WAIT_DEBUG(a)
82 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
83 #define LIBGC_DEBUG(a)
85 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
86 #define SPIN_LOCK(i) do { \
87 if (SPIN_TRYLOCK (i)) \
91 #define SPIN_UNLOCK(i) i = 0
93 #define LOCK_THREAD(thread) lock_thread((thread))
94 #define UNLOCK_THREAD(thread) unlock_thread((thread))
106 typedef struct _StaticDataFreeList StaticDataFreeList;
107 struct _StaticDataFreeList {
108 StaticDataFreeList *next;
116 StaticDataFreeList *freelist;
119 /* Controls access to the 'threads' hash table */
120 static void mono_threads_lock (void);
121 static void mono_threads_unlock (void);
122 static MonoCoopMutex threads_mutex;
124 /* Controls access to the 'joinable_threads' hash table */
125 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
126 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
127 static mono_mutex_t joinable_threads_mutex;
129 /* Holds current status of static data heap */
130 static StaticDataInfo thread_static_info;
131 static StaticDataInfo context_static_info;
133 /* The hash of existing threads (key is thread ID, value is
134 * MonoInternalThread*) that need joining before exit
136 static MonoGHashTable *threads=NULL;
138 /* List of app context GC handles.
139 * Added to from mono_threads_register_app_context ().
141 static GHashTable *contexts = NULL;
143 /* Cleanup queue for contexts. */
144 static MonoReferenceQueue *context_queue;
147 * Threads which are starting up and they are not in the 'threads' hash yet.
148 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
149 * Protected by mono_threads_lock ().
151 static MonoGHashTable *threads_starting_up = NULL;
154 /* Protected by the threads lock */
155 static GHashTable *joinable_threads;
156 static gint32 joinable_thread_count;
158 #define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
159 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
161 /* function called at thread start */
162 static MonoThreadStartCB mono_thread_start_cb = NULL;
164 /* function called at thread attach */
165 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
167 /* function called at thread cleanup */
168 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
170 /* The default stack size for each thread */
171 static guint32 default_stacksize = 0;
172 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
174 static void context_adjust_static_data (MonoAppContext *ctx);
175 static void mono_free_static_data (gpointer* static_data);
176 static void mono_init_static_data_info (StaticDataInfo *static_data);
177 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
178 static gboolean mono_thread_resume (MonoInternalThread* thread);
179 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
180 static void self_abort_internal (MonoError *error);
181 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
182 static void self_suspend_internal (void);
184 static MonoException* mono_thread_execute_interruption (void);
185 static void ref_stack_destroy (gpointer rs);
187 /* Spin lock for InterlockedXXX 64 bit functions */
188 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
189 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
190 static mono_mutex_t interlocked_mutex;
192 /* global count of thread interruptions requested */
193 static gint32 thread_interruption_requested = 0;
195 /* Event signaled when a thread changes its background mode */
196 static MonoOSEvent background_change_event;
198 static gboolean shutting_down = FALSE;
200 static gint32 managed_thread_id_counter = 0;
203 mono_threads_lock (void)
205 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
209 mono_threads_unlock (void)
211 mono_locks_coop_release (&threads_mutex, ThreadsLock);
216 get_next_managed_thread_id (void)
218 return InterlockedIncrement (&managed_thread_id_counter);
222 * We separate interruptions/exceptions into either sync (they can be processed anytime,
223 * normally as soon as they are set, and are set by the same thread) and async (they can't
224 * be processed inside abort protected blocks and are normally set by other threads). We
225 * can have both a pending sync and async interruption. In this case, the sync exception is
226 * processed first. Since we clean sync flag first, mono_thread_execute_interruption must
227 * also handle all sync type exceptions before the async type exceptions.
230 INTERRUPT_SYNC_REQUESTED_BIT = 0x1,
231 INTERRUPT_ASYNC_REQUESTED_BIT = 0x2,
232 INTERRUPT_REQUESTED_MASK = 0x3,
233 ABORT_PROT_BLOCK_SHIFT = 2,
234 ABORT_PROT_BLOCK_BITS = 8,
235 ABORT_PROT_BLOCK_MASK = (((1 << ABORT_PROT_BLOCK_BITS) - 1) << ABORT_PROT_BLOCK_SHIFT)
239 mono_thread_get_abort_prot_block_count (MonoInternalThread *thread)
241 gsize state = thread->thread_state;
242 return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
246 mono_threads_begin_abort_protected_block (void)
248 MonoInternalThread *thread = mono_thread_internal_current ();
249 gsize old_state, new_state;
252 old_state = thread->thread_state;
254 new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) + 1;
255 //bounds check abort_prot_count
256 g_assert (new_val > 0);
257 g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
259 new_state = old_state + (1 << ABORT_PROT_BLOCK_SHIFT);
260 } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
262 /* Defer async request since we won't be able to process until exiting the block */
263 if (new_val == 1 && (new_state & INTERRUPT_ASYNC_REQUESTED_BIT)) {
264 InterlockedDecrement (&thread_interruption_requested);
265 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);
266 if (thread_interruption_requested < 0)
267 g_warning ("bad thread_interruption_requested state");
269 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);
274 mono_thread_state_has_interruption (gsize state)
276 /* pending exception, self abort */
277 if (state & INTERRUPT_SYNC_REQUESTED_BIT)
280 /* abort, interruption, suspend */
281 if ((state & INTERRUPT_ASYNC_REQUESTED_BIT) && !(state & ABORT_PROT_BLOCK_MASK))
288 mono_threads_end_abort_protected_block (void)
290 MonoInternalThread *thread = mono_thread_internal_current ();
291 gsize old_state, new_state;
294 old_state = thread->thread_state;
296 //bounds check abort_prot_count
297 new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
298 g_assert (new_val >= 0);
299 g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
301 new_state = old_state - (1 << ABORT_PROT_BLOCK_SHIFT);
302 } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
304 if (new_val == 0 && (new_state & INTERRUPT_ASYNC_REQUESTED_BIT)) {
305 InterlockedIncrement (&thread_interruption_requested);
306 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);
308 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);
311 return mono_thread_state_has_interruption (new_state);
315 mono_thread_get_interruption_requested (MonoInternalThread *thread)
317 gsize state = thread->thread_state;
319 return mono_thread_state_has_interruption (state);
323 * Returns TRUE is there was a state change
324 * We clear a single interruption request, sync has priority.
327 mono_thread_clear_interruption_requested (MonoInternalThread *thread)
329 gsize old_state, new_state;
331 old_state = thread->thread_state;
333 // no interruption to process
334 if (!(old_state & INTERRUPT_SYNC_REQUESTED_BIT) &&
335 (!(old_state & INTERRUPT_ASYNC_REQUESTED_BIT) || (old_state & ABORT_PROT_BLOCK_MASK)))
338 if (old_state & INTERRUPT_SYNC_REQUESTED_BIT)
339 new_state = old_state & ~INTERRUPT_SYNC_REQUESTED_BIT;
341 new_state = old_state & ~INTERRUPT_ASYNC_REQUESTED_BIT;
342 } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
344 InterlockedDecrement (&thread_interruption_requested);
345 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);
346 if (thread_interruption_requested < 0)
347 g_warning ("bad thread_interruption_requested state");
351 /* Returns TRUE is there was a state change and the interruption can be processed */
353 mono_thread_set_interruption_requested (MonoInternalThread *thread)
355 //always force when the current thread is doing it to itself.
356 gboolean sync = thread == mono_thread_internal_current ();
357 gsize old_state, new_state;
359 old_state = thread->thread_state;
362 if ((sync && (old_state & INTERRUPT_SYNC_REQUESTED_BIT)) ||
363 (!sync && (old_state & INTERRUPT_ASYNC_REQUESTED_BIT)))
367 new_state = old_state | INTERRUPT_SYNC_REQUESTED_BIT;
369 new_state = old_state | INTERRUPT_ASYNC_REQUESTED_BIT;
370 } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
372 if (sync || !(new_state & ABORT_PROT_BLOCK_MASK)) {
373 InterlockedIncrement (&thread_interruption_requested);
374 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);
376 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);
379 return sync || !(new_state & ABORT_PROT_BLOCK_MASK);
382 static inline MonoNativeThreadId
383 thread_get_tid (MonoInternalThread *thread)
385 /* We store the tid as a guint64 to keep the object layout constant between platforms */
386 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
389 static void ensure_synch_cs_set (MonoInternalThread *thread)
391 MonoCoopMutex *synch_cs;
393 if (thread->synch_cs != NULL) {
397 synch_cs = g_new0 (MonoCoopMutex, 1);
398 mono_coop_mutex_init_recursive (synch_cs);
400 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
401 synch_cs, NULL) != NULL) {
402 /* Another thread must have installed this CS */
403 mono_coop_mutex_destroy (synch_cs);
409 lock_thread (MonoInternalThread *thread)
411 if (!thread->synch_cs)
412 ensure_synch_cs_set (thread);
414 g_assert (thread->synch_cs);
416 mono_coop_mutex_lock (thread->synch_cs);
420 unlock_thread (MonoInternalThread *thread)
422 mono_coop_mutex_unlock (thread->synch_cs);
425 static inline gboolean
426 is_appdomainunloaded_exception (MonoClass *klass)
428 return klass == mono_class_get_appdomain_unloaded_exception_class ();
431 static inline gboolean
432 is_threadabort_exception (MonoClass *klass)
434 return klass == mono_defaults.threadabortexception_class;
438 * A special static data offset (guint32) consists of 3 parts:
440 * [0] 6-bit index into the array of chunks.
441 * [6] 25-bit offset into the array.
442 * [31] Bit indicating thread or context static.
447 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
458 } SpecialStaticOffset;
460 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
461 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
463 #define MAKE_SPECIAL_STATIC_OFFSET(idx, off, ty) \
464 ((SpecialStaticOffset) { .fields = { .index = (idx), .offset = (off), .type = (ty) } }.raw)
465 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
466 (((SpecialStaticOffset *) &(x))->fields.f)
469 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
471 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
473 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
474 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
476 return ((char *) thread->static_data [idx]) + off;
480 get_context_static_data (MonoAppContext *ctx, guint32 offset)
482 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
484 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
485 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
487 return ((char *) ctx->static_data [idx]) + off;
491 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
493 static MonoClassField *current_thread_field = NULL;
497 if (!current_thread_field) {
498 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
499 g_assert (current_thread_field);
502 mono_class_vtable (domain, mono_defaults.thread_class);
503 mono_domain_lock (domain);
504 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
505 mono_domain_unlock (domain);
508 return (MonoThread **)get_thread_static_data (thread, offset);
512 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
514 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
516 g_assert (current->obj.vtable->domain == domain);
518 g_assert (!*current_thread_ptr);
519 *current_thread_ptr = current;
523 create_thread_object (MonoDomain *domain, MonoInternalThread *internal)
529 vtable = mono_class_vtable (domain, mono_defaults.thread_class);
532 thread = (MonoThread*)mono_object_new_mature (vtable, &error);
533 /* only possible failure mode is OOM, from which we don't expect to recover. */
534 mono_error_assert_ok (&error);
536 MONO_OBJECT_SETREF (thread, internal_thread, internal);
541 static MonoInternalThread*
542 create_internal_thread_object (void)
545 MonoInternalThread *thread;
548 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
549 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
550 /* only possible failure mode is OOM, from which we don't exect to recover */
551 mono_error_assert_ok (&error);
553 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
554 mono_coop_mutex_init_recursive (thread->synch_cs);
556 thread->apartment_state = ThreadApartmentState_Unknown;
557 thread->managed_id = get_next_managed_thread_id ();
558 if (mono_gc_is_moving ()) {
559 thread->thread_pinning_ref = thread;
560 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
563 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
565 thread->suspended = g_new0 (MonoOSEvent, 1);
566 mono_os_event_init (thread->suspended, TRUE);
572 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
576 g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
577 g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
578 g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
583 g_assert (internal->native_handle);
585 res = SetThreadPriority (internal->native_handle, priority - 2);
587 g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
588 #else /* HOST_WIN32 */
591 struct sched_param param;
594 tid = thread_get_tid (internal);
596 res = pthread_getschedparam (tid, &policy, ¶m);
598 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
600 #ifdef _POSIX_PRIORITY_SCHEDULING
603 /* Necessary to get valid priority range */
605 min = sched_get_priority_min (policy);
606 max = sched_get_priority_max (policy);
608 if (max > 0 && min >= 0 && max > min) {
609 double srange, drange, sposition, dposition;
610 srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
612 sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
613 dposition = (sposition / srange) * drange;
614 param.sched_priority = (int)(dposition + min);
621 param.sched_priority = 50;
627 param.sched_priority = 0;
630 g_warning ("%s: unknown policy %d", __func__, policy);
635 res = pthread_setschedparam (tid, policy, ¶m);
638 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
641 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
643 #endif /* HOST_WIN32 */
647 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
650 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain)
652 MonoThreadInfo *info;
653 MonoInternalThread *internal;
654 MonoDomain *domain, *root_domain;
658 info = mono_thread_info_current ();
661 internal = thread->internal_thread;
664 /* It is needed to store the MonoInternalThread on the MonoThreadInfo, because of the following case:
665 * - the MonoInternalThread TLS key is destroyed: set it to NULL
666 * - the MonoThreadInfo TLS key is destroyed: calls mono_thread_info_detach
667 * - it calls MonoThreadInfoCallbacks.thread_detach
668 * - mono_thread_internal_current returns NULL -> fails to detach the MonoInternalThread. */
669 mono_thread_info_set_internal_thread_gchandle (info, mono_gchandle_new ((MonoObject*) internal, FALSE));
671 internal->handle = mono_threads_open_thread_handle (info->handle);
673 internal->native_handle = OpenThread (THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId ());
675 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
676 internal->thread_info = info;
677 internal->small_id = info->small_id;
679 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
681 SET_CURRENT_OBJECT (internal);
683 domain = mono_object_domain (thread);
685 mono_thread_push_appdomain_ref (domain);
686 if (!mono_domain_set (domain, force_domain)) {
687 mono_thread_pop_appdomain_ref ();
691 mono_threads_lock ();
693 if (threads_starting_up)
694 mono_g_hash_table_remove (threads_starting_up, thread);
696 if (shutting_down && !force_attach) {
697 mono_threads_unlock ();
698 mono_thread_pop_appdomain_ref ();
703 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
706 /* We don't need to duplicate thread->handle, because it is
707 * only closed when the thread object is finalized by the GC. */
708 mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
710 /* We have to do this here because mono_thread_start_cb
711 * requires that root_domain_thread is set up. */
712 if (thread_static_info.offset || thread_static_info.idx > 0) {
713 /* get the current allocated size */
714 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
715 mono_alloc_static_data (&internal->static_data, offset, TRUE);
718 mono_threads_unlock ();
720 root_domain = mono_get_root_domain ();
722 g_assert (!internal->root_domain_thread);
723 if (domain != root_domain)
724 MONO_OBJECT_SETREF (internal, root_domain_thread, create_thread_object (root_domain, internal));
726 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
728 if (domain != root_domain)
729 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
731 set_current_thread_for_domain (domain, internal, thread);
733 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
739 mono_thread_detach_internal (MonoInternalThread *thread)
743 g_assert (thread != NULL);
744 SET_CURRENT_OBJECT (thread);
746 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
749 mono_w32mutex_abandon ();
752 if (thread->abort_state_handle) {
753 mono_gchandle_free (thread->abort_state_handle);
754 thread->abort_state_handle = 0;
757 thread->abort_exc = NULL;
758 thread->current_appcontext = NULL;
761 * thread->synch_cs can be NULL if this was called after
762 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
763 * This can happen only during shutdown.
764 * The shutting_down flag is not always set, so we can't assert on it.
766 if (thread->synch_cs)
767 LOCK_THREAD (thread);
769 thread->state |= ThreadState_Stopped;
770 thread->state &= ~ThreadState_Background;
772 if (thread->synch_cs)
773 UNLOCK_THREAD (thread);
776 An interruption request has leaked to cleanup. Adjust the global counter.
778 This can happen is the abort source thread finds the abortee (this) thread
779 in unmanaged code. If this thread never trips back to managed code or check
780 the local flag it will be left set and positively unbalance the global counter.
782 Leaving the counter unbalanced will cause a performance degradation since all threads
783 will now keep checking their local flags all the time.
785 mono_thread_clear_interruption_requested (thread);
787 mono_threads_lock ();
791 } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
792 /* We have to check whether the thread object for the
793 * tid is still the same in the table because the
794 * thread might have been destroyed and the tid reused
795 * in the meantime, in which case the tid would be in
796 * the table, but with another thread object.
800 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
804 mono_threads_unlock ();
806 /* Don't close the handle here, wait for the object finalizer
807 * to do it. Otherwise, the following race condition applies:
809 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
811 * 2) Some other handle is reassigned the same slot
813 * 3) Another thread tries to join the first thread, and
814 * blocks waiting for the reassigned handle to be signalled
815 * (which might never happen). This is possible, because the
816 * thread calling Join() still has a reference to the first
820 /* if the thread is not in the hash it has been removed already */
822 mono_domain_unset ();
823 mono_memory_barrier ();
825 if (mono_thread_cleanup_fn)
826 mono_thread_cleanup_fn (thread_get_tid (thread));
831 mono_release_type_locks (thread);
833 /* Can happen when we attach the profiler helper thread in order to heapshot. */
834 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
835 MONO_PROFILER_RAISE (thread_stopped, (thread->tid));
837 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
840 * This will signal async signal handlers that the thread has exited.
841 * The profiler callback needs this to be set, so it cannot be done earlier.
843 mono_domain_unset ();
844 mono_memory_barrier ();
846 if (thread == mono_thread_internal_current ())
847 mono_thread_pop_appdomain_ref ();
849 mono_free_static_data (thread->static_data);
850 thread->static_data = NULL;
851 ref_stack_destroy (thread->appdomain_refs);
852 thread->appdomain_refs = NULL;
854 g_assert (thread->suspended);
855 mono_os_event_destroy (thread->suspended);
856 g_free (thread->suspended);
857 thread->suspended = NULL;
859 if (mono_thread_cleanup_fn)
860 mono_thread_cleanup_fn (thread_get_tid (thread));
862 mono_memory_barrier ();
864 if (mono_gc_is_moving ()) {
865 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
866 thread->thread_pinning_ref = NULL;
870 SET_CURRENT_OBJECT (NULL);
871 mono_domain_unset ();
873 mono_thread_info_unset_internal_thread_gchandle ((MonoThreadInfo*) thread->thread_info);
875 /* Don't need to close the handle to this thread, even though we took a
876 * reference in mono_thread_attach (), because the GC will do it
877 * when the Thread object is finalised.
884 MonoObject *start_delegate;
885 MonoObject *start_delegate_arg;
886 MonoThreadStart start_func;
887 gpointer start_func_arg;
888 gboolean force_attach;
890 MonoCoopSem registered;
893 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
896 MonoThreadStart start_func;
897 void *start_func_arg;
900 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
904 MonoInternalThread *internal;
905 MonoObject *start_delegate;
906 MonoObject *start_delegate_arg;
909 thread = start_info->thread;
910 internal = thread->internal_thread;
911 domain = mono_object_domain (start_info->thread);
913 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
915 if (!mono_thread_attach_internal (thread, start_info->force_attach, FALSE)) {
916 start_info->failed = TRUE;
918 mono_coop_sem_post (&start_info->registered);
920 if (InterlockedDecrement (&start_info->ref) == 0) {
921 mono_coop_sem_destroy (&start_info->registered);
928 mono_thread_internal_set_priority (internal, internal->priority);
932 start_delegate = start_info->start_delegate;
933 start_delegate_arg = start_info->start_delegate_arg;
934 start_func = start_info->start_func;
935 start_func_arg = start_info->start_func_arg;
937 /* This MUST be called before any managed code can be
938 * executed, as it calls the callback function that (for the
939 * jit) sets the lmf marker.
942 if (mono_thread_start_cb)
943 mono_thread_start_cb (tid, stack_ptr, start_func);
945 /* On 2.0 profile (and higher), set explicitly since state might have been
947 if (internal->apartment_state == ThreadApartmentState_Unknown)
948 internal->apartment_state = ThreadApartmentState_MTA;
950 mono_thread_init_apartment_state ();
952 /* Let the thread that called Start() know we're ready */
953 mono_coop_sem_post (&start_info->registered);
955 if (InterlockedDecrement (&start_info->ref) == 0) {
956 mono_coop_sem_destroy (&start_info->registered);
960 /* start_info is not valid anymore */
964 * Call this after calling start_notify, since the profiler callback might want
965 * to lock the thread, and the lock is held by thread_start () which waits for
968 MONO_PROFILER_RAISE (thread_started, (tid));
970 /* if the name was set before starting, we didn't invoke the profiler callback */
971 if (internal->name) {
972 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
973 MONO_PROFILER_RAISE (thread_name, (internal->tid, tname));
974 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
978 /* start_func is set only for unmanaged start functions */
980 start_func (start_func_arg);
984 g_assert (start_delegate != NULL);
986 /* we may want to handle the exception here. See comment below on unhandled exceptions */
987 args [0] = (gpointer) start_delegate_arg;
988 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
990 if (!mono_error_ok (&error)) {
991 MonoException *ex = mono_error_convert_to_exception (&error);
993 g_assert (ex != NULL);
994 MonoClass *klass = mono_object_get_class (&ex->object);
995 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
996 !is_threadabort_exception (klass)) {
997 mono_unhandled_exception (&ex->object);
998 mono_invoke_unhandled_exception_hook (&ex->object);
999 g_assert_not_reached ();
1002 mono_error_cleanup (&error);
1006 /* If the thread calls ExitThread at all, this remaining code
1007 * will not be executed, but the main thread will eventually
1008 * call mono_thread_detach_internal() on this thread's behalf.
1011 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
1013 /* Do any cleanup needed for apartment state. This
1014 * cannot be done in mono_thread_detach_internal since
1015 * mono_thread_detach_internal could be called for a
1016 * thread other than the current thread.
1017 * mono_thread_cleanup_apartment_state cleans up apartment
1018 * for the current thead */
1019 mono_thread_cleanup_apartment_state ();
1021 mono_thread_detach_internal (internal);
1027 start_wrapper (gpointer data)
1029 StartInfo *start_info;
1030 MonoThreadInfo *info;
1033 start_info = (StartInfo*) data;
1034 g_assert (start_info);
1036 info = mono_thread_info_attach ();
1037 info->runtime_thread = TRUE;
1039 /* Run the actual main function of the thread */
1040 res = start_wrapper_internal (start_info, info->stack_end);
1042 mono_thread_info_exit (res);
1044 g_assert_not_reached ();
1050 * Common thread creation code.
1051 * LOCKING: Acquires the threads lock.
1054 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
1055 MonoThreadCreateFlags flags, MonoError *error)
1057 StartInfo *start_info = NULL;
1058 MonoNativeThreadId tid;
1060 gsize stack_set_size;
1063 g_assert (!start_func && !start_func_arg);
1065 g_assert (!start_delegate);
1067 if (flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL) {
1068 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER));
1069 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
1071 if (flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER) {
1072 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL));
1073 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
1077 * Join joinable threads to prevent running out of threads since the finalizer
1078 * thread might be blocked/backlogged.
1080 mono_threads_join_threads ();
1084 mono_threads_lock ();
1085 if (shutting_down && !(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE)) {
1086 mono_threads_unlock ();
1089 if (threads_starting_up == NULL) {
1090 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
1092 mono_g_hash_table_insert (threads_starting_up, thread, thread);
1093 mono_threads_unlock ();
1095 internal->threadpool_thread = flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL;
1096 if (internal->threadpool_thread)
1097 mono_thread_set_state (internal, ThreadState_Background);
1099 internal->debugger_thread = flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER;
1101 start_info = g_new0 (StartInfo, 1);
1102 start_info->ref = 2;
1103 start_info->thread = thread;
1104 start_info->start_delegate = start_delegate;
1105 start_info->start_delegate_arg = thread->start_obj;
1106 start_info->start_func = start_func;
1107 start_info->start_func_arg = start_func_arg;
1108 start_info->force_attach = flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE;
1109 start_info->failed = FALSE;
1110 mono_coop_sem_init (&start_info->registered, 0);
1112 if (flags != MONO_THREAD_CREATE_FLAGS_SMALL_STACK)
1113 stack_set_size = default_stacksize_for_thread (internal);
1117 if (!mono_thread_platform_create_thread (start_wrapper, start_info, &stack_set_size, &tid)) {
1118 /* The thread couldn't be created, so set an exception */
1119 mono_threads_lock ();
1120 mono_g_hash_table_remove (threads_starting_up, thread);
1121 mono_threads_unlock ();
1122 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
1123 /* ref is not going to be decremented in start_wrapper_internal */
1124 InterlockedDecrement (&start_info->ref);
1129 internal->stack_size = (int) stack_set_size;
1131 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
1134 * Wait for the thread to set up its TLS data etc, so
1135 * theres no potential race condition if someone tries
1136 * to look up the data believing the thread has
1140 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
1142 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));
1144 ret = !start_info->failed;
1147 if (InterlockedDecrement (&start_info->ref) == 0) {
1148 mono_coop_sem_destroy (&start_info->registered);
1149 g_free (start_info);
1156 * mono_thread_new_init:
1159 mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
1161 if (mono_thread_start_cb) {
1162 mono_thread_start_cb (tid, stack_start, func);
1167 * mono_threads_set_default_stacksize:
1170 mono_threads_set_default_stacksize (guint32 stacksize)
1172 default_stacksize = stacksize;
1176 * mono_threads_get_default_stacksize:
1179 mono_threads_get_default_stacksize (void)
1181 return default_stacksize;
1185 * mono_thread_create_internal:
1187 * ARG should not be a GC reference.
1190 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, MonoThreadCreateFlags flags, MonoError *error)
1193 MonoInternalThread *internal;
1198 internal = create_internal_thread_object ();
1200 thread = create_thread_object (domain, internal);
1202 LOCK_THREAD (internal);
1204 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, flags, error);
1206 UNLOCK_THREAD (internal);
1208 return_val_if_nok (error, NULL);
1213 * mono_thread_create:
1216 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1219 if (!mono_thread_create_checked (domain, func, arg, &error))
1220 mono_error_cleanup (&error);
1224 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1226 return (NULL != mono_thread_create_internal (domain, func, arg, MONO_THREAD_CREATE_FLAGS_NONE, error));
1230 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1232 MonoInternalThread *internal;
1234 MonoThreadInfo *info;
1235 MonoNativeThreadId tid;
1237 if (mono_thread_internal_current_is_attached ()) {
1238 if (domain != mono_domain_get ())
1239 mono_domain_set (domain, TRUE);
1240 /* Already attached */
1241 return mono_thread_current ();
1244 info = mono_thread_info_attach ();
1247 tid=mono_native_thread_id_get ();
1249 internal = create_internal_thread_object ();
1251 thread = create_thread_object (domain, internal);
1253 if (!mono_thread_attach_internal (thread, force_attach, TRUE)) {
1254 /* Mono is shutting down, so just wait for the end */
1256 mono_thread_info_sleep (10000, NULL);
1259 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1261 if (mono_thread_attach_cb)
1262 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), info->stack_end);
1264 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1265 if (!mono_thread_info_current ()->tools_thread)
1266 MONO_PROFILER_RAISE (thread_started, (MONO_NATIVE_THREAD_ID_TO_UINT (tid)));
1272 * mono_thread_attach:
1275 mono_thread_attach (MonoDomain *domain)
1277 return mono_thread_attach_full (domain, FALSE);
1281 * mono_thread_detach:
1284 mono_thread_detach (MonoThread *thread)
1287 mono_thread_detach_internal (thread->internal_thread);
1291 * mono_thread_detach_if_exiting:
1293 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1294 * This should be used at the end of embedding code which calls into managed code, and which
1295 * can be called from pthread dtors, like <code>dealloc:</code> implementations in Objective-C.
1298 mono_thread_detach_if_exiting (void)
1300 if (mono_thread_info_is_exiting ()) {
1301 MonoInternalThread *thread;
1303 thread = mono_thread_internal_current ();
1305 mono_thread_detach_internal (thread);
1306 mono_thread_info_detach ();
1314 mono_thread_internal_current_is_attached (void)
1316 MonoInternalThread *internal;
1318 internal = GET_CURRENT_OBJECT ();
1329 mono_thread_exit (void)
1331 MonoInternalThread *thread = mono_thread_internal_current ();
1333 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1335 mono_thread_detach_internal (thread);
1337 /* we could add a callback here for embedders to use. */
1338 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1339 exit (mono_environment_exitcode_get ());
1341 mono_thread_info_exit (0);
1345 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1347 MonoInternalThread *internal;
1349 internal = create_internal_thread_object ();
1351 internal->state = ThreadState_Unstarted;
1353 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1357 ves_icall_System_Threading_Thread_GetCurrentThread (void)
1359 return mono_thread_current ();
1363 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1367 MonoInternalThread *internal;
1370 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1372 if (!this_obj->internal_thread)
1373 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1374 internal = this_obj->internal_thread;
1376 LOCK_THREAD (internal);
1378 if ((internal->state & ThreadState_Unstarted) == 0) {
1379 UNLOCK_THREAD (internal);
1380 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1384 if ((internal->state & ThreadState_Aborted) != 0) {
1385 UNLOCK_THREAD (internal);
1389 res = create_thread (this_obj, internal, start, NULL, NULL, MONO_THREAD_CREATE_FLAGS_NONE, &error);
1391 mono_error_cleanup (&error);
1392 UNLOCK_THREAD (internal);
1396 internal->state &= ~ThreadState_Unstarted;
1398 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1400 UNLOCK_THREAD (internal);
1401 return internal->handle;
1405 * This is called from the finalizer of the internal thread object.
1408 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj)
1410 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle));
1413 * Since threads keep a reference to their thread object while running, by
1414 * the time this function is called, the thread has already exited/detached,
1415 * i.e. mono_thread_detach_internal () has ran. The exception is during
1416 * shutdown, when mono_thread_detach_internal () can be called after this.
1418 if (this_obj->handle) {
1419 mono_threads_close_thread_handle (this_obj->handle);
1420 this_obj->handle = NULL;
1424 CloseHandle (this_obj->native_handle);
1427 if (this_obj->synch_cs) {
1428 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1429 this_obj->synch_cs = NULL;
1430 mono_coop_mutex_destroy (synch_cs);
1434 if (this_obj->name) {
1435 void *name = this_obj->name;
1436 this_obj->name = NULL;
1442 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1445 MonoInternalThread *thread = mono_thread_internal_current ();
1447 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1449 if (mono_thread_current_check_pending_interrupt ())
1453 gboolean alerted = FALSE;
1455 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1457 res = mono_thread_info_sleep (ms, &alerted);
1459 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1462 MonoException* exc = mono_thread_execute_interruption ();
1464 mono_raise_exception (exc);
1466 // FIXME: !MONO_INFINITE_WAIT
1467 if (ms != MONO_INFINITE_WAIT)
1476 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1481 ves_icall_System_Threading_Thread_GetDomainID (void)
1483 return mono_domain_get()->domain_id;
1487 ves_icall_System_Threading_Thread_Yield (void)
1489 return mono_thread_info_yield ();
1493 * mono_thread_get_name:
1495 * Return the name of the thread. NAME_LEN is set to the length of the name.
1496 * Return NULL if the thread has no name. The returned memory is owned by the
1500 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1504 LOCK_THREAD (this_obj);
1506 if (!this_obj->name) {
1510 *name_len = this_obj->name_len;
1511 res = g_new (gunichar2, this_obj->name_len);
1512 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1515 UNLOCK_THREAD (this_obj);
1521 * mono_thread_get_name_utf8:
1522 * \returns the name of the thread in UTF-8.
1523 * Return NULL if the thread has no name.
1524 * The returned memory is owned by the caller.
1527 mono_thread_get_name_utf8 (MonoThread *thread)
1532 MonoInternalThread *internal = thread->internal_thread;
1533 if (internal == NULL)
1536 LOCK_THREAD (internal);
1538 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1540 UNLOCK_THREAD (internal);
1546 * mono_thread_get_managed_id:
1547 * \returns the \c Thread.ManagedThreadId value of \p thread.
1548 * Returns \c -1 if \p thread is NULL.
1551 mono_thread_get_managed_id (MonoThread *thread)
1556 MonoInternalThread *internal = thread->internal_thread;
1557 if (internal == NULL)
1560 int32_t id = internal->managed_id;
1566 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1571 error_init (&error);
1573 LOCK_THREAD (this_obj);
1575 if (!this_obj->name)
1578 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1580 UNLOCK_THREAD (this_obj);
1582 if (mono_error_set_pending_exception (&error))
1589 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, gboolean reset, MonoError *error)
1591 LOCK_THREAD (this_obj);
1596 this_obj->flags &= ~MONO_THREAD_FLAG_NAME_SET;
1597 } else if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1598 UNLOCK_THREAD (this_obj);
1600 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1603 if (this_obj->name) {
1604 g_free (this_obj->name);
1605 this_obj->name_len = 0;
1608 this_obj->name = g_memdup (mono_string_chars (name), mono_string_length (name) * sizeof (gunichar2));
1609 this_obj->name_len = mono_string_length (name);
1612 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1615 this_obj->name = NULL;
1618 UNLOCK_THREAD (this_obj);
1620 if (this_obj->name && this_obj->tid) {
1621 char *tname = mono_string_to_utf8_checked (name, error);
1622 return_if_nok (error);
1623 MONO_PROFILER_RAISE (thread_name, (this_obj->tid, tname));
1624 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1630 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1633 mono_thread_set_name_internal (this_obj, name, TRUE, FALSE, &error);
1634 mono_error_set_pending_exception (&error);
1638 * ves_icall_System_Threading_Thread_GetPriority_internal:
1639 * @param this_obj: The MonoInternalThread on which to operate.
1641 * Gets the priority of the given thread.
1642 * @return: The priority of the given thread.
1645 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1648 MonoInternalThread *internal = this_obj->internal_thread;
1650 LOCK_THREAD (internal);
1651 priority = internal->priority;
1652 UNLOCK_THREAD (internal);
1658 * ves_icall_System_Threading_Thread_SetPriority_internal:
1659 * @param this_obj: The MonoInternalThread on which to operate.
1660 * @param priority: The priority to set.
1662 * Sets the priority of the given thread.
1665 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1667 MonoInternalThread *internal = this_obj->internal_thread;
1669 LOCK_THREAD (internal);
1670 internal->priority = priority;
1671 if (internal->thread_info != NULL)
1672 mono_thread_internal_set_priority (internal, priority);
1673 UNLOCK_THREAD (internal);
1676 /* If the array is already in the requested domain, we just return it,
1677 otherwise we return a copy in that domain. */
1679 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1687 if (mono_object_domain (arr) == domain)
1690 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1691 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1696 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1699 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1700 mono_error_set_pending_exception (&error);
1705 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1708 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1709 mono_error_set_pending_exception (&error);
1714 * mono_thread_current:
1717 mono_thread_current (void)
1719 MonoDomain *domain = mono_domain_get ();
1720 MonoInternalThread *internal = mono_thread_internal_current ();
1721 MonoThread **current_thread_ptr;
1723 g_assert (internal);
1724 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1726 if (!*current_thread_ptr) {
1727 g_assert (domain != mono_get_root_domain ());
1728 *current_thread_ptr = create_thread_object (domain, internal);
1730 return *current_thread_ptr;
1733 /* Return the thread object belonging to INTERNAL in the current domain */
1735 mono_thread_current_for_thread (MonoInternalThread *internal)
1737 MonoDomain *domain = mono_domain_get ();
1738 MonoThread **current_thread_ptr;
1740 g_assert (internal);
1741 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1743 if (!*current_thread_ptr) {
1744 g_assert (domain != mono_get_root_domain ());
1745 *current_thread_ptr = create_thread_object (domain, internal);
1747 return *current_thread_ptr;
1751 mono_thread_internal_current (void)
1753 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1754 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1758 static MonoThreadInfoWaitRet
1759 mono_join_uninterrupted (MonoThreadHandle* thread_to_join, gint32 ms, MonoError *error)
1762 MonoThreadInfoWaitRet ret;
1769 start = (ms == -1) ? 0 : mono_msec_ticks ();
1772 ret = mono_thread_info_wait_one_handle (thread_to_join, ms, TRUE);
1775 if (ret != MONO_THREAD_INFO_WAIT_RET_ALERTED)
1778 exc = mono_thread_execute_interruption ();
1780 mono_error_set_exception_instance (error, exc);
1787 /* Re-calculate ms according to the time passed */
1788 diff_ms = (gint32)(mono_msec_ticks () - start);
1789 if (diff_ms >= ms) {
1790 ret = MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1793 wait = ms - diff_ms;
1800 ves_icall_System_Threading_Thread_Join_internal (MonoThread *this_obj, int ms)
1802 MonoInternalThread *thread = this_obj->internal_thread;
1803 MonoThreadHandle *handle = thread->handle;
1804 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1808 if (mono_thread_current_check_pending_interrupt ())
1811 LOCK_THREAD (thread);
1813 if ((thread->state & ThreadState_Unstarted) != 0) {
1814 UNLOCK_THREAD (thread);
1816 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1820 MonoNativeThreadId tid = thread_get_tid (thread);
1822 UNLOCK_THREAD (thread);
1825 ms = MONO_INFINITE_WAIT;
1826 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1828 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1830 ret = mono_join_uninterrupted (handle, ms, &error);
1832 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1834 mono_error_set_pending_exception (&error);
1836 if (ret == MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
1837 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1840 /* TODO: Do this on Unix platforms as well. See PR #5454 for context. */
1841 /* Wait for the thread to really exit */
1843 /* This shouldn't block */
1844 mono_threads_join_lock ();
1845 mono_native_thread_join (tid);
1846 mono_threads_join_unlock ();
1853 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1858 #define MANAGED_WAIT_FAILED 0x7fffffff
1861 map_native_wait_result_to_managed (MonoW32HandleWaitRet val, gsize numobjects)
1863 if (val >= MONO_W32HANDLE_WAIT_RET_SUCCESS_0 && val < MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + numobjects) {
1864 return WAIT_OBJECT_0 + (val - MONO_W32HANDLE_WAIT_RET_SUCCESS_0);
1865 } else if (val >= MONO_W32HANDLE_WAIT_RET_ABANDONED_0 && val < MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + numobjects) {
1866 return WAIT_ABANDONED_0 + (val - MONO_W32HANDLE_WAIT_RET_ABANDONED_0);
1867 } else if (val == MONO_W32HANDLE_WAIT_RET_ALERTED) {
1868 return WAIT_IO_COMPLETION;
1869 } else if (val == MONO_W32HANDLE_WAIT_RET_TIMEOUT) {
1870 return WAIT_TIMEOUT;
1871 } else if (val == MONO_W32HANDLE_WAIT_RET_FAILED) {
1872 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1873 return MANAGED_WAIT_FAILED;
1875 g_error ("%s: unknown val value %d", __func__, val);
1880 ves_icall_System_Threading_WaitHandle_Wait_internal (gpointer *handles, gint32 numhandles, MonoBoolean waitall, gint32 timeout, MonoError *error)
1882 MonoW32HandleWaitRet ret;
1883 MonoInternalThread *thread;
1886 guint32 timeoutLeft;
1888 /* Do this WaitSleepJoin check before creating objects */
1889 if (mono_thread_current_check_pending_interrupt ())
1890 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1892 thread = mono_thread_internal_current ();
1894 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1897 timeout = MONO_INFINITE_WAIT;
1898 if (timeout != MONO_INFINITE_WAIT)
1899 start = mono_msec_ticks ();
1901 timeoutLeft = timeout;
1906 if (numhandles != 1)
1907 ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, timeoutLeft, TRUE), numhandles);
1909 ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], timeoutLeft, TRUE), 1);
1911 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
1912 ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, timeoutLeft, TRUE);
1913 #endif /* HOST_WIN32 */
1916 if (ret != MONO_W32HANDLE_WAIT_RET_ALERTED)
1919 exc = mono_thread_execute_interruption ();
1921 mono_error_set_exception_instance (error, exc);
1925 if (timeout != MONO_INFINITE_WAIT) {
1928 elapsed = mono_msec_ticks () - start;
1929 if (elapsed >= timeout) {
1930 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1934 timeoutLeft = timeout - elapsed;
1938 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1940 return map_native_wait_result_to_managed (ret, numhandles);
1944 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (gpointer toSignal, gpointer toWait, gint32 ms, MonoError *error)
1946 MonoW32HandleWaitRet ret;
1947 MonoInternalThread *thread = mono_thread_internal_current ();
1950 ms = MONO_INFINITE_WAIT;
1952 if (mono_thread_current_check_pending_interrupt ())
1953 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1955 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1959 ret = mono_w32handle_convert_wait_ret (SignalObjectAndWait (toSignal, toWait, ms, TRUE), 1);
1961 ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE);
1965 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1967 return map_native_wait_result_to_managed (ret, 1);
1970 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1972 return InterlockedIncrement (location);
1975 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1977 #if SIZEOF_VOID_P == 4
1978 if (G_UNLIKELY ((size_t)location & 0x7)) {
1980 mono_interlocked_lock ();
1983 mono_interlocked_unlock ();
1987 return InterlockedIncrement64 (location);
1990 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1992 return InterlockedDecrement(location);
1995 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1997 #if SIZEOF_VOID_P == 4
1998 if (G_UNLIKELY ((size_t)location & 0x7)) {
2000 mono_interlocked_lock ();
2003 mono_interlocked_unlock ();
2007 return InterlockedDecrement64 (location);
2010 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
2012 return InterlockedExchange(location, value);
2015 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
2018 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
2019 mono_gc_wbarrier_generic_nostore (location);
2023 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
2025 return InterlockedExchangePointer(location, value);
2028 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
2030 IntFloatUnion val, ret;
2033 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
2039 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
2041 #if SIZEOF_VOID_P == 4
2042 if (G_UNLIKELY ((size_t)location & 0x7)) {
2044 mono_interlocked_lock ();
2047 mono_interlocked_unlock ();
2051 return InterlockedExchange64 (location, value);
2055 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
2057 LongDoubleUnion val, ret;
2060 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
2065 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
2067 return InterlockedCompareExchange(location, value, comparand);
2070 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
2072 gint32 r = InterlockedCompareExchange(location, value, comparand);
2073 *success = r == comparand;
2077 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
2080 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
2081 mono_gc_wbarrier_generic_nostore (location);
2085 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
2087 return InterlockedCompareExchangePointer(location, value, comparand);
2090 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2092 IntFloatUnion val, ret, cmp;
2095 cmp.fval = comparand;
2096 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2102 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2104 #if SIZEOF_VOID_P == 8
2105 LongDoubleUnion val, comp, ret;
2108 comp.fval = comparand;
2109 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2115 mono_interlocked_lock ();
2117 if (old == comparand)
2119 mono_interlocked_unlock ();
2126 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2128 #if SIZEOF_VOID_P == 4
2129 if (G_UNLIKELY ((size_t)location & 0x7)) {
2131 mono_interlocked_lock ();
2133 if (old == comparand)
2135 mono_interlocked_unlock ();
2139 return InterlockedCompareExchange64 (location, value, comparand);
2143 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2146 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2147 mono_gc_wbarrier_generic_nostore (location);
2152 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2155 MONO_CHECK_NULL (location, NULL);
2156 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2157 mono_gc_wbarrier_generic_nostore (location);
2162 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2164 return InterlockedAdd (location, value);
2168 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2170 #if SIZEOF_VOID_P == 4
2171 if (G_UNLIKELY ((size_t)location & 0x7)) {
2173 mono_interlocked_lock ();
2176 mono_interlocked_unlock ();
2180 return InterlockedAdd64 (location, value);
2184 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2186 #if SIZEOF_VOID_P == 4
2187 if (G_UNLIKELY ((size_t)location & 0x7)) {
2189 mono_interlocked_lock ();
2191 mono_interlocked_unlock ();
2195 return InterlockedRead64 (location);
2199 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2201 mono_memory_barrier ();
2205 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2207 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2209 if (state & ThreadState_Background) {
2210 /* If the thread changes the background mode, the main thread has to
2211 * be notified, since it has to rebuild the list of threads to
2214 mono_os_event_set (&background_change_event);
2219 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2221 mono_thread_set_state (this_obj, (MonoThreadState)state);
2223 if (state & ThreadState_Background) {
2224 /* If the thread changes the background mode, the main thread has to
2225 * be notified, since it has to rebuild the list of threads to
2228 mono_os_event_set (&background_change_event);
2233 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2237 LOCK_THREAD (this_obj);
2239 state = this_obj->state;
2241 UNLOCK_THREAD (this_obj);
2246 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2248 MonoInternalThread *current;
2250 MonoInternalThread *thread = this_obj->internal_thread;
2252 LOCK_THREAD (thread);
2254 current = mono_thread_internal_current ();
2256 thread->thread_interrupt_requested = TRUE;
2257 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2259 UNLOCK_THREAD (thread);
2262 async_abort_internal (thread, FALSE);
2267 * mono_thread_current_check_pending_interrupt:
2268 * Checks if there's a interruption request and set the pending exception if so.
2269 * \returns true if a pending exception was set
2272 mono_thread_current_check_pending_interrupt (void)
2274 MonoInternalThread *thread = mono_thread_internal_current ();
2275 gboolean throw_ = FALSE;
2277 LOCK_THREAD (thread);
2279 if (thread->thread_interrupt_requested) {
2281 thread->thread_interrupt_requested = FALSE;
2284 UNLOCK_THREAD (thread);
2287 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2292 request_thread_abort (MonoInternalThread *thread, MonoObject *state, gboolean appdomain_unload)
2294 LOCK_THREAD (thread);
2296 if (thread->state & (ThreadState_AbortRequested | ThreadState_Stopped))
2298 UNLOCK_THREAD (thread);
2302 if ((thread->state & ThreadState_Unstarted) != 0) {
2303 thread->state |= ThreadState_Aborted;
2304 UNLOCK_THREAD (thread);
2308 thread->state |= ThreadState_AbortRequested;
2309 if (appdomain_unload)
2310 thread->flags |= MONO_THREAD_FLAG_APPDOMAIN_ABORT;
2312 thread->flags &= ~MONO_THREAD_FLAG_APPDOMAIN_ABORT;
2314 if (thread->abort_state_handle)
2315 mono_gchandle_free (thread->abort_state_handle);
2317 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2318 g_assert (thread->abort_state_handle);
2320 thread->abort_state_handle = 0;
2322 thread->abort_exc = NULL;
2324 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));
2326 /* During shutdown, we can't wait for other threads */
2328 /* Make sure the thread is awake */
2329 mono_thread_resume (thread);
2331 UNLOCK_THREAD (thread);
2336 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2338 if (!request_thread_abort (thread, state, FALSE))
2341 if (thread == mono_thread_internal_current ()) {
2343 self_abort_internal (&error);
2344 mono_error_set_pending_exception (&error);
2346 async_abort_internal (thread, TRUE);
2351 * mono_thread_internal_abort:
2352 * Request thread \p thread to be aborted.
2353 * \p thread MUST NOT be the current thread.
2356 mono_thread_internal_abort (MonoInternalThread *thread, gboolean appdomain_unload)
2358 g_assert (thread != mono_thread_internal_current ());
2360 if (!request_thread_abort (thread, NULL, appdomain_unload))
2362 async_abort_internal (thread, TRUE);
2366 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2368 MonoInternalThread *thread = mono_thread_internal_current ();
2369 gboolean was_aborting, is_domain_abort;
2371 LOCK_THREAD (thread);
2372 was_aborting = thread->state & ThreadState_AbortRequested;
2373 is_domain_abort = thread->flags & MONO_THREAD_FLAG_APPDOMAIN_ABORT;
2375 if (was_aborting && !is_domain_abort)
2376 thread->state &= ~ThreadState_AbortRequested;
2377 UNLOCK_THREAD (thread);
2379 if (!was_aborting) {
2380 const char *msg = "Unable to reset abort because no abort was requested";
2381 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2383 } else if (is_domain_abort) {
2384 /* Silently ignore abort resets in unloading appdomains */
2388 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2389 thread->abort_exc = NULL;
2390 if (thread->abort_state_handle) {
2391 mono_gchandle_free (thread->abort_state_handle);
2392 /* This is actually not necessary - the handle
2393 only counts if the exception is set */
2394 thread->abort_state_handle = 0;
2399 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2401 LOCK_THREAD (thread);
2403 thread->state &= ~ThreadState_AbortRequested;
2405 if (thread->abort_exc) {
2406 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2407 thread->abort_exc = NULL;
2408 if (thread->abort_state_handle) {
2409 mono_gchandle_free (thread->abort_state_handle);
2410 /* This is actually not necessary - the handle
2411 only counts if the exception is set */
2412 thread->abort_state_handle = 0;
2416 UNLOCK_THREAD (thread);
2420 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2423 MonoInternalThread *thread = this_obj->internal_thread;
2424 MonoObject *state, *deserialized = NULL;
2427 if (!thread->abort_state_handle)
2430 state = mono_gchandle_get_target (thread->abort_state_handle);
2433 domain = mono_domain_get ();
2434 if (mono_object_domain (state) == domain)
2437 deserialized = mono_object_xdomain_representation (state, domain, &error);
2439 if (!deserialized) {
2440 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2441 if (!is_ok (&error)) {
2442 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2443 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2445 mono_set_pending_exception (invalid_op_exc);
2449 return deserialized;
2453 mono_thread_suspend (MonoInternalThread *thread)
2455 LOCK_THREAD (thread);
2457 if (thread->state & (ThreadState_Unstarted | ThreadState_Aborted | ThreadState_Stopped))
2459 UNLOCK_THREAD (thread);
2463 if (thread->state & (ThreadState_Suspended | ThreadState_SuspendRequested | ThreadState_AbortRequested))
2465 UNLOCK_THREAD (thread);
2469 thread->state |= ThreadState_SuspendRequested;
2470 mono_os_event_reset (thread->suspended);
2472 if (thread == mono_thread_internal_current ()) {
2473 /* calls UNLOCK_THREAD (thread) */
2474 self_suspend_internal ();
2476 /* calls UNLOCK_THREAD (thread) */
2477 async_suspend_internal (thread, FALSE);
2484 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2486 if (!mono_thread_suspend (this_obj->internal_thread)) {
2487 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2492 /* LOCKING: LOCK_THREAD(thread) must be held */
2494 mono_thread_resume (MonoInternalThread *thread)
2496 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2497 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread));
2498 thread->state &= ~ThreadState_SuspendRequested;
2499 mono_os_event_set (thread->suspended);
2503 if ((thread->state & ThreadState_Suspended) == 0 ||
2504 (thread->state & ThreadState_Unstarted) != 0 ||
2505 (thread->state & ThreadState_Aborted) != 0 ||
2506 (thread->state & ThreadState_Stopped) != 0)
2508 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread));
2512 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread));
2514 mono_os_event_set (thread->suspended);
2516 if (!thread->self_suspended) {
2517 UNLOCK_THREAD (thread);
2519 /* Awake the thread */
2520 if (!mono_thread_info_resume (thread_get_tid (thread)))
2523 LOCK_THREAD (thread);
2526 thread->state &= ~ThreadState_Suspended;
2532 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2534 if (!thread->internal_thread) {
2535 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2537 LOCK_THREAD (thread->internal_thread);
2538 if (!mono_thread_resume (thread->internal_thread))
2539 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2540 UNLOCK_THREAD (thread->internal_thread);
2545 mono_threads_is_critical_method (MonoMethod *method)
2547 switch (method->wrapper_type) {
2548 case MONO_WRAPPER_RUNTIME_INVOKE:
2549 case MONO_WRAPPER_XDOMAIN_INVOKE:
2550 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2557 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2562 if (mono_threads_is_critical_method (m)) {
2563 *((gboolean*)data) = TRUE;
2570 is_running_protected_wrapper (void)
2572 gboolean found = FALSE;
2573 mono_stack_walk (find_wrapper, &found);
2581 mono_thread_stop (MonoThread *thread)
2583 MonoInternalThread *internal = thread->internal_thread;
2585 if (!request_thread_abort (internal, NULL, FALSE))
2588 if (internal == mono_thread_internal_current ()) {
2590 self_abort_internal (&error);
2592 This function is part of the embeding API and has no way to return the exception
2593 to be thrown. So what we do is keep the old behavior and raise the exception.
2595 mono_error_raise_exception (&error); /* OK to throw, see note */
2597 async_abort_internal (internal, TRUE);
2602 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2604 gint8 tmp = *(volatile gint8 *)ptr;
2605 mono_memory_barrier ();
2610 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2612 gint16 tmp = *(volatile gint16 *)ptr;
2613 mono_memory_barrier ();
2618 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2620 gint32 tmp = *(volatile gint32 *)ptr;
2621 mono_memory_barrier ();
2626 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2628 gint64 tmp = *(volatile gint64 *)ptr;
2629 mono_memory_barrier ();
2634 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2636 volatile void *tmp = *(volatile void **)ptr;
2637 mono_memory_barrier ();
2638 return (void *) tmp;
2642 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2644 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2645 mono_memory_barrier ();
2646 return (MonoObject *) tmp;
2650 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2652 double tmp = *(volatile double *)ptr;
2653 mono_memory_barrier ();
2658 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2660 float tmp = *(volatile float *)ptr;
2661 mono_memory_barrier ();
2666 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2668 return InterlockedRead8 ((volatile gint8 *)ptr);
2672 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2674 return InterlockedRead16 ((volatile gint16 *)ptr);
2678 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2680 return InterlockedRead ((volatile gint32 *)ptr);
2684 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2686 #if SIZEOF_VOID_P == 4
2687 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2689 mono_interlocked_lock ();
2690 val = *(gint64*)ptr;
2691 mono_interlocked_unlock ();
2695 return InterlockedRead64 ((volatile gint64 *)ptr);
2699 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2701 return InterlockedReadPointer ((volatile gpointer *)ptr);
2705 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2709 #if SIZEOF_VOID_P == 4
2710 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2712 mono_interlocked_lock ();
2713 val = *(double*)ptr;
2714 mono_interlocked_unlock ();
2719 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2725 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2729 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2735 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2737 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2741 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2743 mono_memory_barrier ();
2744 *(volatile gint8 *)ptr = value;
2748 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2750 mono_memory_barrier ();
2751 *(volatile gint16 *)ptr = value;
2755 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2757 mono_memory_barrier ();
2758 *(volatile gint32 *)ptr = value;
2762 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2764 mono_memory_barrier ();
2765 *(volatile gint64 *)ptr = value;
2769 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2771 mono_memory_barrier ();
2772 *(volatile void **)ptr = value;
2776 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2778 mono_memory_barrier ();
2779 mono_gc_wbarrier_generic_store (ptr, value);
2783 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2785 mono_memory_barrier ();
2786 *(volatile double *)ptr = value;
2790 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2792 mono_memory_barrier ();
2793 *(volatile float *)ptr = value;
2797 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2799 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2803 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2805 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2809 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2811 InterlockedWrite ((volatile gint32 *)ptr, value);
2815 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2817 #if SIZEOF_VOID_P == 4
2818 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2819 mono_interlocked_lock ();
2820 *(gint64*)ptr = value;
2821 mono_interlocked_unlock ();
2826 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2830 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2832 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2836 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2840 #if SIZEOF_VOID_P == 4
2841 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2842 mono_interlocked_lock ();
2843 *(double*)ptr = value;
2844 mono_interlocked_unlock ();
2851 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2855 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2861 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2865 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2867 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2871 free_context (void *user_data)
2873 ContextStaticData *data = user_data;
2875 mono_threads_lock ();
2878 * There is no guarantee that, by the point this reference queue callback
2879 * has been invoked, the GC handle associated with the object will fail to
2880 * resolve as one might expect. So if we don't free and remove the GC
2881 * handle here, free_context_static_data_helper () could end up resolving
2882 * a GC handle to an actually-dead context which would contain a pointer
2883 * to an already-freed static data segment, resulting in a crash when
2886 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2888 mono_threads_unlock ();
2890 mono_gchandle_free (data->gc_handle);
2891 mono_free_static_data (data->static_data);
2896 mono_threads_register_app_context (MonoAppContext *ctx, MonoError *error)
2899 mono_threads_lock ();
2901 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2904 contexts = g_hash_table_new (NULL, NULL);
2907 context_queue = mono_gc_reference_queue_new (free_context);
2909 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2910 g_hash_table_insert (contexts, gch, gch);
2913 * We use this intermediate structure to contain a duplicate pointer to
2914 * the static data because we can't rely on being able to resolve the GC
2915 * handle in the reference queue callback.
2917 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2918 data->gc_handle = GPOINTER_TO_UINT (gch);
2921 context_adjust_static_data (ctx);
2922 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2924 mono_threads_unlock ();
2926 MONO_PROFILER_RAISE (context_loaded, (ctx));
2930 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContextHandle ctx, MonoError *error)
2933 mono_threads_register_app_context (MONO_HANDLE_RAW (ctx), error); /* FIXME use handles in mono_threads_register_app_context */
2937 mono_threads_release_app_context (MonoAppContext* ctx, MonoError *error)
2940 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2941 * cleanup in exceptional circumstances, we don't actually do any
2942 * cleanup work here. We instead do this via a reference queue.
2945 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2947 MONO_PROFILER_RAISE (context_unloaded, (ctx));
2951 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContextHandle ctx, MonoError *error)
2954 mono_threads_release_app_context (MONO_HANDLE_RAW (ctx), error); /* FIXME use handles in mono_threads_release_app_context */
2957 void mono_thread_init (MonoThreadStartCB start_cb,
2958 MonoThreadAttachCB attach_cb)
2960 mono_coop_mutex_init_recursive (&threads_mutex);
2962 mono_os_mutex_init_recursive(&interlocked_mutex);
2963 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2965 mono_os_event_init (&background_change_event, FALSE);
2967 mono_init_static_data_info (&thread_static_info);
2968 mono_init_static_data_info (&context_static_info);
2970 mono_thread_start_cb = start_cb;
2971 mono_thread_attach_cb = attach_cb;
2975 thread_attach (MonoThreadInfo *info)
2977 return mono_gc_thread_attach (info);
2981 thread_detach (MonoThreadInfo *info)
2983 MonoInternalThread *internal;
2986 /* If a delegate is passed to native code and invoked on a thread we dont
2987 * know about, marshal will register it with mono_threads_attach_coop, but
2988 * we have no way of knowing when that thread goes away. SGen has a TSD
2989 * so we assume that if the domain is still registered, we can detach
2994 if (!mono_thread_info_try_get_internal_thread_gchandle (info, &gchandle))
2997 internal = (MonoInternalThread*) mono_gchandle_get_target (gchandle);
2998 g_assert (internal);
3000 mono_gchandle_free (gchandle);
3002 mono_thread_detach_internal (internal);
3006 thread_detach_with_lock (MonoThreadInfo *info)
3008 return mono_gc_thread_detach_with_lock (info);
3012 thread_in_critical_region (MonoThreadInfo *info)
3014 return mono_gc_thread_in_critical_region (info);
3018 ip_in_critical_region (MonoDomain *domain, gpointer ip)
3024 * We pass false for 'try_aot' so this becomes async safe.
3025 * It won't find aot methods whose jit info is not yet loaded,
3026 * so we preload their jit info in the JIT.
3028 ji = mono_jit_info_table_find_internal (domain, ip, FALSE, FALSE);
3032 method = mono_jit_info_get_method (ji);
3035 return mono_gc_is_critical_method (method);
3039 mono_thread_callbacks_init (void)
3041 MonoThreadInfoCallbacks cb;
3043 memset (&cb, 0, sizeof(cb));
3044 cb.thread_attach = thread_attach;
3045 cb.thread_detach = thread_detach;
3046 cb.thread_detach_with_lock = thread_detach_with_lock;
3047 cb.ip_in_critical_region = ip_in_critical_region;
3048 cb.thread_in_critical_region = thread_in_critical_region;
3049 mono_thread_info_callbacks_init (&cb);
3053 * mono_thread_cleanup:
3056 mono_thread_cleanup (void)
3058 mono_threads_join_threads ();
3060 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
3061 /* The main thread must abandon any held mutexes (particularly
3062 * important for named mutexes as they are shared across
3063 * processes, see bug 74680.) This will happen when the
3064 * thread exits, but if it's not running in a subthread it
3065 * won't exit in time.
3067 mono_w32mutex_abandon ();
3071 /* This stuff needs more testing, it seems one of these
3072 * critical sections can be locked when mono_thread_cleanup is
3075 mono_coop_mutex_destroy (&threads_mutex);
3076 mono_os_mutex_destroy (&interlocked_mutex);
3077 mono_os_mutex_destroy (&delayed_free_table_mutex);
3078 mono_os_mutex_destroy (&small_id_mutex);
3079 mono_os_event_destroy (&background_change_event);
3084 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
3086 mono_thread_cleanup_fn = func;
3090 * mono_thread_set_manage_callback:
3093 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
3095 thread->internal_thread->manage_callback = func;
3099 static void print_tids (gpointer key, gpointer value, gpointer user)
3101 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
3102 * sizeof(uint) and a cast to uint would overflow
3104 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
3105 * print this as a pointer.
3107 g_message ("Waiting for: %p", key);
3112 MonoThreadHandle *handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
3113 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
3118 wait_for_tids (struct wait_data *wait, guint32 timeout, gboolean check_state_change)
3121 MonoThreadInfoWaitRet ret;
3123 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3125 /* Add the thread state change event, so it wakes
3126 * up if a thread changes to background mode. */
3129 if (check_state_change)
3130 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, &background_change_event, FALSE, timeout, TRUE);
3132 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, NULL, TRUE, timeout, TRUE);
3135 if (ret == MONO_THREAD_INFO_WAIT_RET_FAILED) {
3136 /* See the comment in build_wait_tids() */
3137 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3141 for( i = 0; i < wait->num; i++)
3142 mono_threads_close_thread_handle (wait->handles [i]);
3144 if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT)
3147 if (ret < wait->num) {
3148 MonoInternalThread *internal;
3150 internal = wait->threads [ret];
3152 mono_threads_lock ();
3153 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
3154 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
3155 mono_threads_unlock ();
3159 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3161 struct wait_data *wait=(struct wait_data *)user;
3163 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS - 1) {
3164 MonoInternalThread *thread=(MonoInternalThread *)value;
3166 /* Ignore background threads, we abort them later */
3167 /* Do not lock here since it is not needed and the caller holds threads_lock */
3168 if (thread->state & ThreadState_Background) {
3169 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3170 return; /* just leave, ignore */
3173 if (mono_gc_is_finalizer_internal_thread (thread)) {
3174 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3178 if (thread == mono_thread_internal_current ()) {
3179 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3183 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3184 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3188 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3189 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3193 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3194 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3195 wait->handles[wait->num]=mono_threads_open_thread_handle (thread->handle);
3196 wait->threads[wait->num]=thread;
3199 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3201 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3206 /* Just ignore the rest, we can't do anything with
3213 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3215 struct wait_data *wait=(struct wait_data *)user;
3216 MonoNativeThreadId self = mono_native_thread_id_get ();
3217 MonoInternalThread *thread = (MonoInternalThread *)value;
3219 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3222 if (mono_native_thread_id_equals (thread_get_tid (thread), self))
3224 if (mono_gc_is_finalizer_internal_thread (thread))
3227 if ((thread->state & ThreadState_Background) && !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3228 wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
3229 wait->threads[wait->num] = thread;
3232 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3233 mono_thread_internal_abort (thread, FALSE);
3240 * mono_threads_set_shutting_down:
3242 * Is called by a thread that wants to shut down Mono. If the runtime is already
3243 * shutting down, the calling thread is suspended/stopped, and this function never
3247 mono_threads_set_shutting_down (void)
3249 MonoInternalThread *current_thread = mono_thread_internal_current ();
3251 mono_threads_lock ();
3253 if (shutting_down) {
3254 mono_threads_unlock ();
3256 /* Make sure we're properly suspended/stopped */
3258 LOCK_THREAD (current_thread);
3260 if (current_thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
3261 UNLOCK_THREAD (current_thread);
3262 mono_thread_execute_interruption ();
3264 UNLOCK_THREAD (current_thread);
3267 /*since we're killing the thread, detach it.*/
3268 mono_thread_detach_internal (current_thread);
3270 /* Wake up other threads potentially waiting for us */
3271 mono_thread_info_exit (0);
3273 shutting_down = TRUE;
3275 /* Not really a background state change, but this will
3276 * interrupt the main thread if it is waiting for all
3277 * the other threads.
3279 mono_os_event_set (&background_change_event);
3281 mono_threads_unlock ();
3286 * mono_thread_manage:
3289 mono_thread_manage (void)
3291 struct wait_data wait_data;
3292 struct wait_data *wait = &wait_data;
3294 memset (wait, 0, sizeof (struct wait_data));
3295 /* join each thread that's still running */
3296 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3298 mono_threads_lock ();
3300 THREAD_DEBUG (g_message("%s: No threads", __func__));
3301 mono_threads_unlock ();
3304 mono_threads_unlock ();
3307 mono_threads_lock ();
3308 if (shutting_down) {
3309 /* somebody else is shutting down */
3310 mono_threads_unlock ();
3313 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3314 mono_g_hash_table_foreach (threads, print_tids, NULL));
3316 mono_os_event_reset (&background_change_event);
3318 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3319 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3320 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3321 mono_threads_unlock ();
3323 /* Something to wait for */
3324 wait_for_tids (wait, MONO_INFINITE_WAIT, TRUE);
3325 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3326 } while(wait->num>0);
3328 /* Mono is shutting down, so just wait for the end */
3329 if (!mono_runtime_try_shutdown ()) {
3330 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3331 mono_thread_suspend (mono_thread_internal_current ());
3332 mono_thread_execute_interruption ();
3336 * Remove everything but the finalizer thread and self.
3337 * Also abort all the background threads
3340 mono_threads_lock ();
3343 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3344 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3345 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3347 mono_threads_unlock ();
3349 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3350 if (wait->num > 0) {
3351 /* Something to wait for */
3352 wait_for_tids (wait, MONO_INFINITE_WAIT, FALSE);
3354 } while (wait->num > 0);
3357 * give the subthreads a chance to really quit (this is mainly needed
3358 * to get correct user and system times from getrusage/wait/time(1)).
3359 * This could be removed if we avoid pthread_detach() and use pthread_join().
3361 mono_thread_info_yield ();
3365 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3367 MonoInternalThread *thread = (MonoInternalThread*)value;
3368 struct wait_data *wait = (struct wait_data*)user_data;
3371 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3373 * This needs no locking.
3375 if ((thread->state & ThreadState_Suspended) != 0 ||
3376 (thread->state & ThreadState_Stopped) != 0)
3379 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3380 wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle);
3381 wait->threads [wait->num] = thread;
3387 * mono_thread_suspend_all_other_threads:
3389 * Suspend all managed threads except the finalizer thread and this thread. It is
3390 * not possible to resume them later.
3392 void mono_thread_suspend_all_other_threads (void)
3394 struct wait_data wait_data;
3395 struct wait_data *wait = &wait_data;
3397 MonoNativeThreadId self = mono_native_thread_id_get ();
3398 guint32 eventidx = 0;
3399 gboolean starting, finished;
3401 memset (wait, 0, sizeof (struct wait_data));
3403 * The other threads could be in an arbitrary state at this point, i.e.
3404 * they could be starting up, shutting down etc. This means that there could be
3405 * threads which are not even in the threads hash table yet.
3409 * First we set a barrier which will be checked by all threads before they
3410 * are added to the threads hash table, and they will exit if the flag is set.
3411 * This ensures that no threads could be added to the hash later.
3412 * We will use shutting_down as the barrier for now.
3414 g_assert (shutting_down);
3417 * We make multiple calls to WaitForMultipleObjects since:
3418 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3419 * - some threads could exit without becoming suspended
3424 * Make a copy of the hashtable since we can't do anything with
3425 * threads while threads_mutex is held.
3428 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3429 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3430 mono_threads_lock ();
3431 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3432 mono_threads_unlock ();
3435 /* Get the suspended events that we'll be waiting for */
3436 for (i = 0; i < wait->num; ++i) {
3437 MonoInternalThread *thread = wait->threads [i];
3439 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3440 || mono_gc_is_finalizer_internal_thread (thread)
3441 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3443 mono_threads_close_thread_handle (wait->handles [i]);
3444 wait->threads [i] = NULL;
3448 LOCK_THREAD (thread);
3450 if (thread->state & (ThreadState_Suspended | ThreadState_Stopped)) {
3451 UNLOCK_THREAD (thread);
3452 mono_threads_close_thread_handle (wait->handles [i]);
3453 wait->threads [i] = NULL;
3459 /* Convert abort requests into suspend requests */
3460 if ((thread->state & ThreadState_AbortRequested) != 0)
3461 thread->state &= ~ThreadState_AbortRequested;
3463 thread->state |= ThreadState_SuspendRequested;
3464 mono_os_event_reset (thread->suspended);
3466 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3467 async_suspend_internal (thread, TRUE);
3469 mono_threads_close_thread_handle (wait->handles [i]);
3470 wait->threads [i] = NULL;
3472 if (eventidx <= 0) {
3474 * If there are threads which are starting up, we wait until they
3475 * are suspended when they try to register in the threads hash.
3476 * This is guaranteed to finish, since the threads which can create new
3477 * threads get suspended after a while.
3478 * FIXME: The finalizer thread can still create new threads.
3480 mono_threads_lock ();
3481 if (threads_starting_up)
3482 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3485 mono_threads_unlock ();
3487 mono_thread_info_sleep (100, NULL);
3495 MonoInternalThread *thread;
3496 MonoStackFrameInfo *frames;
3497 int nframes, max_frames;
3498 int nthreads, max_threads;
3499 MonoInternalThread **threads;
3500 } ThreadDumpUserData;
3502 static gboolean thread_dump_requested;
3504 /* This needs to be async safe */
3506 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3508 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3510 if (ud->nframes < ud->max_frames) {
3511 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3518 /* This needs to be async safe */
3519 static SuspendThreadResult
3520 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3522 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3523 MonoInternalThread *thread = user_data->thread;
3526 /* This no longer works with remote unwinding */
3527 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3528 mono_thread_internal_describe (thread, text);
3529 g_string_append (text, "\n");
3532 if (thread == mono_thread_internal_current ())
3533 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3535 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3537 return MonoResumeThread;
3541 int nthreads, max_threads;
3542 MonoInternalThread **threads;
3543 } CollectThreadsUserData;
3546 collect_thread (gpointer key, gpointer value, gpointer user)
3548 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3549 MonoInternalThread *thread = (MonoInternalThread *)value;
3551 if (ud->nthreads < ud->max_threads)
3552 ud->threads [ud->nthreads ++] = thread;
3556 * Collect running threads into the THREADS array.
3557 * THREADS should be an array allocated on the stack.
3560 collect_threads (MonoInternalThread **thread_array, int max_threads)
3562 CollectThreadsUserData ud;
3564 memset (&ud, 0, sizeof (ud));
3565 /* This array contains refs, but its on the stack, so its ok */
3566 ud.threads = thread_array;
3567 ud.max_threads = max_threads;
3569 mono_threads_lock ();
3570 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3571 mono_threads_unlock ();
3577 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3579 GString* text = g_string_new (0);
3581 GError *error = NULL;
3584 ud->thread = thread;
3587 /* Collect frames for the thread */
3588 if (thread == mono_thread_internal_current ()) {
3589 get_thread_dump (mono_thread_info_current (), ud);
3591 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3595 * Do all the non async-safe work outside of get_thread_dump.
3598 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3600 g_string_append_printf (text, "\n\"%s\"", name);
3603 else if (thread->threadpool_thread) {
3604 g_string_append (text, "\n\"<threadpool thread>\"");
3606 g_string_append (text, "\n\"<unnamed thread>\"");
3609 for (i = 0; i < ud->nframes; ++i) {
3610 MonoStackFrameInfo *frame = &ud->frames [i];
3611 MonoMethod *method = NULL;
3613 if (frame->type == FRAME_TYPE_MANAGED)
3614 method = mono_jit_info_get_method (frame->ji);
3617 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3618 g_string_append_printf (text, " %s\n", location);
3621 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3625 fprintf (stdout, "%s", text->str);
3627 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3628 OutputDebugStringA(text->str);
3631 g_string_free (text, TRUE);
3636 mono_threads_perform_thread_dump (void)
3638 ThreadDumpUserData ud;
3639 MonoInternalThread *thread_array [128];
3640 int tindex, nthreads;
3642 if (!thread_dump_requested)
3645 printf ("Full thread dump:\n");
3647 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3648 nthreads = collect_threads (thread_array, 128);
3650 memset (&ud, 0, sizeof (ud));
3651 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3652 ud.max_frames = 256;
3654 for (tindex = 0; tindex < nthreads; ++tindex)
3655 dump_thread (thread_array [tindex], &ud);
3659 thread_dump_requested = FALSE;
3662 /* Obtain the thread dump of all threads */
3664 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3667 ThreadDumpUserData ud;
3668 MonoInternalThread *thread_array [128];
3669 MonoDomain *domain = mono_domain_get ();
3670 MonoDebugSourceLocation *location;
3671 int tindex, nthreads;
3675 *out_threads = NULL;
3676 *out_stack_frames = NULL;
3678 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3679 nthreads = collect_threads (thread_array, 128);
3681 memset (&ud, 0, sizeof (ud));
3682 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3683 ud.max_frames = 256;
3685 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3688 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3692 for (tindex = 0; tindex < nthreads; ++tindex) {
3693 MonoInternalThread *thread = thread_array [tindex];
3694 MonoArray *thread_frames;
3700 /* Collect frames for the thread */
3701 if (thread == mono_thread_internal_current ()) {
3702 get_thread_dump (mono_thread_info_current (), &ud);
3704 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3707 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3709 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3712 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3714 for (i = 0; i < ud.nframes; ++i) {
3715 MonoStackFrameInfo *frame = &ud.frames [i];
3716 MonoMethod *method = NULL;
3717 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3721 sf->native_offset = frame->native_offset;
3723 if (frame->type == FRAME_TYPE_MANAGED)
3724 method = mono_jit_info_get_method (frame->ji);
3727 sf->method_address = (gsize) frame->ji->code_start;
3729 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3732 MONO_OBJECT_SETREF (sf, method, rm);
3734 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3736 sf->il_offset = location->il_offset;
3738 if (location && location->source_file) {
3739 MonoString *filename = mono_string_new_checked (domain, location->source_file, error);
3742 MONO_OBJECT_SETREF (sf, filename, filename);
3743 sf->line = location->row;
3744 sf->column = location->column;
3746 mono_debug_free_source_location (location);
3751 mono_array_setref (thread_frames, i, sf);
3757 return is_ok (error);
3761 * mono_threads_request_thread_dump:
3763 * Ask all threads except the current to print their stacktrace to stdout.
3766 mono_threads_request_thread_dump (void)
3768 /*The new thread dump code runs out of the finalizer thread. */
3769 thread_dump_requested = TRUE;
3770 mono_gc_finalize_notify ();
3775 gint allocated; /* +1 so that refs [allocated] == NULL */
3779 typedef struct ref_stack RefStack;
3782 ref_stack_new (gint initial_size)
3786 initial_size = MAX (initial_size, 16) + 1;
3787 rs = g_new0 (RefStack, 1);
3788 rs->refs = g_new0 (gpointer, initial_size);
3789 rs->allocated = initial_size;
3794 ref_stack_destroy (gpointer ptr)
3796 RefStack *rs = (RefStack *)ptr;
3805 ref_stack_push (RefStack *rs, gpointer ptr)
3807 g_assert (rs != NULL);
3809 if (rs->bottom >= rs->allocated) {
3810 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3811 rs->allocated <<= 1;
3812 rs->refs [rs->allocated] = NULL;
3814 rs->refs [rs->bottom++] = ptr;
3818 ref_stack_pop (RefStack *rs)
3820 if (rs == NULL || rs->bottom == 0)
3824 rs->refs [rs->bottom] = NULL;
3828 ref_stack_find (RefStack *rs, gpointer ptr)
3835 for (refs = rs->refs; refs && *refs; refs++) {
3843 * mono_thread_push_appdomain_ref:
3845 * Register that the current thread may have references to objects in domain
3846 * @domain on its stack. Each call to this function should be paired with a
3847 * call to pop_appdomain_ref.
3850 mono_thread_push_appdomain_ref (MonoDomain *domain)
3852 MonoInternalThread *thread = mono_thread_internal_current ();
3855 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3856 SPIN_LOCK (thread->lock_thread_id);
3857 if (thread->appdomain_refs == NULL)
3858 thread->appdomain_refs = ref_stack_new (16);
3859 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3860 SPIN_UNLOCK (thread->lock_thread_id);
3865 mono_thread_pop_appdomain_ref (void)
3867 MonoInternalThread *thread = mono_thread_internal_current ();
3870 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3871 SPIN_LOCK (thread->lock_thread_id);
3872 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3873 SPIN_UNLOCK (thread->lock_thread_id);
3878 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3881 SPIN_LOCK (thread->lock_thread_id);
3882 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3883 SPIN_UNLOCK (thread->lock_thread_id);
3888 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3890 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3893 typedef struct abort_appdomain_data {
3894 struct wait_data wait;
3896 } abort_appdomain_data;
3899 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3901 MonoInternalThread *thread = (MonoInternalThread*)value;
3902 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3903 MonoDomain *domain = data->domain;
3905 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3906 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3908 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3909 data->wait.handles [data->wait.num] = mono_threads_open_thread_handle (thread->handle);
3910 data->wait.threads [data->wait.num] = thread;
3913 /* Just ignore the rest, we can't do anything with
3921 * mono_threads_abort_appdomain_threads:
3923 * Abort threads which has references to the given appdomain.
3926 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3928 abort_appdomain_data user_data;
3930 int orig_timeout = timeout;
3933 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3935 start_time = mono_msec_ticks ();
3937 mono_threads_lock ();
3939 user_data.domain = domain;
3940 user_data.wait.num = 0;
3941 /* This shouldn't take any locks */
3942 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3943 mono_threads_unlock ();
3945 if (user_data.wait.num > 0) {
3946 /* Abort the threads outside the threads lock */
3947 for (i = 0; i < user_data.wait.num; ++i)
3948 mono_thread_internal_abort (user_data.wait.threads [i], TRUE);
3951 * We should wait for the threads either to abort, or to leave the
3952 * domain. We can't do the latter, so we wait with a timeout.
3954 wait_for_tids (&user_data.wait, 100, FALSE);
3957 /* Update remaining time */
3958 timeout -= mono_msec_ticks () - start_time;
3959 start_time = mono_msec_ticks ();
3961 if (orig_timeout != -1 && timeout < 0)
3964 while (user_data.wait.num > 0);
3966 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3972 mono_thread_self_abort (void)
3975 self_abort_internal (&error);
3976 mono_error_set_pending_exception (&error);
3980 * mono_thread_get_undeniable_exception:
3982 * Return an exception which needs to be raised when leaving a catch clause.
3983 * This is used for undeniable exception propagation.
3986 mono_thread_get_undeniable_exception (void)
3988 MonoInternalThread *thread = mono_thread_internal_current ();
3990 if (!(thread && thread->abort_exc && !is_running_protected_wrapper ()))
3993 // We don't want to have our exception effect calls made by
3994 // the catching block
3996 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
4000 * FIXME: Clear the abort exception and return an AppDomainUnloaded
4001 * exception if the thread no longer references a dying appdomain.
4003 thread->abort_exc->trace_ips = NULL;
4004 thread->abort_exc->stack_trace = NULL;
4005 return thread->abort_exc;
4008 #if MONO_SMALL_CONFIG
4009 #define NUM_STATIC_DATA_IDX 4
4010 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
4014 #define NUM_STATIC_DATA_IDX 8
4015 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
4016 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
4020 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
4021 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
4024 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
4026 gpointer *static_data = (gpointer *)addr;
4028 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
4029 void **ptr = (void **)static_data [i];
4034 MONO_BITSET_FOREACH (bitmaps [i], idx, {
4035 void **p = ptr + idx;
4038 mark_func ((MonoObject**)p, gc_data);
4044 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4046 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
4050 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4052 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
4056 * mono_alloc_static_data
4058 * Allocate memory blocks for storing threads or context static data
4061 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4063 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4066 gpointer* static_data = *static_data_ptr;
4068 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4069 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4071 if (mono_gc_user_markers_supported ()) {
4072 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4073 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4075 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4076 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4079 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4080 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4081 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4082 *static_data_ptr = static_data;
4083 static_data [0] = static_data;
4086 for (i = 1; i <= idx; ++i) {
4087 if (static_data [i])
4090 if (mono_gc_user_markers_supported ())
4091 static_data [i] = g_malloc0 (static_data_size [i]);
4093 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4094 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4095 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4100 mono_free_static_data (gpointer* static_data)
4103 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4104 gpointer p = static_data [i];
4108 * At this point, the static data pointer array is still registered with the
4109 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4110 * data. Freeing the individual arrays without first nulling their slots
4111 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4112 * such an already freed array. See bug #13813.
4114 static_data [i] = NULL;
4115 mono_memory_write_barrier ();
4116 if (mono_gc_user_markers_supported ())
4119 mono_gc_free_fixed (p);
4121 mono_gc_free_fixed (static_data);
4125 * mono_init_static_data_info
4127 * Initializes static data counters
4129 static void mono_init_static_data_info (StaticDataInfo *static_data)
4131 static_data->idx = 0;
4132 static_data->offset = 0;
4133 static_data->freelist = NULL;
4137 * mono_alloc_static_data_slot
4139 * Generates an offset for static data. static_data contains the counters
4140 * used to generate it.
4143 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4145 if (!static_data->idx && !static_data->offset) {
4147 * we use the first chunk of the first allocation also as
4148 * an array for the rest of the data
4150 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4152 static_data->offset += align - 1;
4153 static_data->offset &= ~(align - 1);
4154 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4155 static_data->idx ++;
4156 g_assert (size <= static_data_size [static_data->idx]);
4157 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4158 static_data->offset = 0;
4160 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4161 static_data->offset += size;
4166 * LOCKING: requires that threads_mutex is held
4169 context_adjust_static_data (MonoAppContext *ctx)
4171 if (context_static_info.offset || context_static_info.idx > 0) {
4172 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4173 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4174 ctx->data->static_data = ctx->static_data;
4179 * LOCKING: requires that threads_mutex is held
4182 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4184 MonoInternalThread *thread = (MonoInternalThread *)value;
4185 guint32 offset = GPOINTER_TO_UINT (user);
4187 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4191 * LOCKING: requires that threads_mutex is held
4194 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4196 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4201 guint32 offset = GPOINTER_TO_UINT (user);
4202 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4203 ctx->data->static_data = ctx->static_data;
4206 static StaticDataFreeList*
4207 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4209 StaticDataFreeList* prev = NULL;
4210 StaticDataFreeList* tmp = static_data->freelist;
4212 if (tmp->size == size) {
4214 prev->next = tmp->next;
4216 static_data->freelist = tmp->next;
4225 #if SIZEOF_VOID_P == 4
4232 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4234 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4236 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4237 MonoBitSet *rb = sets [idx];
4238 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4239 offset /= sizeof (uintptr_t);
4240 /* offset is now the bitmap offset */
4241 for (int i = 0; i < numbits; ++i) {
4242 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4243 mono_bitset_set_fast (rb, offset + i);
4248 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4250 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4251 MonoBitSet *rb = sets [idx];
4252 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4253 offset /= sizeof (uintptr_t);
4254 /* offset is now the bitmap offset */
4255 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4256 mono_bitset_clear_fast (rb, offset + i);
4260 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4262 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4264 StaticDataInfo *info;
4267 if (static_type == SPECIAL_STATIC_THREAD) {
4268 info = &thread_static_info;
4269 sets = thread_reference_bitmaps;
4271 info = &context_static_info;
4272 sets = context_reference_bitmaps;
4275 mono_threads_lock ();
4277 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4281 offset = item->offset;
4284 offset = mono_alloc_static_data_slot (info, size, align);
4287 update_reference_bitmap (sets, offset, bitmap, numbits);
4289 if (static_type == SPECIAL_STATIC_THREAD) {
4290 /* This can be called during startup */
4291 if (threads != NULL)
4292 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4294 if (contexts != NULL)
4295 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4297 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4300 mono_threads_unlock ();
4306 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4308 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4310 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4311 return get_thread_static_data (thread, offset);
4313 return get_context_static_data (thread->current_appcontext, offset);
4318 mono_get_special_static_data (guint32 offset)
4320 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4329 * LOCKING: requires that threads_mutex is held
4332 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4334 MonoInternalThread *thread = (MonoInternalThread *)value;
4335 OffsetSize *data = (OffsetSize *)user;
4336 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4337 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4340 if (!thread->static_data || !thread->static_data [idx])
4342 ptr = ((char*) thread->static_data [idx]) + off;
4343 mono_gc_bzero_atomic (ptr, data->size);
4347 * LOCKING: requires that threads_mutex is held
4350 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4352 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4357 OffsetSize *data = (OffsetSize *)user;
4358 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4359 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4362 if (!ctx->static_data || !ctx->static_data [idx])
4365 ptr = ((char*) ctx->static_data [idx]) + off;
4366 mono_gc_bzero_atomic (ptr, data->size);
4370 do_free_special_slot (guint32 offset, guint32 size)
4372 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4374 StaticDataInfo *info;
4376 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4377 info = &thread_static_info;
4378 sets = thread_reference_bitmaps;
4380 info = &context_static_info;
4381 sets = context_reference_bitmaps;
4384 guint32 data_offset = offset;
4385 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4386 OffsetSize data = { data_offset, size };
4388 clear_reference_bitmap (sets, data.offset, data.size);
4390 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4391 if (threads != NULL)
4392 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4394 if (contexts != NULL)
4395 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4398 if (!mono_runtime_is_shutting_down ()) {
4399 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4401 item->offset = offset;
4404 item->next = info->freelist;
4405 info->freelist = item;
4410 do_free_special (gpointer key, gpointer value, gpointer data)
4412 MonoClassField *field = (MonoClassField *)key;
4413 guint32 offset = GPOINTER_TO_UINT (value);
4416 size = mono_type_size (field->type, &align);
4417 do_free_special_slot (offset, size);
4421 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4423 mono_threads_lock ();
4425 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4427 mono_threads_unlock ();
4431 static void CALLBACK dummy_apc (ULONG_PTR param)
4437 * mono_thread_execute_interruption
4439 * Performs the operation that the requested thread state requires (abort,
4442 static MonoException*
4443 mono_thread_execute_interruption (void)
4445 MonoInternalThread *thread = mono_thread_internal_current ();
4446 MonoThread *sys_thread = mono_thread_current ();
4448 LOCK_THREAD (thread);
4450 /* MonoThread::interruption_requested can only be changed with atomics */
4451 if (!mono_thread_clear_interruption_requested (thread)) {
4452 UNLOCK_THREAD (thread);
4456 /* this will consume pending APC calls */
4458 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4460 /* Clear the interrupted flag of the thread so it can wait again */
4461 mono_thread_info_clear_self_interrupt ();
4463 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4464 if (sys_thread->pending_exception) {
4467 exc = sys_thread->pending_exception;
4468 sys_thread->pending_exception = NULL;
4470 UNLOCK_THREAD (thread);
4472 } else if (thread->state & (ThreadState_AbortRequested)) {
4473 UNLOCK_THREAD (thread);
4474 g_assert (sys_thread->pending_exception == NULL);
4475 if (thread->abort_exc == NULL) {
4477 * This might be racy, but it has to be called outside the lock
4478 * since it calls managed code.
4480 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4482 return thread->abort_exc;
4483 } else if (thread->state & (ThreadState_SuspendRequested)) {
4484 /* calls UNLOCK_THREAD (thread) */
4485 self_suspend_internal ();
4487 } else if (thread->thread_interrupt_requested) {
4489 thread->thread_interrupt_requested = FALSE;
4490 UNLOCK_THREAD (thread);
4492 return(mono_get_exception_thread_interrupted ());
4495 UNLOCK_THREAD (thread);
4501 * mono_thread_request_interruption
4503 * A signal handler can call this method to request the interruption of a
4504 * thread. The result of the interruption will depend on the current state of
4505 * the thread. If the result is an exception that needs to be throw, it is
4506 * provided as return value.
4509 mono_thread_request_interruption (gboolean running_managed)
4511 MonoInternalThread *thread = mono_thread_internal_current ();
4513 /* The thread may already be stopping */
4517 if (!mono_thread_set_interruption_requested (thread))
4520 if (!running_managed || is_running_protected_wrapper ()) {
4521 /* Can't stop while in unmanaged code. Increase the global interruption
4522 request count. When exiting the unmanaged method the count will be
4523 checked and the thread will be interrupted. */
4525 /* this will awake the thread if it is in WaitForSingleObject
4527 /* Our implementation of this function ignores the func argument */
4529 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
4531 mono_thread_info_self_interrupt ();
4536 return mono_thread_execute_interruption ();
4540 /*This function should be called by a thread after it has exited all of
4541 * its handle blocks at interruption time.*/
4543 mono_thread_resume_interruption (gboolean exec)
4545 MonoInternalThread *thread = mono_thread_internal_current ();
4546 gboolean still_aborting;
4548 /* The thread may already be stopping */
4552 LOCK_THREAD (thread);
4553 still_aborting = (thread->state & (ThreadState_AbortRequested)) != 0;
4554 UNLOCK_THREAD (thread);
4556 /*This can happen if the protected block called Thread::ResetAbort*/
4557 if (!still_aborting)
4560 if (!mono_thread_set_interruption_requested (thread))
4563 mono_thread_info_self_interrupt ();
4566 return mono_thread_execute_interruption ();
4571 gboolean mono_thread_interruption_requested ()
4573 if (thread_interruption_requested) {
4574 MonoInternalThread *thread = mono_thread_internal_current ();
4575 /* The thread may already be stopping */
4577 return mono_thread_get_interruption_requested (thread);
4582 static MonoException*
4583 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4585 MonoInternalThread *thread = mono_thread_internal_current ();
4587 /* The thread may already be stopping */
4590 if (!mono_thread_get_interruption_requested (thread))
4592 if (!bypass_abort_protection && is_running_protected_wrapper ())
4595 return mono_thread_execute_interruption ();
4599 * Performs the interruption of the current thread, if one has been requested,
4600 * and the thread is not running a protected wrapper.
4601 * Return the exception which needs to be thrown, if any.
4604 mono_thread_interruption_checkpoint (void)
4606 return mono_thread_interruption_checkpoint_request (FALSE);
4610 * Performs the interruption of the current thread, if one has been requested.
4611 * Return the exception which needs to be thrown, if any.
4614 mono_thread_force_interruption_checkpoint_noraise (void)
4616 return mono_thread_interruption_checkpoint_request (TRUE);
4620 * mono_set_pending_exception:
4622 * Set the pending exception of the current thread to EXC.
4623 * The exception will be thrown when execution returns to managed code.
4626 mono_set_pending_exception (MonoException *exc)
4628 MonoThread *thread = mono_thread_current ();
4630 /* The thread may already be stopping */
4634 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4636 mono_thread_request_interruption (FALSE);
4640 * mono_thread_interruption_request_flag:
4642 * Returns the address of a flag that will be non-zero if an interruption has
4643 * been requested for a thread. The thread to interrupt may not be the current
4644 * thread, so an additional call to mono_thread_interruption_requested() or
4645 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4648 gint32* mono_thread_interruption_request_flag ()
4650 return &thread_interruption_requested;
4654 mono_thread_init_apartment_state (void)
4657 MonoInternalThread* thread = mono_thread_internal_current ();
4659 /* Positive return value indicates success, either
4660 * S_OK if this is first CoInitialize call, or
4661 * S_FALSE if CoInitialize already called, but with same
4662 * threading model. A negative value indicates failure,
4663 * probably due to trying to change the threading model.
4665 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4666 ? COINIT_APARTMENTTHREADED
4667 : COINIT_MULTITHREADED) < 0) {
4668 thread->apartment_state = ThreadApartmentState_Unknown;
4674 mono_thread_cleanup_apartment_state (void)
4677 MonoInternalThread* thread = mono_thread_internal_current ();
4679 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4686 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4688 LOCK_THREAD (thread);
4689 thread->state |= state;
4690 UNLOCK_THREAD (thread);
4694 * mono_thread_test_and_set_state:
4695 * Test if current state of \p thread include \p test. If it does not, OR \p set into the state.
4696 * \returns TRUE if \p set was OR'd in.
4699 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4701 LOCK_THREAD (thread);
4703 if ((thread->state & test) != 0) {
4704 UNLOCK_THREAD (thread);
4708 thread->state |= set;
4709 UNLOCK_THREAD (thread);
4715 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4717 LOCK_THREAD (thread);
4718 thread->state &= ~state;
4719 UNLOCK_THREAD (thread);
4723 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4725 gboolean ret = FALSE;
4727 LOCK_THREAD (thread);
4729 if ((thread->state & test) != 0) {
4733 UNLOCK_THREAD (thread);
4739 self_interrupt_thread (void *_unused)
4742 MonoThreadInfo *info;
4744 exc = mono_thread_execute_interruption ();
4746 if (mono_threads_is_coop_enabled ()) {
4747 /* We can return from an async call in coop, as
4748 * it's simply called when exiting the safepoint */
4752 g_error ("%s: we can't resume from an async call", __func__);
4755 info = mono_thread_info_current ();
4757 /* We must use _with_context since we didn't trampoline into the runtime */
4758 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. */
4762 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4766 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4770 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4772 MonoJitInfo **dest = (MonoJitInfo **)data;
4778 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4780 MonoJitInfo *ji = NULL;
4785 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4786 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4787 * where we hold runtime locks.
4789 if (!mono_threads_is_coop_enabled ())
4790 mono_thread_info_set_is_async_context (TRUE);
4791 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4792 if (!mono_threads_is_coop_enabled ())
4793 mono_thread_info_set_is_async_context (FALSE);
4798 MonoInternalThread *thread;
4799 gboolean install_async_abort;
4800 MonoThreadInfoInterruptToken *interrupt_token;
4803 static SuspendThreadResult
4804 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4806 AbortThreadData *data = (AbortThreadData *)ud;
4807 MonoInternalThread *thread = data->thread;
4808 MonoJitInfo *ji = NULL;
4809 gboolean protected_wrapper;
4810 gboolean running_managed;
4812 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4813 return MonoResumeThread;
4815 /*someone is already interrupting it*/
4816 if (!mono_thread_set_interruption_requested (thread))
4817 return MonoResumeThread;
4819 ji = mono_thread_info_get_last_managed (info);
4820 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4821 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4823 if (!protected_wrapper && running_managed) {
4824 /*We are in managed code*/
4825 /*Set the thread to call */
4826 if (data->install_async_abort)
4827 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4828 return MonoResumeThread;
4831 * This will cause waits to be broken.
4832 * It will also prevent the thread from entering a wait, so if the thread returns
4833 * from the wait before it receives the abort signal, it will just spin in the wait
4834 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4837 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4839 return MonoResumeThread;
4844 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4846 AbortThreadData data;
4848 g_assert (thread != mono_thread_internal_current ());
4850 data.thread = thread;
4851 data.install_async_abort = install_async_abort;
4852 data.interrupt_token = NULL;
4854 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4855 if (data.interrupt_token)
4856 mono_thread_info_finish_interrupt (data.interrupt_token);
4857 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4861 self_abort_internal (MonoError *error)
4867 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4868 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4871 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.
4873 exc = mono_thread_request_interruption (TRUE);
4875 mono_error_set_exception_instance (error, exc);
4877 mono_thread_info_self_interrupt ();
4881 MonoInternalThread *thread;
4883 MonoThreadInfoInterruptToken *interrupt_token;
4884 } SuspendThreadData;
4886 static SuspendThreadResult
4887 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4889 SuspendThreadData *data = (SuspendThreadData *)ud;
4890 MonoInternalThread *thread = data->thread;
4891 MonoJitInfo *ji = NULL;
4892 gboolean protected_wrapper;
4893 gboolean running_managed;
4895 ji = mono_thread_info_get_last_managed (info);
4896 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4897 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4899 if (running_managed && !protected_wrapper) {
4900 if (mono_threads_is_coop_enabled ()) {
4901 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4902 return MonoResumeThread;
4904 thread->state &= ~ThreadState_SuspendRequested;
4905 thread->state |= ThreadState_Suspended;
4906 return KeepSuspended;
4909 mono_thread_set_interruption_requested (thread);
4910 if (data->interrupt)
4911 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4913 return MonoResumeThread;
4917 /* LOCKING: called with @thread synch_cs held, and releases it */
4919 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4921 SuspendThreadData data;
4923 g_assert (thread != mono_thread_internal_current ());
4925 // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4927 thread->self_suspended = FALSE;
4929 data.thread = thread;
4930 data.interrupt = interrupt;
4931 data.interrupt_token = NULL;
4933 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4934 if (data.interrupt_token)
4935 mono_thread_info_finish_interrupt (data.interrupt_token);
4937 UNLOCK_THREAD (thread);
4940 /* LOCKING: called with @thread synch_cs held, and releases it */
4942 self_suspend_internal (void)
4944 MonoInternalThread *thread;
4946 MonoOSEventWaitRet res;
4948 thread = mono_thread_internal_current ();
4950 // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4952 thread->self_suspended = TRUE;
4954 thread->state &= ~ThreadState_SuspendRequested;
4955 thread->state |= ThreadState_Suspended;
4957 UNLOCK_THREAD (thread);
4959 event = thread->suspended;
4962 res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT, TRUE);
4963 g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
4968 suspend_for_shutdown_async_call (gpointer unused)
4971 mono_thread_info_yield ();
4974 static SuspendThreadResult
4975 suspend_for_shutdown_critical (MonoThreadInfo *info, gpointer unused)
4977 mono_thread_info_setup_async_call (info, suspend_for_shutdown_async_call, NULL);
4978 return MonoResumeThread;
4982 mono_thread_internal_suspend_for_shutdown (MonoInternalThread *thread)
4984 g_assert (thread != mono_thread_internal_current ());
4986 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, suspend_for_shutdown_critical, NULL);
4990 * mono_thread_is_foreign:
4991 * \param thread the thread to query
4993 * This function allows one to determine if a thread was created by the mono runtime and has
4994 * a well defined lifecycle or it's a foreign one, created by the native environment.
4996 * \returns TRUE if \p thread was not created by the runtime.
4999 mono_thread_is_foreign (MonoThread *thread)
5001 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
5002 return info->runtime_thread == FALSE;
5006 * mono_add_joinable_thread:
5008 * Add TID to the list of joinable threads.
5009 * LOCKING: Acquires the threads lock.
5012 mono_threads_add_joinable_thread (gpointer tid)
5016 * We cannot detach from threads because it causes problems like
5017 * 2fd16f60/r114307. So we collect them and join them when
5018 * we have time (in he finalizer thread).
5020 joinable_threads_lock ();
5021 if (!joinable_threads)
5022 joinable_threads = g_hash_table_new (NULL, NULL);
5023 g_hash_table_insert (joinable_threads, tid, tid);
5024 UnlockedIncrement (&joinable_thread_count);
5025 joinable_threads_unlock ();
5027 mono_gc_finalize_notify ();
5032 * mono_threads_join_threads:
5034 * Join all joinable threads. This is called from the finalizer thread.
5035 * LOCKING: Acquires the threads lock.
5038 mono_threads_join_threads (void)
5041 GHashTableIter iter;
5048 if (!UnlockedRead (&joinable_thread_count))
5052 joinable_threads_lock ();
5054 if (g_hash_table_size (joinable_threads)) {
5055 g_hash_table_iter_init (&iter, joinable_threads);
5056 g_hash_table_iter_next (&iter, &key, (void**)&tid);
5057 thread = (pthread_t)tid;
5058 g_hash_table_remove (joinable_threads, key);
5059 UnlockedDecrement (&joinable_thread_count);
5062 joinable_threads_unlock ();
5064 if (thread != pthread_self ()) {
5066 /* This shouldn't block */
5067 mono_threads_join_lock ();
5068 mono_native_thread_join (thread);
5069 mono_threads_join_unlock ();
5082 * Wait for thread TID to exit.
5083 * LOCKING: Acquires the threads lock.
5086 mono_thread_join (gpointer tid)
5090 gboolean found = FALSE;
5092 joinable_threads_lock ();
5093 if (!joinable_threads)
5094 joinable_threads = g_hash_table_new (NULL, NULL);
5095 if (g_hash_table_lookup (joinable_threads, tid)) {
5096 g_hash_table_remove (joinable_threads, tid);
5097 UnlockedDecrement (&joinable_thread_count);
5100 joinable_threads_unlock ();
5103 thread = (pthread_t)tid;
5105 mono_native_thread_join (thread);
5111 mono_thread_internal_unhandled_exception (MonoObject* exc)
5113 MonoClass *klass = exc->vtable->klass;
5114 if (is_threadabort_exception (klass)) {
5115 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5116 } else if (!is_appdomainunloaded_exception (klass)
5117 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5118 mono_unhandled_exception (exc);
5119 if (mono_environment_exitcode_get () == 1) {
5120 mono_environment_exitcode_set (255);
5121 mono_invoke_unhandled_exception_hook (exc);
5122 g_assert_not_reached ();
5128 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5131 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5132 mono_error_set_pending_exception (&error);
5136 * mono_threads_attach_coop: called by native->managed wrappers
5139 * - blocking mode: contains gc unsafe transition cookie
5140 * - non-blocking mode: contains random data
5141 * - @return: the original domain which needs to be restored, or NULL.
5144 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5147 MonoThreadInfo *info;
5150 orig = mono_domain_get ();
5153 /* Happens when called from AOTed code which is only used in the root domain. */
5154 domain = mono_get_root_domain ();
5158 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5159 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5160 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5161 * we're only responsible for making the cookie. */
5162 if (mono_threads_is_blocking_transition_enabled ())
5163 external = !(info = mono_thread_info_current_unchecked ()) || !mono_thread_info_is_live (info);
5165 if (!mono_thread_internal_current ()) {
5166 mono_thread_attach_full (domain, FALSE);
5169 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5173 mono_domain_set (domain, TRUE);
5175 if (mono_threads_is_blocking_transition_enabled ()) {
5177 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5178 * return the right cookie. */
5179 *dummy = mono_threads_enter_gc_unsafe_region_cookie ();
5181 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5182 *dummy = mono_threads_enter_gc_unsafe_region (dummy);
5190 * mono_threads_detach_coop: called by native->managed wrappers
5192 * - @cookie: the original domain which needs to be restored, or NULL.
5194 * - blocking mode: contains gc unsafe transition cookie
5195 * - non-blocking mode: contains random data
5198 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5200 MonoDomain *domain, *orig;
5202 orig = (MonoDomain*) cookie;
5204 domain = mono_domain_get ();
5207 if (mono_threads_is_blocking_transition_enabled ()) {
5208 /* it won't do anything if cookie is NULL
5209 * thread state RUNNING -> (RUNNING|BLOCKING) */
5210 mono_threads_exit_gc_unsafe_region (*dummy, dummy);
5213 if (orig != domain) {
5215 mono_domain_unset ();
5217 mono_domain_set (orig, TRUE);
5222 /* Returns TRUE if the current thread is ready to be interrupted. */
5224 mono_threads_is_ready_to_be_interrupted (void)
5226 MonoInternalThread *thread;
5228 thread = mono_thread_internal_current ();
5229 LOCK_THREAD (thread);
5230 if (thread->state & (ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5231 UNLOCK_THREAD (thread);
5235 if (mono_thread_get_abort_prot_block_count (thread) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5236 UNLOCK_THREAD (thread);
5240 UNLOCK_THREAD (thread);
5246 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5248 g_string_append_printf (text, ", thread handle : %p", internal->handle);
5250 if (internal->thread_info) {
5251 g_string_append (text, ", state : ");
5252 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5255 if (internal->owned_mutexes) {
5258 g_string_append (text, ", owns : [");
5259 for (i = 0; i < internal->owned_mutexes->len; i++)
5260 g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5261 g_string_append (text, "]");
5266 mono_thread_internal_is_current (MonoInternalThread *internal)
5268 g_assert (internal);
5269 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));