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);
754 mono_error_cleanup (&error);
758 /* If the thread calls ExitThread at all, this remaining code
759 * will not be executed, but the main thread will eventually
760 * call thread_cleanup() on this thread's behalf.
763 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
765 /* Do any cleanup needed for apartment state. This
766 * cannot be done in thread_cleanup since thread_cleanup could be
767 * called for a thread other than the current thread.
768 * mono_thread_cleanup_apartment_state cleans up apartment
769 * for the current thead */
770 mono_thread_cleanup_apartment_state ();
772 thread_cleanup (internal);
776 /* Remove the reference to the thread object in the TLS data,
777 * so the thread object can be finalized. This won't be
778 * reached if the thread threw an uncaught exception, so those
779 * thread handles will stay referenced :-( (This is due to
780 * missing support for scanning thread-specific data in the
781 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
784 SET_CURRENT_OBJECT (NULL);
789 static guint32 WINAPI start_wrapper(void *data)
793 /* Avoid scanning the frames above this frame during a GC */
794 mono_gc_set_stack_end ((void*)&dummy);
796 return start_wrapper_internal (data);
802 * Common thread creation code.
803 * LOCKING: Acquires the threads lock.
806 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
809 HANDLE thread_handle;
810 MonoNativeThreadId tid;
814 * Join joinable threads to prevent running out of threads since the finalizer
815 * thread might be blocked/backlogged.
817 mono_threads_join_threads ();
819 mono_error_init (error);
821 mono_threads_lock ();
824 mono_threads_unlock ();
827 if (threads_starting_up == NULL) {
828 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
829 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
831 mono_g_hash_table_insert (threads_starting_up, thread, thread);
832 mono_threads_unlock ();
834 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
835 if (!internal->start_notify) {
836 mono_threads_lock ();
837 mono_g_hash_table_remove (threads_starting_up, thread);
838 mono_threads_unlock ();
839 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
845 stack_size = default_stacksize_for_thread (internal);
847 /* Create suspended, so we can do some housekeeping before the thread
850 tp.priority = thread->priority;
851 tp.stack_size = stack_size;
852 tp.creation_flags = CREATE_SUSPENDED;
854 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info, &tp, &tid);
856 if (thread_handle == NULL) {
857 /* The thread couldn't be created, so set an exception */
858 mono_threads_lock ();
859 mono_g_hash_table_remove (threads_starting_up, thread);
860 mono_threads_unlock ();
862 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
865 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
867 internal->handle = thread_handle;
868 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
870 internal->threadpool_thread = threadpool_thread;
871 if (threadpool_thread)
872 mono_thread_set_state (internal, ThreadState_Background);
874 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
876 /* Only store the handle when the thread is about to be
877 * launched, to avoid the main thread deadlocking while trying
878 * to clean up a thread that will never be signalled.
880 if (!handle_store (thread, FALSE))
883 mono_thread_info_resume (tid);
885 if (internal->start_notify) {
887 * Wait for the thread to set up its TLS data etc, so
888 * theres no potential race condition if someone tries
889 * to look up the data believing the thread has
892 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));
895 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
898 CloseHandle (internal->start_notify);
899 internal->start_notify = NULL;
902 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));
907 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
909 if (mono_thread_start_cb) {
910 mono_thread_start_cb (tid, stack_start, func);
914 void mono_threads_set_default_stacksize (guint32 stacksize)
916 default_stacksize = stacksize;
919 guint32 mono_threads_get_default_stacksize (void)
921 return default_stacksize;
925 * mono_thread_create_internal:
927 * ARG should not be a GC reference.
930 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
933 MonoInternalThread *internal;
934 StartInfo *start_info;
937 mono_error_init (error);
939 thread = create_thread_object (domain);
941 internal = create_internal_thread ();
943 MONO_OBJECT_SETREF (thread, internal_thread, internal);
945 start_info = g_new0 (StartInfo, 1);
946 start_info->func = (guint32 (*)(void *))func;
947 start_info->obj = thread;
948 start_info->start_arg = arg;
950 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, error);
951 return_val_if_nok (error, NULL);
953 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
954 #ifndef MONO_CROSS_COMPILE
955 if (mono_check_corlib_version () == NULL)
956 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
963 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
966 if (!mono_thread_create_checked (domain, func, arg, &error))
967 mono_error_cleanup (&error);
971 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
973 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
977 mono_thread_attach (MonoDomain *domain)
979 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
985 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
987 MonoThreadInfo *info;
988 MonoInternalThread *thread;
989 MonoThread *current_thread;
990 HANDLE thread_handle;
991 MonoNativeThreadId tid;
993 if ((thread = mono_thread_internal_current ())) {
994 if (domain != mono_domain_get ())
995 mono_domain_set (domain, TRUE);
996 /* Already attached */
997 return mono_thread_current ();
1000 if (!mono_gc_register_thread (&domain)) {
1001 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 ());
1004 thread = create_internal_thread ();
1006 thread_handle = mono_thread_info_open_handle ();
1007 g_assert (thread_handle);
1009 tid=mono_native_thread_id_get ();
1011 thread->handle = thread_handle;
1012 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
1013 thread->stack_ptr = &tid;
1015 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
1017 info = mono_thread_info_current ();
1019 thread->thread_info = info;
1020 thread->small_id = info->small_id;
1022 current_thread = new_thread_with_internal (domain, thread);
1024 if (!handle_store (current_thread, force_attach)) {
1025 /* Mono is shutting down, so just wait for the end */
1027 mono_thread_info_sleep (10000, NULL);
1030 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
1032 SET_CURRENT_OBJECT (thread);
1033 mono_domain_set (domain, TRUE);
1035 thread_adjust_static_data (thread);
1037 init_root_domain_thread (thread, current_thread);
1039 if (domain != mono_get_root_domain ())
1040 set_current_thread_for_domain (domain, thread, current_thread);
1043 if (mono_thread_attach_cb) {
1047 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1050 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1052 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1055 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1056 if (!info->tools_thread)
1057 // FIXME: Need a separate callback
1058 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1060 return current_thread;
1064 mono_thread_detach_internal (MonoInternalThread *thread)
1066 g_return_if_fail (thread != NULL);
1068 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1070 thread_cleanup (thread);
1072 SET_CURRENT_OBJECT (NULL);
1073 mono_domain_unset ();
1075 /* Don't need to CloseHandle this thread, even though we took a
1076 * reference in mono_thread_attach (), because the GC will do it
1077 * when the Thread object is finalised.
1082 mono_thread_detach (MonoThread *thread)
1085 mono_thread_detach_internal (thread->internal_thread);
1089 * mono_thread_detach_if_exiting:
1091 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1092 * This should be used at the end of embedding code which calls into managed code, and which
1093 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1096 mono_thread_detach_if_exiting (void)
1098 if (mono_thread_info_is_exiting ()) {
1099 MonoInternalThread *thread;
1101 thread = mono_thread_internal_current ();
1103 mono_thread_detach_internal (thread);
1104 mono_thread_info_detach ();
1114 MonoInternalThread *thread = mono_thread_internal_current ();
1116 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1118 thread_cleanup (thread);
1119 SET_CURRENT_OBJECT (NULL);
1120 mono_domain_unset ();
1122 /* we could add a callback here for embedders to use. */
1123 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1124 exit (mono_environment_exitcode_get ());
1125 mono_thread_info_exit ();
1129 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1131 MonoInternalThread *internal;
1133 internal = create_internal_thread ();
1135 internal->state = ThreadState_Unstarted;
1137 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1141 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1145 StartInfo *start_info;
1146 MonoInternalThread *internal;
1149 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1151 if (!this_obj->internal_thread)
1152 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1153 internal = this_obj->internal_thread;
1155 LOCK_THREAD (internal);
1157 if ((internal->state & ThreadState_Unstarted) == 0) {
1158 UNLOCK_THREAD (internal);
1159 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1163 if ((internal->state & ThreadState_Aborted) != 0) {
1164 UNLOCK_THREAD (internal);
1167 /* This is freed in start_wrapper */
1168 start_info = g_new0 (StartInfo, 1);
1169 start_info->func = NULL;
1170 start_info->start_arg = NULL;
1171 start_info->delegate = start;
1172 start_info->obj = this_obj;
1173 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1175 res = create_thread (this_obj, internal, start_info, FALSE, 0, &error);
1177 mono_error_cleanup (&error);
1178 UNLOCK_THREAD (internal);
1182 internal->state &= ~ThreadState_Unstarted;
1184 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1186 UNLOCK_THREAD (internal);
1187 return internal->handle;
1191 * This is called from the finalizer of the internal thread object.
1194 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1196 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1199 * Since threads keep a reference to their thread object while running, by the time this function is called,
1200 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1201 * when thread_cleanup () can be called after this.
1204 CloseHandle (thread);
1206 if (this_obj->synch_cs) {
1207 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1208 this_obj->synch_cs = NULL;
1209 mono_coop_mutex_destroy (synch_cs);
1213 if (this_obj->name) {
1214 void *name = this_obj->name;
1215 this_obj->name = NULL;
1221 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1224 MonoInternalThread *thread = mono_thread_internal_current ();
1226 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1228 if (mono_thread_current_check_pending_interrupt ())
1232 gboolean alerted = FALSE;
1234 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1236 res = mono_thread_info_sleep (ms, &alerted);
1238 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1241 MonoException* exc = mono_thread_execute_interruption ();
1243 mono_raise_exception (exc);
1255 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1260 ves_icall_System_Threading_Thread_GetDomainID (void)
1262 return mono_domain_get()->domain_id;
1266 ves_icall_System_Threading_Thread_Yield (void)
1268 return mono_thread_info_yield ();
1272 * mono_thread_get_name:
1274 * Return the name of the thread. NAME_LEN is set to the length of the name.
1275 * Return NULL if the thread has no name. The returned memory is owned by the
1279 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1283 LOCK_THREAD (this_obj);
1285 if (!this_obj->name) {
1289 *name_len = this_obj->name_len;
1290 res = g_new (gunichar2, this_obj->name_len);
1291 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1294 UNLOCK_THREAD (this_obj);
1300 * mono_thread_get_name_utf8:
1302 * Return the name of the thread in UTF-8.
1303 * Return NULL if the thread has no name.
1304 * The returned memory is owned by the caller.
1307 mono_thread_get_name_utf8 (MonoThread *thread)
1312 MonoInternalThread *internal = thread->internal_thread;
1313 if (internal == NULL)
1316 LOCK_THREAD (internal);
1318 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1320 UNLOCK_THREAD (internal);
1326 * mono_thread_get_managed_id:
1328 * Return the Thread.ManagedThreadId value of `thread`.
1329 * Returns -1 if `thread` is NULL.
1332 mono_thread_get_managed_id (MonoThread *thread)
1337 MonoInternalThread *internal = thread->internal_thread;
1338 if (internal == NULL)
1341 int32_t id = internal->managed_id;
1347 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1352 mono_error_init (&error);
1354 LOCK_THREAD (this_obj);
1356 if (!this_obj->name)
1359 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1361 UNLOCK_THREAD (this_obj);
1363 if (mono_error_set_pending_exception (&error))
1370 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1372 LOCK_THREAD (this_obj);
1374 mono_error_init (error);
1376 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1377 UNLOCK_THREAD (this_obj);
1379 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1382 if (this_obj->name) {
1383 g_free (this_obj->name);
1384 this_obj->name_len = 0;
1387 this_obj->name = g_new (gunichar2, mono_string_length (name));
1388 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1389 this_obj->name_len = mono_string_length (name);
1392 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1395 this_obj->name = NULL;
1398 UNLOCK_THREAD (this_obj);
1400 if (this_obj->name && this_obj->tid) {
1401 char *tname = mono_string_to_utf8_checked (name, error);
1402 return_if_nok (error);
1403 mono_profiler_thread_name (this_obj->tid, tname);
1404 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1410 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1413 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1414 mono_error_set_pending_exception (&error);
1418 * ves_icall_System_Threading_Thread_GetPriority_internal:
1419 * @param this_obj: The MonoInternalThread on which to operate.
1421 * Gets the priority of the given thread.
1422 * @return: The priority of the given thread.
1425 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1428 MonoInternalThread *internal = this_obj->internal_thread;
1430 LOCK_THREAD (internal);
1431 if (internal->handle != NULL)
1432 priority = GetThreadPriority (internal->handle) + 2;
1434 priority = this_obj->priority + 2;
1435 UNLOCK_THREAD (internal);
1440 * ves_icall_System_Threading_Thread_SetPriority_internal:
1441 * @param this_obj: The MonoInternalThread on which to operate.
1442 * @param priority: The priority to set.
1444 * Sets the priority of the given thread.
1447 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1449 MonoInternalThread *internal = this_obj->internal_thread;
1451 LOCK_THREAD (internal);
1452 this_obj->priority = priority - 2;
1453 if (internal->handle != NULL)
1454 SetThreadPriority (internal->handle, this_obj->priority);
1455 UNLOCK_THREAD (internal);
1458 /* If the array is already in the requested domain, we just return it,
1459 otherwise we return a copy in that domain. */
1461 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1465 mono_error_init (error);
1469 if (mono_object_domain (arr) == domain)
1472 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1473 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1478 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1481 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1482 mono_error_set_pending_exception (&error);
1487 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1490 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1491 mono_error_set_pending_exception (&error);
1496 mono_thread_current (void)
1498 MonoDomain *domain = mono_domain_get ();
1499 MonoInternalThread *internal = mono_thread_internal_current ();
1500 MonoThread **current_thread_ptr;
1502 g_assert (internal);
1503 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1505 if (!*current_thread_ptr) {
1506 g_assert (domain != mono_get_root_domain ());
1507 *current_thread_ptr = new_thread_with_internal (domain, internal);
1509 return *current_thread_ptr;
1512 /* Return the thread object belonging to INTERNAL in the current domain */
1514 mono_thread_current_for_thread (MonoInternalThread *internal)
1516 MonoDomain *domain = mono_domain_get ();
1517 MonoThread **current_thread_ptr;
1519 g_assert (internal);
1520 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1522 if (!*current_thread_ptr) {
1523 g_assert (domain != mono_get_root_domain ());
1524 *current_thread_ptr = new_thread_with_internal (domain, internal);
1526 return *current_thread_ptr;
1530 mono_thread_internal_current (void)
1532 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1533 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1538 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1540 MonoInternalThread *thread = this_obj->internal_thread;
1541 HANDLE handle = thread->handle;
1542 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1545 if (mono_thread_current_check_pending_interrupt ())
1548 LOCK_THREAD (thread);
1550 if ((thread->state & ThreadState_Unstarted) != 0) {
1551 UNLOCK_THREAD (thread);
1553 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1557 UNLOCK_THREAD (thread);
1562 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1564 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1567 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1570 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1572 if(ret==WAIT_OBJECT_0) {
1573 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1578 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1583 #define MANAGED_WAIT_FAILED 0x7fffffff
1586 map_native_wait_result_to_managed (gint32 val)
1588 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1589 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1593 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1601 mono_error_init (error);
1603 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1606 if (numhandles != 1)
1607 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1609 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1612 if (ret != WAIT_IO_COMPLETION)
1615 exc = mono_thread_execute_interruption ();
1617 mono_error_set_exception_instance (error, exc);
1624 /* Re-calculate ms according to the time passed */
1625 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1626 if (diff_ms >= ms) {
1630 wait = ms - diff_ms;
1636 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1643 MonoObject *waitHandle;
1644 MonoInternalThread *thread = mono_thread_internal_current ();
1646 /* Do this WaitSleepJoin check before creating objects */
1647 if (mono_thread_current_check_pending_interrupt ())
1648 return map_native_wait_result_to_managed (WAIT_FAILED);
1650 /* We fail in managed if the array has more than 64 elements */
1651 numhandles = (guint32)mono_array_length(mono_handles);
1652 handles = g_new0(HANDLE, numhandles);
1654 for(i = 0; i < numhandles; i++) {
1655 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1656 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1663 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1665 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1667 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1671 mono_error_set_pending_exception (&error);
1673 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1674 return map_native_wait_result_to_managed (ret);
1677 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1680 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1681 uintptr_t numhandles;
1684 MonoObject *waitHandle;
1685 MonoInternalThread *thread = mono_thread_internal_current ();
1687 /* Do this WaitSleepJoin check before creating objects */
1688 if (mono_thread_current_check_pending_interrupt ())
1689 return map_native_wait_result_to_managed (WAIT_FAILED);
1691 numhandles = mono_array_length(mono_handles);
1692 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1693 return map_native_wait_result_to_managed (WAIT_FAILED);
1695 for(i = 0; i < numhandles; i++) {
1696 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1697 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1704 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1706 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1708 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1710 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1712 mono_error_set_pending_exception (&error);
1714 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1716 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1717 return map_native_wait_result_to_managed (ret - WAIT_OBJECT_0);
1719 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1720 return map_native_wait_result_to_managed (ret - WAIT_ABANDONED_0);
1723 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1724 return map_native_wait_result_to_managed (ret);
1728 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1732 MonoInternalThread *thread = mono_thread_internal_current ();
1734 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1740 if (mono_thread_current_check_pending_interrupt ())
1741 return map_native_wait_result_to_managed (WAIT_FAILED);
1743 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1745 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1747 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1749 mono_error_set_pending_exception (&error);
1750 return map_native_wait_result_to_managed (ret);
1754 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1757 MonoInternalThread *thread = mono_thread_internal_current ();
1762 if (mono_thread_current_check_pending_interrupt ())
1763 return map_native_wait_result_to_managed (WAIT_FAILED);
1765 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1768 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1771 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1773 return map_native_wait_result_to_managed (ret);
1776 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1783 mutex = CreateMutex (NULL, owned, NULL);
1785 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1787 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1795 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1796 return(ReleaseMutex (handle));
1799 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1805 *error = ERROR_SUCCESS;
1807 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1809 *error = GetLastError ();
1816 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, gint32 *error)
1821 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1823 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1824 mono_string_chars (name));
1827 *error = GetLastError ();
1831 MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, gint32 *prevcount)
1833 return ReleaseSemaphore (handle, releaseCount, prevcount);
1836 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1840 sem = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1841 *error = GetLastError ();
1846 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1853 event = CreateEvent (NULL, manual, initial, NULL);
1855 event = CreateEvent (NULL, manual, initial,
1856 mono_string_chars (name));
1858 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1866 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1867 return (SetEvent(handle));
1870 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1871 return (ResetEvent(handle));
1875 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1876 CloseHandle (handle);
1879 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1885 *error = ERROR_SUCCESS;
1887 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1889 *error = GetLastError ();
1895 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1897 return InterlockedIncrement (location);
1900 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1902 #if SIZEOF_VOID_P == 4
1903 if (G_UNLIKELY ((size_t)location & 0x7)) {
1905 mono_interlocked_lock ();
1908 mono_interlocked_unlock ();
1912 return InterlockedIncrement64 (location);
1915 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1917 return InterlockedDecrement(location);
1920 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1922 #if SIZEOF_VOID_P == 4
1923 if (G_UNLIKELY ((size_t)location & 0x7)) {
1925 mono_interlocked_lock ();
1928 mono_interlocked_unlock ();
1932 return InterlockedDecrement64 (location);
1935 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1937 return InterlockedExchange(location, value);
1940 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1943 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1944 mono_gc_wbarrier_generic_nostore (location);
1948 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1950 return InterlockedExchangePointer(location, value);
1953 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1955 IntFloatUnion val, ret;
1958 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1964 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1966 #if SIZEOF_VOID_P == 4
1967 if (G_UNLIKELY ((size_t)location & 0x7)) {
1969 mono_interlocked_lock ();
1972 mono_interlocked_unlock ();
1976 return InterlockedExchange64 (location, value);
1980 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1982 LongDoubleUnion val, ret;
1985 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1990 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1992 return InterlockedCompareExchange(location, value, comparand);
1995 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1997 gint32 r = InterlockedCompareExchange(location, value, comparand);
1998 *success = r == comparand;
2002 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
2005 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
2006 mono_gc_wbarrier_generic_nostore (location);
2010 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
2012 return InterlockedCompareExchangePointer(location, value, comparand);
2015 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2017 IntFloatUnion val, ret, cmp;
2020 cmp.fval = comparand;
2021 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2027 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2029 #if SIZEOF_VOID_P == 8
2030 LongDoubleUnion val, comp, ret;
2033 comp.fval = comparand;
2034 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2040 mono_interlocked_lock ();
2042 if (old == comparand)
2044 mono_interlocked_unlock ();
2051 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2053 #if SIZEOF_VOID_P == 4
2054 if (G_UNLIKELY ((size_t)location & 0x7)) {
2056 mono_interlocked_lock ();
2058 if (old == comparand)
2060 mono_interlocked_unlock ();
2064 return InterlockedCompareExchange64 (location, value, comparand);
2068 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2071 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2072 mono_gc_wbarrier_generic_nostore (location);
2077 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2080 MONO_CHECK_NULL (location, NULL);
2081 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2082 mono_gc_wbarrier_generic_nostore (location);
2087 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2089 return InterlockedAdd (location, value);
2093 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2095 #if SIZEOF_VOID_P == 4
2096 if (G_UNLIKELY ((size_t)location & 0x7)) {
2098 mono_interlocked_lock ();
2101 mono_interlocked_unlock ();
2105 return InterlockedAdd64 (location, value);
2109 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2111 #if SIZEOF_VOID_P == 4
2112 if (G_UNLIKELY ((size_t)location & 0x7)) {
2114 mono_interlocked_lock ();
2116 mono_interlocked_unlock ();
2120 return InterlockedRead64 (location);
2124 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2126 mono_memory_barrier ();
2130 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2132 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2134 if (state & ThreadState_Background) {
2135 /* If the thread changes the background mode, the main thread has to
2136 * be notified, since it has to rebuild the list of threads to
2139 SetEvent (background_change_event);
2144 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2146 mono_thread_set_state (this_obj, (MonoThreadState)state);
2148 if (state & ThreadState_Background) {
2149 /* If the thread changes the background mode, the main thread has to
2150 * be notified, since it has to rebuild the list of threads to
2153 SetEvent (background_change_event);
2158 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2162 LOCK_THREAD (this_obj);
2164 state = this_obj->state;
2166 UNLOCK_THREAD (this_obj);
2171 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2173 MonoInternalThread *current;
2175 MonoInternalThread *thread = this_obj->internal_thread;
2177 LOCK_THREAD (thread);
2179 current = mono_thread_internal_current ();
2181 thread->thread_interrupt_requested = TRUE;
2182 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2184 UNLOCK_THREAD (thread);
2187 async_abort_internal (thread, FALSE);
2192 * mono_thread_current_check_pending_interrupt:
2194 * Checks if there's a interruption request and set the pending exception if so.
2196 * @returns true if a pending exception was set
2199 mono_thread_current_check_pending_interrupt (void)
2201 MonoInternalThread *thread = mono_thread_internal_current ();
2202 gboolean throw_ = FALSE;
2204 LOCK_THREAD (thread);
2206 if (thread->thread_interrupt_requested) {
2208 thread->thread_interrupt_requested = FALSE;
2211 UNLOCK_THREAD (thread);
2214 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2219 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2221 LOCK_THREAD (thread);
2223 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2224 (thread->state & ThreadState_StopRequested) != 0 ||
2225 (thread->state & ThreadState_Stopped) != 0)
2227 UNLOCK_THREAD (thread);
2231 if ((thread->state & ThreadState_Unstarted) != 0) {
2232 thread->state |= ThreadState_Aborted;
2233 UNLOCK_THREAD (thread);
2237 thread->state |= ThreadState_AbortRequested;
2238 if (thread->abort_state_handle)
2239 mono_gchandle_free (thread->abort_state_handle);
2241 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2242 g_assert (thread->abort_state_handle);
2244 thread->abort_state_handle = 0;
2246 thread->abort_exc = NULL;
2248 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));
2250 /* During shutdown, we can't wait for other threads */
2252 /* Make sure the thread is awake */
2253 mono_thread_resume (thread);
2255 UNLOCK_THREAD (thread);
2260 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2262 if (!request_thread_abort (thread, state))
2265 if (thread == mono_thread_internal_current ()) {
2267 self_abort_internal (&error);
2268 mono_error_set_pending_exception (&error);
2270 async_abort_internal (thread, TRUE);
2275 * mono_thread_internal_abort:
2277 * Request thread @thread to be aborted.
2279 * @thread MUST NOT be the current thread.
2282 mono_thread_internal_abort (MonoInternalThread *thread)
2284 g_assert (thread != mono_thread_internal_current ());
2286 if (!request_thread_abort (thread, NULL))
2288 async_abort_internal (thread, TRUE);
2292 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2294 MonoInternalThread *thread = mono_thread_internal_current ();
2295 gboolean was_aborting;
2297 LOCK_THREAD (thread);
2298 was_aborting = thread->state & ThreadState_AbortRequested;
2299 thread->state &= ~ThreadState_AbortRequested;
2300 UNLOCK_THREAD (thread);
2302 if (!was_aborting) {
2303 const char *msg = "Unable to reset abort because no abort was requested";
2304 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2307 thread->abort_exc = NULL;
2308 if (thread->abort_state_handle) {
2309 mono_gchandle_free (thread->abort_state_handle);
2310 /* This is actually not necessary - the handle
2311 only counts if the exception is set */
2312 thread->abort_state_handle = 0;
2317 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2319 LOCK_THREAD (thread);
2321 thread->state &= ~ThreadState_AbortRequested;
2323 if (thread->abort_exc) {
2324 thread->abort_exc = NULL;
2325 if (thread->abort_state_handle) {
2326 mono_gchandle_free (thread->abort_state_handle);
2327 /* This is actually not necessary - the handle
2328 only counts if the exception is set */
2329 thread->abort_state_handle = 0;
2333 UNLOCK_THREAD (thread);
2337 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2340 MonoInternalThread *thread = this_obj->internal_thread;
2341 MonoObject *state, *deserialized = NULL;
2344 if (!thread->abort_state_handle)
2347 state = mono_gchandle_get_target (thread->abort_state_handle);
2350 domain = mono_domain_get ();
2351 if (mono_object_domain (state) == domain)
2354 deserialized = mono_object_xdomain_representation (state, domain, &error);
2356 if (!deserialized) {
2357 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2358 if (!is_ok (&error)) {
2359 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2360 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2362 mono_set_pending_exception (invalid_op_exc);
2366 return deserialized;
2370 mono_thread_suspend (MonoInternalThread *thread)
2372 LOCK_THREAD (thread);
2374 if ((thread->state & ThreadState_Unstarted) != 0 ||
2375 (thread->state & ThreadState_Aborted) != 0 ||
2376 (thread->state & ThreadState_Stopped) != 0)
2378 UNLOCK_THREAD (thread);
2382 if ((thread->state & ThreadState_Suspended) != 0 ||
2383 (thread->state & ThreadState_SuspendRequested) != 0 ||
2384 (thread->state & ThreadState_StopRequested) != 0)
2386 UNLOCK_THREAD (thread);
2390 thread->state |= ThreadState_SuspendRequested;
2392 if (thread == mono_thread_internal_current ()) {
2393 /* calls UNLOCK_THREAD (thread) */
2394 self_suspend_internal ();
2396 /* calls UNLOCK_THREAD (thread) */
2397 async_suspend_internal (thread, FALSE);
2404 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2406 if (!mono_thread_suspend (this_obj->internal_thread)) {
2407 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2412 /* LOCKING: LOCK_THREAD(thread) must be held */
2414 mono_thread_resume (MonoInternalThread *thread)
2416 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2417 thread->state &= ~ThreadState_SuspendRequested;
2421 if ((thread->state & ThreadState_Suspended) == 0 ||
2422 (thread->state & ThreadState_Unstarted) != 0 ||
2423 (thread->state & ThreadState_Aborted) != 0 ||
2424 (thread->state & ThreadState_Stopped) != 0)
2429 UNLOCK_THREAD (thread);
2431 /* Awake the thread */
2432 if (!mono_thread_info_resume (thread_get_tid (thread)))
2435 LOCK_THREAD (thread);
2437 thread->state &= ~ThreadState_Suspended;
2443 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2445 if (!thread->internal_thread) {
2446 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2448 LOCK_THREAD (thread->internal_thread);
2449 if (!mono_thread_resume (thread->internal_thread))
2450 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2451 UNLOCK_THREAD (thread->internal_thread);
2456 mono_threads_is_critical_method (MonoMethod *method)
2458 switch (method->wrapper_type) {
2459 case MONO_WRAPPER_RUNTIME_INVOKE:
2460 case MONO_WRAPPER_XDOMAIN_INVOKE:
2461 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2468 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2473 if (mono_threads_is_critical_method (m)) {
2474 *((gboolean*)data) = TRUE;
2481 is_running_protected_wrapper (void)
2483 gboolean found = FALSE;
2484 mono_stack_walk (find_wrapper, &found);
2489 request_thread_stop (MonoInternalThread *thread)
2491 LOCK_THREAD (thread);
2493 if ((thread->state & ThreadState_StopRequested) != 0 ||
2494 (thread->state & ThreadState_Stopped) != 0)
2496 UNLOCK_THREAD (thread);
2500 /* Make sure the thread is awake */
2501 mono_thread_resume (thread);
2503 thread->state |= ThreadState_StopRequested;
2504 thread->state &= ~ThreadState_AbortRequested;
2506 UNLOCK_THREAD (thread);
2511 * mono_thread_internal_stop:
2513 * Request thread @thread to stop.
2515 * @thread MUST NOT be the current thread.
2518 mono_thread_internal_stop (MonoInternalThread *thread)
2520 g_assert (thread != mono_thread_internal_current ());
2522 if (!request_thread_stop (thread))
2525 async_abort_internal (thread, TRUE);
2528 void mono_thread_stop (MonoThread *thread)
2530 MonoInternalThread *internal = thread->internal_thread;
2532 if (!request_thread_stop (internal))
2535 if (internal == mono_thread_internal_current ()) {
2537 self_abort_internal (&error);
2539 This function is part of the embeding API and has no way to return the exception
2540 to be thrown. So what we do is keep the old behavior and raise the exception.
2542 mono_error_raise_exception (&error); /* OK to throw, see note */
2544 async_abort_internal (internal, TRUE);
2549 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2551 gint8 tmp = *(volatile gint8 *)ptr;
2552 mono_memory_barrier ();
2557 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2559 gint16 tmp = *(volatile gint16 *)ptr;
2560 mono_memory_barrier ();
2565 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2567 gint32 tmp = *(volatile gint32 *)ptr;
2568 mono_memory_barrier ();
2573 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2575 gint64 tmp = *(volatile gint64 *)ptr;
2576 mono_memory_barrier ();
2581 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2583 volatile void *tmp = *(volatile void **)ptr;
2584 mono_memory_barrier ();
2585 return (void *) tmp;
2589 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2591 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2592 mono_memory_barrier ();
2593 return (MonoObject *) tmp;
2597 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2599 double tmp = *(volatile double *)ptr;
2600 mono_memory_barrier ();
2605 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2607 float tmp = *(volatile float *)ptr;
2608 mono_memory_barrier ();
2613 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2615 return InterlockedRead8 ((volatile gint8 *)ptr);
2619 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2621 return InterlockedRead16 ((volatile gint16 *)ptr);
2625 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2627 return InterlockedRead ((volatile gint32 *)ptr);
2631 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2633 #if SIZEOF_VOID_P == 4
2634 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2636 mono_interlocked_lock ();
2637 val = *(gint64*)ptr;
2638 mono_interlocked_unlock ();
2642 return InterlockedRead64 ((volatile gint64 *)ptr);
2646 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2648 return InterlockedReadPointer ((volatile gpointer *)ptr);
2652 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2656 #if SIZEOF_VOID_P == 4
2657 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2659 mono_interlocked_lock ();
2660 val = *(double*)ptr;
2661 mono_interlocked_unlock ();
2666 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2672 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2676 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2682 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2684 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2688 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2690 mono_memory_barrier ();
2691 *(volatile gint8 *)ptr = value;
2695 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2697 mono_memory_barrier ();
2698 *(volatile gint16 *)ptr = value;
2702 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2704 mono_memory_barrier ();
2705 *(volatile gint32 *)ptr = value;
2709 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2711 mono_memory_barrier ();
2712 *(volatile gint64 *)ptr = value;
2716 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2718 mono_memory_barrier ();
2719 *(volatile void **)ptr = value;
2723 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2725 mono_memory_barrier ();
2726 mono_gc_wbarrier_generic_store (ptr, value);
2730 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2732 mono_memory_barrier ();
2733 *(volatile double *)ptr = value;
2737 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2739 mono_memory_barrier ();
2740 *(volatile float *)ptr = value;
2744 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2746 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2750 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2752 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2756 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2758 InterlockedWrite ((volatile gint32 *)ptr, value);
2762 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2764 #if SIZEOF_VOID_P == 4
2765 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2766 mono_interlocked_lock ();
2767 *(gint64*)ptr = value;
2768 mono_interlocked_unlock ();
2773 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2777 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2779 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2783 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2787 #if SIZEOF_VOID_P == 4
2788 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2789 mono_interlocked_lock ();
2790 *(double*)ptr = value;
2791 mono_interlocked_unlock ();
2798 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2802 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2808 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2812 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2814 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2818 free_context (void *user_data)
2820 ContextStaticData *data = user_data;
2822 mono_threads_lock ();
2825 * There is no guarantee that, by the point this reference queue callback
2826 * has been invoked, the GC handle associated with the object will fail to
2827 * resolve as one might expect. So if we don't free and remove the GC
2828 * handle here, free_context_static_data_helper () could end up resolving
2829 * a GC handle to an actually-dead context which would contain a pointer
2830 * to an already-freed static data segment, resulting in a crash when
2833 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2835 mono_threads_unlock ();
2837 mono_gchandle_free (data->gc_handle);
2838 mono_free_static_data (data->static_data);
2843 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2845 mono_threads_lock ();
2847 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2850 contexts = g_hash_table_new (NULL, NULL);
2853 context_queue = mono_gc_reference_queue_new (free_context);
2855 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2856 g_hash_table_insert (contexts, gch, gch);
2859 * We use this intermediate structure to contain a duplicate pointer to
2860 * the static data because we can't rely on being able to resolve the GC
2861 * handle in the reference queue callback.
2863 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2864 data->gc_handle = GPOINTER_TO_UINT (gch);
2867 context_adjust_static_data (ctx);
2868 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2870 mono_threads_unlock ();
2872 mono_profiler_context_loaded (ctx);
2876 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2879 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2880 * cleanup in exceptional circumstances, we don't actually do any
2881 * cleanup work here. We instead do this via a reference queue.
2884 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2886 mono_profiler_context_unloaded (ctx);
2890 mono_thread_init_tls (void)
2892 MONO_FAST_TLS_INIT (tls_current_object);
2893 mono_native_tls_alloc (¤t_object_key, NULL);
2896 void mono_thread_init (MonoThreadStartCB start_cb,
2897 MonoThreadAttachCB attach_cb)
2899 mono_coop_mutex_init_recursive (&threads_mutex);
2901 mono_os_mutex_init_recursive(&interlocked_mutex);
2902 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2904 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2905 g_assert(background_change_event != NULL);
2907 mono_init_static_data_info (&thread_static_info);
2908 mono_init_static_data_info (&context_static_info);
2910 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2912 mono_thread_start_cb = start_cb;
2913 mono_thread_attach_cb = attach_cb;
2915 /* Get a pseudo handle to the current process. This is just a
2916 * kludge so that wapi can build a process handle if needed.
2917 * As a pseudo handle is returned, we don't need to clean
2920 GetCurrentProcess ();
2923 void mono_thread_cleanup (void)
2925 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2926 MonoThreadInfo *info;
2928 /* The main thread must abandon any held mutexes (particularly
2929 * important for named mutexes as they are shared across
2930 * processes, see bug 74680.) This will happen when the
2931 * thread exits, but if it's not running in a subthread it
2932 * won't exit in time.
2934 info = mono_thread_info_current ();
2935 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2939 /* This stuff needs more testing, it seems one of these
2940 * critical sections can be locked when mono_thread_cleanup is
2943 mono_coop_mutex_destroy (&threads_mutex);
2944 mono_os_mutex_destroy (&interlocked_mutex);
2945 mono_os_mutex_destroy (&delayed_free_table_mutex);
2946 mono_os_mutex_destroy (&small_id_mutex);
2947 CloseHandle (background_change_event);
2950 mono_native_tls_free (current_object_key);
2954 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2956 mono_thread_cleanup_fn = func;
2960 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2962 thread->internal_thread->manage_callback = func;
2966 static void print_tids (gpointer key, gpointer value, gpointer user)
2968 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2969 * sizeof(uint) and a cast to uint would overflow
2971 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2972 * print this as a pointer.
2974 g_message ("Waiting for: %p", key);
2979 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2980 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2984 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2988 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2991 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2994 if(ret==WAIT_FAILED) {
2995 /* See the comment in build_wait_tids() */
2996 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3000 for(i=0; i<wait->num; i++)
3001 CloseHandle (wait->handles[i]);
3003 if (ret == WAIT_TIMEOUT)
3006 for(i=0; i<wait->num; i++) {
3007 gsize tid = wait->threads[i]->tid;
3010 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
3011 * it can still run io-layer etc. code. So wait for it to really exit.
3012 * FIXME: This won't join threads which are not in the joinable_hash yet.
3014 mono_thread_join ((gpointer)tid);
3016 mono_threads_lock ();
3017 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3018 /* This thread must have been killed, because
3019 * it hasn't cleaned itself up. (It's just
3020 * possible that the thread exited before the
3021 * parent thread had a chance to store the
3022 * handle, and now there is another pointer to
3023 * the already-exited thread stored. In this
3024 * case, we'll just get two
3025 * mono_profiler_thread_end() calls for the
3029 mono_threads_unlock ();
3030 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
3031 thread_cleanup (wait->threads[i]);
3033 mono_threads_unlock ();
3038 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
3040 guint32 i, ret, count;
3042 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3044 /* Add the thread state change event, so it wakes up if a thread changes
3045 * to background mode.
3048 if (count < MAXIMUM_WAIT_OBJECTS) {
3049 wait->handles [count] = background_change_event;
3054 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
3057 if(ret==WAIT_FAILED) {
3058 /* See the comment in build_wait_tids() */
3059 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3063 for(i=0; i<wait->num; i++)
3064 CloseHandle (wait->handles[i]);
3066 if (ret == WAIT_TIMEOUT)
3069 if (ret < wait->num) {
3070 gsize tid = wait->threads[ret]->tid;
3071 mono_threads_lock ();
3072 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3073 /* See comment in wait_for_tids about thread cleanup */
3074 mono_threads_unlock ();
3075 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3076 thread_cleanup (wait->threads [ret]);
3078 mono_threads_unlock ();
3082 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3084 struct wait_data *wait=(struct wait_data *)user;
3086 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
3088 MonoInternalThread *thread=(MonoInternalThread *)value;
3090 /* Ignore background threads, we abort them later */
3091 /* Do not lock here since it is not needed and the caller holds threads_lock */
3092 if (thread->state & ThreadState_Background) {
3093 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3094 return; /* just leave, ignore */
3097 if (mono_gc_is_finalizer_internal_thread (thread)) {
3098 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3102 if (thread == mono_thread_internal_current ()) {
3103 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3107 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3108 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3112 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3113 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3117 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3118 if (handle == NULL) {
3119 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3123 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3124 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3125 wait->handles[wait->num]=handle;
3126 wait->threads[wait->num]=thread;
3129 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3131 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3136 /* Just ignore the rest, we can't do anything with
3143 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3145 struct wait_data *wait=(struct wait_data *)user;
3146 MonoNativeThreadId self = mono_native_thread_id_get ();
3147 MonoInternalThread *thread = (MonoInternalThread *)value;
3150 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
3153 /* The finalizer thread is not a background thread */
3154 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3155 && (thread->state & ThreadState_Background) != 0
3156 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3158 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3162 wait->handles[wait->num] = handle;
3163 wait->threads[wait->num] = thread;
3166 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3167 mono_thread_internal_abort (thread);
3171 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3172 && !mono_gc_is_finalizer_internal_thread (thread);
3176 * mono_threads_set_shutting_down:
3178 * Is called by a thread that wants to shut down Mono. If the runtime is already
3179 * shutting down, the calling thread is suspended/stopped, and this function never
3183 mono_threads_set_shutting_down (void)
3185 MonoInternalThread *current_thread = mono_thread_internal_current ();
3187 mono_threads_lock ();
3189 if (shutting_down) {
3190 mono_threads_unlock ();
3192 /* Make sure we're properly suspended/stopped */
3194 LOCK_THREAD (current_thread);
3196 if ((current_thread->state & ThreadState_SuspendRequested) ||
3197 (current_thread->state & ThreadState_AbortRequested) ||
3198 (current_thread->state & ThreadState_StopRequested)) {
3199 UNLOCK_THREAD (current_thread);
3200 mono_thread_execute_interruption ();
3202 current_thread->state |= ThreadState_Stopped;
3203 UNLOCK_THREAD (current_thread);
3206 /*since we're killing the thread, unset the current domain.*/
3207 mono_domain_unset ();
3209 /* Wake up other threads potentially waiting for us */
3210 mono_thread_info_exit ();
3212 shutting_down = TRUE;
3214 /* Not really a background state change, but this will
3215 * interrupt the main thread if it is waiting for all
3216 * the other threads.
3218 SetEvent (background_change_event);
3220 mono_threads_unlock ();
3224 void mono_thread_manage (void)
3226 struct wait_data wait_data;
3227 struct wait_data *wait = &wait_data;
3229 memset (wait, 0, sizeof (struct wait_data));
3230 /* join each thread that's still running */
3231 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3233 mono_threads_lock ();
3235 THREAD_DEBUG (g_message("%s: No threads", __func__));
3236 mono_threads_unlock ();
3239 mono_threads_unlock ();
3242 mono_threads_lock ();
3243 if (shutting_down) {
3244 /* somebody else is shutting down */
3245 mono_threads_unlock ();
3248 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3249 mono_g_hash_table_foreach (threads, print_tids, NULL));
3251 ResetEvent (background_change_event);
3253 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3254 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3255 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3256 mono_threads_unlock ();
3258 /* Something to wait for */
3259 wait_for_tids_or_state_change (wait, INFINITE);
3261 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3262 } while(wait->num>0);
3264 /* Mono is shutting down, so just wait for the end */
3265 if (!mono_runtime_try_shutdown ()) {
3266 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3267 mono_thread_suspend (mono_thread_internal_current ());
3268 mono_thread_execute_interruption ();
3272 * Remove everything but the finalizer thread and self.
3273 * Also abort all the background threads
3276 mono_threads_lock ();
3279 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3280 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3281 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3283 mono_threads_unlock ();
3285 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3287 /* Something to wait for */
3288 wait_for_tids (wait, INFINITE);
3290 } while (wait->num > 0);
3293 * give the subthreads a chance to really quit (this is mainly needed
3294 * to get correct user and system times from getrusage/wait/time(1)).
3295 * This could be removed if we avoid pthread_detach() and use pthread_join().
3297 mono_thread_info_yield ();
3301 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3303 MonoInternalThread *thread = (MonoInternalThread*)value;
3304 struct wait_data *wait = (struct wait_data*)user_data;
3308 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3310 * This needs no locking.
3312 if ((thread->state & ThreadState_Suspended) != 0 ||
3313 (thread->state & ThreadState_Stopped) != 0)
3316 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3317 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3321 wait->handles [wait->num] = handle;
3322 wait->threads [wait->num] = thread;
3328 * mono_thread_suspend_all_other_threads:
3330 * Suspend all managed threads except the finalizer thread and this thread. It is
3331 * not possible to resume them later.
3333 void mono_thread_suspend_all_other_threads (void)
3335 struct wait_data wait_data;
3336 struct wait_data *wait = &wait_data;
3338 MonoNativeThreadId self = mono_native_thread_id_get ();
3339 guint32 eventidx = 0;
3340 gboolean starting, finished;
3342 memset (wait, 0, sizeof (struct wait_data));
3344 * The other threads could be in an arbitrary state at this point, i.e.
3345 * they could be starting up, shutting down etc. This means that there could be
3346 * threads which are not even in the threads hash table yet.
3350 * First we set a barrier which will be checked by all threads before they
3351 * are added to the threads hash table, and they will exit if the flag is set.
3352 * This ensures that no threads could be added to the hash later.
3353 * We will use shutting_down as the barrier for now.
3355 g_assert (shutting_down);
3358 * We make multiple calls to WaitForMultipleObjects since:
3359 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3360 * - some threads could exit without becoming suspended
3365 * Make a copy of the hashtable since we can't do anything with
3366 * threads while threads_mutex is held.
3369 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3370 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3371 mono_threads_lock ();
3372 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3373 mono_threads_unlock ();
3376 /* Get the suspended events that we'll be waiting for */
3377 for (i = 0; i < wait->num; ++i) {
3378 MonoInternalThread *thread = wait->threads [i];
3380 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3381 || mono_gc_is_finalizer_internal_thread (thread)
3382 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3384 //CloseHandle (wait->handles [i]);
3385 wait->threads [i] = NULL; /* ignore this thread in next loop */
3389 LOCK_THREAD (thread);
3391 if ((thread->state & ThreadState_Suspended) != 0 ||
3392 (thread->state & ThreadState_StopRequested) != 0 ||
3393 (thread->state & ThreadState_Stopped) != 0) {
3394 UNLOCK_THREAD (thread);
3395 CloseHandle (wait->handles [i]);
3396 wait->threads [i] = NULL; /* ignore this thread in next loop */
3402 /* Convert abort requests into suspend requests */
3403 if ((thread->state & ThreadState_AbortRequested) != 0)
3404 thread->state &= ~ThreadState_AbortRequested;
3406 thread->state |= ThreadState_SuspendRequested;
3408 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3409 async_suspend_internal (thread, TRUE);
3411 if (eventidx <= 0) {
3413 * If there are threads which are starting up, we wait until they
3414 * are suspended when they try to register in the threads hash.
3415 * This is guaranteed to finish, since the threads which can create new
3416 * threads get suspended after a while.
3417 * FIXME: The finalizer thread can still create new threads.
3419 mono_threads_lock ();
3420 if (threads_starting_up)
3421 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3424 mono_threads_unlock ();
3426 mono_thread_info_sleep (100, NULL);
3434 MonoInternalThread *thread;
3435 MonoStackFrameInfo *frames;
3436 int nframes, max_frames;
3437 int nthreads, max_threads;
3438 MonoInternalThread **threads;
3439 } ThreadDumpUserData;
3441 static gboolean thread_dump_requested;
3443 /* This needs to be async safe */
3445 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3447 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3449 if (ud->nframes < ud->max_frames) {
3450 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3457 /* This needs to be async safe */
3458 static SuspendThreadResult
3459 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3461 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3462 MonoInternalThread *thread = user_data->thread;
3465 /* This no longer works with remote unwinding */
3467 wapi_desc = wapi_current_thread_desc ();
3468 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3473 if (thread == mono_thread_internal_current ())
3474 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3476 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3478 return MonoResumeThread;
3482 int nthreads, max_threads;
3483 MonoInternalThread **threads;
3484 } CollectThreadsUserData;
3487 collect_thread (gpointer key, gpointer value, gpointer user)
3489 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3490 MonoInternalThread *thread = (MonoInternalThread *)value;
3492 if (ud->nthreads < ud->max_threads)
3493 ud->threads [ud->nthreads ++] = thread;
3497 * Collect running threads into the THREADS array.
3498 * THREADS should be an array allocated on the stack.
3501 collect_threads (MonoInternalThread **thread_array, int max_threads)
3503 CollectThreadsUserData ud;
3505 memset (&ud, 0, sizeof (ud));
3506 /* This array contains refs, but its on the stack, so its ok */
3507 ud.threads = thread_array;
3508 ud.max_threads = max_threads;
3510 mono_threads_lock ();
3511 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3512 mono_threads_unlock ();
3518 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3520 GString* text = g_string_new (0);
3522 GError *error = NULL;
3525 ud->thread = thread;
3528 /* Collect frames for the thread */
3529 if (thread == mono_thread_internal_current ()) {
3530 get_thread_dump (mono_thread_info_current (), ud);
3532 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3536 * Do all the non async-safe work outside of get_thread_dump.
3539 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3541 g_string_append_printf (text, "\n\"%s\"", name);
3544 else if (thread->threadpool_thread) {
3545 g_string_append (text, "\n\"<threadpool thread>\"");
3547 g_string_append (text, "\n\"<unnamed thread>\"");
3550 for (i = 0; i < ud->nframes; ++i) {
3551 MonoStackFrameInfo *frame = &ud->frames [i];
3552 MonoMethod *method = NULL;
3554 if (frame->type == FRAME_TYPE_MANAGED)
3555 method = mono_jit_info_get_method (frame->ji);
3558 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3559 g_string_append_printf (text, " %s\n", location);
3562 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3566 fprintf (stdout, "%s", text->str);
3568 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3569 OutputDebugStringA(text->str);
3572 g_string_free (text, TRUE);
3577 mono_threads_perform_thread_dump (void)
3579 ThreadDumpUserData ud;
3580 MonoInternalThread *thread_array [128];
3581 int tindex, nthreads;
3583 if (!thread_dump_requested)
3586 printf ("Full thread dump:\n");
3588 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3589 nthreads = collect_threads (thread_array, 128);
3591 memset (&ud, 0, sizeof (ud));
3592 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3593 ud.max_frames = 256;
3595 for (tindex = 0; tindex < nthreads; ++tindex)
3596 dump_thread (thread_array [tindex], &ud);
3600 thread_dump_requested = FALSE;
3603 /* Obtain the thread dump of all threads */
3605 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3608 ThreadDumpUserData ud;
3609 MonoInternalThread *thread_array [128];
3610 MonoDomain *domain = mono_domain_get ();
3611 MonoDebugSourceLocation *location;
3612 int tindex, nthreads;
3614 mono_error_init (error);
3616 *out_threads = NULL;
3617 *out_stack_frames = NULL;
3619 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3620 nthreads = collect_threads (thread_array, 128);
3622 memset (&ud, 0, sizeof (ud));
3623 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3624 ud.max_frames = 256;
3626 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3629 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3633 for (tindex = 0; tindex < nthreads; ++tindex) {
3634 MonoInternalThread *thread = thread_array [tindex];
3635 MonoArray *thread_frames;
3641 /* Collect frames for the thread */
3642 if (thread == mono_thread_internal_current ()) {
3643 get_thread_dump (mono_thread_info_current (), &ud);
3645 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3648 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3650 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3653 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3655 for (i = 0; i < ud.nframes; ++i) {
3656 MonoStackFrameInfo *frame = &ud.frames [i];
3657 MonoMethod *method = NULL;
3658 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3662 sf->native_offset = frame->native_offset;
3664 if (frame->type == FRAME_TYPE_MANAGED)
3665 method = mono_jit_info_get_method (frame->ji);
3668 sf->method_address = (gsize) frame->ji->code_start;
3670 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3673 MONO_OBJECT_SETREF (sf, method, rm);
3675 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3677 sf->il_offset = location->il_offset;
3679 if (location && location->source_file) {
3680 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3681 sf->line = location->row;
3682 sf->column = location->column;
3684 mono_debug_free_source_location (location);
3689 mono_array_setref (thread_frames, i, sf);
3695 return is_ok (error);
3699 * mono_threads_request_thread_dump:
3701 * Ask all threads except the current to print their stacktrace to stdout.
3704 mono_threads_request_thread_dump (void)
3706 /*The new thread dump code runs out of the finalizer thread. */
3707 thread_dump_requested = TRUE;
3708 mono_gc_finalize_notify ();
3713 gint allocated; /* +1 so that refs [allocated] == NULL */
3717 typedef struct ref_stack RefStack;
3720 ref_stack_new (gint initial_size)
3724 initial_size = MAX (initial_size, 16) + 1;
3725 rs = g_new0 (RefStack, 1);
3726 rs->refs = g_new0 (gpointer, initial_size);
3727 rs->allocated = initial_size;
3732 ref_stack_destroy (gpointer ptr)
3734 RefStack *rs = (RefStack *)ptr;
3743 ref_stack_push (RefStack *rs, gpointer ptr)
3745 g_assert (rs != NULL);
3747 if (rs->bottom >= rs->allocated) {
3748 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3749 rs->allocated <<= 1;
3750 rs->refs [rs->allocated] = NULL;
3752 rs->refs [rs->bottom++] = ptr;
3756 ref_stack_pop (RefStack *rs)
3758 if (rs == NULL || rs->bottom == 0)
3762 rs->refs [rs->bottom] = NULL;
3766 ref_stack_find (RefStack *rs, gpointer ptr)
3773 for (refs = rs->refs; refs && *refs; refs++) {
3781 * mono_thread_push_appdomain_ref:
3783 * Register that the current thread may have references to objects in domain
3784 * @domain on its stack. Each call to this function should be paired with a
3785 * call to pop_appdomain_ref.
3788 mono_thread_push_appdomain_ref (MonoDomain *domain)
3790 MonoInternalThread *thread = mono_thread_internal_current ();
3793 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3794 SPIN_LOCK (thread->lock_thread_id);
3795 if (thread->appdomain_refs == NULL)
3796 thread->appdomain_refs = ref_stack_new (16);
3797 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3798 SPIN_UNLOCK (thread->lock_thread_id);
3803 mono_thread_pop_appdomain_ref (void)
3805 MonoInternalThread *thread = mono_thread_internal_current ();
3808 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3809 SPIN_LOCK (thread->lock_thread_id);
3810 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3811 SPIN_UNLOCK (thread->lock_thread_id);
3816 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3819 SPIN_LOCK (thread->lock_thread_id);
3820 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3821 SPIN_UNLOCK (thread->lock_thread_id);
3826 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3828 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3831 typedef struct abort_appdomain_data {
3832 struct wait_data wait;
3834 } abort_appdomain_data;
3837 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3839 MonoInternalThread *thread = (MonoInternalThread*)value;
3840 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3841 MonoDomain *domain = data->domain;
3843 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3844 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3846 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3847 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3850 data->wait.handles [data->wait.num] = handle;
3851 data->wait.threads [data->wait.num] = thread;
3854 /* Just ignore the rest, we can't do anything with
3862 * mono_threads_abort_appdomain_threads:
3864 * Abort threads which has references to the given appdomain.
3867 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3869 #ifdef __native_client__
3873 abort_appdomain_data user_data;
3875 int orig_timeout = timeout;
3878 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3880 start_time = mono_msec_ticks ();
3882 mono_threads_lock ();
3884 user_data.domain = domain;
3885 user_data.wait.num = 0;
3886 /* This shouldn't take any locks */
3887 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3888 mono_threads_unlock ();
3890 if (user_data.wait.num > 0) {
3891 /* Abort the threads outside the threads lock */
3892 for (i = 0; i < user_data.wait.num; ++i)
3893 mono_thread_internal_abort (user_data.wait.threads [i]);
3896 * We should wait for the threads either to abort, or to leave the
3897 * domain. We can't do the latter, so we wait with a timeout.
3899 wait_for_tids (&user_data.wait, 100);
3902 /* Update remaining time */
3903 timeout -= mono_msec_ticks () - start_time;
3904 start_time = mono_msec_ticks ();
3906 if (orig_timeout != -1 && timeout < 0)
3909 while (user_data.wait.num > 0);
3911 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3917 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3919 MonoInternalThread *thread = (MonoInternalThread*)value;
3920 MonoDomain *domain = (MonoDomain*)user_data;
3923 /* No locking needed here */
3924 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3926 if (thread->cached_culture_info) {
3927 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3928 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3929 if (obj && obj->vtable->domain == domain)
3930 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3936 * mono_threads_clear_cached_culture:
3938 * Clear the cached_current_culture from all threads if it is in the
3942 mono_threads_clear_cached_culture (MonoDomain *domain)
3944 mono_threads_lock ();
3945 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3946 mono_threads_unlock ();
3950 * mono_thread_get_undeniable_exception:
3952 * Return an exception which needs to be raised when leaving a catch clause.
3953 * This is used for undeniable exception propagation.
3956 mono_thread_get_undeniable_exception (void)
3958 MonoInternalThread *thread = mono_thread_internal_current ();
3960 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3962 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3963 * exception if the thread no longer references a dying appdomain.
3965 thread->abort_exc->trace_ips = NULL;
3966 thread->abort_exc->stack_trace = NULL;
3967 return thread->abort_exc;
3973 #if MONO_SMALL_CONFIG
3974 #define NUM_STATIC_DATA_IDX 4
3975 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3979 #define NUM_STATIC_DATA_IDX 8
3980 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3981 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3985 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3986 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3989 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3991 gpointer *static_data = (gpointer *)addr;
3993 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3994 void **ptr = (void **)static_data [i];
3999 MONO_BITSET_FOREACH (bitmaps [i], idx, {
4000 void **p = ptr + idx;
4003 mark_func ((MonoObject**)p, gc_data);
4009 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4011 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
4015 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4017 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
4021 * mono_alloc_static_data
4023 * Allocate memory blocks for storing threads or context static data
4026 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4028 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4031 gpointer* static_data = *static_data_ptr;
4033 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4034 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4036 if (mono_gc_user_markers_supported ()) {
4037 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4038 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4040 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4041 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4044 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4045 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4046 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4047 *static_data_ptr = static_data;
4048 static_data [0] = static_data;
4051 for (i = 1; i <= idx; ++i) {
4052 if (static_data [i])
4055 if (mono_gc_user_markers_supported ())
4056 static_data [i] = g_malloc0 (static_data_size [i]);
4058 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4059 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4060 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4065 mono_free_static_data (gpointer* static_data)
4068 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4069 gpointer p = static_data [i];
4073 * At this point, the static data pointer array is still registered with the
4074 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4075 * data. Freeing the individual arrays without first nulling their slots
4076 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4077 * such an already freed array. See bug #13813.
4079 static_data [i] = NULL;
4080 mono_memory_write_barrier ();
4081 if (mono_gc_user_markers_supported ())
4084 mono_gc_free_fixed (p);
4086 mono_gc_free_fixed (static_data);
4090 * mono_init_static_data_info
4092 * Initializes static data counters
4094 static void mono_init_static_data_info (StaticDataInfo *static_data)
4096 static_data->idx = 0;
4097 static_data->offset = 0;
4098 static_data->freelist = NULL;
4102 * mono_alloc_static_data_slot
4104 * Generates an offset for static data. static_data contains the counters
4105 * used to generate it.
4108 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4110 if (!static_data->idx && !static_data->offset) {
4112 * we use the first chunk of the first allocation also as
4113 * an array for the rest of the data
4115 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4117 static_data->offset += align - 1;
4118 static_data->offset &= ~(align - 1);
4119 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4120 static_data->idx ++;
4121 g_assert (size <= static_data_size [static_data->idx]);
4122 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4123 static_data->offset = 0;
4125 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4126 static_data->offset += size;
4131 * ensure thread static fields already allocated are valid for thread
4132 * This function is called when a thread is created or on thread attach.
4135 thread_adjust_static_data (MonoInternalThread *thread)
4137 mono_threads_lock ();
4138 if (thread_static_info.offset || thread_static_info.idx > 0) {
4139 /* get the current allocated size */
4140 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
4141 mono_alloc_static_data (&thread->static_data, offset, TRUE);
4143 mono_threads_unlock ();
4147 * LOCKING: requires that threads_mutex is held
4150 context_adjust_static_data (MonoAppContext *ctx)
4152 if (context_static_info.offset || context_static_info.idx > 0) {
4153 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4154 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4155 ctx->data->static_data = ctx->static_data;
4160 * LOCKING: requires that threads_mutex is held
4163 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4165 MonoInternalThread *thread = (MonoInternalThread *)value;
4166 guint32 offset = GPOINTER_TO_UINT (user);
4168 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4172 * LOCKING: requires that threads_mutex is held
4175 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4177 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4182 guint32 offset = GPOINTER_TO_UINT (user);
4183 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4184 ctx->data->static_data = ctx->static_data;
4187 static StaticDataFreeList*
4188 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4190 StaticDataFreeList* prev = NULL;
4191 StaticDataFreeList* tmp = static_data->freelist;
4193 if (tmp->size == size) {
4195 prev->next = tmp->next;
4197 static_data->freelist = tmp->next;
4206 #if SIZEOF_VOID_P == 4
4213 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4215 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4217 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4218 MonoBitSet *rb = sets [idx];
4219 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4220 offset /= sizeof (uintptr_t);
4221 /* offset is now the bitmap offset */
4222 for (int i = 0; i < numbits; ++i) {
4223 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4224 mono_bitset_set_fast (rb, offset + i);
4229 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4231 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4232 MonoBitSet *rb = sets [idx];
4233 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4234 offset /= sizeof (uintptr_t);
4235 /* offset is now the bitmap offset */
4236 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4237 mono_bitset_clear_fast (rb, offset + i);
4241 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4243 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4245 StaticDataInfo *info;
4248 if (static_type == SPECIAL_STATIC_THREAD) {
4249 info = &thread_static_info;
4250 sets = thread_reference_bitmaps;
4252 info = &context_static_info;
4253 sets = context_reference_bitmaps;
4256 mono_threads_lock ();
4258 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4262 offset = item->offset;
4265 offset = mono_alloc_static_data_slot (info, size, align);
4268 update_reference_bitmap (sets, offset, bitmap, numbits);
4270 if (static_type == SPECIAL_STATIC_THREAD) {
4271 /* This can be called during startup */
4272 if (threads != NULL)
4273 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4275 if (contexts != NULL)
4276 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4278 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4281 mono_threads_unlock ();
4287 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4289 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4291 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4292 return get_thread_static_data (thread, offset);
4294 return get_context_static_data (thread->current_appcontext, offset);
4299 mono_get_special_static_data (guint32 offset)
4301 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4310 * LOCKING: requires that threads_mutex is held
4313 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4315 MonoInternalThread *thread = (MonoInternalThread *)value;
4316 OffsetSize *data = (OffsetSize *)user;
4317 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4318 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4321 if (!thread->static_data || !thread->static_data [idx])
4323 ptr = ((char*) thread->static_data [idx]) + off;
4324 mono_gc_bzero_atomic (ptr, data->size);
4328 * LOCKING: requires that threads_mutex is held
4331 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4333 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4338 OffsetSize *data = (OffsetSize *)user;
4339 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4340 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4343 if (!ctx->static_data || !ctx->static_data [idx])
4346 ptr = ((char*) ctx->static_data [idx]) + off;
4347 mono_gc_bzero_atomic (ptr, data->size);
4351 do_free_special_slot (guint32 offset, guint32 size)
4353 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4355 StaticDataInfo *info;
4357 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4358 info = &thread_static_info;
4359 sets = thread_reference_bitmaps;
4361 info = &context_static_info;
4362 sets = context_reference_bitmaps;
4365 guint32 data_offset = offset;
4366 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4367 OffsetSize data = { data_offset, size };
4369 clear_reference_bitmap (sets, data.offset, data.size);
4371 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4372 if (threads != NULL)
4373 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4375 if (contexts != NULL)
4376 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4379 if (!mono_runtime_is_shutting_down ()) {
4380 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4382 item->offset = offset;
4385 item->next = info->freelist;
4386 info->freelist = item;
4391 do_free_special (gpointer key, gpointer value, gpointer data)
4393 MonoClassField *field = (MonoClassField *)key;
4394 guint32 offset = GPOINTER_TO_UINT (value);
4397 size = mono_type_size (field->type, &align);
4398 do_free_special_slot (offset, size);
4402 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4404 mono_threads_lock ();
4406 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4408 mono_threads_unlock ();
4412 static void CALLBACK dummy_apc (ULONG_PTR param)
4418 * mono_thread_execute_interruption
4420 * Performs the operation that the requested thread state requires (abort,
4423 static MonoException*
4424 mono_thread_execute_interruption (void)
4426 MonoInternalThread *thread = mono_thread_internal_current ();
4427 MonoThread *sys_thread = mono_thread_current ();
4429 LOCK_THREAD (thread);
4431 /* MonoThread::interruption_requested can only be changed with atomics */
4432 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4433 /* this will consume pending APC calls */
4435 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4437 InterlockedDecrement (&thread_interruption_requested);
4439 /* Clear the interrupted flag of the thread so it can wait again */
4440 mono_thread_info_clear_self_interrupt ();
4443 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4444 if (sys_thread->pending_exception) {
4447 exc = sys_thread->pending_exception;
4448 sys_thread->pending_exception = NULL;
4450 UNLOCK_THREAD (thread);
4452 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4453 UNLOCK_THREAD (thread);
4454 g_assert (sys_thread->pending_exception == NULL);
4455 if (thread->abort_exc == NULL) {
4457 * This might be racy, but it has to be called outside the lock
4458 * since it calls managed code.
4460 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4462 return thread->abort_exc;
4464 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4465 /* calls UNLOCK_THREAD (thread) */
4466 self_suspend_internal ();
4469 else if ((thread->state & ThreadState_StopRequested) != 0) {
4470 /* FIXME: do this through the JIT? */
4472 UNLOCK_THREAD (thread);
4474 mono_thread_exit ();
4476 } else if (thread->thread_interrupt_requested) {
4478 thread->thread_interrupt_requested = FALSE;
4479 UNLOCK_THREAD (thread);
4481 return(mono_get_exception_thread_interrupted ());
4484 UNLOCK_THREAD (thread);
4490 * mono_thread_request_interruption
4492 * A signal handler can call this method to request the interruption of a
4493 * thread. The result of the interruption will depend on the current state of
4494 * the thread. If the result is an exception that needs to be throw, it is
4495 * provided as return value.
4498 mono_thread_request_interruption (gboolean running_managed)
4500 MonoInternalThread *thread = mono_thread_internal_current ();
4502 /* The thread may already be stopping */
4507 if (thread->interrupt_on_stop &&
4508 thread->state & ThreadState_StopRequested &&
4509 thread->state & ThreadState_Background)
4513 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4515 InterlockedIncrement (&thread_interruption_requested);
4517 if (!running_managed || is_running_protected_wrapper ()) {
4518 /* Can't stop while in unmanaged code. Increase the global interruption
4519 request count. When exiting the unmanaged method the count will be
4520 checked and the thread will be interrupted. */
4522 /* this will awake the thread if it is in WaitForSingleObject
4524 /* Our implementation of this function ignores the func argument */
4526 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4528 mono_thread_info_self_interrupt ();
4533 return mono_thread_execute_interruption ();
4537 /*This function should be called by a thread after it has exited all of
4538 * its handle blocks at interruption time.*/
4540 mono_thread_resume_interruption (void)
4542 MonoInternalThread *thread = mono_thread_internal_current ();
4543 gboolean still_aborting;
4545 /* The thread may already be stopping */
4549 LOCK_THREAD (thread);
4550 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4551 UNLOCK_THREAD (thread);
4553 /*This can happen if the protected block called Thread::ResetAbort*/
4554 if (!still_aborting)
4557 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4559 InterlockedIncrement (&thread_interruption_requested);
4561 mono_thread_info_self_interrupt ();
4563 return mono_thread_execute_interruption ();
4566 gboolean mono_thread_interruption_requested ()
4568 if (thread_interruption_requested) {
4569 MonoInternalThread *thread = mono_thread_internal_current ();
4570 /* The thread may already be stopping */
4572 return (thread->interruption_requested);
4577 static MonoException*
4578 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4580 MonoInternalThread *thread = mono_thread_internal_current ();
4582 /* The thread may already be stopping */
4586 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4587 MonoException* exc = mono_thread_execute_interruption ();
4595 * Performs the interruption of the current thread, if one has been requested,
4596 * and the thread is not running a protected wrapper.
4597 * Return the exception which needs to be thrown, if any.
4600 mono_thread_interruption_checkpoint (void)
4602 return mono_thread_interruption_checkpoint_request (FALSE);
4606 * Performs the interruption of the current thread, if one has been requested.
4607 * Return the exception which needs to be thrown, if any.
4610 mono_thread_force_interruption_checkpoint_noraise (void)
4612 return mono_thread_interruption_checkpoint_request (TRUE);
4616 * mono_set_pending_exception:
4618 * Set the pending exception of the current thread to EXC.
4619 * The exception will be thrown when execution returns to managed code.
4622 mono_set_pending_exception (MonoException *exc)
4624 MonoThread *thread = mono_thread_current ();
4626 /* The thread may already be stopping */
4630 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4632 mono_thread_request_interruption (FALSE);
4636 * mono_thread_interruption_request_flag:
4638 * Returns the address of a flag that will be non-zero if an interruption has
4639 * been requested for a thread. The thread to interrupt may not be the current
4640 * thread, so an additional call to mono_thread_interruption_requested() or
4641 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4644 gint32* mono_thread_interruption_request_flag ()
4646 return &thread_interruption_requested;
4650 mono_thread_init_apartment_state (void)
4653 MonoInternalThread* thread = mono_thread_internal_current ();
4655 /* Positive return value indicates success, either
4656 * S_OK if this is first CoInitialize call, or
4657 * S_FALSE if CoInitialize already called, but with same
4658 * threading model. A negative value indicates failure,
4659 * probably due to trying to change the threading model.
4661 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4662 ? COINIT_APARTMENTTHREADED
4663 : COINIT_MULTITHREADED) < 0) {
4664 thread->apartment_state = ThreadApartmentState_Unknown;
4670 mono_thread_cleanup_apartment_state (void)
4673 MonoInternalThread* thread = mono_thread_internal_current ();
4675 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4682 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4684 LOCK_THREAD (thread);
4685 thread->state |= state;
4686 UNLOCK_THREAD (thread);
4690 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4692 LOCK_THREAD (thread);
4693 thread->state &= ~state;
4694 UNLOCK_THREAD (thread);
4698 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4700 gboolean ret = FALSE;
4702 LOCK_THREAD (thread);
4704 if ((thread->state & test) != 0) {
4708 UNLOCK_THREAD (thread);
4713 static gboolean has_tls_get = FALSE;
4716 mono_runtime_set_has_tls_get (gboolean val)
4722 mono_runtime_has_tls_get (void)
4728 self_interrupt_thread (void *_unused)
4730 MonoThreadInfo *info = mono_thread_info_current ();
4731 MonoException *exc = mono_thread_execute_interruption ();
4732 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4733 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. */
4734 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4738 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4742 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4746 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4748 MonoJitInfo **dest = (MonoJitInfo **)data;
4754 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4756 MonoJitInfo *ji = NULL;
4761 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4762 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4763 * where we hold runtime locks.
4765 if (!mono_threads_is_coop_enabled ())
4766 mono_thread_info_set_is_async_context (TRUE);
4767 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4768 if (!mono_threads_is_coop_enabled ())
4769 mono_thread_info_set_is_async_context (FALSE);
4774 MonoInternalThread *thread;
4775 gboolean install_async_abort;
4776 MonoThreadInfoInterruptToken *interrupt_token;
4779 static SuspendThreadResult
4780 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4782 AbortThreadData *data = (AbortThreadData *)ud;
4783 MonoInternalThread *thread = data->thread;
4784 MonoJitInfo *ji = NULL;
4785 gboolean protected_wrapper;
4786 gboolean running_managed;
4788 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4789 return MonoResumeThread;
4791 /*someone is already interrupting it*/
4792 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4793 return MonoResumeThread;
4795 InterlockedIncrement (&thread_interruption_requested);
4797 ji = mono_thread_info_get_last_managed (info);
4798 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4799 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4801 if (!protected_wrapper && running_managed) {
4802 /*We are in managed code*/
4803 /*Set the thread to call */
4804 if (data->install_async_abort)
4805 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4806 return MonoResumeThread;
4809 * This will cause waits to be broken.
4810 * It will also prevent the thread from entering a wait, so if the thread returns
4811 * from the wait before it receives the abort signal, it will just spin in the wait
4812 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4815 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4817 return MonoResumeThread;
4822 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4824 AbortThreadData data;
4826 g_assert (thread != mono_thread_internal_current ());
4828 data.thread = thread;
4829 data.install_async_abort = install_async_abort;
4830 data.interrupt_token = NULL;
4832 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4833 if (data.interrupt_token)
4834 mono_thread_info_finish_interrupt (data.interrupt_token);
4835 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4839 self_abort_internal (MonoError *error)
4843 mono_error_init (error);
4845 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4846 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4848 exc = mono_thread_request_interruption (TRUE);
4850 mono_error_set_exception_instance (error, exc);
4852 mono_thread_info_self_interrupt ();
4856 MonoInternalThread *thread;
4858 MonoThreadInfoInterruptToken *interrupt_token;
4859 } SuspendThreadData;
4861 static SuspendThreadResult
4862 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4864 SuspendThreadData *data = (SuspendThreadData *)ud;
4865 MonoInternalThread *thread = data->thread;
4866 MonoJitInfo *ji = NULL;
4867 gboolean protected_wrapper;
4868 gboolean running_managed;
4870 ji = mono_thread_info_get_last_managed (info);
4871 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4872 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4874 if (running_managed && !protected_wrapper) {
4875 thread->state &= ~ThreadState_SuspendRequested;
4876 thread->state |= ThreadState_Suspended;
4877 return KeepSuspended;
4879 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4880 InterlockedIncrement (&thread_interruption_requested);
4881 if (data->interrupt)
4882 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4884 return MonoResumeThread;
4888 /* LOCKING: called with @thread synch_cs held, and releases it */
4890 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4892 SuspendThreadData data;
4894 g_assert (thread != mono_thread_internal_current ());
4896 data.thread = thread;
4897 data.interrupt = interrupt;
4898 data.interrupt_token = NULL;
4900 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4901 if (data.interrupt_token)
4902 mono_thread_info_finish_interrupt (data.interrupt_token);
4904 UNLOCK_THREAD (thread);
4907 /* LOCKING: called with @thread synch_cs held, and releases it */
4909 self_suspend_internal (void)
4911 MonoInternalThread *thread;
4913 thread = mono_thread_internal_current ();
4915 mono_thread_info_begin_self_suspend ();
4916 thread->state &= ~ThreadState_SuspendRequested;
4917 thread->state |= ThreadState_Suspended;
4919 UNLOCK_THREAD (thread);
4921 mono_thread_info_end_self_suspend ();
4925 * mono_thread_is_foreign:
4926 * @thread: the thread to query
4928 * This function allows one to determine if a thread was created by the mono runtime and has
4929 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4931 * Returns: TRUE if @thread was not created by the runtime.
4934 mono_thread_is_foreign (MonoThread *thread)
4936 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4937 return info->runtime_thread == FALSE;
4941 * mono_add_joinable_thread:
4943 * Add TID to the list of joinable threads.
4944 * LOCKING: Acquires the threads lock.
4947 mono_threads_add_joinable_thread (gpointer tid)
4951 * We cannot detach from threads because it causes problems like
4952 * 2fd16f60/r114307. So we collect them and join them when
4953 * we have time (in he finalizer thread).
4955 joinable_threads_lock ();
4956 if (!joinable_threads)
4957 joinable_threads = g_hash_table_new (NULL, NULL);
4958 g_hash_table_insert (joinable_threads, tid, tid);
4959 joinable_thread_count ++;
4960 joinable_threads_unlock ();
4962 mono_gc_finalize_notify ();
4967 * mono_threads_join_threads:
4969 * Join all joinable threads. This is called from the finalizer thread.
4970 * LOCKING: Acquires the threads lock.
4973 mono_threads_join_threads (void)
4976 GHashTableIter iter;
4983 if (!joinable_thread_count)
4987 joinable_threads_lock ();
4989 if (g_hash_table_size (joinable_threads)) {
4990 g_hash_table_iter_init (&iter, joinable_threads);
4991 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4992 thread = (pthread_t)tid;
4993 g_hash_table_remove (joinable_threads, key);
4994 joinable_thread_count --;
4997 joinable_threads_unlock ();
4999 if (thread != pthread_self ()) {
5001 /* This shouldn't block */
5002 pthread_join (thread, NULL);
5015 * Wait for thread TID to exit.
5016 * LOCKING: Acquires the threads lock.
5019 mono_thread_join (gpointer tid)
5023 gboolean found = FALSE;
5025 joinable_threads_lock ();
5026 if (!joinable_threads)
5027 joinable_threads = g_hash_table_new (NULL, NULL);
5028 if (g_hash_table_lookup (joinable_threads, tid)) {
5029 g_hash_table_remove (joinable_threads, tid);
5030 joinable_thread_count --;
5033 joinable_threads_unlock ();
5036 thread = (pthread_t)tid;
5038 pthread_join (thread, NULL);
5044 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
5046 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
5047 mono_thread_interruption_checkpoint ();
5050 static inline gboolean
5051 is_appdomainunloaded_exception (MonoClass *klass)
5053 return klass == mono_class_get_appdomain_unloaded_exception_class ();
5056 static inline gboolean
5057 is_threadabort_exception (MonoClass *klass)
5059 return klass == mono_defaults.threadabortexception_class;
5063 mono_thread_internal_unhandled_exception (MonoObject* exc)
5065 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5066 MonoClass *klass = exc->vtable->klass;
5067 if (is_threadabort_exception (klass)) {
5068 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5069 } else if (!is_appdomainunloaded_exception (klass)) {
5070 mono_unhandled_exception (exc);
5071 if (mono_environment_exitcode_get () == 1)
5078 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5081 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5082 mono_error_set_pending_exception (&error);
5086 * mono_threads_attach_coop: called by native->managed wrappers
5090 * - @return: the original domain which needs to be restored, or NULL.
5093 * - @dummy: contains the original domain
5094 * - @return: a cookie containing current MonoThreadInfo*.
5097 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5100 gboolean fresh_thread = FALSE;
5103 /* Happens when called from AOTed code which is only used in the root domain. */
5104 domain = mono_get_root_domain ();
5109 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5110 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5111 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5112 * we're only responsible for making the cookie. */
5113 if (mono_threads_is_coop_enabled ()) {
5114 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5115 fresh_thread = !info || !mono_thread_info_is_live (info);
5118 if (!mono_thread_internal_current ()) {
5119 mono_thread_attach_full (domain, FALSE);
5122 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5125 orig = mono_domain_get ();
5127 mono_domain_set (domain, TRUE);
5129 if (!mono_threads_is_coop_enabled ())
5130 return orig != domain ? orig : NULL;
5134 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5135 * return the right cookie. */
5136 return mono_threads_enter_gc_unsafe_region_cookie ();
5139 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5140 return mono_threads_enter_gc_unsafe_region (dummy);
5145 * mono_threads_detach_coop: called by native->managed wrappers
5148 * - @cookie: the original domain which needs to be restored, or NULL.
5152 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5153 * - @dummy: contains the original domain
5156 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5158 MonoDomain *domain, *orig;
5160 if (!mono_threads_is_coop_enabled ()) {
5161 orig = (MonoDomain*) cookie;
5163 mono_domain_set (orig, TRUE);
5165 orig = (MonoDomain*) *dummy;
5167 domain = mono_domain_get ();
5170 /* it won't do anything if cookie is NULL
5171 * thread state RUNNING -> (RUNNING|BLOCKING) */
5172 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5174 if (orig != domain) {
5176 mono_domain_unset ();
5178 mono_domain_set (orig, TRUE);