2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/threads.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internals.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/mono-threads-coop.h>
41 #include <mono/utils/hazard-pointer.h>
42 #include <mono/utils/mono-tls.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/mono-threads-coop.h>
46 #include <mono/utils/mono-error-internals.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/reflection-internals.h>
55 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
56 #define USE_TKILL_ON_ANDROID 1
59 #ifdef PLATFORM_ANDROID
62 #ifdef USE_TKILL_ON_ANDROID
63 extern int tkill (pid_t tid, int signal);
67 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
68 #define THREAD_DEBUG(a)
69 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
70 #define THREAD_WAIT_DEBUG(a)
71 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
72 #define LIBGC_DEBUG(a)
74 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
75 #define SPIN_LOCK(i) do { \
76 if (SPIN_TRYLOCK (i)) \
80 #define SPIN_UNLOCK(i) i = 0
82 #define LOCK_THREAD(thread) lock_thread((thread))
83 #define UNLOCK_THREAD(thread) unlock_thread((thread))
87 guint32 (*func)(void *);
103 typedef struct _StaticDataFreeList StaticDataFreeList;
104 struct _StaticDataFreeList {
105 StaticDataFreeList *next;
113 StaticDataFreeList *freelist;
116 /* Number of cached culture objects in the MonoThread->cached_culture_info array
117 * (per-type): we use the first NUM entries for CultureInfo and the last for
118 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
120 #define NUM_CACHED_CULTURES 4
121 #define CULTURES_START_IDX 0
122 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
124 /* Controls access to the 'threads' hash table */
125 static void mono_threads_lock (void);
126 static void mono_threads_unlock (void);
127 static MonoCoopMutex threads_mutex;
129 /* Controls access to the 'joinable_threads' hash table */
130 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
131 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
132 static mono_mutex_t joinable_threads_mutex;
134 /* Holds current status of static data heap */
135 static StaticDataInfo thread_static_info;
136 static StaticDataInfo context_static_info;
138 /* The hash of existing threads (key is thread ID, value is
139 * MonoInternalThread*) that need joining before exit
141 static MonoGHashTable *threads=NULL;
143 /* List of app context GC handles.
144 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
146 static GHashTable *contexts = NULL;
148 /* Cleanup queue for contexts. */
149 static MonoReferenceQueue *context_queue;
152 * Threads which are starting up and they are not in the 'threads' hash yet.
153 * When handle_store is called for a thread, it will be removed from this hash table.
154 * Protected by mono_threads_lock ().
156 static MonoGHashTable *threads_starting_up = NULL;
158 /* The TLS key that holds the MonoObject assigned to each thread */
159 static MonoNativeTlsKey current_object_key;
162 /* Protected by the threads lock */
163 static GHashTable *joinable_threads;
164 static int joinable_thread_count;
166 #ifdef MONO_HAVE_FAST_TLS
167 /* we need to use both the Tls* functions and __thread because
168 * the gc needs to see all the threads
170 MONO_FAST_TLS_DECLARE(tls_current_object);
171 #define SET_CURRENT_OBJECT(x) do { \
172 MONO_FAST_TLS_SET (tls_current_object, x); \
173 mono_native_tls_set_value (current_object_key, x); \
175 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
177 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
178 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
181 /* function called at thread start */
182 static MonoThreadStartCB mono_thread_start_cb = NULL;
184 /* function called at thread attach */
185 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
187 /* function called at thread cleanup */
188 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
190 /* The default stack size for each thread */
191 static guint32 default_stacksize = 0;
192 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
194 static void thread_adjust_static_data (MonoInternalThread *thread);
195 static void context_adjust_static_data (MonoAppContext *ctx);
196 static void mono_free_static_data (gpointer* static_data);
197 static void mono_init_static_data_info (StaticDataInfo *static_data);
198 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
199 static gboolean mono_thread_resume (MonoInternalThread* thread);
200 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
201 static void self_abort_internal (MonoError *error);
202 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
203 static void self_suspend_internal (void);
205 static MonoException* mono_thread_execute_interruption (void);
206 static void ref_stack_destroy (gpointer rs);
208 /* Spin lock for InterlockedXXX 64 bit functions */
209 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
210 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
211 static mono_mutex_t interlocked_mutex;
213 /* global count of thread interruptions requested */
214 static gint32 thread_interruption_requested = 0;
216 /* Event signaled when a thread changes its background mode */
217 static HANDLE background_change_event;
219 static gboolean shutting_down = FALSE;
221 static gint32 managed_thread_id_counter = 0;
223 /* Class lazy loading functions */
224 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
227 mono_threads_lock (void)
229 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
233 mono_threads_unlock (void)
235 mono_locks_coop_release (&threads_mutex, ThreadsLock);
240 get_next_managed_thread_id (void)
242 return InterlockedIncrement (&managed_thread_id_counter);
246 mono_thread_get_tls_key (void)
248 return current_object_key;
252 mono_thread_get_tls_offset (void)
257 if (current_object_key)
258 offset = current_object_key;
260 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
265 static inline MonoNativeThreadId
266 thread_get_tid (MonoInternalThread *thread)
268 /* We store the tid as a guint64 to keep the object layout constant between platforms */
269 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
272 /* handle_store() and handle_remove() manage the array of threads that
273 * still need to be waited for when the main thread exits.
275 * If handle_store() returns FALSE the thread must not be started
276 * because Mono is shutting down.
278 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
280 mono_threads_lock ();
282 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
284 if (threads_starting_up)
285 mono_g_hash_table_remove (threads_starting_up, thread);
287 if (shutting_down && !force_attach) {
288 mono_threads_unlock ();
293 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
294 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
297 /* We don't need to duplicate thread->handle, because it is
298 * only closed when the thread object is finalized by the GC.
300 g_assert (thread->internal_thread);
301 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
302 thread->internal_thread);
304 mono_threads_unlock ();
309 static gboolean handle_remove(MonoInternalThread *thread)
312 gsize tid = thread->tid;
314 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
316 mono_threads_lock ();
319 /* We have to check whether the thread object for the
320 * tid is still the same in the table because the
321 * thread might have been destroyed and the tid reused
322 * in the meantime, in which case the tid would be in
323 * the table, but with another thread object.
325 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
326 mono_g_hash_table_remove (threads, (gpointer)tid);
335 mono_threads_unlock ();
337 /* Don't close the handle here, wait for the object finalizer
338 * to do it. Otherwise, the following race condition applies:
340 * 1) Thread exits (and handle_remove() closes the handle)
342 * 2) Some other handle is reassigned the same slot
344 * 3) Another thread tries to join the first thread, and
345 * blocks waiting for the reassigned handle to be signalled
346 * (which might never happen). This is possible, because the
347 * thread calling Join() still has a reference to the first
353 static void ensure_synch_cs_set (MonoInternalThread *thread)
355 MonoCoopMutex *synch_cs;
357 if (thread->synch_cs != NULL) {
361 synch_cs = g_new0 (MonoCoopMutex, 1);
362 mono_coop_mutex_init_recursive (synch_cs);
364 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
365 synch_cs, NULL) != NULL) {
366 /* Another thread must have installed this CS */
367 mono_coop_mutex_destroy (synch_cs);
373 lock_thread (MonoInternalThread *thread)
375 if (!thread->synch_cs)
376 ensure_synch_cs_set (thread);
378 g_assert (thread->synch_cs);
380 mono_coop_mutex_lock (thread->synch_cs);
384 unlock_thread (MonoInternalThread *thread)
386 mono_coop_mutex_unlock (thread->synch_cs);
390 * NOTE: this function can be called also for threads different from the current one:
391 * make sure no code called from it will ever assume it is run on the thread that is
392 * getting cleaned up.
394 static void thread_cleanup (MonoInternalThread *thread)
396 g_assert (thread != NULL);
398 if (thread->abort_state_handle) {
399 mono_gchandle_free (thread->abort_state_handle);
400 thread->abort_state_handle = 0;
402 thread->abort_exc = NULL;
403 thread->current_appcontext = NULL;
406 * This is necessary because otherwise we might have
407 * cross-domain references which will not get cleaned up when
408 * the target domain is unloaded.
410 if (thread->cached_culture_info) {
412 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
413 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
417 * thread->synch_cs can be NULL if this was called after
418 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
419 * This can happen only during shutdown.
420 * The shutting_down flag is not always set, so we can't assert on it.
422 if (thread->synch_cs)
423 LOCK_THREAD (thread);
425 thread->state |= ThreadState_Stopped;
426 thread->state &= ~ThreadState_Background;
428 if (thread->synch_cs)
429 UNLOCK_THREAD (thread);
432 An interruption request has leaked to cleanup. Adjust the global counter.
434 This can happen is the abort source thread finds the abortee (this) thread
435 in unmanaged code. If this thread never trips back to managed code or check
436 the local flag it will be left set and positively unbalance the global counter.
438 Leaving the counter unbalanced will cause a performance degradation since all threads
439 will now keep checking their local flags all the time.
441 if (InterlockedExchange (&thread->interruption_requested, 0))
442 InterlockedDecrement (&thread_interruption_requested);
444 /* if the thread is not in the hash it has been removed already */
445 if (!handle_remove (thread)) {
446 if (thread == mono_thread_internal_current ()) {
447 mono_domain_unset ();
448 mono_memory_barrier ();
450 /* This needs to be called even if handle_remove () fails */
451 if (mono_thread_cleanup_fn)
452 mono_thread_cleanup_fn (thread_get_tid (thread));
455 mono_release_type_locks (thread);
457 /* Can happen when we attach the profiler helper thread in order to heapshot. */
458 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
459 mono_profiler_thread_end (thread->tid);
461 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
463 if (thread == mono_thread_internal_current ()) {
465 * This will signal async signal handlers that the thread has exited.
466 * The profiler callback needs this to be set, so it cannot be done earlier.
468 mono_domain_unset ();
469 mono_memory_barrier ();
472 if (thread == mono_thread_internal_current ())
473 mono_thread_pop_appdomain_ref ();
475 thread->cached_culture_info = NULL;
477 mono_free_static_data (thread->static_data);
478 thread->static_data = NULL;
479 ref_stack_destroy (thread->appdomain_refs);
480 thread->appdomain_refs = NULL;
482 if (mono_thread_cleanup_fn)
483 mono_thread_cleanup_fn (thread_get_tid (thread));
485 if (mono_gc_is_moving ()) {
486 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
487 thread->thread_pinning_ref = NULL;
493 * A special static data offset (guint32) consists of 3 parts:
495 * [0] 6-bit index into the array of chunks.
496 * [6] 25-bit offset into the array.
497 * [31] Bit indicating thread or context static.
502 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
513 } SpecialStaticOffset;
515 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
516 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
518 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
519 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
520 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
521 (((SpecialStaticOffset *) &(x))->fields.f)
524 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
526 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
528 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
529 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
531 return ((char *) thread->static_data [idx]) + off;
535 get_context_static_data (MonoAppContext *ctx, guint32 offset)
537 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
539 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
540 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
542 return ((char *) ctx->static_data [idx]) + off;
546 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
548 static MonoClassField *current_thread_field = NULL;
552 if (!current_thread_field) {
553 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
554 g_assert (current_thread_field);
557 mono_class_vtable (domain, mono_defaults.thread_class);
558 mono_domain_lock (domain);
559 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
560 mono_domain_unlock (domain);
563 return (MonoThread **)get_thread_static_data (thread, offset);
567 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
569 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
571 g_assert (current->obj.vtable->domain == domain);
573 g_assert (!*current_thread_ptr);
574 *current_thread_ptr = current;
578 create_thread_object (MonoDomain *domain)
581 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
582 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, &error);
583 /* only possible failure mode is OOM, from which we don't expect to recover. */
584 mono_error_assert_ok (&error);
589 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
593 thread = create_thread_object (domain);
594 thread->priority = THREAD_PRIORITY_NORMAL;
596 MONO_OBJECT_SETREF (thread, internal_thread, internal);
601 static MonoInternalThread*
602 create_internal_thread (void)
605 MonoInternalThread *thread;
608 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
609 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
610 /* only possible failure mode is OOM, from which we don't exect to recover */
611 mono_error_assert_ok (&error);
613 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
614 mono_coop_mutex_init_recursive (thread->synch_cs);
616 thread->apartment_state = ThreadApartmentState_Unknown;
617 thread->managed_id = get_next_managed_thread_id ();
618 if (mono_gc_is_moving ()) {
619 thread->thread_pinning_ref = thread;
620 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
627 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
629 MonoDomain *domain = mono_get_root_domain ();
631 if (!candidate || candidate->obj.vtable->domain != domain) {
632 candidate = new_thread_with_internal (domain, thread);
634 set_current_thread_for_domain (domain, thread, candidate);
635 g_assert (!thread->root_domain_thread);
636 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
640 static guint32 WINAPI start_wrapper_internal(void *data)
643 MonoThreadInfo *info;
644 StartInfo *start_info = (StartInfo *)data;
645 guint32 (*start_func)(void *);
649 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
652 MonoInternalThread *internal = start_info->obj->internal_thread;
653 MonoObject *start_delegate = start_info->delegate;
654 MonoDomain *domain = start_info->obj->obj.vtable->domain;
656 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
658 /* We can be sure start_info->obj->tid and
659 * start_info->obj->handle have been set, because the thread
660 * was created suspended, and these values were set before the
664 info = mono_thread_info_current ();
666 internal->thread_info = info;
667 internal->small_id = info->small_id;
671 SET_CURRENT_OBJECT (internal);
673 /* Every thread references the appdomain which created it */
674 mono_thread_push_appdomain_ref (domain);
676 if (!mono_domain_set (domain, FALSE)) {
677 /* No point in raising an appdomain_unloaded exception here */
678 /* FIXME: Cleanup here */
679 mono_thread_pop_appdomain_ref ();
683 start_func = start_info->func;
684 start_arg = start_info->obj->start_obj;
686 start_arg = start_info->start_arg;
688 /* We have to do this here because mono_thread_new_init()
689 requires that root_domain_thread is set up. */
690 thread_adjust_static_data (internal);
691 init_root_domain_thread (internal, start_info->obj);
693 /* This MUST be called before any managed code can be
694 * executed, as it calls the callback function that (for the
695 * jit) sets the lmf marker.
697 mono_thread_new_init (tid, &tid, start_func);
698 internal->stack_ptr = &tid;
699 if (domain != mono_get_root_domain ())
700 set_current_thread_for_domain (domain, internal, start_info->obj);
702 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
704 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
706 /* On 2.0 profile (and higher), set explicitly since state might have been
708 if (internal->apartment_state == ThreadApartmentState_Unknown)
709 internal->apartment_state = ThreadApartmentState_MTA;
711 mono_thread_init_apartment_state ();
713 if(internal->start_notify!=NULL) {
714 /* Let the thread that called Start() know we're
717 ReleaseSemaphore (internal->start_notify, 1, NULL);
721 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
725 * Call this after calling start_notify, since the profiler callback might want
726 * to lock the thread, and the lock is held by thread_start () which waits for
729 mono_profiler_thread_start (tid);
731 /* if the name was set before starting, we didn't invoke the profiler callback */
732 if (internal->name) {
733 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
734 mono_profiler_thread_name (internal->tid, tname);
735 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
739 /* start_func is set only for unmanaged start functions */
741 start_func (start_arg);
744 g_assert (start_delegate != NULL);
745 args [0] = start_arg;
746 /* we may want to handle the exception here. See comment below on unhandled exceptions */
747 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
749 if (!mono_error_ok (&error)) {
750 MonoException *ex = mono_error_convert_to_exception (&error);
752 mono_unhandled_exception (&ex->object);
753 mono_invoke_unhandled_exception_hook (&ex->object);
754 g_assert_not_reached ();
757 mono_error_cleanup (&error);
761 /* If the thread calls ExitThread at all, this remaining code
762 * will not be executed, but the main thread will eventually
763 * call thread_cleanup() on this thread's behalf.
766 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
768 /* Do any cleanup needed for apartment state. This
769 * cannot be done in thread_cleanup since thread_cleanup could be
770 * called for a thread other than the current thread.
771 * mono_thread_cleanup_apartment_state cleans up apartment
772 * for the current thead */
773 mono_thread_cleanup_apartment_state ();
775 thread_cleanup (internal);
779 /* Remove the reference to the thread object in the TLS data,
780 * so the thread object can be finalized. This won't be
781 * reached if the thread threw an uncaught exception, so those
782 * thread handles will stay referenced :-( (This is due to
783 * missing support for scanning thread-specific data in the
784 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
787 SET_CURRENT_OBJECT (NULL);
792 static guint32 WINAPI start_wrapper(void *data)
796 /* Avoid scanning the frames above this frame during a GC */
797 mono_gc_set_stack_end ((void*)&dummy);
799 return start_wrapper_internal (data);
805 * Common thread creation code.
806 * LOCKING: Acquires the threads lock.
809 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
812 HANDLE thread_handle;
813 MonoNativeThreadId tid;
817 * Join joinable threads to prevent running out of threads since the finalizer
818 * thread might be blocked/backlogged.
820 mono_threads_join_threads ();
822 mono_error_init (error);
824 mono_threads_lock ();
827 mono_threads_unlock ();
830 if (threads_starting_up == NULL) {
831 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
832 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
834 mono_g_hash_table_insert (threads_starting_up, thread, thread);
835 mono_threads_unlock ();
837 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
838 if (!internal->start_notify) {
839 mono_threads_lock ();
840 mono_g_hash_table_remove (threads_starting_up, thread);
841 mono_threads_unlock ();
842 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
848 stack_size = default_stacksize_for_thread (internal);
850 /* Create suspended, so we can do some housekeeping before the thread
853 tp.priority = thread->priority;
854 tp.stack_size = stack_size;
855 tp.creation_flags = CREATE_SUSPENDED;
857 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info, &tp, &tid);
859 if (thread_handle == NULL) {
860 /* The thread couldn't be created, so set an exception */
861 mono_threads_lock ();
862 mono_g_hash_table_remove (threads_starting_up, thread);
863 mono_threads_unlock ();
865 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
868 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
870 internal->handle = thread_handle;
871 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
873 internal->threadpool_thread = threadpool_thread;
874 if (threadpool_thread)
875 mono_thread_set_state (internal, ThreadState_Background);
877 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
879 /* Only store the handle when the thread is about to be
880 * launched, to avoid the main thread deadlocking while trying
881 * to clean up a thread that will never be signalled.
883 if (!handle_store (thread, FALSE))
886 mono_thread_info_resume (tid);
888 if (internal->start_notify) {
890 * Wait for the thread to set up its TLS data etc, so
891 * theres no potential race condition if someone tries
892 * to look up the data believing the thread has
895 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
898 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
901 CloseHandle (internal->start_notify);
902 internal->start_notify = NULL;
905 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));
910 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
912 if (mono_thread_start_cb) {
913 mono_thread_start_cb (tid, stack_start, func);
917 void mono_threads_set_default_stacksize (guint32 stacksize)
919 default_stacksize = stacksize;
922 guint32 mono_threads_get_default_stacksize (void)
924 return default_stacksize;
928 * mono_thread_create_internal:
930 * ARG should not be a GC reference.
933 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
936 MonoInternalThread *internal;
937 StartInfo *start_info;
940 mono_error_init (error);
942 thread = create_thread_object (domain);
944 internal = create_internal_thread ();
946 MONO_OBJECT_SETREF (thread, internal_thread, internal);
948 start_info = g_new0 (StartInfo, 1);
949 start_info->func = (guint32 (*)(void *))func;
950 start_info->obj = thread;
951 start_info->start_arg = arg;
953 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, error);
954 return_val_if_nok (error, NULL);
956 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
957 #ifndef MONO_CROSS_COMPILE
958 if (mono_check_corlib_version () == NULL)
959 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
966 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
969 if (!mono_thread_create_checked (domain, func, arg, &error))
970 mono_error_cleanup (&error);
974 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
976 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
980 mono_thread_attach (MonoDomain *domain)
982 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
988 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
990 MonoThreadInfo *info;
991 MonoInternalThread *thread;
992 MonoThread *current_thread;
993 HANDLE thread_handle;
994 MonoNativeThreadId tid;
996 if ((thread = mono_thread_internal_current ())) {
997 if (domain != mono_domain_get ())
998 mono_domain_set (domain, TRUE);
999 /* Already attached */
1000 return mono_thread_current ();
1003 if (!mono_gc_register_thread (&domain)) {
1004 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", mono_native_thread_id_get ());
1007 thread = create_internal_thread ();
1009 thread_handle = mono_thread_info_open_handle ();
1010 g_assert (thread_handle);
1012 tid=mono_native_thread_id_get ();
1014 thread->handle = thread_handle;
1015 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
1016 thread->stack_ptr = &tid;
1018 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
1020 info = mono_thread_info_current ();
1022 thread->thread_info = info;
1023 thread->small_id = info->small_id;
1025 current_thread = new_thread_with_internal (domain, thread);
1027 if (!handle_store (current_thread, force_attach)) {
1028 /* Mono is shutting down, so just wait for the end */
1030 mono_thread_info_sleep (10000, NULL);
1033 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
1035 SET_CURRENT_OBJECT (thread);
1036 mono_domain_set (domain, TRUE);
1038 thread_adjust_static_data (thread);
1040 init_root_domain_thread (thread, current_thread);
1042 if (domain != mono_get_root_domain ())
1043 set_current_thread_for_domain (domain, thread, current_thread);
1046 if (mono_thread_attach_cb) {
1050 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1053 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1055 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1058 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1059 if (!info->tools_thread)
1060 // FIXME: Need a separate callback
1061 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1063 return current_thread;
1067 mono_thread_detach_internal (MonoInternalThread *thread)
1069 g_return_if_fail (thread != NULL);
1071 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1073 thread_cleanup (thread);
1075 SET_CURRENT_OBJECT (NULL);
1076 mono_domain_unset ();
1078 /* Don't need to CloseHandle this thread, even though we took a
1079 * reference in mono_thread_attach (), because the GC will do it
1080 * when the Thread object is finalised.
1085 mono_thread_detach (MonoThread *thread)
1088 mono_thread_detach_internal (thread->internal_thread);
1092 * mono_thread_detach_if_exiting:
1094 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1095 * This should be used at the end of embedding code which calls into managed code, and which
1096 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1099 mono_thread_detach_if_exiting (void)
1101 if (mono_thread_info_is_exiting ()) {
1102 MonoInternalThread *thread;
1104 thread = mono_thread_internal_current ();
1106 mono_thread_detach_internal (thread);
1107 mono_thread_info_detach ();
1117 MonoInternalThread *thread = mono_thread_internal_current ();
1119 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1121 thread_cleanup (thread);
1122 SET_CURRENT_OBJECT (NULL);
1123 mono_domain_unset ();
1125 /* we could add a callback here for embedders to use. */
1126 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1127 exit (mono_environment_exitcode_get ());
1128 mono_thread_info_exit ();
1132 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1134 MonoInternalThread *internal;
1136 internal = create_internal_thread ();
1138 internal->state = ThreadState_Unstarted;
1140 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1144 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1148 StartInfo *start_info;
1149 MonoInternalThread *internal;
1152 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1154 if (!this_obj->internal_thread)
1155 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1156 internal = this_obj->internal_thread;
1158 LOCK_THREAD (internal);
1160 if ((internal->state & ThreadState_Unstarted) == 0) {
1161 UNLOCK_THREAD (internal);
1162 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1166 if ((internal->state & ThreadState_Aborted) != 0) {
1167 UNLOCK_THREAD (internal);
1170 /* This is freed in start_wrapper */
1171 start_info = g_new0 (StartInfo, 1);
1172 start_info->func = NULL;
1173 start_info->start_arg = NULL;
1174 start_info->delegate = start;
1175 start_info->obj = this_obj;
1176 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1178 res = create_thread (this_obj, internal, start_info, FALSE, 0, &error);
1180 mono_error_cleanup (&error);
1181 UNLOCK_THREAD (internal);
1185 internal->state &= ~ThreadState_Unstarted;
1187 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1189 UNLOCK_THREAD (internal);
1190 return internal->handle;
1194 * This is called from the finalizer of the internal thread object.
1197 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1199 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1202 * Since threads keep a reference to their thread object while running, by the time this function is called,
1203 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1204 * when thread_cleanup () can be called after this.
1207 CloseHandle (thread);
1209 if (this_obj->synch_cs) {
1210 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1211 this_obj->synch_cs = NULL;
1212 mono_coop_mutex_destroy (synch_cs);
1216 if (this_obj->name) {
1217 void *name = this_obj->name;
1218 this_obj->name = NULL;
1224 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1227 MonoInternalThread *thread = mono_thread_internal_current ();
1229 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1231 if (mono_thread_current_check_pending_interrupt ())
1235 gboolean alerted = FALSE;
1237 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1239 res = mono_thread_info_sleep (ms, &alerted);
1241 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1244 MonoException* exc = mono_thread_execute_interruption ();
1246 mono_raise_exception (exc);
1258 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1263 ves_icall_System_Threading_Thread_GetDomainID (void)
1265 return mono_domain_get()->domain_id;
1269 ves_icall_System_Threading_Thread_Yield (void)
1271 return mono_thread_info_yield ();
1275 * mono_thread_get_name:
1277 * Return the name of the thread. NAME_LEN is set to the length of the name.
1278 * Return NULL if the thread has no name. The returned memory is owned by the
1282 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1286 LOCK_THREAD (this_obj);
1288 if (!this_obj->name) {
1292 *name_len = this_obj->name_len;
1293 res = g_new (gunichar2, this_obj->name_len);
1294 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1297 UNLOCK_THREAD (this_obj);
1303 * mono_thread_get_name_utf8:
1305 * Return the name of the thread in UTF-8.
1306 * Return NULL if the thread has no name.
1307 * The returned memory is owned by the caller.
1310 mono_thread_get_name_utf8 (MonoThread *thread)
1315 MonoInternalThread *internal = thread->internal_thread;
1316 if (internal == NULL)
1319 LOCK_THREAD (internal);
1321 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1323 UNLOCK_THREAD (internal);
1329 * mono_thread_get_managed_id:
1331 * Return the Thread.ManagedThreadId value of `thread`.
1332 * Returns -1 if `thread` is NULL.
1335 mono_thread_get_managed_id (MonoThread *thread)
1340 MonoInternalThread *internal = thread->internal_thread;
1341 if (internal == NULL)
1344 int32_t id = internal->managed_id;
1350 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1355 mono_error_init (&error);
1357 LOCK_THREAD (this_obj);
1359 if (!this_obj->name)
1362 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1364 UNLOCK_THREAD (this_obj);
1366 if (mono_error_set_pending_exception (&error))
1373 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1375 LOCK_THREAD (this_obj);
1377 mono_error_init (error);
1379 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1380 UNLOCK_THREAD (this_obj);
1382 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1385 if (this_obj->name) {
1386 g_free (this_obj->name);
1387 this_obj->name_len = 0;
1390 this_obj->name = g_new (gunichar2, mono_string_length (name));
1391 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1392 this_obj->name_len = mono_string_length (name);
1395 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1398 this_obj->name = NULL;
1401 UNLOCK_THREAD (this_obj);
1403 if (this_obj->name && this_obj->tid) {
1404 char *tname = mono_string_to_utf8_checked (name, error);
1405 return_if_nok (error);
1406 mono_profiler_thread_name (this_obj->tid, tname);
1407 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1413 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1416 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1417 mono_error_set_pending_exception (&error);
1421 * ves_icall_System_Threading_Thread_GetPriority_internal:
1422 * @param this_obj: The MonoInternalThread on which to operate.
1424 * Gets the priority of the given thread.
1425 * @return: The priority of the given thread.
1428 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1431 MonoInternalThread *internal = this_obj->internal_thread;
1433 LOCK_THREAD (internal);
1434 if (internal->handle != NULL)
1435 priority = GetThreadPriority (internal->handle) + 2;
1437 priority = this_obj->priority + 2;
1438 UNLOCK_THREAD (internal);
1443 * ves_icall_System_Threading_Thread_SetPriority_internal:
1444 * @param this_obj: The MonoInternalThread on which to operate.
1445 * @param priority: The priority to set.
1447 * Sets the priority of the given thread.
1450 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1452 MonoInternalThread *internal = this_obj->internal_thread;
1454 LOCK_THREAD (internal);
1455 this_obj->priority = priority - 2;
1456 if (internal->handle != NULL)
1457 SetThreadPriority (internal->handle, this_obj->priority);
1458 UNLOCK_THREAD (internal);
1461 /* If the array is already in the requested domain, we just return it,
1462 otherwise we return a copy in that domain. */
1464 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1468 mono_error_init (error);
1472 if (mono_object_domain (arr) == domain)
1475 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1476 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1481 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1484 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1485 mono_error_set_pending_exception (&error);
1490 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1493 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1494 mono_error_set_pending_exception (&error);
1499 mono_thread_current (void)
1501 MonoDomain *domain = mono_domain_get ();
1502 MonoInternalThread *internal = mono_thread_internal_current ();
1503 MonoThread **current_thread_ptr;
1505 g_assert (internal);
1506 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1508 if (!*current_thread_ptr) {
1509 g_assert (domain != mono_get_root_domain ());
1510 *current_thread_ptr = new_thread_with_internal (domain, internal);
1512 return *current_thread_ptr;
1515 /* Return the thread object belonging to INTERNAL in the current domain */
1517 mono_thread_current_for_thread (MonoInternalThread *internal)
1519 MonoDomain *domain = mono_domain_get ();
1520 MonoThread **current_thread_ptr;
1522 g_assert (internal);
1523 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1525 if (!*current_thread_ptr) {
1526 g_assert (domain != mono_get_root_domain ());
1527 *current_thread_ptr = new_thread_with_internal (domain, internal);
1529 return *current_thread_ptr;
1533 mono_thread_internal_current (void)
1535 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1536 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1541 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1543 MonoInternalThread *thread = this_obj->internal_thread;
1544 HANDLE handle = thread->handle;
1545 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1548 if (mono_thread_current_check_pending_interrupt ())
1551 LOCK_THREAD (thread);
1553 if ((thread->state & ThreadState_Unstarted) != 0) {
1554 UNLOCK_THREAD (thread);
1556 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1560 UNLOCK_THREAD (thread);
1565 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1567 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1570 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1573 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1575 if(ret==WAIT_OBJECT_0) {
1576 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1581 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1586 #define MANAGED_WAIT_FAILED 0x7fffffff
1589 map_native_wait_result_to_managed (gint32 val)
1591 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1592 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1596 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1604 mono_error_init (error);
1606 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1609 if (numhandles != 1)
1610 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1612 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1615 if (ret != WAIT_IO_COMPLETION)
1618 exc = mono_thread_execute_interruption ();
1620 mono_error_set_exception_instance (error, exc);
1627 /* Re-calculate ms according to the time passed */
1628 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1629 if (diff_ms >= ms) {
1633 wait = ms - diff_ms;
1639 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1646 MonoObject *waitHandle;
1647 MonoInternalThread *thread = mono_thread_internal_current ();
1649 /* Do this WaitSleepJoin check before creating objects */
1650 if (mono_thread_current_check_pending_interrupt ())
1651 return map_native_wait_result_to_managed (WAIT_FAILED);
1653 /* We fail in managed if the array has more than 64 elements */
1654 numhandles = (guint32)mono_array_length(mono_handles);
1655 handles = g_new0(HANDLE, numhandles);
1657 for(i = 0; i < numhandles; i++) {
1658 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1659 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1666 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1668 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1670 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1674 mono_error_set_pending_exception (&error);
1676 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1677 return map_native_wait_result_to_managed (ret);
1680 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1683 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1684 uintptr_t numhandles;
1687 MonoObject *waitHandle;
1688 MonoInternalThread *thread = mono_thread_internal_current ();
1690 /* Do this WaitSleepJoin check before creating objects */
1691 if (mono_thread_current_check_pending_interrupt ())
1692 return map_native_wait_result_to_managed (WAIT_FAILED);
1694 numhandles = mono_array_length(mono_handles);
1695 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1696 return map_native_wait_result_to_managed (WAIT_FAILED);
1698 for(i = 0; i < numhandles; i++) {
1699 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1700 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1707 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1709 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1711 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1713 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1715 mono_error_set_pending_exception (&error);
1717 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1719 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1720 return map_native_wait_result_to_managed (ret - WAIT_OBJECT_0);
1722 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1723 return map_native_wait_result_to_managed (ret - WAIT_ABANDONED_0);
1726 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1727 return map_native_wait_result_to_managed (ret);
1731 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1735 MonoInternalThread *thread = mono_thread_internal_current ();
1737 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1743 if (mono_thread_current_check_pending_interrupt ())
1744 return map_native_wait_result_to_managed (WAIT_FAILED);
1746 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1748 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1750 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1752 mono_error_set_pending_exception (&error);
1753 return map_native_wait_result_to_managed (ret);
1757 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1760 MonoInternalThread *thread = mono_thread_internal_current ();
1765 if (mono_thread_current_check_pending_interrupt ())
1766 return map_native_wait_result_to_managed (WAIT_FAILED);
1768 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1771 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1774 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1776 return map_native_wait_result_to_managed (ret);
1779 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1786 mutex = CreateMutex (NULL, owned, NULL);
1788 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1790 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1798 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1799 return(ReleaseMutex (handle));
1802 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1808 *error = ERROR_SUCCESS;
1810 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1812 *error = GetLastError ();
1819 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, gint32 *error)
1824 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1826 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1827 mono_string_chars (name));
1830 *error = GetLastError ();
1834 MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, gint32 *prevcount)
1836 return ReleaseSemaphore (handle, releaseCount, prevcount);
1839 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1843 sem = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1844 *error = GetLastError ();
1849 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1856 event = CreateEvent (NULL, manual, initial, NULL);
1858 event = CreateEvent (NULL, manual, initial,
1859 mono_string_chars (name));
1861 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1869 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1870 return (SetEvent(handle));
1873 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1874 return (ResetEvent(handle));
1878 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1879 CloseHandle (handle);
1882 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1888 *error = ERROR_SUCCESS;
1890 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1892 *error = GetLastError ();
1898 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1900 return InterlockedIncrement (location);
1903 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1905 #if SIZEOF_VOID_P == 4
1906 if (G_UNLIKELY ((size_t)location & 0x7)) {
1908 mono_interlocked_lock ();
1911 mono_interlocked_unlock ();
1915 return InterlockedIncrement64 (location);
1918 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1920 return InterlockedDecrement(location);
1923 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1925 #if SIZEOF_VOID_P == 4
1926 if (G_UNLIKELY ((size_t)location & 0x7)) {
1928 mono_interlocked_lock ();
1931 mono_interlocked_unlock ();
1935 return InterlockedDecrement64 (location);
1938 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1940 return InterlockedExchange(location, value);
1943 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1946 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1947 mono_gc_wbarrier_generic_nostore (location);
1951 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1953 return InterlockedExchangePointer(location, value);
1956 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1958 IntFloatUnion val, ret;
1961 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1967 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1969 #if SIZEOF_VOID_P == 4
1970 if (G_UNLIKELY ((size_t)location & 0x7)) {
1972 mono_interlocked_lock ();
1975 mono_interlocked_unlock ();
1979 return InterlockedExchange64 (location, value);
1983 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1985 LongDoubleUnion val, ret;
1988 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1993 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1995 return InterlockedCompareExchange(location, value, comparand);
1998 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
2000 gint32 r = InterlockedCompareExchange(location, value, comparand);
2001 *success = r == comparand;
2005 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
2008 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
2009 mono_gc_wbarrier_generic_nostore (location);
2013 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
2015 return InterlockedCompareExchangePointer(location, value, comparand);
2018 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2020 IntFloatUnion val, ret, cmp;
2023 cmp.fval = comparand;
2024 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2030 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2032 #if SIZEOF_VOID_P == 8
2033 LongDoubleUnion val, comp, ret;
2036 comp.fval = comparand;
2037 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2043 mono_interlocked_lock ();
2045 if (old == comparand)
2047 mono_interlocked_unlock ();
2054 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2056 #if SIZEOF_VOID_P == 4
2057 if (G_UNLIKELY ((size_t)location & 0x7)) {
2059 mono_interlocked_lock ();
2061 if (old == comparand)
2063 mono_interlocked_unlock ();
2067 return InterlockedCompareExchange64 (location, value, comparand);
2071 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2074 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2075 mono_gc_wbarrier_generic_nostore (location);
2080 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2083 MONO_CHECK_NULL (location, NULL);
2084 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2085 mono_gc_wbarrier_generic_nostore (location);
2090 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2092 return InterlockedAdd (location, value);
2096 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2098 #if SIZEOF_VOID_P == 4
2099 if (G_UNLIKELY ((size_t)location & 0x7)) {
2101 mono_interlocked_lock ();
2104 mono_interlocked_unlock ();
2108 return InterlockedAdd64 (location, value);
2112 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2114 #if SIZEOF_VOID_P == 4
2115 if (G_UNLIKELY ((size_t)location & 0x7)) {
2117 mono_interlocked_lock ();
2119 mono_interlocked_unlock ();
2123 return InterlockedRead64 (location);
2127 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2129 mono_memory_barrier ();
2133 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2135 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2137 if (state & ThreadState_Background) {
2138 /* If the thread changes the background mode, the main thread has to
2139 * be notified, since it has to rebuild the list of threads to
2142 SetEvent (background_change_event);
2147 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2149 mono_thread_set_state (this_obj, (MonoThreadState)state);
2151 if (state & ThreadState_Background) {
2152 /* If the thread changes the background mode, the main thread has to
2153 * be notified, since it has to rebuild the list of threads to
2156 SetEvent (background_change_event);
2161 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2165 LOCK_THREAD (this_obj);
2167 state = this_obj->state;
2169 UNLOCK_THREAD (this_obj);
2174 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2176 MonoInternalThread *current;
2178 MonoInternalThread *thread = this_obj->internal_thread;
2180 LOCK_THREAD (thread);
2182 current = mono_thread_internal_current ();
2184 thread->thread_interrupt_requested = TRUE;
2185 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2187 UNLOCK_THREAD (thread);
2190 async_abort_internal (thread, FALSE);
2195 * mono_thread_current_check_pending_interrupt:
2197 * Checks if there's a interruption request and set the pending exception if so.
2199 * @returns true if a pending exception was set
2202 mono_thread_current_check_pending_interrupt (void)
2204 MonoInternalThread *thread = mono_thread_internal_current ();
2205 gboolean throw_ = FALSE;
2207 LOCK_THREAD (thread);
2209 if (thread->thread_interrupt_requested) {
2211 thread->thread_interrupt_requested = FALSE;
2214 UNLOCK_THREAD (thread);
2217 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2222 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2224 LOCK_THREAD (thread);
2226 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2227 (thread->state & ThreadState_StopRequested) != 0 ||
2228 (thread->state & ThreadState_Stopped) != 0)
2230 UNLOCK_THREAD (thread);
2234 if ((thread->state & ThreadState_Unstarted) != 0) {
2235 thread->state |= ThreadState_Aborted;
2236 UNLOCK_THREAD (thread);
2240 thread->state |= ThreadState_AbortRequested;
2241 if (thread->abort_state_handle)
2242 mono_gchandle_free (thread->abort_state_handle);
2244 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2245 g_assert (thread->abort_state_handle);
2247 thread->abort_state_handle = 0;
2249 thread->abort_exc = NULL;
2251 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));
2253 /* During shutdown, we can't wait for other threads */
2255 /* Make sure the thread is awake */
2256 mono_thread_resume (thread);
2258 UNLOCK_THREAD (thread);
2263 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2265 if (!request_thread_abort (thread, state))
2268 if (thread == mono_thread_internal_current ()) {
2270 self_abort_internal (&error);
2271 mono_error_set_pending_exception (&error);
2273 async_abort_internal (thread, TRUE);
2278 * mono_thread_internal_abort:
2280 * Request thread @thread to be aborted.
2282 * @thread MUST NOT be the current thread.
2285 mono_thread_internal_abort (MonoInternalThread *thread)
2287 g_assert (thread != mono_thread_internal_current ());
2289 if (!request_thread_abort (thread, NULL))
2291 async_abort_internal (thread, TRUE);
2295 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2297 MonoInternalThread *thread = mono_thread_internal_current ();
2298 gboolean was_aborting;
2300 LOCK_THREAD (thread);
2301 was_aborting = thread->state & ThreadState_AbortRequested;
2302 thread->state &= ~ThreadState_AbortRequested;
2303 UNLOCK_THREAD (thread);
2305 if (!was_aborting) {
2306 const char *msg = "Unable to reset abort because no abort was requested";
2307 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2310 thread->abort_exc = NULL;
2311 if (thread->abort_state_handle) {
2312 mono_gchandle_free (thread->abort_state_handle);
2313 /* This is actually not necessary - the handle
2314 only counts if the exception is set */
2315 thread->abort_state_handle = 0;
2320 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2322 LOCK_THREAD (thread);
2324 thread->state &= ~ThreadState_AbortRequested;
2326 if (thread->abort_exc) {
2327 thread->abort_exc = NULL;
2328 if (thread->abort_state_handle) {
2329 mono_gchandle_free (thread->abort_state_handle);
2330 /* This is actually not necessary - the handle
2331 only counts if the exception is set */
2332 thread->abort_state_handle = 0;
2336 UNLOCK_THREAD (thread);
2340 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2343 MonoInternalThread *thread = this_obj->internal_thread;
2344 MonoObject *state, *deserialized = NULL;
2347 if (!thread->abort_state_handle)
2350 state = mono_gchandle_get_target (thread->abort_state_handle);
2353 domain = mono_domain_get ();
2354 if (mono_object_domain (state) == domain)
2357 deserialized = mono_object_xdomain_representation (state, domain, &error);
2359 if (!deserialized) {
2360 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2361 if (!is_ok (&error)) {
2362 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2363 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2365 mono_set_pending_exception (invalid_op_exc);
2369 return deserialized;
2373 mono_thread_suspend (MonoInternalThread *thread)
2375 LOCK_THREAD (thread);
2377 if ((thread->state & ThreadState_Unstarted) != 0 ||
2378 (thread->state & ThreadState_Aborted) != 0 ||
2379 (thread->state & ThreadState_Stopped) != 0)
2381 UNLOCK_THREAD (thread);
2385 if ((thread->state & ThreadState_Suspended) != 0 ||
2386 (thread->state & ThreadState_SuspendRequested) != 0 ||
2387 (thread->state & ThreadState_StopRequested) != 0)
2389 UNLOCK_THREAD (thread);
2393 thread->state |= ThreadState_SuspendRequested;
2395 if (thread == mono_thread_internal_current ()) {
2396 /* calls UNLOCK_THREAD (thread) */
2397 self_suspend_internal ();
2399 /* calls UNLOCK_THREAD (thread) */
2400 async_suspend_internal (thread, FALSE);
2407 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2409 if (!mono_thread_suspend (this_obj->internal_thread)) {
2410 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2415 /* LOCKING: LOCK_THREAD(thread) must be held */
2417 mono_thread_resume (MonoInternalThread *thread)
2419 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2420 thread->state &= ~ThreadState_SuspendRequested;
2424 if ((thread->state & ThreadState_Suspended) == 0 ||
2425 (thread->state & ThreadState_Unstarted) != 0 ||
2426 (thread->state & ThreadState_Aborted) != 0 ||
2427 (thread->state & ThreadState_Stopped) != 0)
2432 UNLOCK_THREAD (thread);
2434 /* Awake the thread */
2435 if (!mono_thread_info_resume (thread_get_tid (thread)))
2438 LOCK_THREAD (thread);
2440 thread->state &= ~ThreadState_Suspended;
2446 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2448 if (!thread->internal_thread) {
2449 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2451 LOCK_THREAD (thread->internal_thread);
2452 if (!mono_thread_resume (thread->internal_thread))
2453 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2454 UNLOCK_THREAD (thread->internal_thread);
2459 mono_threads_is_critical_method (MonoMethod *method)
2461 switch (method->wrapper_type) {
2462 case MONO_WRAPPER_RUNTIME_INVOKE:
2463 case MONO_WRAPPER_XDOMAIN_INVOKE:
2464 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2471 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2476 if (mono_threads_is_critical_method (m)) {
2477 *((gboolean*)data) = TRUE;
2484 is_running_protected_wrapper (void)
2486 gboolean found = FALSE;
2487 mono_stack_walk (find_wrapper, &found);
2492 request_thread_stop (MonoInternalThread *thread)
2494 LOCK_THREAD (thread);
2496 if ((thread->state & ThreadState_StopRequested) != 0 ||
2497 (thread->state & ThreadState_Stopped) != 0)
2499 UNLOCK_THREAD (thread);
2503 /* Make sure the thread is awake */
2504 mono_thread_resume (thread);
2506 thread->state |= ThreadState_StopRequested;
2507 thread->state &= ~ThreadState_AbortRequested;
2509 UNLOCK_THREAD (thread);
2514 * mono_thread_internal_stop:
2516 * Request thread @thread to stop.
2518 * @thread MUST NOT be the current thread.
2521 mono_thread_internal_stop (MonoInternalThread *thread)
2523 g_assert (thread != mono_thread_internal_current ());
2525 if (!request_thread_stop (thread))
2528 async_abort_internal (thread, TRUE);
2531 void mono_thread_stop (MonoThread *thread)
2533 MonoInternalThread *internal = thread->internal_thread;
2535 if (!request_thread_stop (internal))
2538 if (internal == mono_thread_internal_current ()) {
2540 self_abort_internal (&error);
2542 This function is part of the embeding API and has no way to return the exception
2543 to be thrown. So what we do is keep the old behavior and raise the exception.
2545 mono_error_raise_exception (&error); /* OK to throw, see note */
2547 async_abort_internal (internal, TRUE);
2552 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2554 gint8 tmp = *(volatile gint8 *)ptr;
2555 mono_memory_barrier ();
2560 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2562 gint16 tmp = *(volatile gint16 *)ptr;
2563 mono_memory_barrier ();
2568 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2570 gint32 tmp = *(volatile gint32 *)ptr;
2571 mono_memory_barrier ();
2576 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2578 gint64 tmp = *(volatile gint64 *)ptr;
2579 mono_memory_barrier ();
2584 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2586 volatile void *tmp = *(volatile void **)ptr;
2587 mono_memory_barrier ();
2588 return (void *) tmp;
2592 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2594 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2595 mono_memory_barrier ();
2596 return (MonoObject *) tmp;
2600 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2602 double tmp = *(volatile double *)ptr;
2603 mono_memory_barrier ();
2608 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2610 float tmp = *(volatile float *)ptr;
2611 mono_memory_barrier ();
2616 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2618 return InterlockedRead8 ((volatile gint8 *)ptr);
2622 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2624 return InterlockedRead16 ((volatile gint16 *)ptr);
2628 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2630 return InterlockedRead ((volatile gint32 *)ptr);
2634 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2636 #if SIZEOF_VOID_P == 4
2637 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2639 mono_interlocked_lock ();
2640 val = *(gint64*)ptr;
2641 mono_interlocked_unlock ();
2645 return InterlockedRead64 ((volatile gint64 *)ptr);
2649 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2651 return InterlockedReadPointer ((volatile gpointer *)ptr);
2655 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2659 #if SIZEOF_VOID_P == 4
2660 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2662 mono_interlocked_lock ();
2663 val = *(double*)ptr;
2664 mono_interlocked_unlock ();
2669 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2675 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2679 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2685 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2687 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2691 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2693 mono_memory_barrier ();
2694 *(volatile gint8 *)ptr = value;
2698 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2700 mono_memory_barrier ();
2701 *(volatile gint16 *)ptr = value;
2705 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2707 mono_memory_barrier ();
2708 *(volatile gint32 *)ptr = value;
2712 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2714 mono_memory_barrier ();
2715 *(volatile gint64 *)ptr = value;
2719 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2721 mono_memory_barrier ();
2722 *(volatile void **)ptr = value;
2726 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2728 mono_memory_barrier ();
2729 mono_gc_wbarrier_generic_store (ptr, value);
2733 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2735 mono_memory_barrier ();
2736 *(volatile double *)ptr = value;
2740 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2742 mono_memory_barrier ();
2743 *(volatile float *)ptr = value;
2747 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2749 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2753 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2755 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2759 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2761 InterlockedWrite ((volatile gint32 *)ptr, value);
2765 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2767 #if SIZEOF_VOID_P == 4
2768 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2769 mono_interlocked_lock ();
2770 *(gint64*)ptr = value;
2771 mono_interlocked_unlock ();
2776 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2780 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2782 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2786 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2790 #if SIZEOF_VOID_P == 4
2791 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2792 mono_interlocked_lock ();
2793 *(double*)ptr = value;
2794 mono_interlocked_unlock ();
2801 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2805 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2811 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2815 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2817 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2821 free_context (void *user_data)
2823 ContextStaticData *data = user_data;
2825 mono_threads_lock ();
2828 * There is no guarantee that, by the point this reference queue callback
2829 * has been invoked, the GC handle associated with the object will fail to
2830 * resolve as one might expect. So if we don't free and remove the GC
2831 * handle here, free_context_static_data_helper () could end up resolving
2832 * a GC handle to an actually-dead context which would contain a pointer
2833 * to an already-freed static data segment, resulting in a crash when
2836 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2838 mono_threads_unlock ();
2840 mono_gchandle_free (data->gc_handle);
2841 mono_free_static_data (data->static_data);
2846 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2848 mono_threads_lock ();
2850 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2853 contexts = g_hash_table_new (NULL, NULL);
2856 context_queue = mono_gc_reference_queue_new (free_context);
2858 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2859 g_hash_table_insert (contexts, gch, gch);
2862 * We use this intermediate structure to contain a duplicate pointer to
2863 * the static data because we can't rely on being able to resolve the GC
2864 * handle in the reference queue callback.
2866 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2867 data->gc_handle = GPOINTER_TO_UINT (gch);
2870 context_adjust_static_data (ctx);
2871 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2873 mono_threads_unlock ();
2875 mono_profiler_context_loaded (ctx);
2879 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2882 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2883 * cleanup in exceptional circumstances, we don't actually do any
2884 * cleanup work here. We instead do this via a reference queue.
2887 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2889 mono_profiler_context_unloaded (ctx);
2893 mono_thread_init_tls (void)
2895 MONO_FAST_TLS_INIT (tls_current_object);
2896 mono_native_tls_alloc (¤t_object_key, NULL);
2899 void mono_thread_init (MonoThreadStartCB start_cb,
2900 MonoThreadAttachCB attach_cb)
2902 mono_coop_mutex_init_recursive (&threads_mutex);
2904 mono_os_mutex_init_recursive(&interlocked_mutex);
2905 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2907 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2908 g_assert(background_change_event != NULL);
2910 mono_init_static_data_info (&thread_static_info);
2911 mono_init_static_data_info (&context_static_info);
2913 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2915 mono_thread_start_cb = start_cb;
2916 mono_thread_attach_cb = attach_cb;
2918 /* Get a pseudo handle to the current process. This is just a
2919 * kludge so that wapi can build a process handle if needed.
2920 * As a pseudo handle is returned, we don't need to clean
2923 GetCurrentProcess ();
2926 void mono_thread_cleanup (void)
2928 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2929 MonoThreadInfo *info;
2931 /* The main thread must abandon any held mutexes (particularly
2932 * important for named mutexes as they are shared across
2933 * processes, see bug 74680.) This will happen when the
2934 * thread exits, but if it's not running in a subthread it
2935 * won't exit in time.
2937 info = mono_thread_info_current ();
2938 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2942 /* This stuff needs more testing, it seems one of these
2943 * critical sections can be locked when mono_thread_cleanup is
2946 mono_coop_mutex_destroy (&threads_mutex);
2947 mono_os_mutex_destroy (&interlocked_mutex);
2948 mono_os_mutex_destroy (&delayed_free_table_mutex);
2949 mono_os_mutex_destroy (&small_id_mutex);
2950 CloseHandle (background_change_event);
2953 mono_native_tls_free (current_object_key);
2957 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2959 mono_thread_cleanup_fn = func;
2963 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2965 thread->internal_thread->manage_callback = func;
2969 static void print_tids (gpointer key, gpointer value, gpointer user)
2971 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2972 * sizeof(uint) and a cast to uint would overflow
2974 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2975 * print this as a pointer.
2977 g_message ("Waiting for: %p", key);
2982 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2983 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2987 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2991 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2994 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2997 if(ret==WAIT_FAILED) {
2998 /* See the comment in build_wait_tids() */
2999 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3003 for(i=0; i<wait->num; i++)
3004 CloseHandle (wait->handles[i]);
3006 if (ret == WAIT_TIMEOUT)
3009 for(i=0; i<wait->num; i++) {
3010 gsize tid = wait->threads[i]->tid;
3013 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
3014 * it can still run io-layer etc. code. So wait for it to really exit.
3015 * FIXME: This won't join threads which are not in the joinable_hash yet.
3017 mono_thread_join ((gpointer)tid);
3019 mono_threads_lock ();
3020 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3021 /* This thread must have been killed, because
3022 * it hasn't cleaned itself up. (It's just
3023 * possible that the thread exited before the
3024 * parent thread had a chance to store the
3025 * handle, and now there is another pointer to
3026 * the already-exited thread stored. In this
3027 * case, we'll just get two
3028 * mono_profiler_thread_end() calls for the
3032 mono_threads_unlock ();
3033 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
3034 thread_cleanup (wait->threads[i]);
3036 mono_threads_unlock ();
3041 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
3043 guint32 i, ret, count;
3045 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3047 /* Add the thread state change event, so it wakes up if a thread changes
3048 * to background mode.
3051 if (count < MAXIMUM_WAIT_OBJECTS) {
3052 wait->handles [count] = background_change_event;
3057 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
3060 if(ret==WAIT_FAILED) {
3061 /* See the comment in build_wait_tids() */
3062 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3066 for(i=0; i<wait->num; i++)
3067 CloseHandle (wait->handles[i]);
3069 if (ret == WAIT_TIMEOUT)
3072 if (ret < wait->num) {
3073 gsize tid = wait->threads[ret]->tid;
3074 mono_threads_lock ();
3075 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3076 /* See comment in wait_for_tids about thread cleanup */
3077 mono_threads_unlock ();
3078 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3079 thread_cleanup (wait->threads [ret]);
3081 mono_threads_unlock ();
3085 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3087 struct wait_data *wait=(struct wait_data *)user;
3089 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
3091 MonoInternalThread *thread=(MonoInternalThread *)value;
3093 /* Ignore background threads, we abort them later */
3094 /* Do not lock here since it is not needed and the caller holds threads_lock */
3095 if (thread->state & ThreadState_Background) {
3096 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3097 return; /* just leave, ignore */
3100 if (mono_gc_is_finalizer_internal_thread (thread)) {
3101 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3105 if (thread == mono_thread_internal_current ()) {
3106 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3110 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3111 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3115 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3116 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3120 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3121 if (handle == NULL) {
3122 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3126 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3127 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3128 wait->handles[wait->num]=handle;
3129 wait->threads[wait->num]=thread;
3132 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3134 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3139 /* Just ignore the rest, we can't do anything with
3146 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3148 struct wait_data *wait=(struct wait_data *)user;
3149 MonoNativeThreadId self = mono_native_thread_id_get ();
3150 MonoInternalThread *thread = (MonoInternalThread *)value;
3153 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
3156 /* The finalizer thread is not a background thread */
3157 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3158 && (thread->state & ThreadState_Background) != 0
3159 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3161 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3165 wait->handles[wait->num] = handle;
3166 wait->threads[wait->num] = thread;
3169 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3170 mono_thread_internal_abort (thread);
3174 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3175 && !mono_gc_is_finalizer_internal_thread (thread);
3179 * mono_threads_set_shutting_down:
3181 * Is called by a thread that wants to shut down Mono. If the runtime is already
3182 * shutting down, the calling thread is suspended/stopped, and this function never
3186 mono_threads_set_shutting_down (void)
3188 MonoInternalThread *current_thread = mono_thread_internal_current ();
3190 mono_threads_lock ();
3192 if (shutting_down) {
3193 mono_threads_unlock ();
3195 /* Make sure we're properly suspended/stopped */
3197 LOCK_THREAD (current_thread);
3199 if ((current_thread->state & ThreadState_SuspendRequested) ||
3200 (current_thread->state & ThreadState_AbortRequested) ||
3201 (current_thread->state & ThreadState_StopRequested)) {
3202 UNLOCK_THREAD (current_thread);
3203 mono_thread_execute_interruption ();
3205 current_thread->state |= ThreadState_Stopped;
3206 UNLOCK_THREAD (current_thread);
3209 /*since we're killing the thread, unset the current domain.*/
3210 mono_domain_unset ();
3212 /* Wake up other threads potentially waiting for us */
3213 mono_thread_info_exit ();
3215 shutting_down = TRUE;
3217 /* Not really a background state change, but this will
3218 * interrupt the main thread if it is waiting for all
3219 * the other threads.
3221 SetEvent (background_change_event);
3223 mono_threads_unlock ();
3227 void mono_thread_manage (void)
3229 struct wait_data wait_data;
3230 struct wait_data *wait = &wait_data;
3232 memset (wait, 0, sizeof (struct wait_data));
3233 /* join each thread that's still running */
3234 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3236 mono_threads_lock ();
3238 THREAD_DEBUG (g_message("%s: No threads", __func__));
3239 mono_threads_unlock ();
3242 mono_threads_unlock ();
3245 mono_threads_lock ();
3246 if (shutting_down) {
3247 /* somebody else is shutting down */
3248 mono_threads_unlock ();
3251 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3252 mono_g_hash_table_foreach (threads, print_tids, NULL));
3254 ResetEvent (background_change_event);
3256 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3257 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3258 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3259 mono_threads_unlock ();
3261 /* Something to wait for */
3262 wait_for_tids_or_state_change (wait, INFINITE);
3264 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3265 } while(wait->num>0);
3267 /* Mono is shutting down, so just wait for the end */
3268 if (!mono_runtime_try_shutdown ()) {
3269 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3270 mono_thread_suspend (mono_thread_internal_current ());
3271 mono_thread_execute_interruption ();
3275 * Remove everything but the finalizer thread and self.
3276 * Also abort all the background threads
3279 mono_threads_lock ();
3282 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3283 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3284 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3286 mono_threads_unlock ();
3288 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3290 /* Something to wait for */
3291 wait_for_tids (wait, INFINITE);
3293 } while (wait->num > 0);
3296 * give the subthreads a chance to really quit (this is mainly needed
3297 * to get correct user and system times from getrusage/wait/time(1)).
3298 * This could be removed if we avoid pthread_detach() and use pthread_join().
3300 mono_thread_info_yield ();
3304 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3306 MonoInternalThread *thread = (MonoInternalThread*)value;
3307 struct wait_data *wait = (struct wait_data*)user_data;
3311 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3313 * This needs no locking.
3315 if ((thread->state & ThreadState_Suspended) != 0 ||
3316 (thread->state & ThreadState_Stopped) != 0)
3319 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3320 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3324 wait->handles [wait->num] = handle;
3325 wait->threads [wait->num] = thread;
3331 * mono_thread_suspend_all_other_threads:
3333 * Suspend all managed threads except the finalizer thread and this thread. It is
3334 * not possible to resume them later.
3336 void mono_thread_suspend_all_other_threads (void)
3338 struct wait_data wait_data;
3339 struct wait_data *wait = &wait_data;
3341 MonoNativeThreadId self = mono_native_thread_id_get ();
3342 guint32 eventidx = 0;
3343 gboolean starting, finished;
3345 memset (wait, 0, sizeof (struct wait_data));
3347 * The other threads could be in an arbitrary state at this point, i.e.
3348 * they could be starting up, shutting down etc. This means that there could be
3349 * threads which are not even in the threads hash table yet.
3353 * First we set a barrier which will be checked by all threads before they
3354 * are added to the threads hash table, and they will exit if the flag is set.
3355 * This ensures that no threads could be added to the hash later.
3356 * We will use shutting_down as the barrier for now.
3358 g_assert (shutting_down);
3361 * We make multiple calls to WaitForMultipleObjects since:
3362 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3363 * - some threads could exit without becoming suspended
3368 * Make a copy of the hashtable since we can't do anything with
3369 * threads while threads_mutex is held.
3372 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3373 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3374 mono_threads_lock ();
3375 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3376 mono_threads_unlock ();
3379 /* Get the suspended events that we'll be waiting for */
3380 for (i = 0; i < wait->num; ++i) {
3381 MonoInternalThread *thread = wait->threads [i];
3383 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3384 || mono_gc_is_finalizer_internal_thread (thread)
3385 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3387 //CloseHandle (wait->handles [i]);
3388 wait->threads [i] = NULL; /* ignore this thread in next loop */
3392 LOCK_THREAD (thread);
3394 if ((thread->state & ThreadState_Suspended) != 0 ||
3395 (thread->state & ThreadState_StopRequested) != 0 ||
3396 (thread->state & ThreadState_Stopped) != 0) {
3397 UNLOCK_THREAD (thread);
3398 CloseHandle (wait->handles [i]);
3399 wait->threads [i] = NULL; /* ignore this thread in next loop */
3405 /* Convert abort requests into suspend requests */
3406 if ((thread->state & ThreadState_AbortRequested) != 0)
3407 thread->state &= ~ThreadState_AbortRequested;
3409 thread->state |= ThreadState_SuspendRequested;
3411 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3412 async_suspend_internal (thread, TRUE);
3414 if (eventidx <= 0) {
3416 * If there are threads which are starting up, we wait until they
3417 * are suspended when they try to register in the threads hash.
3418 * This is guaranteed to finish, since the threads which can create new
3419 * threads get suspended after a while.
3420 * FIXME: The finalizer thread can still create new threads.
3422 mono_threads_lock ();
3423 if (threads_starting_up)
3424 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3427 mono_threads_unlock ();
3429 mono_thread_info_sleep (100, NULL);
3437 MonoInternalThread *thread;
3438 MonoStackFrameInfo *frames;
3439 int nframes, max_frames;
3440 int nthreads, max_threads;
3441 MonoInternalThread **threads;
3442 } ThreadDumpUserData;
3444 static gboolean thread_dump_requested;
3446 /* This needs to be async safe */
3448 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3450 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3452 if (ud->nframes < ud->max_frames) {
3453 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3460 /* This needs to be async safe */
3461 static SuspendThreadResult
3462 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3464 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3465 MonoInternalThread *thread = user_data->thread;
3468 /* This no longer works with remote unwinding */
3470 wapi_desc = wapi_current_thread_desc ();
3471 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3476 if (thread == mono_thread_internal_current ())
3477 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3479 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3481 return MonoResumeThread;
3485 int nthreads, max_threads;
3486 MonoInternalThread **threads;
3487 } CollectThreadsUserData;
3490 collect_thread (gpointer key, gpointer value, gpointer user)
3492 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3493 MonoInternalThread *thread = (MonoInternalThread *)value;
3495 if (ud->nthreads < ud->max_threads)
3496 ud->threads [ud->nthreads ++] = thread;
3500 * Collect running threads into the THREADS array.
3501 * THREADS should be an array allocated on the stack.
3504 collect_threads (MonoInternalThread **thread_array, int max_threads)
3506 CollectThreadsUserData ud;
3508 memset (&ud, 0, sizeof (ud));
3509 /* This array contains refs, but its on the stack, so its ok */
3510 ud.threads = thread_array;
3511 ud.max_threads = max_threads;
3513 mono_threads_lock ();
3514 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3515 mono_threads_unlock ();
3521 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3523 GString* text = g_string_new (0);
3525 GError *error = NULL;
3528 ud->thread = thread;
3531 /* Collect frames for the thread */
3532 if (thread == mono_thread_internal_current ()) {
3533 get_thread_dump (mono_thread_info_current (), ud);
3535 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3539 * Do all the non async-safe work outside of get_thread_dump.
3542 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3544 g_string_append_printf (text, "\n\"%s\"", name);
3547 else if (thread->threadpool_thread) {
3548 g_string_append (text, "\n\"<threadpool thread>\"");
3550 g_string_append (text, "\n\"<unnamed thread>\"");
3553 for (i = 0; i < ud->nframes; ++i) {
3554 MonoStackFrameInfo *frame = &ud->frames [i];
3555 MonoMethod *method = NULL;
3557 if (frame->type == FRAME_TYPE_MANAGED)
3558 method = mono_jit_info_get_method (frame->ji);
3561 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3562 g_string_append_printf (text, " %s\n", location);
3565 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3569 fprintf (stdout, "%s", text->str);
3571 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3572 OutputDebugStringA(text->str);
3575 g_string_free (text, TRUE);
3580 mono_threads_perform_thread_dump (void)
3582 ThreadDumpUserData ud;
3583 MonoInternalThread *thread_array [128];
3584 int tindex, nthreads;
3586 if (!thread_dump_requested)
3589 printf ("Full thread dump:\n");
3591 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3592 nthreads = collect_threads (thread_array, 128);
3594 memset (&ud, 0, sizeof (ud));
3595 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3596 ud.max_frames = 256;
3598 for (tindex = 0; tindex < nthreads; ++tindex)
3599 dump_thread (thread_array [tindex], &ud);
3603 thread_dump_requested = FALSE;
3606 /* Obtain the thread dump of all threads */
3608 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3611 ThreadDumpUserData ud;
3612 MonoInternalThread *thread_array [128];
3613 MonoDomain *domain = mono_domain_get ();
3614 MonoDebugSourceLocation *location;
3615 int tindex, nthreads;
3617 mono_error_init (error);
3619 *out_threads = NULL;
3620 *out_stack_frames = NULL;
3622 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3623 nthreads = collect_threads (thread_array, 128);
3625 memset (&ud, 0, sizeof (ud));
3626 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3627 ud.max_frames = 256;
3629 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3632 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3636 for (tindex = 0; tindex < nthreads; ++tindex) {
3637 MonoInternalThread *thread = thread_array [tindex];
3638 MonoArray *thread_frames;
3644 /* Collect frames for the thread */
3645 if (thread == mono_thread_internal_current ()) {
3646 get_thread_dump (mono_thread_info_current (), &ud);
3648 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3651 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3653 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3656 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3658 for (i = 0; i < ud.nframes; ++i) {
3659 MonoStackFrameInfo *frame = &ud.frames [i];
3660 MonoMethod *method = NULL;
3661 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3665 sf->native_offset = frame->native_offset;
3667 if (frame->type == FRAME_TYPE_MANAGED)
3668 method = mono_jit_info_get_method (frame->ji);
3671 sf->method_address = (gsize) frame->ji->code_start;
3673 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3676 MONO_OBJECT_SETREF (sf, method, rm);
3678 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3680 sf->il_offset = location->il_offset;
3682 if (location && location->source_file) {
3683 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3684 sf->line = location->row;
3685 sf->column = location->column;
3687 mono_debug_free_source_location (location);
3692 mono_array_setref (thread_frames, i, sf);
3698 return is_ok (error);
3702 * mono_threads_request_thread_dump:
3704 * Ask all threads except the current to print their stacktrace to stdout.
3707 mono_threads_request_thread_dump (void)
3709 /*The new thread dump code runs out of the finalizer thread. */
3710 thread_dump_requested = TRUE;
3711 mono_gc_finalize_notify ();
3716 gint allocated; /* +1 so that refs [allocated] == NULL */
3720 typedef struct ref_stack RefStack;
3723 ref_stack_new (gint initial_size)
3727 initial_size = MAX (initial_size, 16) + 1;
3728 rs = g_new0 (RefStack, 1);
3729 rs->refs = g_new0 (gpointer, initial_size);
3730 rs->allocated = initial_size;
3735 ref_stack_destroy (gpointer ptr)
3737 RefStack *rs = (RefStack *)ptr;
3746 ref_stack_push (RefStack *rs, gpointer ptr)
3748 g_assert (rs != NULL);
3750 if (rs->bottom >= rs->allocated) {
3751 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3752 rs->allocated <<= 1;
3753 rs->refs [rs->allocated] = NULL;
3755 rs->refs [rs->bottom++] = ptr;
3759 ref_stack_pop (RefStack *rs)
3761 if (rs == NULL || rs->bottom == 0)
3765 rs->refs [rs->bottom] = NULL;
3769 ref_stack_find (RefStack *rs, gpointer ptr)
3776 for (refs = rs->refs; refs && *refs; refs++) {
3784 * mono_thread_push_appdomain_ref:
3786 * Register that the current thread may have references to objects in domain
3787 * @domain on its stack. Each call to this function should be paired with a
3788 * call to pop_appdomain_ref.
3791 mono_thread_push_appdomain_ref (MonoDomain *domain)
3793 MonoInternalThread *thread = mono_thread_internal_current ();
3796 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3797 SPIN_LOCK (thread->lock_thread_id);
3798 if (thread->appdomain_refs == NULL)
3799 thread->appdomain_refs = ref_stack_new (16);
3800 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3801 SPIN_UNLOCK (thread->lock_thread_id);
3806 mono_thread_pop_appdomain_ref (void)
3808 MonoInternalThread *thread = mono_thread_internal_current ();
3811 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3812 SPIN_LOCK (thread->lock_thread_id);
3813 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3814 SPIN_UNLOCK (thread->lock_thread_id);
3819 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3822 SPIN_LOCK (thread->lock_thread_id);
3823 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3824 SPIN_UNLOCK (thread->lock_thread_id);
3829 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3831 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3834 typedef struct abort_appdomain_data {
3835 struct wait_data wait;
3837 } abort_appdomain_data;
3840 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3842 MonoInternalThread *thread = (MonoInternalThread*)value;
3843 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3844 MonoDomain *domain = data->domain;
3846 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3847 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3849 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3850 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3853 data->wait.handles [data->wait.num] = handle;
3854 data->wait.threads [data->wait.num] = thread;
3857 /* Just ignore the rest, we can't do anything with
3865 * mono_threads_abort_appdomain_threads:
3867 * Abort threads which has references to the given appdomain.
3870 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3872 #ifdef __native_client__
3876 abort_appdomain_data user_data;
3878 int orig_timeout = timeout;
3881 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3883 start_time = mono_msec_ticks ();
3885 mono_threads_lock ();
3887 user_data.domain = domain;
3888 user_data.wait.num = 0;
3889 /* This shouldn't take any locks */
3890 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3891 mono_threads_unlock ();
3893 if (user_data.wait.num > 0) {
3894 /* Abort the threads outside the threads lock */
3895 for (i = 0; i < user_data.wait.num; ++i)
3896 mono_thread_internal_abort (user_data.wait.threads [i]);
3899 * We should wait for the threads either to abort, or to leave the
3900 * domain. We can't do the latter, so we wait with a timeout.
3902 wait_for_tids (&user_data.wait, 100);
3905 /* Update remaining time */
3906 timeout -= mono_msec_ticks () - start_time;
3907 start_time = mono_msec_ticks ();
3909 if (orig_timeout != -1 && timeout < 0)
3912 while (user_data.wait.num > 0);
3914 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3920 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3922 MonoInternalThread *thread = (MonoInternalThread*)value;
3923 MonoDomain *domain = (MonoDomain*)user_data;
3926 /* No locking needed here */
3927 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3929 if (thread->cached_culture_info) {
3930 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3931 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3932 if (obj && obj->vtable->domain == domain)
3933 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3939 * mono_threads_clear_cached_culture:
3941 * Clear the cached_current_culture from all threads if it is in the
3945 mono_threads_clear_cached_culture (MonoDomain *domain)
3947 mono_threads_lock ();
3948 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3949 mono_threads_unlock ();
3953 * mono_thread_get_undeniable_exception:
3955 * Return an exception which needs to be raised when leaving a catch clause.
3956 * This is used for undeniable exception propagation.
3959 mono_thread_get_undeniable_exception (void)
3961 MonoInternalThread *thread = mono_thread_internal_current ();
3963 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3965 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3966 * exception if the thread no longer references a dying appdomain.
3968 thread->abort_exc->trace_ips = NULL;
3969 thread->abort_exc->stack_trace = NULL;
3970 return thread->abort_exc;
3976 #if MONO_SMALL_CONFIG
3977 #define NUM_STATIC_DATA_IDX 4
3978 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3982 #define NUM_STATIC_DATA_IDX 8
3983 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3984 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3988 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3989 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3992 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3994 gpointer *static_data = (gpointer *)addr;
3996 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3997 void **ptr = (void **)static_data [i];
4002 MONO_BITSET_FOREACH (bitmaps [i], idx, {
4003 void **p = ptr + idx;
4006 mark_func ((MonoObject**)p, gc_data);
4012 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4014 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
4018 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4020 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
4024 * mono_alloc_static_data
4026 * Allocate memory blocks for storing threads or context static data
4029 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4031 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4034 gpointer* static_data = *static_data_ptr;
4036 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4037 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4039 if (mono_gc_user_markers_supported ()) {
4040 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4041 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4043 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4044 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4047 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4048 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4049 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4050 *static_data_ptr = static_data;
4051 static_data [0] = static_data;
4054 for (i = 1; i <= idx; ++i) {
4055 if (static_data [i])
4058 if (mono_gc_user_markers_supported ())
4059 static_data [i] = g_malloc0 (static_data_size [i]);
4061 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4062 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4063 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4068 mono_free_static_data (gpointer* static_data)
4071 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4072 gpointer p = static_data [i];
4076 * At this point, the static data pointer array is still registered with the
4077 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4078 * data. Freeing the individual arrays without first nulling their slots
4079 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4080 * such an already freed array. See bug #13813.
4082 static_data [i] = NULL;
4083 mono_memory_write_barrier ();
4084 if (mono_gc_user_markers_supported ())
4087 mono_gc_free_fixed (p);
4089 mono_gc_free_fixed (static_data);
4093 * mono_init_static_data_info
4095 * Initializes static data counters
4097 static void mono_init_static_data_info (StaticDataInfo *static_data)
4099 static_data->idx = 0;
4100 static_data->offset = 0;
4101 static_data->freelist = NULL;
4105 * mono_alloc_static_data_slot
4107 * Generates an offset for static data. static_data contains the counters
4108 * used to generate it.
4111 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4113 if (!static_data->idx && !static_data->offset) {
4115 * we use the first chunk of the first allocation also as
4116 * an array for the rest of the data
4118 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4120 static_data->offset += align - 1;
4121 static_data->offset &= ~(align - 1);
4122 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4123 static_data->idx ++;
4124 g_assert (size <= static_data_size [static_data->idx]);
4125 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4126 static_data->offset = 0;
4128 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4129 static_data->offset += size;
4134 * ensure thread static fields already allocated are valid for thread
4135 * This function is called when a thread is created or on thread attach.
4138 thread_adjust_static_data (MonoInternalThread *thread)
4140 mono_threads_lock ();
4141 if (thread_static_info.offset || thread_static_info.idx > 0) {
4142 /* get the current allocated size */
4143 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
4144 mono_alloc_static_data (&thread->static_data, offset, TRUE);
4146 mono_threads_unlock ();
4150 * LOCKING: requires that threads_mutex is held
4153 context_adjust_static_data (MonoAppContext *ctx)
4155 if (context_static_info.offset || context_static_info.idx > 0) {
4156 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4157 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4158 ctx->data->static_data = ctx->static_data;
4163 * LOCKING: requires that threads_mutex is held
4166 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4168 MonoInternalThread *thread = (MonoInternalThread *)value;
4169 guint32 offset = GPOINTER_TO_UINT (user);
4171 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4175 * LOCKING: requires that threads_mutex is held
4178 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4180 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4185 guint32 offset = GPOINTER_TO_UINT (user);
4186 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4187 ctx->data->static_data = ctx->static_data;
4190 static StaticDataFreeList*
4191 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4193 StaticDataFreeList* prev = NULL;
4194 StaticDataFreeList* tmp = static_data->freelist;
4196 if (tmp->size == size) {
4198 prev->next = tmp->next;
4200 static_data->freelist = tmp->next;
4209 #if SIZEOF_VOID_P == 4
4216 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4218 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4220 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4221 MonoBitSet *rb = sets [idx];
4222 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4223 offset /= sizeof (uintptr_t);
4224 /* offset is now the bitmap offset */
4225 for (int i = 0; i < numbits; ++i) {
4226 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4227 mono_bitset_set_fast (rb, offset + i);
4232 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4234 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4235 MonoBitSet *rb = sets [idx];
4236 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4237 offset /= sizeof (uintptr_t);
4238 /* offset is now the bitmap offset */
4239 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4240 mono_bitset_clear_fast (rb, offset + i);
4244 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4246 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4248 StaticDataInfo *info;
4251 if (static_type == SPECIAL_STATIC_THREAD) {
4252 info = &thread_static_info;
4253 sets = thread_reference_bitmaps;
4255 info = &context_static_info;
4256 sets = context_reference_bitmaps;
4259 mono_threads_lock ();
4261 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4265 offset = item->offset;
4268 offset = mono_alloc_static_data_slot (info, size, align);
4271 update_reference_bitmap (sets, offset, bitmap, numbits);
4273 if (static_type == SPECIAL_STATIC_THREAD) {
4274 /* This can be called during startup */
4275 if (threads != NULL)
4276 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4278 if (contexts != NULL)
4279 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4281 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4284 mono_threads_unlock ();
4290 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4292 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4294 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4295 return get_thread_static_data (thread, offset);
4297 return get_context_static_data (thread->current_appcontext, offset);
4302 mono_get_special_static_data (guint32 offset)
4304 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4313 * LOCKING: requires that threads_mutex is held
4316 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4318 MonoInternalThread *thread = (MonoInternalThread *)value;
4319 OffsetSize *data = (OffsetSize *)user;
4320 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4321 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4324 if (!thread->static_data || !thread->static_data [idx])
4326 ptr = ((char*) thread->static_data [idx]) + off;
4327 mono_gc_bzero_atomic (ptr, data->size);
4331 * LOCKING: requires that threads_mutex is held
4334 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4336 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4341 OffsetSize *data = (OffsetSize *)user;
4342 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4343 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4346 if (!ctx->static_data || !ctx->static_data [idx])
4349 ptr = ((char*) ctx->static_data [idx]) + off;
4350 mono_gc_bzero_atomic (ptr, data->size);
4354 do_free_special_slot (guint32 offset, guint32 size)
4356 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4358 StaticDataInfo *info;
4360 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4361 info = &thread_static_info;
4362 sets = thread_reference_bitmaps;
4364 info = &context_static_info;
4365 sets = context_reference_bitmaps;
4368 guint32 data_offset = offset;
4369 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4370 OffsetSize data = { data_offset, size };
4372 clear_reference_bitmap (sets, data.offset, data.size);
4374 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4375 if (threads != NULL)
4376 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4378 if (contexts != NULL)
4379 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4382 if (!mono_runtime_is_shutting_down ()) {
4383 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4385 item->offset = offset;
4388 item->next = info->freelist;
4389 info->freelist = item;
4394 do_free_special (gpointer key, gpointer value, gpointer data)
4396 MonoClassField *field = (MonoClassField *)key;
4397 guint32 offset = GPOINTER_TO_UINT (value);
4400 size = mono_type_size (field->type, &align);
4401 do_free_special_slot (offset, size);
4405 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4407 mono_threads_lock ();
4409 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4411 mono_threads_unlock ();
4415 static void CALLBACK dummy_apc (ULONG_PTR param)
4421 * mono_thread_execute_interruption
4423 * Performs the operation that the requested thread state requires (abort,
4426 static MonoException*
4427 mono_thread_execute_interruption (void)
4429 MonoInternalThread *thread = mono_thread_internal_current ();
4430 MonoThread *sys_thread = mono_thread_current ();
4432 LOCK_THREAD (thread);
4434 /* MonoThread::interruption_requested can only be changed with atomics */
4435 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4436 /* this will consume pending APC calls */
4438 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4440 InterlockedDecrement (&thread_interruption_requested);
4442 /* Clear the interrupted flag of the thread so it can wait again */
4443 mono_thread_info_clear_self_interrupt ();
4446 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4447 if (sys_thread->pending_exception) {
4450 exc = sys_thread->pending_exception;
4451 sys_thread->pending_exception = NULL;
4453 UNLOCK_THREAD (thread);
4455 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4456 UNLOCK_THREAD (thread);
4457 g_assert (sys_thread->pending_exception == NULL);
4458 if (thread->abort_exc == NULL) {
4460 * This might be racy, but it has to be called outside the lock
4461 * since it calls managed code.
4463 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4465 return thread->abort_exc;
4467 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4468 /* calls UNLOCK_THREAD (thread) */
4469 self_suspend_internal ();
4472 else if ((thread->state & ThreadState_StopRequested) != 0) {
4473 /* FIXME: do this through the JIT? */
4475 UNLOCK_THREAD (thread);
4477 mono_thread_exit ();
4479 } else if (thread->thread_interrupt_requested) {
4481 thread->thread_interrupt_requested = FALSE;
4482 UNLOCK_THREAD (thread);
4484 return(mono_get_exception_thread_interrupted ());
4487 UNLOCK_THREAD (thread);
4493 * mono_thread_request_interruption
4495 * A signal handler can call this method to request the interruption of a
4496 * thread. The result of the interruption will depend on the current state of
4497 * the thread. If the result is an exception that needs to be throw, it is
4498 * provided as return value.
4501 mono_thread_request_interruption (gboolean running_managed)
4503 MonoInternalThread *thread = mono_thread_internal_current ();
4505 /* The thread may already be stopping */
4510 if (thread->interrupt_on_stop &&
4511 thread->state & ThreadState_StopRequested &&
4512 thread->state & ThreadState_Background)
4516 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4518 InterlockedIncrement (&thread_interruption_requested);
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->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 (void)
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|ThreadState_StopRequested)) != 0;
4554 UNLOCK_THREAD (thread);
4556 /*This can happen if the protected block called Thread::ResetAbort*/
4557 if (!still_aborting)
4560 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4562 InterlockedIncrement (&thread_interruption_requested);
4564 mono_thread_info_self_interrupt ();
4566 return mono_thread_execute_interruption ();
4569 gboolean mono_thread_interruption_requested ()
4571 if (thread_interruption_requested) {
4572 MonoInternalThread *thread = mono_thread_internal_current ();
4573 /* The thread may already be stopping */
4575 return (thread->interruption_requested);
4580 static MonoException*
4581 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4583 MonoInternalThread *thread = mono_thread_internal_current ();
4585 /* The thread may already be stopping */
4589 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4590 MonoException* exc = mono_thread_execute_interruption ();
4598 * Performs the interruption of the current thread, if one has been requested,
4599 * and the thread is not running a protected wrapper.
4600 * Return the exception which needs to be thrown, if any.
4603 mono_thread_interruption_checkpoint (void)
4605 return mono_thread_interruption_checkpoint_request (FALSE);
4609 * Performs the interruption of the current thread, if one has been requested.
4610 * Return the exception which needs to be thrown, if any.
4613 mono_thread_force_interruption_checkpoint_noraise (void)
4615 return mono_thread_interruption_checkpoint_request (TRUE);
4619 * mono_set_pending_exception:
4621 * Set the pending exception of the current thread to EXC.
4622 * The exception will be thrown when execution returns to managed code.
4625 mono_set_pending_exception (MonoException *exc)
4627 MonoThread *thread = mono_thread_current ();
4629 /* The thread may already be stopping */
4633 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4635 mono_thread_request_interruption (FALSE);
4639 * mono_thread_interruption_request_flag:
4641 * Returns the address of a flag that will be non-zero if an interruption has
4642 * been requested for a thread. The thread to interrupt may not be the current
4643 * thread, so an additional call to mono_thread_interruption_requested() or
4644 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4647 gint32* mono_thread_interruption_request_flag ()
4649 return &thread_interruption_requested;
4653 mono_thread_init_apartment_state (void)
4656 MonoInternalThread* thread = mono_thread_internal_current ();
4658 /* Positive return value indicates success, either
4659 * S_OK if this is first CoInitialize call, or
4660 * S_FALSE if CoInitialize already called, but with same
4661 * threading model. A negative value indicates failure,
4662 * probably due to trying to change the threading model.
4664 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4665 ? COINIT_APARTMENTTHREADED
4666 : COINIT_MULTITHREADED) < 0) {
4667 thread->apartment_state = ThreadApartmentState_Unknown;
4673 mono_thread_cleanup_apartment_state (void)
4676 MonoInternalThread* thread = mono_thread_internal_current ();
4678 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4685 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4687 LOCK_THREAD (thread);
4688 thread->state |= state;
4689 UNLOCK_THREAD (thread);
4693 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4695 LOCK_THREAD (thread);
4696 thread->state &= ~state;
4697 UNLOCK_THREAD (thread);
4701 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4703 gboolean ret = FALSE;
4705 LOCK_THREAD (thread);
4707 if ((thread->state & test) != 0) {
4711 UNLOCK_THREAD (thread);
4716 static gboolean has_tls_get = FALSE;
4719 mono_runtime_set_has_tls_get (gboolean val)
4725 mono_runtime_has_tls_get (void)
4731 self_interrupt_thread (void *_unused)
4733 MonoThreadInfo *info = mono_thread_info_current ();
4734 MonoException *exc = mono_thread_execute_interruption ();
4735 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4736 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. */
4737 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4741 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4745 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4749 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4751 MonoJitInfo **dest = (MonoJitInfo **)data;
4757 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4759 MonoJitInfo *ji = NULL;
4764 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4765 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4766 * where we hold runtime locks.
4768 if (!mono_threads_is_coop_enabled ())
4769 mono_thread_info_set_is_async_context (TRUE);
4770 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4771 if (!mono_threads_is_coop_enabled ())
4772 mono_thread_info_set_is_async_context (FALSE);
4777 MonoInternalThread *thread;
4778 gboolean install_async_abort;
4779 MonoThreadInfoInterruptToken *interrupt_token;
4782 static SuspendThreadResult
4783 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4785 AbortThreadData *data = (AbortThreadData *)ud;
4786 MonoInternalThread *thread = data->thread;
4787 MonoJitInfo *ji = NULL;
4788 gboolean protected_wrapper;
4789 gboolean running_managed;
4791 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4792 return MonoResumeThread;
4794 /*someone is already interrupting it*/
4795 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4796 return MonoResumeThread;
4798 InterlockedIncrement (&thread_interruption_requested);
4800 ji = mono_thread_info_get_last_managed (info);
4801 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4802 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4804 if (!protected_wrapper && running_managed) {
4805 /*We are in managed code*/
4806 /*Set the thread to call */
4807 if (data->install_async_abort)
4808 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4809 return MonoResumeThread;
4812 * This will cause waits to be broken.
4813 * It will also prevent the thread from entering a wait, so if the thread returns
4814 * from the wait before it receives the abort signal, it will just spin in the wait
4815 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4818 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4820 return MonoResumeThread;
4825 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4827 AbortThreadData data;
4829 g_assert (thread != mono_thread_internal_current ());
4831 data.thread = thread;
4832 data.install_async_abort = install_async_abort;
4833 data.interrupt_token = NULL;
4835 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4836 if (data.interrupt_token)
4837 mono_thread_info_finish_interrupt (data.interrupt_token);
4838 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4842 self_abort_internal (MonoError *error)
4846 mono_error_init (error);
4848 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4849 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4851 exc = mono_thread_request_interruption (TRUE);
4853 mono_error_set_exception_instance (error, exc);
4855 mono_thread_info_self_interrupt ();
4859 MonoInternalThread *thread;
4861 MonoThreadInfoInterruptToken *interrupt_token;
4862 } SuspendThreadData;
4864 static SuspendThreadResult
4865 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4867 SuspendThreadData *data = (SuspendThreadData *)ud;
4868 MonoInternalThread *thread = data->thread;
4869 MonoJitInfo *ji = NULL;
4870 gboolean protected_wrapper;
4871 gboolean running_managed;
4873 ji = mono_thread_info_get_last_managed (info);
4874 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4875 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4877 if (running_managed && !protected_wrapper) {
4878 thread->state &= ~ThreadState_SuspendRequested;
4879 thread->state |= ThreadState_Suspended;
4880 return KeepSuspended;
4882 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4883 InterlockedIncrement (&thread_interruption_requested);
4884 if (data->interrupt)
4885 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4887 return MonoResumeThread;
4891 /* LOCKING: called with @thread synch_cs held, and releases it */
4893 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4895 SuspendThreadData data;
4897 g_assert (thread != mono_thread_internal_current ());
4899 data.thread = thread;
4900 data.interrupt = interrupt;
4901 data.interrupt_token = NULL;
4903 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4904 if (data.interrupt_token)
4905 mono_thread_info_finish_interrupt (data.interrupt_token);
4907 UNLOCK_THREAD (thread);
4910 /* LOCKING: called with @thread synch_cs held, and releases it */
4912 self_suspend_internal (void)
4914 MonoInternalThread *thread;
4916 thread = mono_thread_internal_current ();
4918 mono_thread_info_begin_self_suspend ();
4919 thread->state &= ~ThreadState_SuspendRequested;
4920 thread->state |= ThreadState_Suspended;
4922 UNLOCK_THREAD (thread);
4924 mono_thread_info_end_self_suspend ();
4928 * mono_thread_is_foreign:
4929 * @thread: the thread to query
4931 * This function allows one to determine if a thread was created by the mono runtime and has
4932 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4934 * Returns: TRUE if @thread was not created by the runtime.
4937 mono_thread_is_foreign (MonoThread *thread)
4939 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4940 return info->runtime_thread == FALSE;
4944 * mono_add_joinable_thread:
4946 * Add TID to the list of joinable threads.
4947 * LOCKING: Acquires the threads lock.
4950 mono_threads_add_joinable_thread (gpointer tid)
4954 * We cannot detach from threads because it causes problems like
4955 * 2fd16f60/r114307. So we collect them and join them when
4956 * we have time (in he finalizer thread).
4958 joinable_threads_lock ();
4959 if (!joinable_threads)
4960 joinable_threads = g_hash_table_new (NULL, NULL);
4961 g_hash_table_insert (joinable_threads, tid, tid);
4962 joinable_thread_count ++;
4963 joinable_threads_unlock ();
4965 mono_gc_finalize_notify ();
4970 * mono_threads_join_threads:
4972 * Join all joinable threads. This is called from the finalizer thread.
4973 * LOCKING: Acquires the threads lock.
4976 mono_threads_join_threads (void)
4979 GHashTableIter iter;
4986 if (!joinable_thread_count)
4990 joinable_threads_lock ();
4992 if (g_hash_table_size (joinable_threads)) {
4993 g_hash_table_iter_init (&iter, joinable_threads);
4994 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4995 thread = (pthread_t)tid;
4996 g_hash_table_remove (joinable_threads, key);
4997 joinable_thread_count --;
5000 joinable_threads_unlock ();
5002 if (thread != pthread_self ()) {
5004 /* This shouldn't block */
5005 pthread_join (thread, NULL);
5018 * Wait for thread TID to exit.
5019 * LOCKING: Acquires the threads lock.
5022 mono_thread_join (gpointer tid)
5026 gboolean found = FALSE;
5028 joinable_threads_lock ();
5029 if (!joinable_threads)
5030 joinable_threads = g_hash_table_new (NULL, NULL);
5031 if (g_hash_table_lookup (joinable_threads, tid)) {
5032 g_hash_table_remove (joinable_threads, tid);
5033 joinable_thread_count --;
5036 joinable_threads_unlock ();
5039 thread = (pthread_t)tid;
5041 pthread_join (thread, NULL);
5047 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
5049 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
5050 mono_thread_interruption_checkpoint ();
5053 static inline gboolean
5054 is_appdomainunloaded_exception (MonoClass *klass)
5056 return klass == mono_class_get_appdomain_unloaded_exception_class ();
5059 static inline gboolean
5060 is_threadabort_exception (MonoClass *klass)
5062 return klass == mono_defaults.threadabortexception_class;
5066 mono_thread_internal_unhandled_exception (MonoObject* exc)
5068 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5069 MonoClass *klass = exc->vtable->klass;
5070 if (is_threadabort_exception (klass)) {
5071 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5072 } else if (!is_appdomainunloaded_exception (klass)) {
5073 mono_unhandled_exception (exc);
5074 if (mono_environment_exitcode_get () == 1) {
5075 mono_environment_exitcode_set (255);
5076 mono_invoke_unhandled_exception_hook (exc);
5077 g_assert_not_reached ();
5084 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5087 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5088 mono_error_set_pending_exception (&error);
5092 * mono_threads_attach_coop: called by native->managed wrappers
5096 * - @return: the original domain which needs to be restored, or NULL.
5099 * - @dummy: contains the original domain
5100 * - @return: a cookie containing current MonoThreadInfo*.
5103 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5106 gboolean fresh_thread = FALSE;
5109 /* Happens when called from AOTed code which is only used in the root domain. */
5110 domain = mono_get_root_domain ();
5115 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5116 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5117 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5118 * we're only responsible for making the cookie. */
5119 if (mono_threads_is_coop_enabled ()) {
5120 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5121 fresh_thread = !info || !mono_thread_info_is_live (info);
5124 if (!mono_thread_internal_current ()) {
5125 mono_thread_attach_full (domain, FALSE);
5128 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5131 orig = mono_domain_get ();
5133 mono_domain_set (domain, TRUE);
5135 if (!mono_threads_is_coop_enabled ())
5136 return orig != domain ? orig : NULL;
5140 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5141 * return the right cookie. */
5142 return mono_threads_enter_gc_unsafe_region_cookie ();
5145 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5146 return mono_threads_enter_gc_unsafe_region (dummy);
5151 * mono_threads_detach_coop: called by native->managed wrappers
5154 * - @cookie: the original domain which needs to be restored, or NULL.
5158 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5159 * - @dummy: contains the original domain
5162 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5164 MonoDomain *domain, *orig;
5166 if (!mono_threads_is_coop_enabled ()) {
5167 orig = (MonoDomain*) cookie;
5169 mono_domain_set (orig, TRUE);
5171 orig = (MonoDomain*) *dummy;
5173 domain = mono_domain_get ();
5176 /* it won't do anything if cookie is NULL
5177 * thread state RUNNING -> (RUNNING|BLOCKING) */
5178 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5180 if (orig != domain) {
5182 mono_domain_unset ();
5184 mono_domain_set (orig, TRUE);