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);
595 MONO_OBJECT_SETREF (thread, internal_thread, internal);
600 static MonoInternalThread*
601 create_internal_thread (void)
604 MonoInternalThread *thread;
607 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
608 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
609 /* only possible failure mode is OOM, from which we don't exect to recover */
610 mono_error_assert_ok (&error);
612 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
613 mono_coop_mutex_init_recursive (thread->synch_cs);
615 thread->apartment_state = ThreadApartmentState_Unknown;
616 thread->managed_id = get_next_managed_thread_id ();
617 if (mono_gc_is_moving ()) {
618 thread->thread_pinning_ref = thread;
619 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
626 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
628 MonoDomain *domain = mono_get_root_domain ();
630 if (!candidate || candidate->obj.vtable->domain != domain) {
631 candidate = new_thread_with_internal (domain, thread);
633 set_current_thread_for_domain (domain, thread, candidate);
634 g_assert (!thread->root_domain_thread);
635 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
639 static guint32 WINAPI start_wrapper_internal(void *data)
642 MonoThreadInfo *info;
643 StartInfo *start_info = (StartInfo *)data;
644 guint32 (*start_func)(void *);
648 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
651 MonoInternalThread *internal = start_info->obj->internal_thread;
652 MonoObject *start_delegate = start_info->delegate;
653 MonoDomain *domain = start_info->obj->obj.vtable->domain;
655 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
657 /* We can be sure start_info->obj->tid and
658 * start_info->obj->handle have been set, because the thread
659 * was created suspended, and these values were set before the
663 info = mono_thread_info_current ();
665 internal->thread_info = info;
666 internal->small_id = info->small_id;
670 SET_CURRENT_OBJECT (internal);
672 /* Every thread references the appdomain which created it */
673 mono_thread_push_appdomain_ref (domain);
675 if (!mono_domain_set (domain, FALSE)) {
676 /* No point in raising an appdomain_unloaded exception here */
677 /* FIXME: Cleanup here */
678 mono_thread_pop_appdomain_ref ();
682 start_func = start_info->func;
683 start_arg = start_info->obj->start_obj;
685 start_arg = start_info->start_arg;
687 /* We have to do this here because mono_thread_new_init()
688 requires that root_domain_thread is set up. */
689 thread_adjust_static_data (internal);
690 init_root_domain_thread (internal, start_info->obj);
692 /* This MUST be called before any managed code can be
693 * executed, as it calls the callback function that (for the
694 * jit) sets the lmf marker.
696 mono_thread_new_init (tid, &tid, start_func);
697 internal->stack_ptr = &tid;
698 if (domain != mono_get_root_domain ())
699 set_current_thread_for_domain (domain, internal, start_info->obj);
701 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
703 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
705 /* On 2.0 profile (and higher), set explicitly since state might have been
707 if (internal->apartment_state == ThreadApartmentState_Unknown)
708 internal->apartment_state = ThreadApartmentState_MTA;
710 mono_thread_init_apartment_state ();
712 if(internal->start_notify!=NULL) {
713 /* Let the thread that called Start() know we're
716 ReleaseSemaphore (internal->start_notify, 1, NULL);
720 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
724 * Call this after calling start_notify, since the profiler callback might want
725 * to lock the thread, and the lock is held by thread_start () which waits for
728 mono_profiler_thread_start (tid);
730 /* if the name was set before starting, we didn't invoke the profiler callback */
731 if (internal->name) {
732 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
733 mono_profiler_thread_name (internal->tid, tname);
734 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
738 /* start_func is set only for unmanaged start functions */
740 start_func (start_arg);
743 g_assert (start_delegate != NULL);
744 args [0] = start_arg;
745 /* we may want to handle the exception here. See comment below on unhandled exceptions */
746 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
747 mono_error_raise_exception (&error); /* FIXME don't raise here */
750 /* If the thread calls ExitThread at all, this remaining code
751 * will not be executed, but the main thread will eventually
752 * call thread_cleanup() on this thread's behalf.
755 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
757 /* Do any cleanup needed for apartment state. This
758 * cannot be done in thread_cleanup since thread_cleanup could be
759 * called for a thread other than the current thread.
760 * mono_thread_cleanup_apartment_state cleans up apartment
761 * for the current thead */
762 mono_thread_cleanup_apartment_state ();
764 thread_cleanup (internal);
768 /* Remove the reference to the thread object in the TLS data,
769 * so the thread object can be finalized. This won't be
770 * reached if the thread threw an uncaught exception, so those
771 * thread handles will stay referenced :-( (This is due to
772 * missing support for scanning thread-specific data in the
773 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
776 SET_CURRENT_OBJECT (NULL);
781 static guint32 WINAPI start_wrapper(void *data)
785 /* Avoid scanning the frames above this frame during a GC */
786 mono_gc_set_stack_end ((void*)&dummy);
788 return start_wrapper_internal (data);
794 * Common thread creation code.
795 * LOCKING: Acquires the threads lock.
798 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
801 HANDLE thread_handle;
802 MonoNativeThreadId tid;
803 guint32 create_flags;
806 * Join joinable threads to prevent running out of threads since the finalizer
807 * thread might be blocked/backlogged.
809 mono_threads_join_threads ();
811 mono_error_init (error);
813 mono_threads_lock ();
816 mono_threads_unlock ();
819 if (threads_starting_up == NULL) {
820 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
821 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
823 mono_g_hash_table_insert (threads_starting_up, thread, thread);
824 mono_threads_unlock ();
826 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
827 if (!internal->start_notify) {
828 mono_threads_lock ();
829 mono_g_hash_table_remove (threads_starting_up, thread);
830 mono_threads_unlock ();
831 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
837 stack_size = default_stacksize_for_thread (internal);
839 /* Create suspended, so we can do some housekeeping before the thread
842 create_flags = CREATE_SUSPENDED;
844 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
845 stack_size, create_flags, &tid);
847 if (thread_handle == NULL) {
848 /* The thread couldn't be created, so set an exception */
849 mono_threads_lock ();
850 mono_g_hash_table_remove (threads_starting_up, thread);
851 mono_threads_unlock ();
853 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
856 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
858 internal->handle = thread_handle;
859 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
861 internal->threadpool_thread = threadpool_thread;
862 if (threadpool_thread)
863 mono_thread_set_state (internal, ThreadState_Background);
865 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
867 /* Only store the handle when the thread is about to be
868 * launched, to avoid the main thread deadlocking while trying
869 * to clean up a thread that will never be signalled.
871 if (!handle_store (thread, FALSE))
874 mono_thread_info_resume (tid);
876 if (internal->start_notify) {
878 * Wait for the thread to set up its TLS data etc, so
879 * theres no potential race condition if someone tries
880 * to look up the data believing the thread has
883 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));
886 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
889 CloseHandle (internal->start_notify);
890 internal->start_notify = NULL;
893 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));
898 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
900 if (mono_thread_start_cb) {
901 mono_thread_start_cb (tid, stack_start, func);
905 void mono_threads_set_default_stacksize (guint32 stacksize)
907 default_stacksize = stacksize;
910 guint32 mono_threads_get_default_stacksize (void)
912 return default_stacksize;
916 * mono_thread_create_internal:
918 * ARG should not be a GC reference.
921 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
924 MonoInternalThread *internal;
925 StartInfo *start_info;
928 mono_error_init (error);
930 thread = create_thread_object (domain);
932 internal = create_internal_thread ();
934 MONO_OBJECT_SETREF (thread, internal_thread, internal);
936 start_info = g_new0 (StartInfo, 1);
937 start_info->func = (guint32 (*)(void *))func;
938 start_info->obj = thread;
939 start_info->start_arg = arg;
941 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, error);
942 return_val_if_nok (error, NULL);
944 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
945 #ifndef MONO_CROSS_COMPILE
946 if (mono_check_corlib_version () == NULL)
947 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
954 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
957 if (!mono_thread_create_checked (domain, func, arg, &error))
958 mono_error_cleanup (&error);
962 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
964 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
968 mono_thread_attach (MonoDomain *domain)
970 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
976 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
978 MonoThreadInfo *info;
979 MonoInternalThread *thread;
980 MonoThread *current_thread;
981 HANDLE thread_handle;
982 MonoNativeThreadId tid;
984 if ((thread = mono_thread_internal_current ())) {
985 if (domain != mono_domain_get ())
986 mono_domain_set (domain, TRUE);
987 /* Already attached */
988 return mono_thread_current ();
991 if (!mono_gc_register_thread (&domain)) {
992 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 ());
995 thread = create_internal_thread ();
997 thread_handle = mono_thread_info_open_handle ();
998 g_assert (thread_handle);
1000 tid=mono_native_thread_id_get ();
1002 thread->handle = thread_handle;
1003 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
1004 thread->stack_ptr = &tid;
1006 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
1008 info = mono_thread_info_current ();
1010 thread->thread_info = info;
1011 thread->small_id = info->small_id;
1013 current_thread = new_thread_with_internal (domain, thread);
1015 if (!handle_store (current_thread, force_attach)) {
1016 /* Mono is shutting down, so just wait for the end */
1018 mono_thread_info_sleep (10000, NULL);
1021 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
1023 SET_CURRENT_OBJECT (thread);
1024 mono_domain_set (domain, TRUE);
1026 thread_adjust_static_data (thread);
1028 init_root_domain_thread (thread, current_thread);
1030 if (domain != mono_get_root_domain ())
1031 set_current_thread_for_domain (domain, thread, current_thread);
1034 if (mono_thread_attach_cb) {
1038 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1041 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1043 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1046 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1047 if (!info->tools_thread)
1048 // FIXME: Need a separate callback
1049 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1051 return current_thread;
1055 mono_thread_detach_internal (MonoInternalThread *thread)
1057 g_return_if_fail (thread != NULL);
1059 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1061 thread_cleanup (thread);
1063 SET_CURRENT_OBJECT (NULL);
1064 mono_domain_unset ();
1066 /* Don't need to CloseHandle this thread, even though we took a
1067 * reference in mono_thread_attach (), because the GC will do it
1068 * when the Thread object is finalised.
1073 mono_thread_detach (MonoThread *thread)
1076 mono_thread_detach_internal (thread->internal_thread);
1080 * mono_thread_detach_if_exiting:
1082 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1083 * This should be used at the end of embedding code which calls into managed code, and which
1084 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1087 mono_thread_detach_if_exiting (void)
1089 if (mono_thread_info_is_exiting ()) {
1090 MonoInternalThread *thread;
1092 thread = mono_thread_internal_current ();
1094 mono_thread_detach_internal (thread);
1095 mono_thread_info_detach ();
1105 MonoInternalThread *thread = mono_thread_internal_current ();
1107 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1109 thread_cleanup (thread);
1110 SET_CURRENT_OBJECT (NULL);
1111 mono_domain_unset ();
1113 /* we could add a callback here for embedders to use. */
1114 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1115 exit (mono_environment_exitcode_get ());
1116 mono_thread_info_exit ();
1120 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1122 MonoInternalThread *internal;
1124 internal = create_internal_thread ();
1126 internal->state = ThreadState_Unstarted;
1128 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1132 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1136 StartInfo *start_info;
1137 MonoInternalThread *internal;
1140 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1142 if (!this_obj->internal_thread)
1143 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1144 internal = this_obj->internal_thread;
1146 LOCK_THREAD (internal);
1148 if ((internal->state & ThreadState_Unstarted) == 0) {
1149 UNLOCK_THREAD (internal);
1150 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1154 if ((internal->state & ThreadState_Aborted) != 0) {
1155 UNLOCK_THREAD (internal);
1158 /* This is freed in start_wrapper */
1159 start_info = g_new0 (StartInfo, 1);
1160 start_info->func = NULL;
1161 start_info->start_arg = NULL;
1162 start_info->delegate = start;
1163 start_info->obj = this_obj;
1164 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1166 res = create_thread (this_obj, internal, start_info, FALSE, 0, &error);
1168 mono_error_cleanup (&error);
1169 UNLOCK_THREAD (internal);
1173 internal->state &= ~ThreadState_Unstarted;
1175 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1177 UNLOCK_THREAD (internal);
1178 return internal->handle;
1182 * This is called from the finalizer of the internal thread object.
1185 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1187 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1190 * Since threads keep a reference to their thread object while running, by the time this function is called,
1191 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1192 * when thread_cleanup () can be called after this.
1195 CloseHandle (thread);
1197 if (this_obj->synch_cs) {
1198 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1199 this_obj->synch_cs = NULL;
1200 mono_coop_mutex_destroy (synch_cs);
1204 if (this_obj->name) {
1205 void *name = this_obj->name;
1206 this_obj->name = NULL;
1212 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1215 MonoInternalThread *thread = mono_thread_internal_current ();
1217 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1219 if (mono_thread_current_check_pending_interrupt ())
1223 gboolean alerted = FALSE;
1225 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1227 res = mono_thread_info_sleep (ms, &alerted);
1229 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1232 MonoException* exc = mono_thread_execute_interruption ();
1234 mono_raise_exception (exc);
1246 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1251 ves_icall_System_Threading_Thread_GetDomainID (void)
1253 return mono_domain_get()->domain_id;
1257 ves_icall_System_Threading_Thread_Yield (void)
1259 return mono_thread_info_yield ();
1263 * mono_thread_get_name:
1265 * Return the name of the thread. NAME_LEN is set to the length of the name.
1266 * Return NULL if the thread has no name. The returned memory is owned by the
1270 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1274 LOCK_THREAD (this_obj);
1276 if (!this_obj->name) {
1280 *name_len = this_obj->name_len;
1281 res = g_new (gunichar2, this_obj->name_len);
1282 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1285 UNLOCK_THREAD (this_obj);
1291 * mono_thread_get_name_utf8:
1293 * Return the name of the thread in UTF-8.
1294 * Return NULL if the thread has no name.
1295 * The returned memory is owned by the caller.
1298 mono_thread_get_name_utf8 (MonoThread *thread)
1303 MonoInternalThread *internal = thread->internal_thread;
1304 if (internal == NULL)
1307 LOCK_THREAD (internal);
1309 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1311 UNLOCK_THREAD (internal);
1317 * mono_thread_get_managed_id:
1319 * Return the Thread.ManagedThreadId value of `thread`.
1320 * Returns -1 if `thread` is NULL.
1323 mono_thread_get_managed_id (MonoThread *thread)
1328 MonoInternalThread *internal = thread->internal_thread;
1329 if (internal == NULL)
1332 int32_t id = internal->managed_id;
1338 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1343 mono_error_init (&error);
1345 LOCK_THREAD (this_obj);
1347 if (!this_obj->name)
1350 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1352 UNLOCK_THREAD (this_obj);
1354 if (mono_error_set_pending_exception (&error))
1361 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1363 LOCK_THREAD (this_obj);
1365 mono_error_init (error);
1367 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1368 UNLOCK_THREAD (this_obj);
1370 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1373 if (this_obj->name) {
1374 g_free (this_obj->name);
1375 this_obj->name_len = 0;
1378 this_obj->name = g_new (gunichar2, mono_string_length (name));
1379 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1380 this_obj->name_len = mono_string_length (name);
1383 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1386 this_obj->name = NULL;
1389 UNLOCK_THREAD (this_obj);
1391 if (this_obj->name && this_obj->tid) {
1392 char *tname = mono_string_to_utf8_checked (name, error);
1393 return_if_nok (error);
1394 mono_profiler_thread_name (this_obj->tid, tname);
1395 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1401 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1404 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1405 mono_error_set_pending_exception (&error);
1409 * ves_icall_System_Threading_Thread_GetPriority_internal:
1410 * @param this_obj: The MonoInternalThread on which to operate.
1412 * Gets the priority of the given thread.
1413 * @return: The priority of the given thread.
1416 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1419 MonoInternalThread *internal = this_obj->internal_thread;
1421 LOCK_THREAD (internal);
1422 priority = GetThreadPriority (internal->handle) + 2;
1423 UNLOCK_THREAD (internal);
1428 * ves_icall_System_Threading_Thread_SetPriority_internal:
1429 * @param this_obj: The MonoInternalThread on which to operate.
1430 * @param priority: The priority to set.
1432 * Sets the priority of the given thread.
1435 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1437 MonoInternalThread *internal = this_obj->internal_thread;
1439 LOCK_THREAD (internal);
1440 SetThreadPriority (internal->handle, priority - 2);
1441 UNLOCK_THREAD (internal);
1444 /* If the array is already in the requested domain, we just return it,
1445 otherwise we return a copy in that domain. */
1447 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1451 mono_error_init (error);
1455 if (mono_object_domain (arr) == domain)
1458 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1459 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1464 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1467 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1468 mono_error_set_pending_exception (&error);
1473 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1476 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1477 mono_error_set_pending_exception (&error);
1482 mono_thread_current (void)
1484 MonoDomain *domain = mono_domain_get ();
1485 MonoInternalThread *internal = mono_thread_internal_current ();
1486 MonoThread **current_thread_ptr;
1488 g_assert (internal);
1489 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1491 if (!*current_thread_ptr) {
1492 g_assert (domain != mono_get_root_domain ());
1493 *current_thread_ptr = new_thread_with_internal (domain, internal);
1495 return *current_thread_ptr;
1498 /* Return the thread object belonging to INTERNAL in the current domain */
1500 mono_thread_current_for_thread (MonoInternalThread *internal)
1502 MonoDomain *domain = mono_domain_get ();
1503 MonoThread **current_thread_ptr;
1505 g_assert (internal);
1506 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1508 if (!*current_thread_ptr) {
1509 g_assert (domain != mono_get_root_domain ());
1510 *current_thread_ptr = new_thread_with_internal (domain, internal);
1512 return *current_thread_ptr;
1516 mono_thread_internal_current (void)
1518 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1519 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1524 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1526 MonoInternalThread *thread = this_obj->internal_thread;
1527 HANDLE handle = thread->handle;
1528 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1531 if (mono_thread_current_check_pending_interrupt ())
1534 LOCK_THREAD (thread);
1536 if ((thread->state & ThreadState_Unstarted) != 0) {
1537 UNLOCK_THREAD (thread);
1539 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1543 UNLOCK_THREAD (thread);
1548 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1550 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1553 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1556 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1558 if(ret==WAIT_OBJECT_0) {
1559 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1564 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1569 #define MANAGED_WAIT_FAILED 0x7fffffff
1572 map_native_wait_result_to_managed (gint32 val)
1574 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1575 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1579 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1587 mono_error_init (error);
1589 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1592 if (numhandles != 1)
1593 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1595 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1598 if (ret != WAIT_IO_COMPLETION)
1601 exc = mono_thread_execute_interruption ();
1603 mono_error_set_exception_instance (error, exc);
1610 /* Re-calculate ms according to the time passed */
1611 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1612 if (diff_ms >= ms) {
1616 wait = ms - diff_ms;
1622 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1629 MonoObject *waitHandle;
1630 MonoInternalThread *thread = mono_thread_internal_current ();
1632 /* Do this WaitSleepJoin check before creating objects */
1633 if (mono_thread_current_check_pending_interrupt ())
1634 return map_native_wait_result_to_managed (WAIT_FAILED);
1636 /* We fail in managed if the array has more than 64 elements */
1637 numhandles = (guint32)mono_array_length(mono_handles);
1638 handles = g_new0(HANDLE, numhandles);
1640 for(i = 0; i < numhandles; i++) {
1641 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1642 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1649 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1651 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1653 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1657 mono_error_set_pending_exception (&error);
1659 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1660 return map_native_wait_result_to_managed (ret);
1663 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1666 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1667 uintptr_t numhandles;
1670 MonoObject *waitHandle;
1671 MonoInternalThread *thread = mono_thread_internal_current ();
1673 /* Do this WaitSleepJoin check before creating objects */
1674 if (mono_thread_current_check_pending_interrupt ())
1675 return map_native_wait_result_to_managed (WAIT_FAILED);
1677 numhandles = mono_array_length(mono_handles);
1678 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1679 return map_native_wait_result_to_managed (WAIT_FAILED);
1681 for(i = 0; i < numhandles; i++) {
1682 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1683 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1690 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1692 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1694 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1696 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1698 mono_error_set_pending_exception (&error);
1700 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1702 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1703 return map_native_wait_result_to_managed (ret - WAIT_OBJECT_0);
1705 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1706 return map_native_wait_result_to_managed (ret - WAIT_ABANDONED_0);
1709 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1710 return map_native_wait_result_to_managed (ret);
1714 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1718 MonoInternalThread *thread = mono_thread_internal_current ();
1720 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1726 if (mono_thread_current_check_pending_interrupt ())
1727 return map_native_wait_result_to_managed (WAIT_FAILED);
1729 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1731 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1733 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1735 mono_error_set_pending_exception (&error);
1736 return map_native_wait_result_to_managed (ret);
1740 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1743 MonoInternalThread *thread = mono_thread_internal_current ();
1748 if (mono_thread_current_check_pending_interrupt ())
1749 return map_native_wait_result_to_managed (WAIT_FAILED);
1751 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1754 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1757 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1759 return map_native_wait_result_to_managed (ret);
1762 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1769 mutex = CreateMutex (NULL, owned, NULL);
1771 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1773 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1781 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1782 return(ReleaseMutex (handle));
1785 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1791 *error = ERROR_SUCCESS;
1793 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1795 *error = GetLastError ();
1802 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, gint32 *error)
1807 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1809 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1810 mono_string_chars (name));
1813 *error = GetLastError ();
1817 MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, gint32 *prevcount)
1819 return ReleaseSemaphore (handle, releaseCount, prevcount);
1822 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1826 sem = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1827 *error = GetLastError ();
1832 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1839 event = CreateEvent (NULL, manual, initial, NULL);
1841 event = CreateEvent (NULL, manual, initial,
1842 mono_string_chars (name));
1844 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1852 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1853 return (SetEvent(handle));
1856 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1857 return (ResetEvent(handle));
1861 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1862 CloseHandle (handle);
1865 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1871 *error = ERROR_SUCCESS;
1873 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1875 *error = GetLastError ();
1881 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1883 return InterlockedIncrement (location);
1886 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1888 #if SIZEOF_VOID_P == 4
1889 if (G_UNLIKELY ((size_t)location & 0x7)) {
1891 mono_interlocked_lock ();
1894 mono_interlocked_unlock ();
1898 return InterlockedIncrement64 (location);
1901 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1903 return InterlockedDecrement(location);
1906 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1908 #if SIZEOF_VOID_P == 4
1909 if (G_UNLIKELY ((size_t)location & 0x7)) {
1911 mono_interlocked_lock ();
1914 mono_interlocked_unlock ();
1918 return InterlockedDecrement64 (location);
1921 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1923 return InterlockedExchange(location, value);
1926 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1929 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1930 mono_gc_wbarrier_generic_nostore (location);
1934 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1936 return InterlockedExchangePointer(location, value);
1939 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1941 IntFloatUnion val, ret;
1944 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1950 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1952 #if SIZEOF_VOID_P == 4
1953 if (G_UNLIKELY ((size_t)location & 0x7)) {
1955 mono_interlocked_lock ();
1958 mono_interlocked_unlock ();
1962 return InterlockedExchange64 (location, value);
1966 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1968 LongDoubleUnion val, ret;
1971 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1976 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1978 return InterlockedCompareExchange(location, value, comparand);
1981 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1983 gint32 r = InterlockedCompareExchange(location, value, comparand);
1984 *success = r == comparand;
1988 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1991 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1992 mono_gc_wbarrier_generic_nostore (location);
1996 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1998 return InterlockedCompareExchangePointer(location, value, comparand);
2001 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2003 IntFloatUnion val, ret, cmp;
2006 cmp.fval = comparand;
2007 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2013 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2015 #if SIZEOF_VOID_P == 8
2016 LongDoubleUnion val, comp, ret;
2019 comp.fval = comparand;
2020 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2026 mono_interlocked_lock ();
2028 if (old == comparand)
2030 mono_interlocked_unlock ();
2037 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2039 #if SIZEOF_VOID_P == 4
2040 if (G_UNLIKELY ((size_t)location & 0x7)) {
2042 mono_interlocked_lock ();
2044 if (old == comparand)
2046 mono_interlocked_unlock ();
2050 return InterlockedCompareExchange64 (location, value, comparand);
2054 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2057 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2058 mono_gc_wbarrier_generic_nostore (location);
2063 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2066 MONO_CHECK_NULL (location, NULL);
2067 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2068 mono_gc_wbarrier_generic_nostore (location);
2073 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2075 return InterlockedAdd (location, value);
2079 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2081 #if SIZEOF_VOID_P == 4
2082 if (G_UNLIKELY ((size_t)location & 0x7)) {
2084 mono_interlocked_lock ();
2087 mono_interlocked_unlock ();
2091 return InterlockedAdd64 (location, value);
2095 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2097 #if SIZEOF_VOID_P == 4
2098 if (G_UNLIKELY ((size_t)location & 0x7)) {
2100 mono_interlocked_lock ();
2102 mono_interlocked_unlock ();
2106 return InterlockedRead64 (location);
2110 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2112 mono_memory_barrier ();
2116 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2118 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2120 if (state & ThreadState_Background) {
2121 /* If the thread changes the background mode, the main thread has to
2122 * be notified, since it has to rebuild the list of threads to
2125 SetEvent (background_change_event);
2130 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2132 mono_thread_set_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_GetState (MonoInternalThread* this_obj)
2148 LOCK_THREAD (this_obj);
2150 state = this_obj->state;
2152 UNLOCK_THREAD (this_obj);
2157 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2159 MonoInternalThread *current;
2161 MonoInternalThread *thread = this_obj->internal_thread;
2163 LOCK_THREAD (thread);
2165 current = mono_thread_internal_current ();
2167 thread->thread_interrupt_requested = TRUE;
2168 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2170 UNLOCK_THREAD (thread);
2173 async_abort_internal (thread, FALSE);
2178 * mono_thread_current_check_pending_interrupt:
2180 * Checks if there's a interruption request and set the pending exception if so.
2182 * @returns true if a pending exception was set
2185 mono_thread_current_check_pending_interrupt (void)
2187 MonoInternalThread *thread = mono_thread_internal_current ();
2188 gboolean throw_ = FALSE;
2190 LOCK_THREAD (thread);
2192 if (thread->thread_interrupt_requested) {
2194 thread->thread_interrupt_requested = FALSE;
2197 UNLOCK_THREAD (thread);
2200 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2205 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2207 LOCK_THREAD (thread);
2209 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2210 (thread->state & ThreadState_StopRequested) != 0 ||
2211 (thread->state & ThreadState_Stopped) != 0)
2213 UNLOCK_THREAD (thread);
2217 if ((thread->state & ThreadState_Unstarted) != 0) {
2218 thread->state |= ThreadState_Aborted;
2219 UNLOCK_THREAD (thread);
2223 thread->state |= ThreadState_AbortRequested;
2224 if (thread->abort_state_handle)
2225 mono_gchandle_free (thread->abort_state_handle);
2227 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2228 g_assert (thread->abort_state_handle);
2230 thread->abort_state_handle = 0;
2232 thread->abort_exc = NULL;
2234 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));
2236 /* During shutdown, we can't wait for other threads */
2238 /* Make sure the thread is awake */
2239 mono_thread_resume (thread);
2241 UNLOCK_THREAD (thread);
2246 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2248 if (!request_thread_abort (thread, state))
2251 if (thread == mono_thread_internal_current ()) {
2253 self_abort_internal (&error);
2254 mono_error_set_pending_exception (&error);
2256 async_abort_internal (thread, TRUE);
2261 * mono_thread_internal_abort:
2263 * Request thread @thread to be aborted.
2265 * @thread MUST NOT be the current thread.
2268 mono_thread_internal_abort (MonoInternalThread *thread)
2270 g_assert (thread != mono_thread_internal_current ());
2272 if (!request_thread_abort (thread, NULL))
2274 async_abort_internal (thread, TRUE);
2278 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2280 MonoInternalThread *thread = mono_thread_internal_current ();
2281 gboolean was_aborting;
2283 LOCK_THREAD (thread);
2284 was_aborting = thread->state & ThreadState_AbortRequested;
2285 thread->state &= ~ThreadState_AbortRequested;
2286 UNLOCK_THREAD (thread);
2288 if (!was_aborting) {
2289 const char *msg = "Unable to reset abort because no abort was requested";
2290 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2293 thread->abort_exc = NULL;
2294 if (thread->abort_state_handle) {
2295 mono_gchandle_free (thread->abort_state_handle);
2296 /* This is actually not necessary - the handle
2297 only counts if the exception is set */
2298 thread->abort_state_handle = 0;
2303 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2305 LOCK_THREAD (thread);
2307 thread->state &= ~ThreadState_AbortRequested;
2309 if (thread->abort_exc) {
2310 thread->abort_exc = NULL;
2311 if (thread->abort_state_handle) {
2312 mono_gchandle_free (thread->abort_state_handle);
2313 /* This is actually not necessary - the handle
2314 only counts if the exception is set */
2315 thread->abort_state_handle = 0;
2319 UNLOCK_THREAD (thread);
2323 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2326 MonoInternalThread *thread = this_obj->internal_thread;
2327 MonoObject *state, *deserialized = NULL;
2330 if (!thread->abort_state_handle)
2333 state = mono_gchandle_get_target (thread->abort_state_handle);
2336 domain = mono_domain_get ();
2337 if (mono_object_domain (state) == domain)
2340 deserialized = mono_object_xdomain_representation (state, domain, &error);
2342 if (!deserialized) {
2343 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2344 if (!is_ok (&error)) {
2345 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2346 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2348 mono_set_pending_exception (invalid_op_exc);
2352 return deserialized;
2356 mono_thread_suspend (MonoInternalThread *thread)
2358 LOCK_THREAD (thread);
2360 if ((thread->state & ThreadState_Unstarted) != 0 ||
2361 (thread->state & ThreadState_Aborted) != 0 ||
2362 (thread->state & ThreadState_Stopped) != 0)
2364 UNLOCK_THREAD (thread);
2368 if ((thread->state & ThreadState_Suspended) != 0 ||
2369 (thread->state & ThreadState_SuspendRequested) != 0 ||
2370 (thread->state & ThreadState_StopRequested) != 0)
2372 UNLOCK_THREAD (thread);
2376 thread->state |= ThreadState_SuspendRequested;
2378 if (thread == mono_thread_internal_current ()) {
2379 /* calls UNLOCK_THREAD (thread) */
2380 self_suspend_internal ();
2382 /* calls UNLOCK_THREAD (thread) */
2383 async_suspend_internal (thread, FALSE);
2390 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2392 if (!mono_thread_suspend (this_obj->internal_thread)) {
2393 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2398 /* LOCKING: LOCK_THREAD(thread) must be held */
2400 mono_thread_resume (MonoInternalThread *thread)
2402 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2403 thread->state &= ~ThreadState_SuspendRequested;
2407 if ((thread->state & ThreadState_Suspended) == 0 ||
2408 (thread->state & ThreadState_Unstarted) != 0 ||
2409 (thread->state & ThreadState_Aborted) != 0 ||
2410 (thread->state & ThreadState_Stopped) != 0)
2415 UNLOCK_THREAD (thread);
2417 /* Awake the thread */
2418 if (!mono_thread_info_resume (thread_get_tid (thread)))
2421 LOCK_THREAD (thread);
2423 thread->state &= ~ThreadState_Suspended;
2429 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2431 if (!thread->internal_thread) {
2432 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2434 LOCK_THREAD (thread->internal_thread);
2435 if (!mono_thread_resume (thread->internal_thread))
2436 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2437 UNLOCK_THREAD (thread->internal_thread);
2442 mono_threads_is_critical_method (MonoMethod *method)
2444 switch (method->wrapper_type) {
2445 case MONO_WRAPPER_RUNTIME_INVOKE:
2446 case MONO_WRAPPER_XDOMAIN_INVOKE:
2447 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2454 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2459 if (mono_threads_is_critical_method (m)) {
2460 *((gboolean*)data) = TRUE;
2467 is_running_protected_wrapper (void)
2469 gboolean found = FALSE;
2470 mono_stack_walk (find_wrapper, &found);
2475 request_thread_stop (MonoInternalThread *thread)
2477 LOCK_THREAD (thread);
2479 if ((thread->state & ThreadState_StopRequested) != 0 ||
2480 (thread->state & ThreadState_Stopped) != 0)
2482 UNLOCK_THREAD (thread);
2486 /* Make sure the thread is awake */
2487 mono_thread_resume (thread);
2489 thread->state |= ThreadState_StopRequested;
2490 thread->state &= ~ThreadState_AbortRequested;
2492 UNLOCK_THREAD (thread);
2497 * mono_thread_internal_stop:
2499 * Request thread @thread to stop.
2501 * @thread MUST NOT be the current thread.
2504 mono_thread_internal_stop (MonoInternalThread *thread)
2506 g_assert (thread != mono_thread_internal_current ());
2508 if (!request_thread_stop (thread))
2511 async_abort_internal (thread, TRUE);
2514 void mono_thread_stop (MonoThread *thread)
2516 MonoInternalThread *internal = thread->internal_thread;
2518 if (!request_thread_stop (internal))
2521 if (internal == mono_thread_internal_current ()) {
2523 self_abort_internal (&error);
2525 This function is part of the embeding API and has no way to return the exception
2526 to be thrown. So what we do is keep the old behavior and raise the exception.
2528 mono_error_raise_exception (&error); /* OK to throw, see note */
2530 async_abort_internal (internal, TRUE);
2535 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2537 gint8 tmp = *(volatile gint8 *)ptr;
2538 mono_memory_barrier ();
2543 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2545 gint16 tmp = *(volatile gint16 *)ptr;
2546 mono_memory_barrier ();
2551 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2553 gint32 tmp = *(volatile gint32 *)ptr;
2554 mono_memory_barrier ();
2559 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2561 gint64 tmp = *(volatile gint64 *)ptr;
2562 mono_memory_barrier ();
2567 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2569 volatile void *tmp = *(volatile void **)ptr;
2570 mono_memory_barrier ();
2571 return (void *) tmp;
2575 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2577 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2578 mono_memory_barrier ();
2579 return (MonoObject *) tmp;
2583 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2585 double tmp = *(volatile double *)ptr;
2586 mono_memory_barrier ();
2591 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2593 float tmp = *(volatile float *)ptr;
2594 mono_memory_barrier ();
2599 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2601 return InterlockedRead8 ((volatile gint8 *)ptr);
2605 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2607 return InterlockedRead16 ((volatile gint16 *)ptr);
2611 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2613 return InterlockedRead ((volatile gint32 *)ptr);
2617 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2619 #if SIZEOF_VOID_P == 4
2620 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2622 mono_interlocked_lock ();
2623 val = *(gint64*)ptr;
2624 mono_interlocked_unlock ();
2628 return InterlockedRead64 ((volatile gint64 *)ptr);
2632 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2634 return InterlockedReadPointer ((volatile gpointer *)ptr);
2638 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2642 #if SIZEOF_VOID_P == 4
2643 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2645 mono_interlocked_lock ();
2646 val = *(double*)ptr;
2647 mono_interlocked_unlock ();
2652 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2658 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2662 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2668 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2670 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2674 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2676 mono_memory_barrier ();
2677 *(volatile gint8 *)ptr = value;
2681 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2683 mono_memory_barrier ();
2684 *(volatile gint16 *)ptr = value;
2688 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2690 mono_memory_barrier ();
2691 *(volatile gint32 *)ptr = value;
2695 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2697 mono_memory_barrier ();
2698 *(volatile gint64 *)ptr = value;
2702 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2704 mono_memory_barrier ();
2705 *(volatile void **)ptr = value;
2709 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2711 mono_memory_barrier ();
2712 mono_gc_wbarrier_generic_store (ptr, value);
2716 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2718 mono_memory_barrier ();
2719 *(volatile double *)ptr = value;
2723 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2725 mono_memory_barrier ();
2726 *(volatile float *)ptr = value;
2730 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2732 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2736 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2738 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2742 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2744 InterlockedWrite ((volatile gint32 *)ptr, value);
2748 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2750 #if SIZEOF_VOID_P == 4
2751 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2752 mono_interlocked_lock ();
2753 *(gint64*)ptr = value;
2754 mono_interlocked_unlock ();
2759 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2763 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2765 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2769 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2773 #if SIZEOF_VOID_P == 4
2774 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2775 mono_interlocked_lock ();
2776 *(double*)ptr = value;
2777 mono_interlocked_unlock ();
2784 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2788 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2794 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2798 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2800 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2804 free_context (void *user_data)
2806 ContextStaticData *data = user_data;
2808 mono_threads_lock ();
2811 * There is no guarantee that, by the point this reference queue callback
2812 * has been invoked, the GC handle associated with the object will fail to
2813 * resolve as one might expect. So if we don't free and remove the GC
2814 * handle here, free_context_static_data_helper () could end up resolving
2815 * a GC handle to an actually-dead context which would contain a pointer
2816 * to an already-freed static data segment, resulting in a crash when
2819 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2821 mono_threads_unlock ();
2823 mono_gchandle_free (data->gc_handle);
2824 mono_free_static_data (data->static_data);
2829 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2831 mono_threads_lock ();
2833 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2836 contexts = g_hash_table_new (NULL, NULL);
2839 context_queue = mono_gc_reference_queue_new (free_context);
2841 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2842 g_hash_table_insert (contexts, gch, gch);
2845 * We use this intermediate structure to contain a duplicate pointer to
2846 * the static data because we can't rely on being able to resolve the GC
2847 * handle in the reference queue callback.
2849 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2850 data->gc_handle = GPOINTER_TO_UINT (gch);
2853 context_adjust_static_data (ctx);
2854 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2856 mono_threads_unlock ();
2858 mono_profiler_context_loaded (ctx);
2862 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2865 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2866 * cleanup in exceptional circumstances, we don't actually do any
2867 * cleanup work here. We instead do this via a reference queue.
2870 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2872 mono_profiler_context_unloaded (ctx);
2876 mono_thread_init_tls (void)
2878 MONO_FAST_TLS_INIT (tls_current_object);
2879 mono_native_tls_alloc (¤t_object_key, NULL);
2882 void mono_thread_init (MonoThreadStartCB start_cb,
2883 MonoThreadAttachCB attach_cb)
2885 mono_coop_mutex_init_recursive (&threads_mutex);
2887 mono_os_mutex_init_recursive(&interlocked_mutex);
2888 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2890 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2891 g_assert(background_change_event != NULL);
2893 mono_init_static_data_info (&thread_static_info);
2894 mono_init_static_data_info (&context_static_info);
2896 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2898 mono_thread_start_cb = start_cb;
2899 mono_thread_attach_cb = attach_cb;
2901 /* Get a pseudo handle to the current process. This is just a
2902 * kludge so that wapi can build a process handle if needed.
2903 * As a pseudo handle is returned, we don't need to clean
2906 GetCurrentProcess ();
2909 void mono_thread_cleanup (void)
2911 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2912 MonoThreadInfo *info;
2914 /* The main thread must abandon any held mutexes (particularly
2915 * important for named mutexes as they are shared across
2916 * processes, see bug 74680.) This will happen when the
2917 * thread exits, but if it's not running in a subthread it
2918 * won't exit in time.
2920 info = mono_thread_info_current ();
2921 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2925 /* This stuff needs more testing, it seems one of these
2926 * critical sections can be locked when mono_thread_cleanup is
2929 mono_coop_mutex_destroy (&threads_mutex);
2930 mono_os_mutex_destroy (&interlocked_mutex);
2931 mono_os_mutex_destroy (&delayed_free_table_mutex);
2932 mono_os_mutex_destroy (&small_id_mutex);
2933 CloseHandle (background_change_event);
2936 mono_native_tls_free (current_object_key);
2940 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2942 mono_thread_cleanup_fn = func;
2946 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2948 thread->internal_thread->manage_callback = func;
2952 static void print_tids (gpointer key, gpointer value, gpointer user)
2954 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2955 * sizeof(uint) and a cast to uint would overflow
2957 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2958 * print this as a pointer.
2960 g_message ("Waiting for: %p", key);
2965 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2966 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2970 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2974 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2977 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2980 if(ret==WAIT_FAILED) {
2981 /* See the comment in build_wait_tids() */
2982 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2986 for(i=0; i<wait->num; i++)
2987 CloseHandle (wait->handles[i]);
2989 if (ret == WAIT_TIMEOUT)
2992 for(i=0; i<wait->num; i++) {
2993 gsize tid = wait->threads[i]->tid;
2996 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2997 * it can still run io-layer etc. code. So wait for it to really exit.
2998 * FIXME: This won't join threads which are not in the joinable_hash yet.
3000 mono_thread_join ((gpointer)tid);
3002 mono_threads_lock ();
3003 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3004 /* This thread must have been killed, because
3005 * it hasn't cleaned itself up. (It's just
3006 * possible that the thread exited before the
3007 * parent thread had a chance to store the
3008 * handle, and now there is another pointer to
3009 * the already-exited thread stored. In this
3010 * case, we'll just get two
3011 * mono_profiler_thread_end() calls for the
3015 mono_threads_unlock ();
3016 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
3017 thread_cleanup (wait->threads[i]);
3019 mono_threads_unlock ();
3024 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
3026 guint32 i, ret, count;
3028 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3030 /* Add the thread state change event, so it wakes up if a thread changes
3031 * to background mode.
3034 if (count < MAXIMUM_WAIT_OBJECTS) {
3035 wait->handles [count] = background_change_event;
3040 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
3043 if(ret==WAIT_FAILED) {
3044 /* See the comment in build_wait_tids() */
3045 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3049 for(i=0; i<wait->num; i++)
3050 CloseHandle (wait->handles[i]);
3052 if (ret == WAIT_TIMEOUT)
3055 if (ret < wait->num) {
3056 gsize tid = wait->threads[ret]->tid;
3057 mono_threads_lock ();
3058 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3059 /* See comment in wait_for_tids about thread cleanup */
3060 mono_threads_unlock ();
3061 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3062 thread_cleanup (wait->threads [ret]);
3064 mono_threads_unlock ();
3068 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3070 struct wait_data *wait=(struct wait_data *)user;
3072 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
3074 MonoInternalThread *thread=(MonoInternalThread *)value;
3076 /* Ignore background threads, we abort them later */
3077 /* Do not lock here since it is not needed and the caller holds threads_lock */
3078 if (thread->state & ThreadState_Background) {
3079 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3080 return; /* just leave, ignore */
3083 if (mono_gc_is_finalizer_internal_thread (thread)) {
3084 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3088 if (thread == mono_thread_internal_current ()) {
3089 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3093 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3094 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3098 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3099 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3103 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3104 if (handle == NULL) {
3105 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3109 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3110 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3111 wait->handles[wait->num]=handle;
3112 wait->threads[wait->num]=thread;
3115 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3117 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3122 /* Just ignore the rest, we can't do anything with
3129 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3131 struct wait_data *wait=(struct wait_data *)user;
3132 MonoNativeThreadId self = mono_native_thread_id_get ();
3133 MonoInternalThread *thread = (MonoInternalThread *)value;
3136 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
3139 /* The finalizer thread is not a background thread */
3140 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3141 && (thread->state & ThreadState_Background) != 0
3142 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3144 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3148 wait->handles[wait->num] = handle;
3149 wait->threads[wait->num] = thread;
3152 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3153 mono_thread_internal_stop (thread);
3157 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3158 && !mono_gc_is_finalizer_internal_thread (thread);
3162 * mono_threads_set_shutting_down:
3164 * Is called by a thread that wants to shut down Mono. If the runtime is already
3165 * shutting down, the calling thread is suspended/stopped, and this function never
3169 mono_threads_set_shutting_down (void)
3171 MonoInternalThread *current_thread = mono_thread_internal_current ();
3173 mono_threads_lock ();
3175 if (shutting_down) {
3176 mono_threads_unlock ();
3178 /* Make sure we're properly suspended/stopped */
3180 LOCK_THREAD (current_thread);
3182 if ((current_thread->state & ThreadState_SuspendRequested) ||
3183 (current_thread->state & ThreadState_AbortRequested) ||
3184 (current_thread->state & ThreadState_StopRequested)) {
3185 UNLOCK_THREAD (current_thread);
3186 mono_thread_execute_interruption ();
3188 current_thread->state |= ThreadState_Stopped;
3189 UNLOCK_THREAD (current_thread);
3192 /*since we're killing the thread, unset the current domain.*/
3193 mono_domain_unset ();
3195 /* Wake up other threads potentially waiting for us */
3196 mono_thread_info_exit ();
3198 shutting_down = TRUE;
3200 /* Not really a background state change, but this will
3201 * interrupt the main thread if it is waiting for all
3202 * the other threads.
3204 SetEvent (background_change_event);
3206 mono_threads_unlock ();
3210 void mono_thread_manage (void)
3212 struct wait_data wait_data;
3213 struct wait_data *wait = &wait_data;
3215 memset (wait, 0, sizeof (struct wait_data));
3216 /* join each thread that's still running */
3217 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3219 mono_threads_lock ();
3221 THREAD_DEBUG (g_message("%s: No threads", __func__));
3222 mono_threads_unlock ();
3225 mono_threads_unlock ();
3228 mono_threads_lock ();
3229 if (shutting_down) {
3230 /* somebody else is shutting down */
3231 mono_threads_unlock ();
3234 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3235 mono_g_hash_table_foreach (threads, print_tids, NULL));
3237 ResetEvent (background_change_event);
3239 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3240 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3241 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3242 mono_threads_unlock ();
3244 /* Something to wait for */
3245 wait_for_tids_or_state_change (wait, INFINITE);
3247 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3248 } while(wait->num>0);
3250 /* Mono is shutting down, so just wait for the end */
3251 if (!mono_runtime_try_shutdown ()) {
3252 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3253 mono_thread_suspend (mono_thread_internal_current ());
3254 mono_thread_execute_interruption ();
3258 * Remove everything but the finalizer thread and self.
3259 * Also abort all the background threads
3262 mono_threads_lock ();
3265 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3266 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3267 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3269 mono_threads_unlock ();
3271 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3273 /* Something to wait for */
3274 wait_for_tids (wait, INFINITE);
3276 } while (wait->num > 0);
3279 * give the subthreads a chance to really quit (this is mainly needed
3280 * to get correct user and system times from getrusage/wait/time(1)).
3281 * This could be removed if we avoid pthread_detach() and use pthread_join().
3283 mono_thread_info_yield ();
3287 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3289 MonoInternalThread *thread = (MonoInternalThread*)value;
3290 struct wait_data *wait = (struct wait_data*)user_data;
3294 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3296 * This needs no locking.
3298 if ((thread->state & ThreadState_Suspended) != 0 ||
3299 (thread->state & ThreadState_Stopped) != 0)
3302 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3303 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3307 wait->handles [wait->num] = handle;
3308 wait->threads [wait->num] = thread;
3314 * mono_thread_suspend_all_other_threads:
3316 * Suspend all managed threads except the finalizer thread and this thread. It is
3317 * not possible to resume them later.
3319 void mono_thread_suspend_all_other_threads (void)
3321 struct wait_data wait_data;
3322 struct wait_data *wait = &wait_data;
3324 MonoNativeThreadId self = mono_native_thread_id_get ();
3325 guint32 eventidx = 0;
3326 gboolean starting, finished;
3328 memset (wait, 0, sizeof (struct wait_data));
3330 * The other threads could be in an arbitrary state at this point, i.e.
3331 * they could be starting up, shutting down etc. This means that there could be
3332 * threads which are not even in the threads hash table yet.
3336 * First we set a barrier which will be checked by all threads before they
3337 * are added to the threads hash table, and they will exit if the flag is set.
3338 * This ensures that no threads could be added to the hash later.
3339 * We will use shutting_down as the barrier for now.
3341 g_assert (shutting_down);
3344 * We make multiple calls to WaitForMultipleObjects since:
3345 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3346 * - some threads could exit without becoming suspended
3351 * Make a copy of the hashtable since we can't do anything with
3352 * threads while threads_mutex is held.
3355 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3356 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3357 mono_threads_lock ();
3358 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3359 mono_threads_unlock ();
3362 /* Get the suspended events that we'll be waiting for */
3363 for (i = 0; i < wait->num; ++i) {
3364 MonoInternalThread *thread = wait->threads [i];
3366 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3367 || mono_gc_is_finalizer_internal_thread (thread)
3368 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3370 //CloseHandle (wait->handles [i]);
3371 wait->threads [i] = NULL; /* ignore this thread in next loop */
3375 LOCK_THREAD (thread);
3377 if ((thread->state & ThreadState_Suspended) != 0 ||
3378 (thread->state & ThreadState_StopRequested) != 0 ||
3379 (thread->state & ThreadState_Stopped) != 0) {
3380 UNLOCK_THREAD (thread);
3381 CloseHandle (wait->handles [i]);
3382 wait->threads [i] = NULL; /* ignore this thread in next loop */
3388 /* Convert abort requests into suspend requests */
3389 if ((thread->state & ThreadState_AbortRequested) != 0)
3390 thread->state &= ~ThreadState_AbortRequested;
3392 thread->state |= ThreadState_SuspendRequested;
3394 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3395 async_suspend_internal (thread, TRUE);
3397 if (eventidx <= 0) {
3399 * If there are threads which are starting up, we wait until they
3400 * are suspended when they try to register in the threads hash.
3401 * This is guaranteed to finish, since the threads which can create new
3402 * threads get suspended after a while.
3403 * FIXME: The finalizer thread can still create new threads.
3405 mono_threads_lock ();
3406 if (threads_starting_up)
3407 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3410 mono_threads_unlock ();
3412 mono_thread_info_sleep (100, NULL);
3420 MonoInternalThread *thread;
3421 MonoStackFrameInfo *frames;
3422 int nframes, max_frames;
3423 int nthreads, max_threads;
3424 MonoInternalThread **threads;
3425 } ThreadDumpUserData;
3427 static gboolean thread_dump_requested;
3429 /* This needs to be async safe */
3431 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3433 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3435 if (ud->nframes < ud->max_frames) {
3436 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3443 /* This needs to be async safe */
3444 static SuspendThreadResult
3445 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3447 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3448 MonoInternalThread *thread = user_data->thread;
3451 /* This no longer works with remote unwinding */
3453 wapi_desc = wapi_current_thread_desc ();
3454 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3459 if (thread == mono_thread_internal_current ())
3460 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3462 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3464 return MonoResumeThread;
3468 int nthreads, max_threads;
3469 MonoInternalThread **threads;
3470 } CollectThreadsUserData;
3473 collect_thread (gpointer key, gpointer value, gpointer user)
3475 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3476 MonoInternalThread *thread = (MonoInternalThread *)value;
3478 if (ud->nthreads < ud->max_threads)
3479 ud->threads [ud->nthreads ++] = thread;
3483 * Collect running threads into the THREADS array.
3484 * THREADS should be an array allocated on the stack.
3487 collect_threads (MonoInternalThread **thread_array, int max_threads)
3489 CollectThreadsUserData ud;
3491 memset (&ud, 0, sizeof (ud));
3492 /* This array contains refs, but its on the stack, so its ok */
3493 ud.threads = thread_array;
3494 ud.max_threads = max_threads;
3496 mono_threads_lock ();
3497 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3498 mono_threads_unlock ();
3504 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3506 GString* text = g_string_new (0);
3508 GError *error = NULL;
3511 ud->thread = thread;
3514 /* Collect frames for the thread */
3515 if (thread == mono_thread_internal_current ()) {
3516 get_thread_dump (mono_thread_info_current (), ud);
3518 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3522 * Do all the non async-safe work outside of get_thread_dump.
3525 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3527 g_string_append_printf (text, "\n\"%s\"", name);
3530 else if (thread->threadpool_thread) {
3531 g_string_append (text, "\n\"<threadpool thread>\"");
3533 g_string_append (text, "\n\"<unnamed thread>\"");
3536 for (i = 0; i < ud->nframes; ++i) {
3537 MonoStackFrameInfo *frame = &ud->frames [i];
3538 MonoMethod *method = NULL;
3540 if (frame->type == FRAME_TYPE_MANAGED)
3541 method = mono_jit_info_get_method (frame->ji);
3544 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3545 g_string_append_printf (text, " %s\n", location);
3548 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3552 fprintf (stdout, "%s", text->str);
3554 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3555 OutputDebugStringA(text->str);
3558 g_string_free (text, TRUE);
3563 mono_threads_perform_thread_dump (void)
3565 ThreadDumpUserData ud;
3566 MonoInternalThread *thread_array [128];
3567 int tindex, nthreads;
3569 if (!thread_dump_requested)
3572 printf ("Full thread dump:\n");
3574 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3575 nthreads = collect_threads (thread_array, 128);
3577 memset (&ud, 0, sizeof (ud));
3578 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3579 ud.max_frames = 256;
3581 for (tindex = 0; tindex < nthreads; ++tindex)
3582 dump_thread (thread_array [tindex], &ud);
3586 thread_dump_requested = FALSE;
3589 /* Obtain the thread dump of all threads */
3591 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3594 ThreadDumpUserData ud;
3595 MonoInternalThread *thread_array [128];
3596 MonoDomain *domain = mono_domain_get ();
3597 MonoDebugSourceLocation *location;
3598 int tindex, nthreads;
3600 mono_error_init (error);
3602 *out_threads = NULL;
3603 *out_stack_frames = NULL;
3605 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3606 nthreads = collect_threads (thread_array, 128);
3608 memset (&ud, 0, sizeof (ud));
3609 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3610 ud.max_frames = 256;
3612 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3615 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3619 for (tindex = 0; tindex < nthreads; ++tindex) {
3620 MonoInternalThread *thread = thread_array [tindex];
3621 MonoArray *thread_frames;
3627 /* Collect frames for the thread */
3628 if (thread == mono_thread_internal_current ()) {
3629 get_thread_dump (mono_thread_info_current (), &ud);
3631 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3634 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3636 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3639 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3641 for (i = 0; i < ud.nframes; ++i) {
3642 MonoStackFrameInfo *frame = &ud.frames [i];
3643 MonoMethod *method = NULL;
3644 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3648 sf->native_offset = frame->native_offset;
3650 if (frame->type == FRAME_TYPE_MANAGED)
3651 method = mono_jit_info_get_method (frame->ji);
3654 sf->method_address = (gsize) frame->ji->code_start;
3656 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3659 MONO_OBJECT_SETREF (sf, method, rm);
3661 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3663 sf->il_offset = location->il_offset;
3665 if (location && location->source_file) {
3666 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3667 sf->line = location->row;
3668 sf->column = location->column;
3670 mono_debug_free_source_location (location);
3675 mono_array_setref (thread_frames, i, sf);
3681 return is_ok (error);
3685 * mono_threads_request_thread_dump:
3687 * Ask all threads except the current to print their stacktrace to stdout.
3690 mono_threads_request_thread_dump (void)
3692 /*The new thread dump code runs out of the finalizer thread. */
3693 thread_dump_requested = TRUE;
3694 mono_gc_finalize_notify ();
3699 gint allocated; /* +1 so that refs [allocated] == NULL */
3703 typedef struct ref_stack RefStack;
3706 ref_stack_new (gint initial_size)
3710 initial_size = MAX (initial_size, 16) + 1;
3711 rs = g_new0 (RefStack, 1);
3712 rs->refs = g_new0 (gpointer, initial_size);
3713 rs->allocated = initial_size;
3718 ref_stack_destroy (gpointer ptr)
3720 RefStack *rs = (RefStack *)ptr;
3729 ref_stack_push (RefStack *rs, gpointer ptr)
3731 g_assert (rs != NULL);
3733 if (rs->bottom >= rs->allocated) {
3734 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3735 rs->allocated <<= 1;
3736 rs->refs [rs->allocated] = NULL;
3738 rs->refs [rs->bottom++] = ptr;
3742 ref_stack_pop (RefStack *rs)
3744 if (rs == NULL || rs->bottom == 0)
3748 rs->refs [rs->bottom] = NULL;
3752 ref_stack_find (RefStack *rs, gpointer ptr)
3759 for (refs = rs->refs; refs && *refs; refs++) {
3767 * mono_thread_push_appdomain_ref:
3769 * Register that the current thread may have references to objects in domain
3770 * @domain on its stack. Each call to this function should be paired with a
3771 * call to pop_appdomain_ref.
3774 mono_thread_push_appdomain_ref (MonoDomain *domain)
3776 MonoInternalThread *thread = mono_thread_internal_current ();
3779 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3780 SPIN_LOCK (thread->lock_thread_id);
3781 if (thread->appdomain_refs == NULL)
3782 thread->appdomain_refs = ref_stack_new (16);
3783 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3784 SPIN_UNLOCK (thread->lock_thread_id);
3789 mono_thread_pop_appdomain_ref (void)
3791 MonoInternalThread *thread = mono_thread_internal_current ();
3794 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3795 SPIN_LOCK (thread->lock_thread_id);
3796 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3797 SPIN_UNLOCK (thread->lock_thread_id);
3802 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3805 SPIN_LOCK (thread->lock_thread_id);
3806 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3807 SPIN_UNLOCK (thread->lock_thread_id);
3812 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3814 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3817 typedef struct abort_appdomain_data {
3818 struct wait_data wait;
3820 } abort_appdomain_data;
3823 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3825 MonoInternalThread *thread = (MonoInternalThread*)value;
3826 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3827 MonoDomain *domain = data->domain;
3829 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3830 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3832 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3833 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3836 data->wait.handles [data->wait.num] = handle;
3837 data->wait.threads [data->wait.num] = thread;
3840 /* Just ignore the rest, we can't do anything with
3848 * mono_threads_abort_appdomain_threads:
3850 * Abort threads which has references to the given appdomain.
3853 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3855 #ifdef __native_client__
3859 abort_appdomain_data user_data;
3861 int orig_timeout = timeout;
3864 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3866 start_time = mono_msec_ticks ();
3868 mono_threads_lock ();
3870 user_data.domain = domain;
3871 user_data.wait.num = 0;
3872 /* This shouldn't take any locks */
3873 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3874 mono_threads_unlock ();
3876 if (user_data.wait.num > 0) {
3877 /* Abort the threads outside the threads lock */
3878 for (i = 0; i < user_data.wait.num; ++i)
3879 mono_thread_internal_abort (user_data.wait.threads [i]);
3882 * We should wait for the threads either to abort, or to leave the
3883 * domain. We can't do the latter, so we wait with a timeout.
3885 wait_for_tids (&user_data.wait, 100);
3888 /* Update remaining time */
3889 timeout -= mono_msec_ticks () - start_time;
3890 start_time = mono_msec_ticks ();
3892 if (orig_timeout != -1 && timeout < 0)
3895 while (user_data.wait.num > 0);
3897 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3903 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3905 MonoInternalThread *thread = (MonoInternalThread*)value;
3906 MonoDomain *domain = (MonoDomain*)user_data;
3909 /* No locking needed here */
3910 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3912 if (thread->cached_culture_info) {
3913 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3914 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3915 if (obj && obj->vtable->domain == domain)
3916 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3922 * mono_threads_clear_cached_culture:
3924 * Clear the cached_current_culture from all threads if it is in the
3928 mono_threads_clear_cached_culture (MonoDomain *domain)
3930 mono_threads_lock ();
3931 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3932 mono_threads_unlock ();
3936 * mono_thread_get_undeniable_exception:
3938 * Return an exception which needs to be raised when leaving a catch clause.
3939 * This is used for undeniable exception propagation.
3942 mono_thread_get_undeniable_exception (void)
3944 MonoInternalThread *thread = mono_thread_internal_current ();
3946 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3948 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3949 * exception if the thread no longer references a dying appdomain.
3951 thread->abort_exc->trace_ips = NULL;
3952 thread->abort_exc->stack_trace = NULL;
3953 return thread->abort_exc;
3959 #if MONO_SMALL_CONFIG
3960 #define NUM_STATIC_DATA_IDX 4
3961 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3965 #define NUM_STATIC_DATA_IDX 8
3966 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3967 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3971 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3972 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3975 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3977 gpointer *static_data = (gpointer *)addr;
3979 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3980 void **ptr = (void **)static_data [i];
3985 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3986 void **p = ptr + idx;
3989 mark_func ((MonoObject**)p, gc_data);
3995 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3997 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
4001 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4003 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
4007 * mono_alloc_static_data
4009 * Allocate memory blocks for storing threads or context static data
4012 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4014 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4017 gpointer* static_data = *static_data_ptr;
4019 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4020 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4022 if (mono_gc_user_markers_supported ()) {
4023 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4024 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4026 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4027 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4030 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4031 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4032 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4033 *static_data_ptr = static_data;
4034 static_data [0] = static_data;
4037 for (i = 1; i <= idx; ++i) {
4038 if (static_data [i])
4041 if (mono_gc_user_markers_supported ())
4042 static_data [i] = g_malloc0 (static_data_size [i]);
4044 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4045 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4046 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4051 mono_free_static_data (gpointer* static_data)
4054 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4055 gpointer p = static_data [i];
4059 * At this point, the static data pointer array is still registered with the
4060 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4061 * data. Freeing the individual arrays without first nulling their slots
4062 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4063 * such an already freed array. See bug #13813.
4065 static_data [i] = NULL;
4066 mono_memory_write_barrier ();
4067 if (mono_gc_user_markers_supported ())
4070 mono_gc_free_fixed (p);
4072 mono_gc_free_fixed (static_data);
4076 * mono_init_static_data_info
4078 * Initializes static data counters
4080 static void mono_init_static_data_info (StaticDataInfo *static_data)
4082 static_data->idx = 0;
4083 static_data->offset = 0;
4084 static_data->freelist = NULL;
4088 * mono_alloc_static_data_slot
4090 * Generates an offset for static data. static_data contains the counters
4091 * used to generate it.
4094 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4096 if (!static_data->idx && !static_data->offset) {
4098 * we use the first chunk of the first allocation also as
4099 * an array for the rest of the data
4101 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4103 static_data->offset += align - 1;
4104 static_data->offset &= ~(align - 1);
4105 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4106 static_data->idx ++;
4107 g_assert (size <= static_data_size [static_data->idx]);
4108 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4109 static_data->offset = 0;
4111 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4112 static_data->offset += size;
4117 * ensure thread static fields already allocated are valid for thread
4118 * This function is called when a thread is created or on thread attach.
4121 thread_adjust_static_data (MonoInternalThread *thread)
4123 mono_threads_lock ();
4124 if (thread_static_info.offset || thread_static_info.idx > 0) {
4125 /* get the current allocated size */
4126 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
4127 mono_alloc_static_data (&thread->static_data, offset, TRUE);
4129 mono_threads_unlock ();
4133 * LOCKING: requires that threads_mutex is held
4136 context_adjust_static_data (MonoAppContext *ctx)
4138 if (context_static_info.offset || context_static_info.idx > 0) {
4139 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4140 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4141 ctx->data->static_data = ctx->static_data;
4146 * LOCKING: requires that threads_mutex is held
4149 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4151 MonoInternalThread *thread = (MonoInternalThread *)value;
4152 guint32 offset = GPOINTER_TO_UINT (user);
4154 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4158 * LOCKING: requires that threads_mutex is held
4161 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4163 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4168 guint32 offset = GPOINTER_TO_UINT (user);
4169 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4170 ctx->data->static_data = ctx->static_data;
4173 static StaticDataFreeList*
4174 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4176 StaticDataFreeList* prev = NULL;
4177 StaticDataFreeList* tmp = static_data->freelist;
4179 if (tmp->size == size) {
4181 prev->next = tmp->next;
4183 static_data->freelist = tmp->next;
4192 #if SIZEOF_VOID_P == 4
4199 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4201 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4203 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4204 MonoBitSet *rb = sets [idx];
4205 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4206 offset /= sizeof (uintptr_t);
4207 /* offset is now the bitmap offset */
4208 for (int i = 0; i < numbits; ++i) {
4209 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4210 mono_bitset_set_fast (rb, offset + i);
4215 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4217 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
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 < size / sizeof (uintptr_t); i++)
4223 mono_bitset_clear_fast (rb, offset + i);
4227 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4229 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4231 StaticDataInfo *info;
4234 if (static_type == SPECIAL_STATIC_THREAD) {
4235 info = &thread_static_info;
4236 sets = thread_reference_bitmaps;
4238 info = &context_static_info;
4239 sets = context_reference_bitmaps;
4242 mono_threads_lock ();
4244 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4248 offset = item->offset;
4251 offset = mono_alloc_static_data_slot (info, size, align);
4254 update_reference_bitmap (sets, offset, bitmap, numbits);
4256 if (static_type == SPECIAL_STATIC_THREAD) {
4257 /* This can be called during startup */
4258 if (threads != NULL)
4259 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4261 if (contexts != NULL)
4262 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4264 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4267 mono_threads_unlock ();
4273 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4275 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4277 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4278 return get_thread_static_data (thread, offset);
4280 return get_context_static_data (thread->current_appcontext, offset);
4285 mono_get_special_static_data (guint32 offset)
4287 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4296 * LOCKING: requires that threads_mutex is held
4299 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4301 MonoInternalThread *thread = (MonoInternalThread *)value;
4302 OffsetSize *data = (OffsetSize *)user;
4303 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4304 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4307 if (!thread->static_data || !thread->static_data [idx])
4309 ptr = ((char*) thread->static_data [idx]) + off;
4310 mono_gc_bzero_atomic (ptr, data->size);
4314 * LOCKING: requires that threads_mutex is held
4317 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4319 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4324 OffsetSize *data = (OffsetSize *)user;
4325 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4326 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4329 if (!ctx->static_data || !ctx->static_data [idx])
4332 ptr = ((char*) ctx->static_data [idx]) + off;
4333 mono_gc_bzero_atomic (ptr, data->size);
4337 do_free_special_slot (guint32 offset, guint32 size)
4339 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4341 StaticDataInfo *info;
4343 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4344 info = &thread_static_info;
4345 sets = thread_reference_bitmaps;
4347 info = &context_static_info;
4348 sets = context_reference_bitmaps;
4351 guint32 data_offset = offset;
4352 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4353 OffsetSize data = { data_offset, size };
4355 clear_reference_bitmap (sets, data.offset, data.size);
4357 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4358 if (threads != NULL)
4359 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4361 if (contexts != NULL)
4362 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4365 if (!mono_runtime_is_shutting_down ()) {
4366 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4368 item->offset = offset;
4371 item->next = info->freelist;
4372 info->freelist = item;
4377 do_free_special (gpointer key, gpointer value, gpointer data)
4379 MonoClassField *field = (MonoClassField *)key;
4380 guint32 offset = GPOINTER_TO_UINT (value);
4383 size = mono_type_size (field->type, &align);
4384 do_free_special_slot (offset, size);
4388 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4390 mono_threads_lock ();
4392 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4394 mono_threads_unlock ();
4398 static void CALLBACK dummy_apc (ULONG_PTR param)
4404 * mono_thread_execute_interruption
4406 * Performs the operation that the requested thread state requires (abort,
4409 static MonoException*
4410 mono_thread_execute_interruption (void)
4412 MonoInternalThread *thread = mono_thread_internal_current ();
4413 MonoThread *sys_thread = mono_thread_current ();
4415 LOCK_THREAD (thread);
4417 /* MonoThread::interruption_requested can only be changed with atomics */
4418 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4419 /* this will consume pending APC calls */
4421 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4423 InterlockedDecrement (&thread_interruption_requested);
4425 /* Clear the interrupted flag of the thread so it can wait again */
4426 mono_thread_info_clear_self_interrupt ();
4429 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4430 if (sys_thread->pending_exception) {
4433 exc = sys_thread->pending_exception;
4434 sys_thread->pending_exception = NULL;
4436 UNLOCK_THREAD (thread);
4438 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4439 UNLOCK_THREAD (thread);
4440 g_assert (sys_thread->pending_exception == NULL);
4441 if (thread->abort_exc == NULL) {
4443 * This might be racy, but it has to be called outside the lock
4444 * since it calls managed code.
4446 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4448 return thread->abort_exc;
4450 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4451 /* calls UNLOCK_THREAD (thread) */
4452 self_suspend_internal ();
4455 else if ((thread->state & ThreadState_StopRequested) != 0) {
4456 /* FIXME: do this through the JIT? */
4458 UNLOCK_THREAD (thread);
4460 mono_thread_exit ();
4462 } else if (thread->thread_interrupt_requested) {
4464 thread->thread_interrupt_requested = FALSE;
4465 UNLOCK_THREAD (thread);
4467 return(mono_get_exception_thread_interrupted ());
4470 UNLOCK_THREAD (thread);
4476 * mono_thread_request_interruption
4478 * A signal handler can call this method to request the interruption of a
4479 * thread. The result of the interruption will depend on the current state of
4480 * the thread. If the result is an exception that needs to be throw, it is
4481 * provided as return value.
4484 mono_thread_request_interruption (gboolean running_managed)
4486 MonoInternalThread *thread = mono_thread_internal_current ();
4488 /* The thread may already be stopping */
4493 if (thread->interrupt_on_stop &&
4494 thread->state & ThreadState_StopRequested &&
4495 thread->state & ThreadState_Background)
4499 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4501 InterlockedIncrement (&thread_interruption_requested);
4503 if (!running_managed || is_running_protected_wrapper ()) {
4504 /* Can't stop while in unmanaged code. Increase the global interruption
4505 request count. When exiting the unmanaged method the count will be
4506 checked and the thread will be interrupted. */
4508 /* this will awake the thread if it is in WaitForSingleObject
4510 /* Our implementation of this function ignores the func argument */
4512 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4514 mono_thread_info_self_interrupt ();
4519 return mono_thread_execute_interruption ();
4523 /*This function should be called by a thread after it has exited all of
4524 * its handle blocks at interruption time.*/
4526 mono_thread_resume_interruption (void)
4528 MonoInternalThread *thread = mono_thread_internal_current ();
4529 gboolean still_aborting;
4531 /* The thread may already be stopping */
4535 LOCK_THREAD (thread);
4536 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4537 UNLOCK_THREAD (thread);
4539 /*This can happen if the protected block called Thread::ResetAbort*/
4540 if (!still_aborting)
4543 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4545 InterlockedIncrement (&thread_interruption_requested);
4547 mono_thread_info_self_interrupt ();
4549 return mono_thread_execute_interruption ();
4552 gboolean mono_thread_interruption_requested ()
4554 if (thread_interruption_requested) {
4555 MonoInternalThread *thread = mono_thread_internal_current ();
4556 /* The thread may already be stopping */
4558 return (thread->interruption_requested);
4563 static MonoException*
4564 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4566 MonoInternalThread *thread = mono_thread_internal_current ();
4568 /* The thread may already be stopping */
4572 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4573 MonoException* exc = mono_thread_execute_interruption ();
4581 * Performs the interruption of the current thread, if one has been requested,
4582 * and the thread is not running a protected wrapper.
4583 * Return the exception which needs to be thrown, if any.
4586 mono_thread_interruption_checkpoint (void)
4588 return mono_thread_interruption_checkpoint_request (FALSE);
4592 * Performs the interruption of the current thread, if one has been requested.
4593 * Return the exception which needs to be thrown, if any.
4596 mono_thread_force_interruption_checkpoint_noraise (void)
4598 return mono_thread_interruption_checkpoint_request (TRUE);
4602 * mono_set_pending_exception:
4604 * Set the pending exception of the current thread to EXC.
4605 * The exception will be thrown when execution returns to managed code.
4608 mono_set_pending_exception (MonoException *exc)
4610 MonoThread *thread = mono_thread_current ();
4612 /* The thread may already be stopping */
4616 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4618 mono_thread_request_interruption (FALSE);
4622 * mono_thread_interruption_request_flag:
4624 * Returns the address of a flag that will be non-zero if an interruption has
4625 * been requested for a thread. The thread to interrupt may not be the current
4626 * thread, so an additional call to mono_thread_interruption_requested() or
4627 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4630 gint32* mono_thread_interruption_request_flag ()
4632 return &thread_interruption_requested;
4636 mono_thread_init_apartment_state (void)
4639 MonoInternalThread* thread = mono_thread_internal_current ();
4641 /* Positive return value indicates success, either
4642 * S_OK if this is first CoInitialize call, or
4643 * S_FALSE if CoInitialize already called, but with same
4644 * threading model. A negative value indicates failure,
4645 * probably due to trying to change the threading model.
4647 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4648 ? COINIT_APARTMENTTHREADED
4649 : COINIT_MULTITHREADED) < 0) {
4650 thread->apartment_state = ThreadApartmentState_Unknown;
4656 mono_thread_cleanup_apartment_state (void)
4659 MonoInternalThread* thread = mono_thread_internal_current ();
4661 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4668 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4670 LOCK_THREAD (thread);
4671 thread->state |= state;
4672 UNLOCK_THREAD (thread);
4676 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4678 LOCK_THREAD (thread);
4679 thread->state &= ~state;
4680 UNLOCK_THREAD (thread);
4684 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4686 gboolean ret = FALSE;
4688 LOCK_THREAD (thread);
4690 if ((thread->state & test) != 0) {
4694 UNLOCK_THREAD (thread);
4699 static gboolean has_tls_get = FALSE;
4702 mono_runtime_set_has_tls_get (gboolean val)
4708 mono_runtime_has_tls_get (void)
4714 self_interrupt_thread (void *_unused)
4716 MonoThreadInfo *info = mono_thread_info_current ();
4717 MonoException *exc = mono_thread_execute_interruption ();
4718 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4719 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. */
4720 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4724 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4728 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4732 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4734 MonoJitInfo **dest = (MonoJitInfo **)data;
4740 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4742 MonoJitInfo *ji = NULL;
4747 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4748 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4749 * where we hold runtime locks.
4751 if (!mono_threads_is_coop_enabled ())
4752 mono_thread_info_set_is_async_context (TRUE);
4753 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4754 if (!mono_threads_is_coop_enabled ())
4755 mono_thread_info_set_is_async_context (FALSE);
4760 MonoInternalThread *thread;
4761 gboolean install_async_abort;
4762 MonoThreadInfoInterruptToken *interrupt_token;
4765 static SuspendThreadResult
4766 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4768 AbortThreadData *data = (AbortThreadData *)ud;
4769 MonoInternalThread *thread = data->thread;
4770 MonoJitInfo *ji = NULL;
4771 gboolean protected_wrapper;
4772 gboolean running_managed;
4774 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4775 return MonoResumeThread;
4777 /*someone is already interrupting it*/
4778 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4779 return MonoResumeThread;
4781 InterlockedIncrement (&thread_interruption_requested);
4783 ji = mono_thread_info_get_last_managed (info);
4784 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4785 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4787 if (!protected_wrapper && running_managed) {
4788 /*We are in managed code*/
4789 /*Set the thread to call */
4790 if (data->install_async_abort)
4791 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4792 return MonoResumeThread;
4795 * This will cause waits to be broken.
4796 * It will also prevent the thread from entering a wait, so if the thread returns
4797 * from the wait before it receives the abort signal, it will just spin in the wait
4798 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4801 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4803 return MonoResumeThread;
4808 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4810 AbortThreadData data;
4812 g_assert (thread != mono_thread_internal_current ());
4814 data.thread = thread;
4815 data.install_async_abort = install_async_abort;
4816 data.interrupt_token = NULL;
4818 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4819 if (data.interrupt_token)
4820 mono_thread_info_finish_interrupt (data.interrupt_token);
4821 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4825 self_abort_internal (MonoError *error)
4829 mono_error_init (error);
4831 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4832 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4834 exc = mono_thread_request_interruption (TRUE);
4836 mono_error_set_exception_instance (error, exc);
4838 mono_thread_info_self_interrupt ();
4842 MonoInternalThread *thread;
4844 MonoThreadInfoInterruptToken *interrupt_token;
4845 } SuspendThreadData;
4847 static SuspendThreadResult
4848 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4850 SuspendThreadData *data = (SuspendThreadData *)ud;
4851 MonoInternalThread *thread = data->thread;
4852 MonoJitInfo *ji = NULL;
4853 gboolean protected_wrapper;
4854 gboolean running_managed;
4856 ji = mono_thread_info_get_last_managed (info);
4857 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4858 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4860 if (running_managed && !protected_wrapper) {
4861 thread->state &= ~ThreadState_SuspendRequested;
4862 thread->state |= ThreadState_Suspended;
4863 return KeepSuspended;
4865 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4866 InterlockedIncrement (&thread_interruption_requested);
4867 if (data->interrupt)
4868 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4870 return MonoResumeThread;
4874 /* LOCKING: called with @thread synch_cs held, and releases it */
4876 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4878 SuspendThreadData data;
4880 g_assert (thread != mono_thread_internal_current ());
4882 data.thread = thread;
4883 data.interrupt = interrupt;
4884 data.interrupt_token = NULL;
4886 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4887 if (data.interrupt_token)
4888 mono_thread_info_finish_interrupt (data.interrupt_token);
4890 UNLOCK_THREAD (thread);
4893 /* LOCKING: called with @thread synch_cs held, and releases it */
4895 self_suspend_internal (void)
4897 MonoInternalThread *thread;
4899 thread = mono_thread_internal_current ();
4901 mono_thread_info_begin_self_suspend ();
4902 thread->state &= ~ThreadState_SuspendRequested;
4903 thread->state |= ThreadState_Suspended;
4905 UNLOCK_THREAD (thread);
4907 mono_thread_info_end_self_suspend ();
4911 * mono_thread_is_foreign:
4912 * @thread: the thread to query
4914 * This function allows one to determine if a thread was created by the mono runtime and has
4915 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4917 * Returns: TRUE if @thread was not created by the runtime.
4920 mono_thread_is_foreign (MonoThread *thread)
4922 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4923 return info->runtime_thread == FALSE;
4927 * mono_add_joinable_thread:
4929 * Add TID to the list of joinable threads.
4930 * LOCKING: Acquires the threads lock.
4933 mono_threads_add_joinable_thread (gpointer tid)
4937 * We cannot detach from threads because it causes problems like
4938 * 2fd16f60/r114307. So we collect them and join them when
4939 * we have time (in he finalizer thread).
4941 joinable_threads_lock ();
4942 if (!joinable_threads)
4943 joinable_threads = g_hash_table_new (NULL, NULL);
4944 g_hash_table_insert (joinable_threads, tid, tid);
4945 joinable_thread_count ++;
4946 joinable_threads_unlock ();
4948 mono_gc_finalize_notify ();
4953 * mono_threads_join_threads:
4955 * Join all joinable threads. This is called from the finalizer thread.
4956 * LOCKING: Acquires the threads lock.
4959 mono_threads_join_threads (void)
4962 GHashTableIter iter;
4969 if (!joinable_thread_count)
4973 joinable_threads_lock ();
4975 if (g_hash_table_size (joinable_threads)) {
4976 g_hash_table_iter_init (&iter, joinable_threads);
4977 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4978 thread = (pthread_t)tid;
4979 g_hash_table_remove (joinable_threads, key);
4980 joinable_thread_count --;
4983 joinable_threads_unlock ();
4985 if (thread != pthread_self ()) {
4987 /* This shouldn't block */
4988 pthread_join (thread, NULL);
5001 * Wait for thread TID to exit.
5002 * LOCKING: Acquires the threads lock.
5005 mono_thread_join (gpointer tid)
5009 gboolean found = FALSE;
5011 joinable_threads_lock ();
5012 if (!joinable_threads)
5013 joinable_threads = g_hash_table_new (NULL, NULL);
5014 if (g_hash_table_lookup (joinable_threads, tid)) {
5015 g_hash_table_remove (joinable_threads, tid);
5016 joinable_thread_count --;
5019 joinable_threads_unlock ();
5022 thread = (pthread_t)tid;
5024 pthread_join (thread, NULL);
5030 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
5032 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
5033 mono_thread_interruption_checkpoint ();
5036 static inline gboolean
5037 is_appdomainunloaded_exception (MonoClass *klass)
5039 return klass == mono_class_get_appdomain_unloaded_exception_class ();
5042 static inline gboolean
5043 is_threadabort_exception (MonoClass *klass)
5045 return klass == mono_defaults.threadabortexception_class;
5049 mono_thread_internal_unhandled_exception (MonoObject* exc)
5051 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5052 MonoClass *klass = exc->vtable->klass;
5053 if (is_threadabort_exception (klass)) {
5054 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5055 } else if (!is_appdomainunloaded_exception (klass)) {
5056 mono_unhandled_exception (exc);
5057 if (mono_environment_exitcode_get () == 1)
5064 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5067 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5068 mono_error_set_pending_exception (&error);
5072 * mono_threads_attach_coop: called by native->managed wrappers
5076 * - @return: the original domain which needs to be restored, or NULL.
5079 * - @dummy: contains the original domain
5080 * - @return: a cookie containing current MonoThreadInfo*.
5083 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5086 gboolean fresh_thread;
5089 /* Happens when called from AOTed code which is only used in the root domain. */
5090 domain = mono_get_root_domain ();
5095 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5096 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5097 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5098 * we're only responsible for making the cookie. */
5099 if (mono_threads_is_coop_enabled ()) {
5100 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5101 fresh_thread = !info || !mono_thread_info_is_live (info);
5104 if (!mono_thread_internal_current ()) {
5105 mono_thread_attach_full (domain, FALSE);
5108 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5111 orig = mono_domain_get ();
5113 mono_domain_set (domain, TRUE);
5115 if (!mono_threads_is_coop_enabled ())
5116 return orig != domain ? orig : NULL;
5120 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5121 * return the right cookie. */
5122 return mono_threads_enter_gc_unsafe_region_cookie ();
5125 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5126 return mono_threads_enter_gc_unsafe_region (dummy);
5131 * mono_threads_detach_coop: called by native->managed wrappers
5134 * - @cookie: the original domain which needs to be restored, or NULL.
5138 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5139 * - @dummy: contains the original domain
5142 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5144 MonoDomain *domain, *orig;
5146 if (!mono_threads_is_coop_enabled ()) {
5147 orig = (MonoDomain*) cookie;
5149 mono_domain_set (orig, TRUE);
5151 orig = (MonoDomain*) *dummy;
5153 domain = mono_domain_get ();
5156 /* it won't do anything if cookie is NULL
5157 * thread state RUNNING -> (RUNNING|BLOCKING) */
5158 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5160 if (orig != domain) {
5162 mono_domain_unset ();
5164 mono_domain_set (orig, TRUE);