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)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threads-types.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/environment.h>
26 #include <mono/metadata/monitor.h>
27 #include <mono/metadata/gc-internal.h>
28 #include <mono/metadata/marshal.h>
29 #include <mono/metadata/runtime.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/mono-debug-debugger.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internal.h>
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
51 #define USE_TKILL_ON_ANDROID 1
54 #ifdef PLATFORM_ANDROID
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid, int signal);
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func)(void *);
107 typedef struct _StaticDataFreeList StaticDataFreeList;
108 struct _StaticDataFreeList {
109 StaticDataFreeList *next;
117 StaticDataFreeList *freelist;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 static void mono_threads_lock (void);
130 static void mono_threads_unlock (void);
131 static mono_mutex_t threads_mutex;
133 /* Controls access to the 'joinable_threads' hash table */
134 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
135 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
136 static mono_mutex_t joinable_threads_mutex;
138 /* Holds current status of static data heap */
139 static StaticDataInfo thread_static_info;
140 static StaticDataInfo context_static_info;
142 /* The hash of existing threads (key is thread ID, value is
143 * MonoInternalThread*) that need joining before exit
145 static MonoGHashTable *threads=NULL;
147 /* List of app context GC handles.
148 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
150 static GHashTable *contexts = NULL;
152 /* Cleanup queue for contexts. */
153 static MonoReferenceQueue *context_queue;
156 * Threads which are starting up and they are not in the 'threads' hash yet.
157 * When handle_store is called for a thread, it will be removed from this hash table.
158 * Protected by mono_threads_lock ().
160 static MonoGHashTable *threads_starting_up = NULL;
162 /* The TLS key that holds the MonoObject assigned to each thread */
163 static MonoNativeTlsKey current_object_key;
166 /* Protected by the threads lock */
167 static GHashTable *joinable_threads;
168 static int joinable_thread_count;
170 #ifdef MONO_HAVE_FAST_TLS
171 /* we need to use both the Tls* functions and __thread because
172 * the gc needs to see all the threads
174 MONO_FAST_TLS_DECLARE(tls_current_object);
175 #define SET_CURRENT_OBJECT(x) do { \
176 MONO_FAST_TLS_SET (tls_current_object, x); \
177 mono_native_tls_set_value (current_object_key, x); \
179 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
181 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
182 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
185 /* function called at thread start */
186 static MonoThreadStartCB mono_thread_start_cb = NULL;
188 /* function called at thread attach */
189 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
191 /* function called at thread cleanup */
192 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
194 /* function called to notify the runtime about a pending exception on the current thread */
195 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
197 /* The default stack size for each thread */
198 static guint32 default_stacksize = 0;
199 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
201 static void thread_adjust_static_data (MonoInternalThread *thread);
202 static void context_adjust_static_data (MonoAppContext *ctx);
203 static void mono_free_static_data (gpointer* static_data);
204 static void mono_init_static_data_info (StaticDataInfo *static_data);
205 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
206 static gboolean mono_thread_resume (MonoInternalThread* thread);
207 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
208 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
209 static void self_suspend_internal (MonoInternalThread *thread);
210 static gboolean resume_thread_internal (MonoInternalThread *thread);
212 static MonoException* mono_thread_execute_interruption ();
213 static void ref_stack_destroy (gpointer rs);
215 /* Spin lock for InterlockedXXX 64 bit functions */
216 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
217 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
218 static mono_mutex_t interlocked_mutex;
220 /* global count of thread interruptions requested */
221 static gint32 thread_interruption_requested = 0;
223 /* Event signaled when a thread changes its background mode */
224 static HANDLE background_change_event;
226 static gboolean shutting_down = FALSE;
228 static gint32 managed_thread_id_counter = 0;
231 mono_threads_lock (void)
234 mono_locks_acquire (&threads_mutex, ThreadsLock);
235 MONO_FINISH_TRY_BLOCKING;
239 mono_threads_unlock (void)
241 mono_locks_release (&threads_mutex, ThreadsLock);
246 get_next_managed_thread_id (void)
248 return InterlockedIncrement (&managed_thread_id_counter);
252 mono_thread_get_tls_key (void)
254 return current_object_key;
258 mono_thread_get_tls_offset (void)
261 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 mono_mutex_t *synch_cs;
357 if (thread->synch_cs != NULL) {
361 synch_cs = g_new0 (mono_mutex_t, 1);
362 mono_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_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);
381 mono_mutex_lock (thread->synch_cs);
382 MONO_FINISH_TRY_BLOCKING;
386 unlock_thread (MonoInternalThread *thread)
388 mono_mutex_unlock (thread->synch_cs);
392 * NOTE: this function can be called also for threads different from the current one:
393 * make sure no code called from it will ever assume it is run on the thread that is
394 * getting cleaned up.
396 static void thread_cleanup (MonoInternalThread *thread)
398 g_assert (thread != NULL);
400 if (thread->abort_state_handle) {
401 mono_gchandle_free (thread->abort_state_handle);
402 thread->abort_state_handle = 0;
404 thread->abort_exc = NULL;
405 thread->current_appcontext = NULL;
408 * This is necessary because otherwise we might have
409 * cross-domain references which will not get cleaned up when
410 * the target domain is unloaded.
412 if (thread->cached_culture_info) {
414 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
415 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
419 * thread->synch_cs can be NULL if this was called after
420 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
421 * This can happen only during shutdown.
422 * The shutting_down flag is not always set, so we can't assert on it.
424 if (thread->synch_cs)
425 LOCK_THREAD (thread);
427 thread->state |= ThreadState_Stopped;
428 thread->state &= ~ThreadState_Background;
430 if (thread->synch_cs)
431 UNLOCK_THREAD (thread);
434 An interruption request has leaked to cleanup. Adjust the global counter.
436 This can happen is the abort source thread finds the abortee (this) thread
437 in unmanaged code. If this thread never trips back to managed code or check
438 the local flag it will be left set and positively unbalance the global counter.
440 Leaving the counter unbalanced will cause a performance degradation since all threads
441 will now keep checking their local flags all the time.
443 if (InterlockedExchange (&thread->interruption_requested, 0))
444 InterlockedDecrement (&thread_interruption_requested);
446 /* if the thread is not in the hash it has been removed already */
447 if (!handle_remove (thread)) {
448 if (thread == mono_thread_internal_current ()) {
449 mono_domain_unset ();
450 mono_memory_barrier ();
452 /* This needs to be called even if handle_remove () fails */
453 if (mono_thread_cleanup_fn)
454 mono_thread_cleanup_fn (thread_get_tid (thread));
457 mono_release_type_locks (thread);
459 mono_profiler_thread_end (thread->tid);
461 if (thread == mono_thread_internal_current ()) {
463 * This will signal async signal handlers that the thread has exited.
464 * The profiler callback needs this to be set, so it cannot be done earlier.
466 mono_domain_unset ();
467 mono_memory_barrier ();
470 if (thread == mono_thread_internal_current ())
471 mono_thread_pop_appdomain_ref ();
473 thread->cached_culture_info = NULL;
475 mono_free_static_data (thread->static_data);
476 thread->static_data = NULL;
477 ref_stack_destroy (thread->appdomain_refs);
478 thread->appdomain_refs = NULL;
480 if (mono_thread_cleanup_fn)
481 mono_thread_cleanup_fn (thread_get_tid (thread));
483 if (mono_gc_is_moving ()) {
484 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
485 thread->thread_pinning_ref = NULL;
490 * A special static data offset (guint32) consists of 3 parts:
492 * [0] 6-bit index into the array of chunks.
493 * [6] 25-bit offset into the array.
494 * [31] Bit indicating thread or context static.
499 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
510 } SpecialStaticOffset;
512 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
513 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
515 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
516 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
517 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
518 (((SpecialStaticOffset *) &(x))->fields.f)
521 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
523 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
525 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
526 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
528 return ((char *) thread->static_data [idx]) + off;
532 get_context_static_data (MonoAppContext *ctx, guint32 offset)
534 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
536 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
537 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
539 return ((char *) ctx->static_data [idx]) + off;
543 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
545 static MonoClassField *current_thread_field = NULL;
549 if (!current_thread_field) {
550 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
551 g_assert (current_thread_field);
554 mono_class_vtable (domain, mono_defaults.thread_class);
555 mono_domain_lock (domain);
556 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
557 mono_domain_unlock (domain);
560 return get_thread_static_data (thread, offset);
564 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
566 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
568 g_assert (current->obj.vtable->domain == domain);
570 g_assert (!*current_thread_ptr);
571 *current_thread_ptr = current;
575 create_thread_object (MonoDomain *domain)
577 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
578 return (MonoThread*)mono_gc_alloc_mature (vt);
582 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
584 MonoThread *thread = create_thread_object (domain);
585 MONO_OBJECT_SETREF (thread, internal_thread, internal);
589 static MonoInternalThread*
590 create_internal_thread (void)
592 MonoInternalThread *thread;
595 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
596 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
598 thread->synch_cs = g_new0 (mono_mutex_t, 1);
599 mono_mutex_init_recursive (thread->synch_cs);
601 thread->apartment_state = ThreadApartmentState_Unknown;
602 thread->managed_id = get_next_managed_thread_id ();
603 if (mono_gc_is_moving ()) {
604 thread->thread_pinning_ref = thread;
605 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
612 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
614 MonoDomain *domain = mono_get_root_domain ();
616 if (!candidate || candidate->obj.vtable->domain != domain)
617 candidate = new_thread_with_internal (domain, thread);
618 set_current_thread_for_domain (domain, thread, candidate);
619 g_assert (!thread->root_domain_thread);
620 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
623 static guint32 WINAPI start_wrapper_internal(void *data)
625 MonoThreadInfo *info;
626 StartInfo *start_info = (StartInfo *)data;
627 guint32 (*start_func)(void *);
631 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
634 MonoInternalThread *internal = start_info->obj->internal_thread;
635 MonoObject *start_delegate = start_info->delegate;
636 MonoDomain *domain = start_info->obj->obj.vtable->domain;
638 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
640 /* We can be sure start_info->obj->tid and
641 * start_info->obj->handle have been set, because the thread
642 * was created suspended, and these values were set before the
646 info = mono_thread_info_current ();
648 internal->thread_info = info;
649 internal->small_id = info->small_id;
653 SET_CURRENT_OBJECT (internal);
655 /* Every thread references the appdomain which created it */
656 mono_thread_push_appdomain_ref (domain);
658 if (!mono_domain_set (domain, FALSE)) {
659 /* No point in raising an appdomain_unloaded exception here */
660 /* FIXME: Cleanup here */
661 mono_thread_pop_appdomain_ref ();
665 start_func = start_info->func;
666 start_arg = start_info->obj->start_obj;
668 start_arg = start_info->start_arg;
670 /* We have to do this here because mono_thread_new_init()
671 requires that root_domain_thread is set up. */
672 thread_adjust_static_data (internal);
673 init_root_domain_thread (internal, start_info->obj);
675 /* This MUST be called before any managed code can be
676 * executed, as it calls the callback function that (for the
677 * jit) sets the lmf marker.
679 mono_thread_new_init (tid, &tid, start_func);
680 internal->stack_ptr = &tid;
682 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
684 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
686 /* On 2.0 profile (and higher), set explicitly since state might have been
688 if (internal->apartment_state == ThreadApartmentState_Unknown)
689 internal->apartment_state = ThreadApartmentState_MTA;
691 mono_thread_init_apartment_state ();
693 if(internal->start_notify!=NULL) {
694 /* Let the thread that called Start() know we're
697 ReleaseSemaphore (internal->start_notify, 1, NULL);
701 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
705 * Call this after calling start_notify, since the profiler callback might want
706 * to lock the thread, and the lock is held by thread_start () which waits for
709 mono_profiler_thread_start (tid);
711 /* if the name was set before starting, we didn't invoke the profiler callback */
712 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
713 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
714 mono_profiler_thread_name (internal->tid, tname);
717 /* start_func is set only for unmanaged start functions */
719 start_func (start_arg);
722 g_assert (start_delegate != NULL);
723 args [0] = start_arg;
724 /* we may want to handle the exception here. See comment below on unhandled exceptions */
725 mono_runtime_delegate_invoke (start_delegate, args, NULL);
728 /* If the thread calls ExitThread at all, this remaining code
729 * will not be executed, but the main thread will eventually
730 * call thread_cleanup() on this thread's behalf.
733 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
735 /* Do any cleanup needed for apartment state. This
736 * cannot be done in thread_cleanup since thread_cleanup could be
737 * called for a thread other than the current thread.
738 * mono_thread_cleanup_apartment_state cleans up apartment
739 * for the current thead */
740 mono_thread_cleanup_apartment_state ();
742 thread_cleanup (internal);
746 /* Remove the reference to the thread object in the TLS data,
747 * so the thread object can be finalized. This won't be
748 * reached if the thread threw an uncaught exception, so those
749 * thread handles will stay referenced :-( (This is due to
750 * missing support for scanning thread-specific data in the
751 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
754 SET_CURRENT_OBJECT (NULL);
759 static guint32 WINAPI start_wrapper(void *data)
763 /* Avoid scanning the frames above this frame during a GC */
764 mono_gc_set_stack_end ((void*)&dummy);
766 return start_wrapper_internal (data);
772 * Common thread creation code.
773 * LOCKING: Acquires the threads lock.
776 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
777 gboolean throw_on_failure)
779 HANDLE thread_handle;
780 MonoNativeThreadId tid;
781 guint32 create_flags;
784 * Join joinable threads to prevent running out of threads since the finalizer
785 * thread might be blocked/backlogged.
787 mono_threads_join_threads ();
789 mono_threads_lock ();
792 mono_threads_unlock ();
795 if (threads_starting_up == NULL) {
796 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
797 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
799 mono_g_hash_table_insert (threads_starting_up, thread, thread);
800 mono_threads_unlock ();
802 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
803 if (!internal->start_notify) {
804 mono_threads_lock ();
805 mono_g_hash_table_remove (threads_starting_up, thread);
806 mono_threads_unlock ();
807 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
813 stack_size = default_stacksize_for_thread (internal);
815 /* Create suspended, so we can do some housekeeping before the thread
818 create_flags = CREATE_SUSPENDED;
820 MONO_PREPARE_BLOCKING;
821 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
822 stack_size, create_flags, &tid);
823 MONO_FINISH_BLOCKING;
825 if (thread_handle == NULL) {
826 /* The thread couldn't be created, so throw an exception */
827 mono_threads_lock ();
828 mono_g_hash_table_remove (threads_starting_up, thread);
829 mono_threads_unlock ();
831 if (throw_on_failure)
832 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
834 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
837 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
839 internal->handle = thread_handle;
840 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
842 internal->threadpool_thread = threadpool_thread;
843 if (threadpool_thread)
844 mono_thread_set_state (internal, ThreadState_Background);
846 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
848 /* Only store the handle when the thread is about to be
849 * launched, to avoid the main thread deadlocking while trying
850 * to clean up a thread that will never be signalled.
852 if (!handle_store (thread, FALSE))
855 MONO_PREPARE_BLOCKING;
856 mono_thread_info_resume (tid);
857 MONO_FINISH_BLOCKING;
859 if (internal->start_notify) {
861 * Wait for the thread to set up its TLS data etc, so
862 * theres no potential race condition if someone tries
863 * to look up the data believing the thread has
866 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
868 MONO_PREPARE_BLOCKING;
869 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
870 MONO_FINISH_BLOCKING;
872 CloseHandle (internal->start_notify);
873 internal->start_notify = NULL;
876 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
881 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
883 if (mono_thread_start_cb) {
884 mono_thread_start_cb (tid, stack_start, func);
888 void mono_threads_set_default_stacksize (guint32 stacksize)
890 default_stacksize = stacksize;
893 guint32 mono_threads_get_default_stacksize (void)
895 return default_stacksize;
899 * mono_thread_create_internal:
901 * ARG should not be a GC reference.
904 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
907 MonoInternalThread *internal;
908 StartInfo *start_info;
911 thread = create_thread_object (domain);
912 internal = create_internal_thread ();
913 MONO_OBJECT_SETREF (thread, internal_thread, internal);
915 start_info = g_new0 (StartInfo, 1);
916 start_info->func = func;
917 start_info->obj = thread;
918 start_info->start_arg = arg;
920 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
924 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
925 if (mono_check_corlib_version () == NULL)
926 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
932 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
934 mono_thread_create_internal (domain, func, arg, FALSE, 0);
938 mono_thread_attach (MonoDomain *domain)
940 return mono_thread_attach_full (domain, FALSE);
944 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
946 MonoThreadInfo *info;
947 MonoInternalThread *thread;
948 MonoThread *current_thread;
949 HANDLE thread_handle;
952 if ((thread = mono_thread_internal_current ())) {
953 if (domain != mono_domain_get ())
954 mono_domain_set (domain, TRUE);
955 /* Already attached */
956 return mono_thread_current ();
959 if (!mono_gc_register_thread (&domain)) {
960 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.", GetCurrentThreadId ());
963 thread = create_internal_thread ();
965 thread_handle = mono_thread_info_open_handle ();
966 g_assert (thread_handle);
968 tid=GetCurrentThreadId ();
970 thread->handle = thread_handle;
972 thread->stack_ptr = &tid;
974 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
976 info = mono_thread_info_current ();
978 thread->thread_info = info;
979 thread->small_id = info->small_id;
981 current_thread = new_thread_with_internal (domain, thread);
983 if (!handle_store (current_thread, force_attach)) {
984 /* Mono is shutting down, so just wait for the end */
989 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
991 SET_CURRENT_OBJECT (thread);
992 mono_domain_set (domain, TRUE);
994 thread_adjust_static_data (thread);
996 init_root_domain_thread (thread, current_thread);
997 if (domain != mono_get_root_domain ())
998 set_current_thread_for_domain (domain, thread, current_thread);
1001 if (mono_thread_attach_cb) {
1005 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1008 mono_thread_attach_cb (tid, &tid);
1010 mono_thread_attach_cb (tid, staddr + stsize);
1013 // FIXME: Need a separate callback
1014 mono_profiler_thread_start (tid);
1016 return current_thread;
1020 mono_thread_detach_internal (MonoInternalThread *thread)
1022 g_return_if_fail (thread != NULL);
1024 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1026 thread_cleanup (thread);
1028 SET_CURRENT_OBJECT (NULL);
1029 mono_domain_unset ();
1031 /* Don't need to CloseHandle this thread, even though we took a
1032 * reference in mono_thread_attach (), because the GC will do it
1033 * when the Thread object is finalised.
1038 mono_thread_detach (MonoThread *thread)
1041 mono_thread_detach_internal (thread->internal_thread);
1045 * mono_thread_detach_if_exiting:
1047 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1048 * This should be used at the end of embedding code which calls into managed code, and which
1049 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1052 mono_thread_detach_if_exiting (void)
1054 if (mono_thread_info_is_exiting ()) {
1055 MonoInternalThread *thread;
1057 thread = mono_thread_internal_current ();
1059 mono_thread_detach_internal (thread);
1060 mono_thread_info_detach ();
1068 MonoInternalThread *thread = mono_thread_internal_current ();
1070 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1072 thread_cleanup (thread);
1073 SET_CURRENT_OBJECT (NULL);
1074 mono_domain_unset ();
1076 /* we could add a callback here for embedders to use. */
1077 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1078 exit (mono_environment_exitcode_get ());
1079 mono_thread_info_exit ();
1083 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1085 MonoInternalThread *internal = create_internal_thread ();
1087 internal->state = ThreadState_Unstarted;
1089 InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
1093 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1096 StartInfo *start_info;
1097 MonoInternalThread *internal;
1100 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1102 if (!this_obj->internal_thread)
1103 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1104 internal = this_obj->internal_thread;
1106 LOCK_THREAD (internal);
1108 if ((internal->state & ThreadState_Unstarted) == 0) {
1109 UNLOCK_THREAD (internal);
1110 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1114 if ((internal->state & ThreadState_Aborted) != 0) {
1115 UNLOCK_THREAD (internal);
1118 /* This is freed in start_wrapper */
1119 start_info = g_new0 (StartInfo, 1);
1120 start_info->func = NULL;
1121 start_info->start_arg = NULL;
1122 start_info->delegate = start;
1123 start_info->obj = this_obj;
1124 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1126 res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
1128 UNLOCK_THREAD (internal);
1132 internal->state &= ~ThreadState_Unstarted;
1134 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1136 UNLOCK_THREAD (internal);
1137 return internal->handle;
1141 * This is called from the finalizer of the internal thread object.
1144 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1146 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1149 * Since threads keep a reference to their thread object while running, by the time this function is called,
1150 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1151 * when thread_cleanup () can be called after this.
1154 CloseHandle (thread);
1156 if (this_obj->synch_cs) {
1157 mono_mutex_t *synch_cs = this_obj->synch_cs;
1158 this_obj->synch_cs = NULL;
1159 mono_mutex_destroy (synch_cs);
1163 if (this_obj->name) {
1164 void *name = this_obj->name;
1165 this_obj->name = NULL;
1171 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1174 MonoInternalThread *thread = mono_thread_internal_current ();
1176 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1178 mono_thread_current_check_pending_interrupt ();
1181 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1183 MONO_PREPARE_BLOCKING;
1184 res = SleepEx(ms,TRUE);
1185 MONO_FINISH_BLOCKING;
1187 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1189 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1190 MonoException* exc = mono_thread_execute_interruption ();
1192 mono_raise_exception (exc);
1204 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1209 ves_icall_System_Threading_Thread_GetDomainID (void)
1211 return mono_domain_get()->domain_id;
1215 ves_icall_System_Threading_Thread_Yield (void)
1217 return mono_thread_info_yield ();
1221 * mono_thread_get_name:
1223 * Return the name of the thread. NAME_LEN is set to the length of the name.
1224 * Return NULL if the thread has no name. The returned memory is owned by the
1228 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1232 LOCK_THREAD (this_obj);
1234 if (!this_obj->name) {
1238 *name_len = this_obj->name_len;
1239 res = g_new (gunichar2, this_obj->name_len);
1240 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1243 UNLOCK_THREAD (this_obj);
1249 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1253 LOCK_THREAD (this_obj);
1255 if (!this_obj->name)
1258 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1260 UNLOCK_THREAD (this_obj);
1266 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1268 LOCK_THREAD (this_obj);
1270 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1271 UNLOCK_THREAD (this_obj);
1273 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1276 if (this_obj->name) {
1277 g_free (this_obj->name);
1278 this_obj->name_len = 0;
1281 this_obj->name = g_new (gunichar2, mono_string_length (name));
1282 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1283 this_obj->name_len = mono_string_length (name);
1286 this_obj->name = NULL;
1289 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1291 UNLOCK_THREAD (this_obj);
1293 if (this_obj->name && this_obj->tid) {
1294 char *tname = mono_string_to_utf8 (name);
1295 mono_profiler_thread_name (this_obj->tid, tname);
1296 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1302 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1304 mono_thread_set_name_internal (this_obj, name, TRUE);
1308 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
1310 return ThreadPriority_Lowest;
1314 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1318 /* If the array is already in the requested domain, we just return it,
1319 otherwise we return a copy in that domain. */
1321 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1328 if (mono_object_domain (arr) == domain)
1331 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1332 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1337 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1339 return byte_array_to_domain (arr, mono_get_root_domain ());
1343 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1345 return byte_array_to_domain (arr, mono_domain_get ());
1349 mono_thread_current (void)
1351 MonoDomain *domain = mono_domain_get ();
1352 MonoInternalThread *internal = mono_thread_internal_current ();
1353 MonoThread **current_thread_ptr;
1355 g_assert (internal);
1356 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1358 if (!*current_thread_ptr) {
1359 g_assert (domain != mono_get_root_domain ());
1360 *current_thread_ptr = new_thread_with_internal (domain, internal);
1362 return *current_thread_ptr;
1366 mono_thread_internal_current (void)
1368 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1369 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1374 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1376 MonoInternalThread *thread = this_obj->internal_thread;
1377 HANDLE handle = thread->handle;
1378 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1381 mono_thread_current_check_pending_interrupt ();
1383 LOCK_THREAD (thread);
1385 if ((thread->state & ThreadState_Unstarted) != 0) {
1386 UNLOCK_THREAD (thread);
1388 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1392 UNLOCK_THREAD (thread);
1397 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1399 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1401 MONO_PREPARE_BLOCKING;
1402 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1403 MONO_FINISH_BLOCKING;
1405 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1407 if(ret==WAIT_OBJECT_0) {
1408 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1413 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1419 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1427 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1429 MONO_PREPARE_BLOCKING;
1431 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1433 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1434 MONO_FINISH_BLOCKING;
1436 if (ret != WAIT_IO_COMPLETION)
1439 exc = mono_thread_execute_interruption ();
1441 mono_raise_exception (exc);
1446 /* Re-calculate ms according to the time passed */
1447 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1448 if (diff_ms >= ms) {
1452 wait = ms - diff_ms;
1458 /* FIXME: exitContext isnt documented */
1459 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1465 MonoObject *waitHandle;
1466 MonoInternalThread *thread = mono_thread_internal_current ();
1468 /* Do this WaitSleepJoin check before creating objects */
1469 mono_thread_current_check_pending_interrupt ();
1471 /* We fail in managed if the array has more than 64 elements */
1472 numhandles = (guint32)mono_array_length(mono_handles);
1473 handles = g_new0(HANDLE, numhandles);
1475 for(i = 0; i < numhandles; i++) {
1476 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1477 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1484 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1486 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1488 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1492 if(ret==WAIT_FAILED) {
1493 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1495 } else if(ret==WAIT_TIMEOUT) {
1496 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1503 /* FIXME: exitContext isnt documented */
1504 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1506 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1507 uintptr_t numhandles;
1510 MonoObject *waitHandle;
1511 MonoInternalThread *thread = mono_thread_internal_current ();
1513 /* Do this WaitSleepJoin check before creating objects */
1514 mono_thread_current_check_pending_interrupt ();
1516 numhandles = mono_array_length(mono_handles);
1517 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1520 for(i = 0; i < numhandles; i++) {
1521 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1522 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1529 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1531 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1533 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1535 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1538 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1540 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1541 return ret - WAIT_OBJECT_0;
1543 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1544 return ret - WAIT_ABANDONED_0;
1551 /* FIXME: exitContext isnt documented */
1552 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
1555 MonoInternalThread *thread = mono_thread_internal_current ();
1557 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1563 mono_thread_current_check_pending_interrupt ();
1565 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1567 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1569 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1571 if(ret==WAIT_FAILED) {
1572 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1574 } else if(ret==WAIT_TIMEOUT) {
1575 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1583 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1586 MonoInternalThread *thread = mono_thread_internal_current ();
1591 mono_thread_current_check_pending_interrupt ();
1593 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1595 MONO_PREPARE_BLOCKING;
1596 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1597 MONO_FINISH_BLOCKING;
1599 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1601 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1604 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1611 mutex = CreateMutex (NULL, owned, NULL);
1613 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1615 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1623 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1624 return(ReleaseMutex (handle));
1627 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1633 *error = ERROR_SUCCESS;
1635 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1637 *error = GetLastError ();
1644 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1651 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1653 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1654 mono_string_chars (name));
1656 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1664 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1668 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1673 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1677 *error = ERROR_SUCCESS;
1679 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1681 *error = GetLastError ();
1687 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1694 event = CreateEvent (NULL, manual, initial, NULL);
1696 event = CreateEvent (NULL, manual, initial,
1697 mono_string_chars (name));
1699 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1707 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1708 return (SetEvent(handle));
1711 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1712 return (ResetEvent(handle));
1716 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1717 CloseHandle (handle);
1720 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1726 *error = ERROR_SUCCESS;
1728 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1730 *error = GetLastError ();
1736 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1738 return InterlockedIncrement (location);
1741 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1743 #if SIZEOF_VOID_P == 4
1744 if (G_UNLIKELY ((size_t)location & 0x7)) {
1746 mono_interlocked_lock ();
1749 mono_interlocked_unlock ();
1753 return InterlockedIncrement64 (location);
1756 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1758 return InterlockedDecrement(location);
1761 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1763 #if SIZEOF_VOID_P == 4
1764 if (G_UNLIKELY ((size_t)location & 0x7)) {
1766 mono_interlocked_lock ();
1769 mono_interlocked_unlock ();
1773 return InterlockedDecrement64 (location);
1776 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1778 return InterlockedExchange(location, value);
1781 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1784 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1785 mono_gc_wbarrier_generic_nostore (location);
1789 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1791 return InterlockedExchangePointer(location, value);
1794 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1796 IntFloatUnion val, ret;
1799 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1805 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1807 #if SIZEOF_VOID_P == 4
1808 if (G_UNLIKELY ((size_t)location & 0x7)) {
1810 mono_interlocked_lock ();
1813 mono_interlocked_unlock ();
1817 return InterlockedExchange64 (location, value);
1821 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1823 LongDoubleUnion val, ret;
1826 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1831 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1833 return InterlockedCompareExchange(location, value, comparand);
1836 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1838 gint32 r = InterlockedCompareExchange(location, value, comparand);
1839 *success = r == comparand;
1843 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1846 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1847 mono_gc_wbarrier_generic_nostore (location);
1851 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1853 return InterlockedCompareExchangePointer(location, value, comparand);
1856 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1858 IntFloatUnion val, ret, cmp;
1861 cmp.fval = comparand;
1862 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1868 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1870 #if SIZEOF_VOID_P == 8
1871 LongDoubleUnion val, comp, ret;
1874 comp.fval = comparand;
1875 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1881 mono_interlocked_lock ();
1883 if (old == comparand)
1885 mono_interlocked_unlock ();
1892 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1894 #if SIZEOF_VOID_P == 4
1895 if (G_UNLIKELY ((size_t)location & 0x7)) {
1897 mono_interlocked_lock ();
1899 if (old == comparand)
1901 mono_interlocked_unlock ();
1905 return InterlockedCompareExchange64 (location, value, comparand);
1909 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1912 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1913 mono_gc_wbarrier_generic_nostore (location);
1918 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1921 res = InterlockedExchangePointer ((gpointer *)location, value);
1922 mono_gc_wbarrier_generic_nostore (location);
1927 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1929 return InterlockedAdd (location, value);
1933 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1935 #if SIZEOF_VOID_P == 4
1936 if (G_UNLIKELY ((size_t)location & 0x7)) {
1938 mono_interlocked_lock ();
1941 mono_interlocked_unlock ();
1945 return InterlockedAdd64 (location, value);
1949 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1951 #if SIZEOF_VOID_P == 4
1952 if (G_UNLIKELY ((size_t)location & 0x7)) {
1954 mono_interlocked_lock ();
1956 mono_interlocked_unlock ();
1960 return InterlockedRead64 (location);
1964 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1966 mono_memory_barrier ();
1970 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1972 mono_thread_clr_state (this, state);
1974 if (state & ThreadState_Background) {
1975 /* If the thread changes the background mode, the main thread has to
1976 * be notified, since it has to rebuild the list of threads to
1979 SetEvent (background_change_event);
1984 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1986 mono_thread_set_state (this, state);
1988 if (state & ThreadState_Background) {
1989 /* If the thread changes the background mode, the main thread has to
1990 * be notified, since it has to rebuild the list of threads to
1993 SetEvent (background_change_event);
1998 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2004 state = this->state;
2006 UNLOCK_THREAD (this);
2011 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2013 MonoInternalThread *current;
2015 MonoInternalThread *thread = this_obj->internal_thread;
2017 LOCK_THREAD (thread);
2019 current = mono_thread_internal_current ();
2021 thread->thread_interrupt_requested = TRUE;
2022 throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2024 UNLOCK_THREAD (thread);
2027 abort_thread_internal (thread, TRUE, FALSE);
2031 void mono_thread_current_check_pending_interrupt ()
2033 MonoInternalThread *thread = mono_thread_internal_current ();
2034 gboolean throw = FALSE;
2036 LOCK_THREAD (thread);
2038 if (thread->thread_interrupt_requested) {
2040 thread->thread_interrupt_requested = FALSE;
2043 UNLOCK_THREAD (thread);
2046 mono_raise_exception (mono_get_exception_thread_interrupted ());
2051 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2053 LOCK_THREAD (thread);
2055 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2056 (thread->state & ThreadState_StopRequested) != 0 ||
2057 (thread->state & ThreadState_Stopped) != 0)
2059 UNLOCK_THREAD (thread);
2063 if ((thread->state & ThreadState_Unstarted) != 0) {
2064 thread->state |= ThreadState_Aborted;
2065 UNLOCK_THREAD (thread);
2069 thread->state |= ThreadState_AbortRequested;
2070 if (thread->abort_state_handle)
2071 mono_gchandle_free (thread->abort_state_handle);
2073 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2074 g_assert (thread->abort_state_handle);
2076 thread->abort_state_handle = 0;
2078 thread->abort_exc = NULL;
2080 UNLOCK_THREAD (thread);
2082 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2084 /* During shutdown, we can't wait for other threads */
2086 /* Make sure the thread is awake */
2087 mono_thread_resume (thread);
2089 abort_thread_internal (thread, TRUE, TRUE);
2093 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2095 MonoInternalThread *thread = mono_thread_internal_current ();
2096 gboolean was_aborting;
2098 LOCK_THREAD (thread);
2099 was_aborting = thread->state & ThreadState_AbortRequested;
2100 thread->state &= ~ThreadState_AbortRequested;
2101 UNLOCK_THREAD (thread);
2103 if (!was_aborting) {
2104 const char *msg = "Unable to reset abort because no abort was requested";
2105 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2108 thread->abort_exc = NULL;
2109 if (thread->abort_state_handle) {
2110 mono_gchandle_free (thread->abort_state_handle);
2111 /* This is actually not necessary - the handle
2112 only counts if the exception is set */
2113 thread->abort_state_handle = 0;
2118 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2120 LOCK_THREAD (thread);
2122 thread->state &= ~ThreadState_AbortRequested;
2124 if (thread->abort_exc) {
2125 thread->abort_exc = NULL;
2126 if (thread->abort_state_handle) {
2127 mono_gchandle_free (thread->abort_state_handle);
2128 /* This is actually not necessary - the handle
2129 only counts if the exception is set */
2130 thread->abort_state_handle = 0;
2134 UNLOCK_THREAD (thread);
2138 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2140 MonoInternalThread *thread = this_obj->internal_thread;
2141 MonoObject *state, *deserialized = NULL, *exc;
2144 if (!thread->abort_state_handle)
2147 state = mono_gchandle_get_target (thread->abort_state_handle);
2150 domain = mono_domain_get ();
2151 if (mono_object_domain (state) == domain)
2154 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2156 if (!deserialized) {
2157 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2159 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2160 mono_set_pending_exception (invalid_op_exc);
2164 return deserialized;
2168 mono_thread_suspend (MonoInternalThread *thread)
2170 LOCK_THREAD (thread);
2172 if ((thread->state & ThreadState_Unstarted) != 0 ||
2173 (thread->state & ThreadState_Aborted) != 0 ||
2174 (thread->state & ThreadState_Stopped) != 0)
2176 UNLOCK_THREAD (thread);
2180 if ((thread->state & ThreadState_Suspended) != 0 ||
2181 (thread->state & ThreadState_SuspendRequested) != 0 ||
2182 (thread->state & ThreadState_StopRequested) != 0)
2184 UNLOCK_THREAD (thread);
2188 thread->state |= ThreadState_SuspendRequested;
2190 UNLOCK_THREAD (thread);
2192 suspend_thread_internal (thread, FALSE);
2197 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2199 if (!mono_thread_suspend (this_obj->internal_thread)) {
2200 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2206 mono_thread_resume (MonoInternalThread *thread)
2208 LOCK_THREAD (thread);
2210 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2211 thread->state &= ~ThreadState_SuspendRequested;
2212 UNLOCK_THREAD (thread);
2216 if ((thread->state & ThreadState_Suspended) == 0 ||
2217 (thread->state & ThreadState_Unstarted) != 0 ||
2218 (thread->state & ThreadState_Aborted) != 0 ||
2219 (thread->state & ThreadState_Stopped) != 0)
2221 UNLOCK_THREAD (thread);
2225 return resume_thread_internal (thread);
2229 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2231 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2232 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2238 mono_threads_is_critical_method (MonoMethod *method)
2240 switch (method->wrapper_type) {
2241 case MONO_WRAPPER_RUNTIME_INVOKE:
2242 case MONO_WRAPPER_XDOMAIN_INVOKE:
2243 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2250 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2255 if (mono_threads_is_critical_method (m)) {
2256 *((gboolean*)data) = TRUE;
2263 is_running_protected_wrapper (void)
2265 gboolean found = FALSE;
2266 mono_stack_walk (find_wrapper, &found);
2270 void mono_thread_internal_stop (MonoInternalThread *thread)
2272 LOCK_THREAD (thread);
2274 if ((thread->state & ThreadState_StopRequested) != 0 ||
2275 (thread->state & ThreadState_Stopped) != 0)
2277 UNLOCK_THREAD (thread);
2281 /* Make sure the thread is awake */
2282 mono_thread_resume (thread);
2284 thread->state |= ThreadState_StopRequested;
2285 thread->state &= ~ThreadState_AbortRequested;
2287 UNLOCK_THREAD (thread);
2289 abort_thread_internal (thread, TRUE, TRUE);
2292 void mono_thread_stop (MonoThread *thread)
2294 mono_thread_internal_stop (thread->internal_thread);
2298 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2301 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2306 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2309 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2314 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2317 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2322 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2325 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2330 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2333 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2334 return (void *) tmp;
2338 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2340 volatile MonoObject *tmp;
2341 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2342 return (MonoObject *) tmp;
2346 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2349 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2354 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2357 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2362 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2364 return InterlockedRead8 (ptr);
2368 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2370 return InterlockedRead16 (ptr);
2374 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2376 return InterlockedRead (ptr);
2380 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2382 #if SIZEOF_VOID_P == 4
2383 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2385 mono_interlocked_lock ();
2386 val = *(gint64*)ptr;
2387 mono_interlocked_unlock ();
2391 return InterlockedRead64 (ptr);
2395 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2397 return InterlockedReadPointer (ptr);
2401 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2405 #if SIZEOF_VOID_P == 4
2406 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2408 mono_interlocked_lock ();
2409 val = *(double*)ptr;
2410 mono_interlocked_unlock ();
2415 u.ival = InterlockedRead64 (ptr);
2421 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2425 u.ival = InterlockedRead (ptr);
2431 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2433 return InterlockedReadPointer (ptr);
2437 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2439 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2443 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2445 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2449 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2451 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2455 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2457 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2461 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2463 mono_atomic_store_release ((volatile void **) ptr, value);
2467 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2469 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2473 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2475 mono_atomic_store_release ((volatile double *) ptr, value);
2479 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2481 mono_atomic_store_release ((volatile float *) ptr, value);
2485 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2487 InterlockedWrite8 (ptr, value);
2491 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2493 InterlockedWrite16 (ptr, value);
2497 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2499 InterlockedWrite (ptr, value);
2503 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2505 #if SIZEOF_VOID_P == 4
2506 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2507 mono_interlocked_lock ();
2508 *(gint64*)ptr = value;
2509 mono_interlocked_unlock ();
2514 InterlockedWrite64 (ptr, value);
2518 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2520 InterlockedWritePointer (ptr, value);
2524 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2528 #if SIZEOF_VOID_P == 4
2529 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2530 mono_interlocked_lock ();
2531 *(double*)ptr = value;
2532 mono_interlocked_unlock ();
2539 InterlockedWrite64 (ptr, u.ival);
2543 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2549 InterlockedWrite (ptr, u.ival);
2553 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2555 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2559 free_context (void *user_data)
2561 ContextStaticData *data = user_data;
2563 mono_threads_lock ();
2566 * There is no guarantee that, by the point this reference queue callback
2567 * has been invoked, the GC handle associated with the object will fail to
2568 * resolve as one might expect. So if we don't free and remove the GC
2569 * handle here, free_context_static_data_helper () could end up resolving
2570 * a GC handle to an actually-dead context which would contain a pointer
2571 * to an already-freed static data segment, resulting in a crash when
2574 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2576 mono_threads_unlock ();
2578 mono_gchandle_free (data->gc_handle);
2579 mono_free_static_data (data->static_data);
2584 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2586 mono_threads_lock ();
2588 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2591 contexts = g_hash_table_new (NULL, NULL);
2594 context_queue = mono_gc_reference_queue_new (free_context);
2596 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2597 g_hash_table_insert (contexts, gch, gch);
2600 * We use this intermediate structure to contain a duplicate pointer to
2601 * the static data because we can't rely on being able to resolve the GC
2602 * handle in the reference queue callback.
2604 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2605 data->gc_handle = GPOINTER_TO_UINT (gch);
2608 context_adjust_static_data (ctx);
2609 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2611 mono_threads_unlock ();
2613 mono_profiler_context_loaded (ctx);
2617 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2620 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2621 * cleanup in exceptional circumstances, we don't actually do any
2622 * cleanup work here. We instead do this via a reference queue.
2625 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2627 mono_profiler_context_unloaded (ctx);
2631 mono_thread_init_tls (void)
2633 MONO_FAST_TLS_INIT (tls_current_object);
2634 mono_native_tls_alloc (¤t_object_key, NULL);
2637 void mono_thread_init (MonoThreadStartCB start_cb,
2638 MonoThreadAttachCB attach_cb)
2640 mono_mutex_init_recursive(&threads_mutex);
2641 mono_mutex_init_recursive(&interlocked_mutex);
2642 mono_mutex_init_recursive(&joinable_threads_mutex);
2644 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2645 g_assert(background_change_event != NULL);
2647 mono_init_static_data_info (&thread_static_info);
2648 mono_init_static_data_info (&context_static_info);
2650 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2652 mono_thread_start_cb = start_cb;
2653 mono_thread_attach_cb = attach_cb;
2655 /* Get a pseudo handle to the current process. This is just a
2656 * kludge so that wapi can build a process handle if needed.
2657 * As a pseudo handle is returned, we don't need to clean
2660 GetCurrentProcess ();
2663 void mono_thread_cleanup (void)
2665 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2666 MonoThreadInfo *info;
2668 /* The main thread must abandon any held mutexes (particularly
2669 * important for named mutexes as they are shared across
2670 * processes, see bug 74680.) This will happen when the
2671 * thread exits, but if it's not running in a subthread it
2672 * won't exit in time.
2674 info = mono_thread_info_current ();
2675 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2679 /* This stuff needs more testing, it seems one of these
2680 * critical sections can be locked when mono_thread_cleanup is
2683 mono_mutex_destroy (&threads_mutex);
2684 mono_mutex_destroy (&interlocked_mutex);
2685 mono_mutex_destroy (&delayed_free_table_mutex);
2686 mono_mutex_destroy (&small_id_mutex);
2687 CloseHandle (background_change_event);
2690 mono_native_tls_free (current_object_key);
2694 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2696 mono_thread_cleanup_fn = func;
2700 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2702 thread->internal_thread->manage_callback = func;
2705 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2707 mono_thread_notify_pending_exc_fn = func;
2711 static void print_tids (gpointer key, gpointer value, gpointer user)
2713 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2714 * sizeof(uint) and a cast to uint would overflow
2716 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2717 * print this as a pointer.
2719 g_message ("Waiting for: %p", key);
2724 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2725 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2729 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2733 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2735 MONO_PREPARE_BLOCKING;
2736 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2737 MONO_FINISH_BLOCKING;
2739 if(ret==WAIT_FAILED) {
2740 /* See the comment in build_wait_tids() */
2741 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2745 for(i=0; i<wait->num; i++)
2746 CloseHandle (wait->handles[i]);
2748 if (ret == WAIT_TIMEOUT)
2751 for(i=0; i<wait->num; i++) {
2752 gsize tid = wait->threads[i]->tid;
2755 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2756 * it can still run io-layer etc. code. So wait for it to really exit.
2757 * FIXME: This won't join threads which are not in the joinable_hash yet.
2759 mono_thread_join ((gpointer)tid);
2761 mono_threads_lock ();
2762 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2763 /* This thread must have been killed, because
2764 * it hasn't cleaned itself up. (It's just
2765 * possible that the thread exited before the
2766 * parent thread had a chance to store the
2767 * handle, and now there is another pointer to
2768 * the already-exited thread stored. In this
2769 * case, we'll just get two
2770 * mono_profiler_thread_end() calls for the
2774 mono_threads_unlock ();
2775 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2776 thread_cleanup (wait->threads[i]);
2778 mono_threads_unlock ();
2783 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2785 guint32 i, ret, count;
2787 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2789 /* Add the thread state change event, so it wakes up if a thread changes
2790 * to background mode.
2793 if (count < MAXIMUM_WAIT_OBJECTS) {
2794 wait->handles [count] = background_change_event;
2798 MONO_PREPARE_BLOCKING;
2799 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2800 MONO_FINISH_BLOCKING;
2802 if(ret==WAIT_FAILED) {
2803 /* See the comment in build_wait_tids() */
2804 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2808 for(i=0; i<wait->num; i++)
2809 CloseHandle (wait->handles[i]);
2811 if (ret == WAIT_TIMEOUT)
2814 if (ret < wait->num) {
2815 gsize tid = wait->threads[ret]->tid;
2816 mono_threads_lock ();
2817 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2818 /* See comment in wait_for_tids about thread cleanup */
2819 mono_threads_unlock ();
2820 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2821 thread_cleanup (wait->threads [ret]);
2823 mono_threads_unlock ();
2827 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2829 struct wait_data *wait=(struct wait_data *)user;
2831 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2833 MonoInternalThread *thread=(MonoInternalThread *)value;
2835 /* Ignore background threads, we abort them later */
2836 /* Do not lock here since it is not needed and the caller holds threads_lock */
2837 if (thread->state & ThreadState_Background) {
2838 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2839 return; /* just leave, ignore */
2842 if (mono_gc_is_finalizer_internal_thread (thread)) {
2843 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2847 if (thread == mono_thread_internal_current ()) {
2848 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2852 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2853 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2857 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2858 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2862 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2863 if (handle == NULL) {
2864 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2868 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2869 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2870 wait->handles[wait->num]=handle;
2871 wait->threads[wait->num]=thread;
2874 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2876 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2881 /* Just ignore the rest, we can't do anything with
2888 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2890 struct wait_data *wait=(struct wait_data *)user;
2891 gsize self = GetCurrentThreadId ();
2892 MonoInternalThread *thread = value;
2895 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2898 /* The finalizer thread is not a background thread */
2899 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2900 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2902 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2906 /* printf ("A: %d\n", wait->num); */
2907 wait->handles[wait->num]=thread->handle;
2908 wait->threads[wait->num]=thread;
2911 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2912 mono_thread_internal_stop (thread);
2916 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2920 * mono_threads_set_shutting_down:
2922 * Is called by a thread that wants to shut down Mono. If the runtime is already
2923 * shutting down, the calling thread is suspended/stopped, and this function never
2927 mono_threads_set_shutting_down (void)
2929 MonoInternalThread *current_thread = mono_thread_internal_current ();
2931 mono_threads_lock ();
2933 if (shutting_down) {
2934 mono_threads_unlock ();
2936 /* Make sure we're properly suspended/stopped */
2938 LOCK_THREAD (current_thread);
2940 if ((current_thread->state & ThreadState_SuspendRequested) ||
2941 (current_thread->state & ThreadState_AbortRequested) ||
2942 (current_thread->state & ThreadState_StopRequested)) {
2943 UNLOCK_THREAD (current_thread);
2944 mono_thread_execute_interruption ();
2946 current_thread->state |= ThreadState_Stopped;
2947 UNLOCK_THREAD (current_thread);
2950 /*since we're killing the thread, unset the current domain.*/
2951 mono_domain_unset ();
2953 /* Wake up other threads potentially waiting for us */
2954 mono_thread_info_exit ();
2956 shutting_down = TRUE;
2958 /* Not really a background state change, but this will
2959 * interrupt the main thread if it is waiting for all
2960 * the other threads.
2962 SetEvent (background_change_event);
2964 mono_threads_unlock ();
2968 void mono_thread_manage (void)
2970 struct wait_data wait_data;
2971 struct wait_data *wait = &wait_data;
2973 memset (wait, 0, sizeof (struct wait_data));
2974 /* join each thread that's still running */
2975 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2977 mono_threads_lock ();
2979 THREAD_DEBUG (g_message("%s: No threads", __func__));
2980 mono_threads_unlock ();
2983 mono_threads_unlock ();
2986 mono_threads_lock ();
2987 if (shutting_down) {
2988 /* somebody else is shutting down */
2989 mono_threads_unlock ();
2992 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2993 mono_g_hash_table_foreach (threads, print_tids, NULL));
2995 ResetEvent (background_change_event);
2997 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2998 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2999 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3000 mono_threads_unlock ();
3002 /* Something to wait for */
3003 wait_for_tids_or_state_change (wait, INFINITE);
3005 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3006 } while(wait->num>0);
3008 /* Mono is shutting down, so just wait for the end */
3009 if (!mono_runtime_try_shutdown ()) {
3010 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3011 mono_thread_suspend (mono_thread_internal_current ());
3012 mono_thread_execute_interruption ();
3016 * Remove everything but the finalizer thread and self.
3017 * Also abort all the background threads
3020 mono_threads_lock ();
3023 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3024 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3025 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3027 mono_threads_unlock ();
3029 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3031 /* Something to wait for */
3032 wait_for_tids (wait, INFINITE);
3034 } while (wait->num > 0);
3037 * give the subthreads a chance to really quit (this is mainly needed
3038 * to get correct user and system times from getrusage/wait/time(1)).
3039 * This could be removed if we avoid pthread_detach() and use pthread_join().
3041 mono_thread_info_yield ();
3044 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3046 MonoInternalThread *thread=(MonoInternalThread *)value;
3048 if(thread->tid != (gsize)user) {
3049 /*TerminateThread (thread->handle, -1);*/
3053 void mono_thread_abort_all_other_threads (void)
3055 gsize self = GetCurrentThreadId ();
3057 mono_threads_lock ();
3058 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3059 mono_g_hash_table_size (threads));
3060 mono_g_hash_table_foreach (threads, print_tids, NULL));
3062 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3064 mono_threads_unlock ();
3068 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3070 MonoInternalThread *thread = (MonoInternalThread*)value;
3071 struct wait_data *wait = (struct wait_data*)user_data;
3075 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3077 * This needs no locking.
3079 if ((thread->state & ThreadState_Suspended) != 0 ||
3080 (thread->state & ThreadState_Stopped) != 0)
3083 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3084 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3088 wait->handles [wait->num] = handle;
3089 wait->threads [wait->num] = thread;
3095 * mono_thread_suspend_all_other_threads:
3097 * Suspend all managed threads except the finalizer thread and this thread. It is
3098 * not possible to resume them later.
3100 void mono_thread_suspend_all_other_threads (void)
3102 struct wait_data wait_data;
3103 struct wait_data *wait = &wait_data;
3105 gsize self = GetCurrentThreadId ();
3106 guint32 eventidx = 0;
3107 gboolean starting, finished;
3109 memset (wait, 0, sizeof (struct wait_data));
3111 * The other threads could be in an arbitrary state at this point, i.e.
3112 * they could be starting up, shutting down etc. This means that there could be
3113 * threads which are not even in the threads hash table yet.
3117 * First we set a barrier which will be checked by all threads before they
3118 * are added to the threads hash table, and they will exit if the flag is set.
3119 * This ensures that no threads could be added to the hash later.
3120 * We will use shutting_down as the barrier for now.
3122 g_assert (shutting_down);
3125 * We make multiple calls to WaitForMultipleObjects since:
3126 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3127 * - some threads could exit without becoming suspended
3132 * Make a copy of the hashtable since we can't do anything with
3133 * threads while threads_mutex is held.
3136 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3137 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3138 mono_threads_lock ();
3139 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3140 mono_threads_unlock ();
3143 /* Get the suspended events that we'll be waiting for */
3144 for (i = 0; i < wait->num; ++i) {
3145 MonoInternalThread *thread = wait->threads [i];
3147 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3148 //CloseHandle (wait->handles [i]);
3149 wait->threads [i] = NULL; /* ignore this thread in next loop */
3153 LOCK_THREAD (thread);
3155 if ((thread->state & ThreadState_Suspended) != 0 ||
3156 (thread->state & ThreadState_StopRequested) != 0 ||
3157 (thread->state & ThreadState_Stopped) != 0) {
3158 UNLOCK_THREAD (thread);
3159 CloseHandle (wait->handles [i]);
3160 wait->threads [i] = NULL; /* ignore this thread in next loop */
3166 /* Convert abort requests into suspend requests */
3167 if ((thread->state & ThreadState_AbortRequested) != 0)
3168 thread->state &= ~ThreadState_AbortRequested;
3170 thread->state |= ThreadState_SuspendRequested;
3172 UNLOCK_THREAD (thread);
3174 /* Signal the thread to suspend */
3175 suspend_thread_internal (thread, TRUE);
3177 if (eventidx <= 0) {
3179 * If there are threads which are starting up, we wait until they
3180 * are suspended when they try to register in the threads hash.
3181 * This is guaranteed to finish, since the threads which can create new
3182 * threads get suspended after a while.
3183 * FIXME: The finalizer thread can still create new threads.
3185 mono_threads_lock ();
3186 if (threads_starting_up)
3187 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3190 mono_threads_unlock ();
3199 static gboolean thread_dump_requested;
3201 static G_GNUC_UNUSED gboolean
3202 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3204 GString *p = (GString*)data;
3205 MonoMethod *method = NULL;
3206 if (frame->type == FRAME_TYPE_MANAGED)
3207 method = mono_jit_info_get_method (frame->ji);
3210 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3211 g_string_append_printf (p, " %s\n", location);
3214 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3219 static SuspendThreadResult
3220 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3222 MonoInternalThread *thread = ud;
3223 GString* text = g_string_new (0);
3225 GError *error = NULL;
3228 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3230 g_string_append_printf (text, "\n\"%s\"", name);
3233 else if (thread->threadpool_thread)
3234 g_string_append (text, "\n\"<threadpool thread>\"");
3236 g_string_append (text, "\n\"<unnamed thread>\"");
3239 /* This no longer works with remote unwinding */
3241 wapi_desc = wapi_current_thread_desc ();
3242 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3247 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, text);
3249 fprintf (stdout, "%s", text->str);
3251 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3252 OutputDebugStringA(text->str);
3255 g_string_free (text, TRUE);
3257 return MonoResumeThread;
3261 dump_thread (gpointer key, gpointer value, gpointer user)
3263 MonoInternalThread *thread = (MonoInternalThread *)value;
3265 if (thread == mono_thread_internal_current ())
3269 FIXME This still can hang if we stop a thread during malloc.
3270 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3271 that takes a callback and runs it with the target suspended.
3272 We probably should loop a bit around trying to get it to either managed code
3275 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, print_thread_dump, thread);
3279 mono_threads_perform_thread_dump (void)
3281 if (!thread_dump_requested)
3284 printf ("Full thread dump:\n");
3286 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3287 something needs then in the process.
3289 mono_loader_lock ();
3290 mono_domain_lock (mono_get_root_domain ());
3292 mono_threads_lock ();
3293 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3294 mono_threads_unlock ();
3296 mono_domain_unlock (mono_get_root_domain ());
3297 mono_loader_unlock ();
3299 thread_dump_requested = FALSE;
3303 * mono_threads_request_thread_dump:
3305 * Ask all threads except the current to print their stacktrace to stdout.
3308 mono_threads_request_thread_dump (void)
3310 /*The new thread dump code runs out of the finalizer thread. */
3311 thread_dump_requested = TRUE;
3312 mono_gc_finalize_notify ();
3317 gint allocated; /* +1 so that refs [allocated] == NULL */
3321 typedef struct ref_stack RefStack;
3324 ref_stack_new (gint initial_size)
3328 initial_size = MAX (initial_size, 16) + 1;
3329 rs = g_new0 (RefStack, 1);
3330 rs->refs = g_new0 (gpointer, initial_size);
3331 rs->allocated = initial_size;
3336 ref_stack_destroy (gpointer ptr)
3347 ref_stack_push (RefStack *rs, gpointer ptr)
3349 g_assert (rs != NULL);
3351 if (rs->bottom >= rs->allocated) {
3352 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3353 rs->allocated <<= 1;
3354 rs->refs [rs->allocated] = NULL;
3356 rs->refs [rs->bottom++] = ptr;
3360 ref_stack_pop (RefStack *rs)
3362 if (rs == NULL || rs->bottom == 0)
3366 rs->refs [rs->bottom] = NULL;
3370 ref_stack_find (RefStack *rs, gpointer ptr)
3377 for (refs = rs->refs; refs && *refs; refs++) {
3385 * mono_thread_push_appdomain_ref:
3387 * Register that the current thread may have references to objects in domain
3388 * @domain on its stack. Each call to this function should be paired with a
3389 * call to pop_appdomain_ref.
3392 mono_thread_push_appdomain_ref (MonoDomain *domain)
3394 MonoInternalThread *thread = mono_thread_internal_current ();
3397 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3398 SPIN_LOCK (thread->lock_thread_id);
3399 if (thread->appdomain_refs == NULL)
3400 thread->appdomain_refs = ref_stack_new (16);
3401 ref_stack_push (thread->appdomain_refs, domain);
3402 SPIN_UNLOCK (thread->lock_thread_id);
3407 mono_thread_pop_appdomain_ref (void)
3409 MonoInternalThread *thread = mono_thread_internal_current ();
3412 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3413 SPIN_LOCK (thread->lock_thread_id);
3414 ref_stack_pop (thread->appdomain_refs);
3415 SPIN_UNLOCK (thread->lock_thread_id);
3420 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3423 SPIN_LOCK (thread->lock_thread_id);
3424 res = ref_stack_find (thread->appdomain_refs, domain);
3425 SPIN_UNLOCK (thread->lock_thread_id);
3430 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3432 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3435 typedef struct abort_appdomain_data {
3436 struct wait_data wait;
3438 } abort_appdomain_data;
3441 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3443 MonoInternalThread *thread = (MonoInternalThread*)value;
3444 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3445 MonoDomain *domain = data->domain;
3447 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3448 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3450 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3451 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3454 data->wait.handles [data->wait.num] = handle;
3455 data->wait.threads [data->wait.num] = thread;
3458 /* Just ignore the rest, we can't do anything with
3466 * mono_threads_abort_appdomain_threads:
3468 * Abort threads which has references to the given appdomain.
3471 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3473 #ifdef __native_client__
3477 abort_appdomain_data user_data;
3479 int orig_timeout = timeout;
3482 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3484 start_time = mono_msec_ticks ();
3486 mono_threads_lock ();
3488 user_data.domain = domain;
3489 user_data.wait.num = 0;
3490 /* This shouldn't take any locks */
3491 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3492 mono_threads_unlock ();
3494 if (user_data.wait.num > 0) {
3495 /* Abort the threads outside the threads lock */
3496 for (i = 0; i < user_data.wait.num; ++i)
3497 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3500 * We should wait for the threads either to abort, or to leave the
3501 * domain. We can't do the latter, so we wait with a timeout.
3503 wait_for_tids (&user_data.wait, 100);
3506 /* Update remaining time */
3507 timeout -= mono_msec_ticks () - start_time;
3508 start_time = mono_msec_ticks ();
3510 if (orig_timeout != -1 && timeout < 0)
3513 while (user_data.wait.num > 0);
3515 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3521 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3523 MonoInternalThread *thread = (MonoInternalThread*)value;
3524 MonoDomain *domain = (MonoDomain*)user_data;
3527 /* No locking needed here */
3528 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3530 if (thread->cached_culture_info) {
3531 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3532 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3533 if (obj && obj->vtable->domain == domain)
3534 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3540 * mono_threads_clear_cached_culture:
3542 * Clear the cached_current_culture from all threads if it is in the
3546 mono_threads_clear_cached_culture (MonoDomain *domain)
3548 mono_threads_lock ();
3549 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3550 mono_threads_unlock ();
3554 * mono_thread_get_undeniable_exception:
3556 * Return an exception which needs to be raised when leaving a catch clause.
3557 * This is used for undeniable exception propagation.
3560 mono_thread_get_undeniable_exception (void)
3562 MonoInternalThread *thread = mono_thread_internal_current ();
3564 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3566 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3567 * exception if the thread no longer references a dying appdomain.
3569 thread->abort_exc->trace_ips = NULL;
3570 thread->abort_exc->stack_trace = NULL;
3571 return thread->abort_exc;
3577 #if MONO_SMALL_CONFIG
3578 #define NUM_STATIC_DATA_IDX 4
3579 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3583 #define NUM_STATIC_DATA_IDX 8
3584 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3585 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3589 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3590 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3593 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3595 gpointer *static_data = addr;
3597 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3598 void **ptr = static_data [i];
3603 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3604 void **p = ptr + idx;
3607 mark_func ((MonoObject**)p, gc_data);
3613 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3615 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3619 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3621 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3625 * mono_alloc_static_data
3627 * Allocate memory blocks for storing threads or context static data
3630 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3632 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3635 gpointer* static_data = *static_data_ptr;
3637 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3638 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3640 if (mono_gc_user_markers_supported ()) {
3641 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3642 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3644 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3645 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3648 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3649 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3650 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3651 *static_data_ptr = static_data;
3652 static_data [0] = static_data;
3655 for (i = 1; i <= idx; ++i) {
3656 if (static_data [i])
3659 if (mono_gc_user_markers_supported ())
3660 static_data [i] = g_malloc0 (static_data_size [i]);
3662 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3663 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3664 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3669 mono_free_static_data (gpointer* static_data)
3672 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3673 gpointer p = static_data [i];
3677 * At this point, the static data pointer array is still registered with the
3678 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3679 * data. Freeing the individual arrays without first nulling their slots
3680 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3681 * such an already freed array. See bug #13813.
3683 static_data [i] = NULL;
3684 mono_memory_write_barrier ();
3685 if (mono_gc_user_markers_supported ())
3688 mono_gc_free_fixed (p);
3690 mono_gc_free_fixed (static_data);
3694 * mono_init_static_data_info
3696 * Initializes static data counters
3698 static void mono_init_static_data_info (StaticDataInfo *static_data)
3700 static_data->idx = 0;
3701 static_data->offset = 0;
3702 static_data->freelist = NULL;
3706 * mono_alloc_static_data_slot
3708 * Generates an offset for static data. static_data contains the counters
3709 * used to generate it.
3712 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3714 if (!static_data->idx && !static_data->offset) {
3716 * we use the first chunk of the first allocation also as
3717 * an array for the rest of the data
3719 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3721 static_data->offset += align - 1;
3722 static_data->offset &= ~(align - 1);
3723 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3724 static_data->idx ++;
3725 g_assert (size <= static_data_size [static_data->idx]);
3726 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3727 static_data->offset = 0;
3729 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3730 static_data->offset += size;
3735 * ensure thread static fields already allocated are valid for thread
3736 * This function is called when a thread is created or on thread attach.
3739 thread_adjust_static_data (MonoInternalThread *thread)
3741 mono_threads_lock ();
3742 if (thread_static_info.offset || thread_static_info.idx > 0) {
3743 /* get the current allocated size */
3744 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3745 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3747 mono_threads_unlock ();
3751 * LOCKING: requires that threads_mutex is held
3754 context_adjust_static_data (MonoAppContext *ctx)
3756 if (context_static_info.offset || context_static_info.idx > 0) {
3757 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3758 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3759 ctx->data->static_data = ctx->static_data;
3764 * LOCKING: requires that threads_mutex is held
3767 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3769 MonoInternalThread *thread = value;
3770 guint32 offset = GPOINTER_TO_UINT (user);
3772 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3776 * LOCKING: requires that threads_mutex is held
3779 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3781 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
3786 guint32 offset = GPOINTER_TO_UINT (user);
3787 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3788 ctx->data->static_data = ctx->static_data;
3791 static StaticDataFreeList*
3792 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3794 StaticDataFreeList* prev = NULL;
3795 StaticDataFreeList* tmp = static_data->freelist;
3797 if (tmp->size == size) {
3799 prev->next = tmp->next;
3801 static_data->freelist = tmp->next;
3810 #if SIZEOF_VOID_P == 4
3817 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3819 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3821 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3822 MonoBitSet *rb = sets [idx];
3823 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3824 offset /= sizeof (uintptr_t);
3825 /* offset is now the bitmap offset */
3826 for (int i = 0; i < numbits; ++i) {
3827 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3828 mono_bitset_set_fast (rb, offset + i);
3833 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3835 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3836 MonoBitSet *rb = sets [idx];
3837 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3838 offset /= sizeof (uintptr_t);
3839 /* offset is now the bitmap offset */
3840 for (int i = 0; i < size / sizeof (uintptr_t); i++)
3841 mono_bitset_clear_fast (rb, offset + i);
3845 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3847 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3849 StaticDataInfo *info;
3852 if (static_type == SPECIAL_STATIC_THREAD) {
3853 info = &thread_static_info;
3854 sets = thread_reference_bitmaps;
3856 info = &context_static_info;
3857 sets = context_reference_bitmaps;
3860 mono_threads_lock ();
3862 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3866 offset = item->offset;
3869 offset = mono_alloc_static_data_slot (info, size, align);
3872 update_reference_bitmap (sets, offset, bitmap, numbits);
3874 if (static_type == SPECIAL_STATIC_THREAD) {
3875 /* This can be called during startup */
3876 if (threads != NULL)
3877 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3879 if (contexts != NULL)
3880 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3882 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3885 mono_threads_unlock ();
3891 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3893 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3895 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3896 return get_thread_static_data (thread, offset);
3898 return get_context_static_data (thread->current_appcontext, offset);
3903 mono_get_special_static_data (guint32 offset)
3905 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3914 * LOCKING: requires that threads_mutex is held
3917 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3919 MonoInternalThread *thread = value;
3920 OffsetSize *data = user;
3921 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3922 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3925 if (!thread->static_data || !thread->static_data [idx])
3927 ptr = ((char*) thread->static_data [idx]) + off;
3928 mono_gc_bzero_atomic (ptr, data->size);
3932 * LOCKING: requires that threads_mutex is held
3935 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3937 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
3942 OffsetSize *data = user;
3943 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3944 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3947 if (!ctx->static_data || !ctx->static_data [idx])
3950 ptr = ((char*) ctx->static_data [idx]) + off;
3951 mono_gc_bzero_atomic (ptr, data->size);
3955 do_free_special_slot (guint32 offset, guint32 size)
3957 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3959 StaticDataInfo *info;
3961 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3962 info = &thread_static_info;
3963 sets = thread_reference_bitmaps;
3965 info = &context_static_info;
3966 sets = context_reference_bitmaps;
3969 guint32 data_offset = offset;
3970 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
3971 OffsetSize data = { data_offset, size };
3973 clear_reference_bitmap (sets, data.offset, data.size);
3975 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3976 if (threads != NULL)
3977 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3979 if (contexts != NULL)
3980 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
3983 if (!mono_runtime_is_shutting_down ()) {
3984 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
3986 item->offset = offset;
3989 item->next = info->freelist;
3990 info->freelist = item;
3995 do_free_special (gpointer key, gpointer value, gpointer data)
3997 MonoClassField *field = key;
3998 guint32 offset = GPOINTER_TO_UINT (value);
4001 size = mono_type_size (field->type, &align);
4002 do_free_special_slot (offset, size);
4006 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4008 mono_threads_lock ();
4010 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4012 mono_threads_unlock ();
4016 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4018 /* Only ever called for ThreadLocal instances */
4019 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
4021 mono_threads_lock ();
4022 do_free_special_slot (offset, size);
4023 mono_threads_unlock ();
4027 static void CALLBACK dummy_apc (ULONG_PTR param)
4033 * mono_thread_execute_interruption
4035 * Performs the operation that the requested thread state requires (abort,
4038 static MonoException*
4039 mono_thread_execute_interruption (void)
4041 MonoInternalThread *thread = mono_thread_internal_current ();
4043 LOCK_THREAD (thread);
4045 /* MonoThread::interruption_requested can only be changed with atomics */
4046 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4047 /* this will consume pending APC calls */
4049 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4051 InterlockedDecrement (&thread_interruption_requested);
4053 /* Clear the interrupted flag of the thread so it can wait again */
4054 mono_thread_info_clear_self_interrupt ();
4057 if ((thread->state & ThreadState_AbortRequested) != 0) {
4058 UNLOCK_THREAD (thread);
4059 if (thread->abort_exc == NULL) {
4061 * This might be racy, but it has to be called outside the lock
4062 * since it calls managed code.
4064 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4066 return thread->abort_exc;
4068 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4069 self_suspend_internal (thread);
4072 else if ((thread->state & ThreadState_StopRequested) != 0) {
4073 /* FIXME: do this through the JIT? */
4075 UNLOCK_THREAD (thread);
4077 mono_thread_exit ();
4079 } else if (thread->pending_exception) {
4082 exc = thread->pending_exception;
4083 thread->pending_exception = NULL;
4085 UNLOCK_THREAD (thread);
4087 } else if (thread->thread_interrupt_requested) {
4089 thread->thread_interrupt_requested = FALSE;
4090 UNLOCK_THREAD (thread);
4092 return(mono_get_exception_thread_interrupted ());
4095 UNLOCK_THREAD (thread);
4101 * mono_thread_request_interruption
4103 * A signal handler can call this method to request the interruption of a
4104 * thread. The result of the interruption will depend on the current state of
4105 * the thread. If the result is an exception that needs to be throw, it is
4106 * provided as return value.
4109 mono_thread_request_interruption (gboolean running_managed)
4111 MonoInternalThread *thread = mono_thread_internal_current ();
4113 /* The thread may already be stopping */
4118 if (thread->interrupt_on_stop &&
4119 thread->state & ThreadState_StopRequested &&
4120 thread->state & ThreadState_Background)
4124 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4126 InterlockedIncrement (&thread_interruption_requested);
4128 if (!running_managed || is_running_protected_wrapper ()) {
4129 /* Can't stop while in unmanaged code. Increase the global interruption
4130 request count. When exiting the unmanaged method the count will be
4131 checked and the thread will be interrupted. */
4133 if (mono_thread_notify_pending_exc_fn && !running_managed)
4134 /* The JIT will notify the thread about the interruption */
4135 /* This shouldn't take any locks */
4136 mono_thread_notify_pending_exc_fn (NULL);
4138 /* this will awake the thread if it is in WaitForSingleObject
4140 /* Our implementation of this function ignores the func argument */
4142 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4144 mono_thread_info_self_interrupt ();
4149 return mono_thread_execute_interruption ();
4153 /*This function should be called by a thread after it has exited all of
4154 * its handle blocks at interruption time.*/
4156 mono_thread_resume_interruption (void)
4158 MonoInternalThread *thread = mono_thread_internal_current ();
4159 gboolean still_aborting;
4161 /* The thread may already be stopping */
4165 LOCK_THREAD (thread);
4166 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4167 UNLOCK_THREAD (thread);
4169 /*This can happen if the protected block called Thread::ResetAbort*/
4170 if (!still_aborting)
4173 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4175 InterlockedIncrement (&thread_interruption_requested);
4177 mono_thread_info_self_interrupt ();
4179 return mono_thread_execute_interruption ();
4182 gboolean mono_thread_interruption_requested ()
4184 if (thread_interruption_requested) {
4185 MonoInternalThread *thread = mono_thread_internal_current ();
4186 /* The thread may already be stopping */
4188 return (thread->interruption_requested);
4193 static MonoException*
4194 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4196 MonoInternalThread *thread = mono_thread_internal_current ();
4198 /* The thread may already be stopping */
4202 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4203 MonoException* exc = mono_thread_execute_interruption ();
4211 * Performs the interruption of the current thread, if one has been requested,
4212 * and the thread is not running a protected wrapper.
4213 * Return the exception which needs to be thrown, if any.
4216 mono_thread_interruption_checkpoint (void)
4218 return mono_thread_interruption_checkpoint_request (FALSE);
4222 * Performs the interruption of the current thread, if one has been requested.
4223 * Return the exception which needs to be thrown, if any.
4226 mono_thread_force_interruption_checkpoint_noraise (void)
4228 return mono_thread_interruption_checkpoint_request (TRUE);
4232 * Performs the interruption of the current thread, if one has been requested.
4233 * Throw the exception which needs to be thrown, if any.
4236 mono_thread_force_interruption_checkpoint (void)
4240 ex = mono_thread_interruption_checkpoint_request (TRUE);
4242 mono_raise_exception (ex);
4246 * mono_thread_get_and_clear_pending_exception:
4248 * Return any pending exceptions for the current thread and clear it as a side effect.
4251 mono_thread_get_and_clear_pending_exception (void)
4253 MonoInternalThread *thread = mono_thread_internal_current ();
4255 /* The thread may already be stopping */
4259 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4260 return mono_thread_execute_interruption ();
4263 if (thread->pending_exception) {
4264 MonoException *exc = thread->pending_exception;
4266 thread->pending_exception = NULL;
4274 * mono_set_pending_exception:
4276 * Set the pending exception of the current thread to EXC.
4277 * The exception will be thrown when execution returns to managed code.
4280 mono_set_pending_exception (MonoException *exc)
4282 MonoInternalThread *thread = mono_thread_internal_current ();
4284 /* The thread may already be stopping */
4288 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4290 mono_thread_request_interruption (FALSE);
4294 * mono_thread_interruption_request_flag:
4296 * Returns the address of a flag that will be non-zero if an interruption has
4297 * been requested for a thread. The thread to interrupt may not be the current
4298 * thread, so an additional call to mono_thread_interruption_requested() or
4299 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4302 gint32* mono_thread_interruption_request_flag ()
4304 return &thread_interruption_requested;
4308 mono_thread_init_apartment_state (void)
4311 MonoInternalThread* thread = mono_thread_internal_current ();
4313 /* Positive return value indicates success, either
4314 * S_OK if this is first CoInitialize call, or
4315 * S_FALSE if CoInitialize already called, but with same
4316 * threading model. A negative value indicates failure,
4317 * probably due to trying to change the threading model.
4319 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4320 ? COINIT_APARTMENTTHREADED
4321 : COINIT_MULTITHREADED) < 0) {
4322 thread->apartment_state = ThreadApartmentState_Unknown;
4328 mono_thread_cleanup_apartment_state (void)
4331 MonoInternalThread* thread = mono_thread_internal_current ();
4333 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4340 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4342 LOCK_THREAD (thread);
4343 thread->state |= state;
4344 UNLOCK_THREAD (thread);
4348 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4350 LOCK_THREAD (thread);
4351 thread->state &= ~state;
4352 UNLOCK_THREAD (thread);
4356 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4358 gboolean ret = FALSE;
4360 LOCK_THREAD (thread);
4362 if ((thread->state & test) != 0) {
4366 UNLOCK_THREAD (thread);
4371 static gboolean has_tls_get = FALSE;
4374 mono_runtime_set_has_tls_get (gboolean val)
4380 mono_runtime_has_tls_get (void)
4386 self_interrupt_thread (void *_unused)
4388 MonoThreadInfo *info = mono_thread_info_current ();
4389 MonoException *exc = mono_thread_execute_interruption ();
4390 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4391 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. */
4392 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4396 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4400 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4404 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4406 MonoJitInfo **dest = data;
4412 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4414 MonoJitInfo *ji = NULL;
4417 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4422 MonoInternalThread *thread;
4423 gboolean install_async_abort;
4424 MonoThreadInfoInterruptToken *interrupt_token;
4427 static SuspendThreadResult
4428 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4430 AbortThreadData *data = ud;
4431 MonoInternalThread *thread = data->thread;
4432 MonoJitInfo *ji = NULL;
4433 gboolean protected_wrapper;
4434 gboolean running_managed;
4436 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4437 return MonoResumeThread;
4439 /*someone is already interrupting it*/
4440 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4441 return MonoResumeThread;
4443 InterlockedIncrement (&thread_interruption_requested);
4445 ji = mono_thread_info_get_last_managed (info);
4446 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4447 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4449 if (!protected_wrapper && running_managed) {
4450 /*We are in managed code*/
4451 /*Set the thread to call */
4452 if (data->install_async_abort)
4453 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4454 return MonoResumeThread;
4456 if (mono_thread_notify_pending_exc_fn)
4457 /* The JIT will notify the thread about the interruption */
4458 mono_thread_notify_pending_exc_fn (info);
4461 * This will cause waits to be broken.
4462 * It will also prevent the thread from entering a wait, so if the thread returns
4463 * from the wait before it receives the abort signal, it will just spin in the wait
4464 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4467 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4469 return MonoResumeThread;
4474 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4476 AbortThreadData data = { 0 };
4477 data.thread = thread;
4478 data.install_async_abort = install_async_abort;
4481 FIXME this is insanely broken, it doesn't cause interruption to happen
4482 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4484 if (thread == mono_thread_internal_current ()) {
4485 /* Do it synchronously */
4486 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4488 mono_raise_exception (exc);
4490 mono_thread_info_self_interrupt ();
4495 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_critical, &data);
4496 if (data.interrupt_token)
4497 mono_thread_info_finish_interrupt (data.interrupt_token);
4498 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4502 MonoInternalThread *thread;
4504 MonoThreadInfoInterruptToken *interrupt_token;
4505 } SuspendThreadData;
4507 static SuspendThreadResult
4508 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4510 SuspendThreadData *data = ud;
4511 MonoInternalThread *thread = data->thread;
4512 MonoJitInfo *ji = NULL;
4513 gboolean protected_wrapper;
4514 gboolean running_managed;
4516 ji = mono_thread_info_get_last_managed (info);
4517 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4518 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4520 if (running_managed && !protected_wrapper) {
4521 thread->state &= ~ThreadState_SuspendRequested;
4522 thread->state |= ThreadState_Suspended;
4523 return KeepSuspended;
4525 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4526 InterlockedIncrement (&thread_interruption_requested);
4527 if (data->interrupt)
4528 data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
4530 if (mono_thread_notify_pending_exc_fn && !running_managed)
4531 /* The JIT will notify the thread about the interruption */
4532 mono_thread_notify_pending_exc_fn (info);
4533 return MonoResumeThread;
4538 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4540 LOCK_THREAD (thread);
4541 if (thread == mono_thread_internal_current ()) {
4542 mono_thread_info_begin_self_suspend ();
4543 //XXX replace this with better named functions
4544 thread->state &= ~ThreadState_SuspendRequested;
4545 thread->state |= ThreadState_Suspended;
4546 UNLOCK_THREAD (thread);
4547 mono_thread_info_end_self_suspend ();
4549 SuspendThreadData data = { 0 };
4550 data.thread = thread;
4551 data.interrupt = interrupt;
4553 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, suspend_thread_critical, &data);
4554 if (data.interrupt_token)
4555 mono_thread_info_finish_interrupt (data.interrupt_token);
4556 UNLOCK_THREAD (thread);
4560 /*This is called with @thread synch_cs held and it must release it*/
4562 self_suspend_internal (MonoInternalThread *thread)
4564 mono_thread_info_begin_self_suspend ();
4565 thread->state &= ~ThreadState_SuspendRequested;
4566 thread->state |= ThreadState_Suspended;
4567 UNLOCK_THREAD (thread);
4568 mono_thread_info_end_self_suspend ();
4571 /*This is called with @thread synch_cs held and it must release it*/
4573 resume_thread_internal (MonoInternalThread *thread)
4575 UNLOCK_THREAD (thread);
4576 /* Awake the thread */
4577 if (!mono_thread_info_resume (thread_get_tid (thread)))
4579 LOCK_THREAD (thread);
4580 thread->state &= ~ThreadState_Suspended;
4581 UNLOCK_THREAD (thread);
4587 * mono_thread_is_foreign:
4588 * @thread: the thread to query
4590 * This function allows one to determine if a thread was created by the mono runtime and has
4591 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4593 * Returns: true if @thread was not created by the runtime.
4596 mono_thread_is_foreign (MonoThread *thread)
4598 MonoThreadInfo *info = thread->internal_thread->thread_info;
4599 return info->runtime_thread == FALSE;
4603 * mono_add_joinable_thread:
4605 * Add TID to the list of joinable threads.
4606 * LOCKING: Acquires the threads lock.
4609 mono_threads_add_joinable_thread (gpointer tid)
4613 * We cannot detach from threads because it causes problems like
4614 * 2fd16f60/r114307. So we collect them and join them when
4615 * we have time (in he finalizer thread).
4617 joinable_threads_lock ();
4618 if (!joinable_threads)
4619 joinable_threads = g_hash_table_new (NULL, NULL);
4620 g_hash_table_insert (joinable_threads, tid, tid);
4621 joinable_thread_count ++;
4622 joinable_threads_unlock ();
4624 mono_gc_finalize_notify ();
4629 * mono_threads_join_threads:
4631 * Join all joinable threads. This is called from the finalizer thread.
4632 * LOCKING: Acquires the threads lock.
4635 mono_threads_join_threads (void)
4638 GHashTableIter iter;
4645 if (!joinable_thread_count)
4649 joinable_threads_lock ();
4651 if (g_hash_table_size (joinable_threads)) {
4652 g_hash_table_iter_init (&iter, joinable_threads);
4653 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4654 thread = (pthread_t)tid;
4655 g_hash_table_remove (joinable_threads, key);
4656 joinable_thread_count --;
4659 joinable_threads_unlock ();
4661 if (thread != pthread_self ())
4662 /* This shouldn't block */
4663 pthread_join (thread, NULL);
4674 * Wait for thread TID to exit.
4675 * LOCKING: Acquires the threads lock.
4678 mono_thread_join (gpointer tid)
4682 gboolean found = FALSE;
4684 joinable_threads_lock ();
4685 if (!joinable_threads)
4686 joinable_threads = g_hash_table_new (NULL, NULL);
4687 if (g_hash_table_lookup (joinable_threads, tid)) {
4688 g_hash_table_remove (joinable_threads, tid);
4689 joinable_thread_count --;
4692 joinable_threads_unlock ();
4695 thread = (pthread_t)tid;
4696 pthread_join (thread, NULL);
4701 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4703 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4704 mono_thread_interruption_checkpoint ();
4707 static inline gboolean
4708 is_appdomainunloaded_exception (MonoClass *klass)
4710 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4712 if (!app_domain_unloaded_exception_klass)
4713 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4714 g_assert (app_domain_unloaded_exception_klass);
4716 return klass == app_domain_unloaded_exception_klass;
4719 static inline gboolean
4720 is_threadabort_exception (MonoClass *klass)
4722 return klass == mono_defaults.threadabortexception_class;
4726 mono_thread_internal_unhandled_exception (MonoObject* exc)
4728 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4729 MonoClass *klass = exc->vtable->klass;
4730 if (is_threadabort_exception (klass)) {
4731 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4732 } else if (!is_appdomainunloaded_exception (klass)) {
4733 mono_unhandled_exception (exc);
4734 if (mono_environment_exitcode_get () == 1)