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-internals.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-internals.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;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable *threads_starting_up = NULL;
159 /* The TLS key that holds the MonoObject assigned to each thread */
160 static MonoNativeTlsKey current_object_key;
163 /* Protected by the threads lock */
164 static GHashTable *joinable_threads;
165 static int joinable_thread_count;
167 #ifdef MONO_HAVE_FAST_TLS
168 /* we need to use both the Tls* functions and __thread because
169 * the gc needs to see all the threads
171 MONO_FAST_TLS_DECLARE(tls_current_object);
172 #define SET_CURRENT_OBJECT(x) do { \
173 MONO_FAST_TLS_SET (tls_current_object, x); \
174 mono_native_tls_set_value (current_object_key, x); \
176 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
178 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
179 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
182 /* function called at thread start */
183 static MonoThreadStartCB mono_thread_start_cb = NULL;
185 /* function called at thread attach */
186 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
188 /* function called at thread cleanup */
189 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
191 /* function called to notify the runtime about a pending exception on the current thread */
192 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
194 /* The default stack size for each thread */
195 static guint32 default_stacksize = 0;
196 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
198 static void thread_adjust_static_data (MonoInternalThread *thread);
199 static void context_adjust_static_data (MonoAppContext *ctx);
200 static void mono_free_static_data (gpointer* static_data);
201 static void mono_init_static_data_info (StaticDataInfo *static_data);
202 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
203 static gboolean mono_thread_resume (MonoInternalThread* thread);
204 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
205 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
206 static void self_suspend_internal (MonoInternalThread *thread);
207 static gboolean resume_thread_internal (MonoInternalThread *thread);
209 static MonoException* mono_thread_execute_interruption ();
210 static void ref_stack_destroy (gpointer rs);
212 /* Spin lock for InterlockedXXX 64 bit functions */
213 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
214 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
215 static mono_mutex_t interlocked_mutex;
217 /* global count of thread interruptions requested */
218 static gint32 thread_interruption_requested = 0;
220 /* Event signaled when a thread changes its background mode */
221 static HANDLE background_change_event;
223 static gboolean shutting_down = FALSE;
225 static gint32 managed_thread_id_counter = 0;
228 mono_threads_lock (void)
231 mono_locks_acquire (&threads_mutex, ThreadsLock);
232 MONO_FINISH_TRY_BLOCKING;
236 mono_threads_unlock (void)
238 mono_locks_release (&threads_mutex, ThreadsLock);
243 get_next_managed_thread_id (void)
245 return InterlockedIncrement (&managed_thread_id_counter);
249 mono_thread_get_tls_key (void)
251 return current_object_key;
255 mono_thread_get_tls_offset (void)
258 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
262 static inline MonoNativeThreadId
263 thread_get_tid (MonoInternalThread *thread)
265 /* We store the tid as a guint64 to keep the object layout constant between platforms */
266 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
269 /* handle_store() and handle_remove() manage the array of threads that
270 * still need to be waited for when the main thread exits.
272 * If handle_store() returns FALSE the thread must not be started
273 * because Mono is shutting down.
275 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
277 mono_threads_lock ();
279 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
281 if (threads_starting_up)
282 mono_g_hash_table_remove (threads_starting_up, thread);
284 if (shutting_down && !force_attach) {
285 mono_threads_unlock ();
290 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
291 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
294 /* We don't need to duplicate thread->handle, because it is
295 * only closed when the thread object is finalized by the GC.
297 g_assert (thread->internal_thread);
298 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
299 thread->internal_thread);
301 mono_threads_unlock ();
306 static gboolean handle_remove(MonoInternalThread *thread)
309 gsize tid = thread->tid;
311 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
313 mono_threads_lock ();
316 /* We have to check whether the thread object for the
317 * tid is still the same in the table because the
318 * thread might have been destroyed and the tid reused
319 * in the meantime, in which case the tid would be in
320 * the table, but with another thread object.
322 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
323 mono_g_hash_table_remove (threads, (gpointer)tid);
332 mono_threads_unlock ();
334 /* Don't close the handle here, wait for the object finalizer
335 * to do it. Otherwise, the following race condition applies:
337 * 1) Thread exits (and handle_remove() closes the handle)
339 * 2) Some other handle is reassigned the same slot
341 * 3) Another thread tries to join the first thread, and
342 * blocks waiting for the reassigned handle to be signalled
343 * (which might never happen). This is possible, because the
344 * thread calling Join() still has a reference to the first
350 static void ensure_synch_cs_set (MonoInternalThread *thread)
352 mono_mutex_t *synch_cs;
354 if (thread->synch_cs != NULL) {
358 synch_cs = g_new0 (mono_mutex_t, 1);
359 mono_mutex_init_recursive (synch_cs);
361 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
362 synch_cs, NULL) != NULL) {
363 /* Another thread must have installed this CS */
364 mono_mutex_destroy (synch_cs);
370 lock_thread (MonoInternalThread *thread)
372 if (!thread->synch_cs)
373 ensure_synch_cs_set (thread);
375 g_assert (thread->synch_cs);
378 mono_mutex_lock (thread->synch_cs);
379 MONO_FINISH_TRY_BLOCKING;
383 unlock_thread (MonoInternalThread *thread)
385 mono_mutex_unlock (thread->synch_cs);
389 * NOTE: this function can be called also for threads different from the current one:
390 * make sure no code called from it will ever assume it is run on the thread that is
391 * getting cleaned up.
393 static void thread_cleanup (MonoInternalThread *thread)
395 g_assert (thread != NULL);
397 if (thread->abort_state_handle) {
398 mono_gchandle_free (thread->abort_state_handle);
399 thread->abort_state_handle = 0;
401 thread->abort_exc = NULL;
402 thread->current_appcontext = NULL;
405 * This is necessary because otherwise we might have
406 * cross-domain references which will not get cleaned up when
407 * the target domain is unloaded.
409 if (thread->cached_culture_info) {
411 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
412 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
416 * thread->synch_cs can be NULL if this was called after
417 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
418 * This can happen only during shutdown.
419 * The shutting_down flag is not always set, so we can't assert on it.
421 if (thread->synch_cs)
422 LOCK_THREAD (thread);
424 thread->state |= ThreadState_Stopped;
425 thread->state &= ~ThreadState_Background;
427 if (thread->synch_cs)
428 UNLOCK_THREAD (thread);
431 An interruption request has leaked to cleanup. Adjust the global counter.
433 This can happen is the abort source thread finds the abortee (this) thread
434 in unmanaged code. If this thread never trips back to managed code or check
435 the local flag it will be left set and positively unbalance the global counter.
437 Leaving the counter unbalanced will cause a performance degradation since all threads
438 will now keep checking their local flags all the time.
440 if (InterlockedExchange (&thread->interruption_requested, 0))
441 InterlockedDecrement (&thread_interruption_requested);
443 /* if the thread is not in the hash it has been removed already */
444 if (!handle_remove (thread)) {
445 if (thread == mono_thread_internal_current ()) {
446 mono_domain_unset ();
447 mono_memory_barrier ();
449 /* This needs to be called even if handle_remove () fails */
450 if (mono_thread_cleanup_fn)
451 mono_thread_cleanup_fn (thread_get_tid (thread));
454 mono_release_type_locks (thread);
456 mono_profiler_thread_end (thread->tid);
458 if (thread == mono_thread_internal_current ()) {
460 * This will signal async signal handlers that the thread has exited.
461 * The profiler callback needs this to be set, so it cannot be done earlier.
463 mono_domain_unset ();
464 mono_memory_barrier ();
467 if (thread == mono_thread_internal_current ())
468 mono_thread_pop_appdomain_ref ();
470 thread->cached_culture_info = NULL;
472 mono_free_static_data (thread->static_data);
473 thread->static_data = NULL;
474 ref_stack_destroy (thread->appdomain_refs);
475 thread->appdomain_refs = NULL;
477 if (mono_thread_cleanup_fn)
478 mono_thread_cleanup_fn (thread_get_tid (thread));
480 if (mono_gc_is_moving ()) {
481 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
482 thread->thread_pinning_ref = NULL;
487 * A special static data offset (guint32) consists of 3 parts:
489 * [0] 6-bit index into the array of chunks.
490 * [6] 25-bit offset into the array.
491 * [31] Bit indicating thread or context static.
496 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
507 } SpecialStaticOffset;
509 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
510 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
512 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
513 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
514 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
515 (((SpecialStaticOffset *) &(x))->fields.f)
518 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
520 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
522 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
523 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
525 return ((char *) thread->static_data [idx]) + off;
529 get_context_static_data (MonoAppContext *ctx, guint32 offset)
531 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
533 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
534 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
536 return ((char *) ctx->static_data [idx]) + off;
540 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
542 static MonoClassField *current_thread_field = NULL;
546 if (!current_thread_field) {
547 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
548 g_assert (current_thread_field);
551 mono_class_vtable (domain, mono_defaults.thread_class);
552 mono_domain_lock (domain);
553 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
554 mono_domain_unlock (domain);
557 return get_thread_static_data (thread, offset);
561 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
563 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
565 g_assert (current->obj.vtable->domain == domain);
567 g_assert (!*current_thread_ptr);
568 *current_thread_ptr = current;
572 create_thread_object (MonoDomain *domain)
574 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
575 return (MonoThread*)mono_gc_alloc_mature (vt);
579 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
581 MonoThread *thread = create_thread_object (domain);
582 MONO_OBJECT_SETREF (thread, internal_thread, internal);
586 static MonoInternalThread*
587 create_internal_thread (void)
589 MonoInternalThread *thread;
592 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
593 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
595 thread->synch_cs = g_new0 (mono_mutex_t, 1);
596 mono_mutex_init_recursive (thread->synch_cs);
598 thread->apartment_state = ThreadApartmentState_Unknown;
599 thread->managed_id = get_next_managed_thread_id ();
600 if (mono_gc_is_moving ()) {
601 thread->thread_pinning_ref = thread;
602 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
609 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
611 MonoDomain *domain = mono_get_root_domain ();
613 if (!candidate || candidate->obj.vtable->domain != domain)
614 candidate = new_thread_with_internal (domain, thread);
615 set_current_thread_for_domain (domain, thread, candidate);
616 g_assert (!thread->root_domain_thread);
617 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
620 static guint32 WINAPI start_wrapper_internal(void *data)
622 MonoThreadInfo *info;
623 StartInfo *start_info = (StartInfo *)data;
624 guint32 (*start_func)(void *);
628 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
631 MonoInternalThread *internal = start_info->obj->internal_thread;
632 MonoObject *start_delegate = start_info->delegate;
633 MonoDomain *domain = start_info->obj->obj.vtable->domain;
635 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
637 /* We can be sure start_info->obj->tid and
638 * start_info->obj->handle have been set, because the thread
639 * was created suspended, and these values were set before the
643 info = mono_thread_info_current ();
645 internal->thread_info = info;
646 internal->small_id = info->small_id;
650 SET_CURRENT_OBJECT (internal);
652 /* Every thread references the appdomain which created it */
653 mono_thread_push_appdomain_ref (domain);
655 if (!mono_domain_set (domain, FALSE)) {
656 /* No point in raising an appdomain_unloaded exception here */
657 /* FIXME: Cleanup here */
658 mono_thread_pop_appdomain_ref ();
662 start_func = start_info->func;
663 start_arg = start_info->obj->start_obj;
665 start_arg = start_info->start_arg;
667 /* We have to do this here because mono_thread_new_init()
668 requires that root_domain_thread is set up. */
669 thread_adjust_static_data (internal);
670 init_root_domain_thread (internal, start_info->obj);
672 /* This MUST be called before any managed code can be
673 * executed, as it calls the callback function that (for the
674 * jit) sets the lmf marker.
676 mono_thread_new_init (tid, &tid, start_func);
677 internal->stack_ptr = &tid;
678 if (domain != mono_get_root_domain ())
679 set_current_thread_for_domain (domain, internal, start_info->obj);
681 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
683 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
685 /* On 2.0 profile (and higher), set explicitly since state might have been
687 if (internal->apartment_state == ThreadApartmentState_Unknown)
688 internal->apartment_state = ThreadApartmentState_MTA;
690 mono_thread_init_apartment_state ();
692 if(internal->start_notify!=NULL) {
693 /* Let the thread that called Start() know we're
696 ReleaseSemaphore (internal->start_notify, 1, NULL);
700 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
704 * Call this after calling start_notify, since the profiler callback might want
705 * to lock the thread, and the lock is held by thread_start () which waits for
708 mono_profiler_thread_start (tid);
710 /* if the name was set before starting, we didn't invoke the profiler callback */
711 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
712 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
713 mono_profiler_thread_name (internal->tid, tname);
716 /* start_func is set only for unmanaged start functions */
718 start_func (start_arg);
721 g_assert (start_delegate != NULL);
722 args [0] = start_arg;
723 /* we may want to handle the exception here. See comment below on unhandled exceptions */
724 mono_runtime_delegate_invoke (start_delegate, args, NULL);
727 /* If the thread calls ExitThread at all, this remaining code
728 * will not be executed, but the main thread will eventually
729 * call thread_cleanup() on this thread's behalf.
732 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
734 /* Do any cleanup needed for apartment state. This
735 * cannot be done in thread_cleanup since thread_cleanup could be
736 * called for a thread other than the current thread.
737 * mono_thread_cleanup_apartment_state cleans up apartment
738 * for the current thead */
739 mono_thread_cleanup_apartment_state ();
741 thread_cleanup (internal);
745 /* Remove the reference to the thread object in the TLS data,
746 * so the thread object can be finalized. This won't be
747 * reached if the thread threw an uncaught exception, so those
748 * thread handles will stay referenced :-( (This is due to
749 * missing support for scanning thread-specific data in the
750 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
753 SET_CURRENT_OBJECT (NULL);
758 static guint32 WINAPI start_wrapper(void *data)
762 /* Avoid scanning the frames above this frame during a GC */
763 mono_gc_set_stack_end ((void*)&dummy);
765 return start_wrapper_internal (data);
771 * Common thread creation code.
772 * LOCKING: Acquires the threads lock.
775 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
776 gboolean throw_on_failure)
778 HANDLE thread_handle;
779 MonoNativeThreadId tid;
780 guint32 create_flags;
783 * Join joinable threads to prevent running out of threads since the finalizer
784 * thread might be blocked/backlogged.
786 mono_threads_join_threads ();
788 mono_threads_lock ();
791 mono_threads_unlock ();
794 if (threads_starting_up == NULL) {
795 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
796 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
798 mono_g_hash_table_insert (threads_starting_up, thread, thread);
799 mono_threads_unlock ();
801 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
802 if (!internal->start_notify) {
803 mono_threads_lock ();
804 mono_g_hash_table_remove (threads_starting_up, thread);
805 mono_threads_unlock ();
806 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
812 stack_size = default_stacksize_for_thread (internal);
814 /* Create suspended, so we can do some housekeeping before the thread
817 create_flags = CREATE_SUSPENDED;
819 MONO_PREPARE_BLOCKING;
820 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
821 stack_size, create_flags, &tid);
822 MONO_FINISH_BLOCKING;
824 if (thread_handle == NULL) {
825 /* The thread couldn't be created, so throw an exception */
826 mono_threads_lock ();
827 mono_g_hash_table_remove (threads_starting_up, thread);
828 mono_threads_unlock ();
830 if (throw_on_failure)
831 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
833 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
836 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
838 internal->handle = thread_handle;
839 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
841 internal->threadpool_thread = threadpool_thread;
842 if (threadpool_thread)
843 mono_thread_set_state (internal, ThreadState_Background);
845 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
847 /* Only store the handle when the thread is about to be
848 * launched, to avoid the main thread deadlocking while trying
849 * to clean up a thread that will never be signalled.
851 if (!handle_store (thread, FALSE))
854 MONO_PREPARE_BLOCKING;
855 mono_thread_info_resume (tid);
856 MONO_FINISH_BLOCKING;
858 if (internal->start_notify) {
860 * Wait for the thread to set up its TLS data etc, so
861 * theres no potential race condition if someone tries
862 * to look up the data believing the thread has
865 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
867 MONO_PREPARE_BLOCKING;
868 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
869 MONO_FINISH_BLOCKING;
871 CloseHandle (internal->start_notify);
872 internal->start_notify = NULL;
875 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
880 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
882 if (mono_thread_start_cb) {
883 mono_thread_start_cb (tid, stack_start, func);
887 void mono_threads_set_default_stacksize (guint32 stacksize)
889 default_stacksize = stacksize;
892 guint32 mono_threads_get_default_stacksize (void)
894 return default_stacksize;
898 * mono_thread_create_internal:
900 * ARG should not be a GC reference.
903 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
906 MonoInternalThread *internal;
907 StartInfo *start_info;
910 thread = create_thread_object (domain);
911 internal = create_internal_thread ();
912 MONO_OBJECT_SETREF (thread, internal_thread, internal);
914 start_info = g_new0 (StartInfo, 1);
915 start_info->func = func;
916 start_info->obj = thread;
917 start_info->start_arg = arg;
919 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
923 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
924 #ifndef MONO_CROSS_COMPILE
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);
933 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
935 mono_thread_create_internal (domain, func, arg, FALSE, 0);
939 mono_thread_attach (MonoDomain *domain)
941 return mono_thread_attach_full (domain, FALSE);
945 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
947 MonoThreadInfo *info;
948 MonoInternalThread *thread;
949 MonoThread *current_thread;
950 HANDLE thread_handle;
951 MonoNativeThreadId tid;
953 if ((thread = mono_thread_internal_current ())) {
954 if (domain != mono_domain_get ())
955 mono_domain_set (domain, TRUE);
956 /* Already attached */
957 return mono_thread_current ();
960 if (!mono_gc_register_thread (&domain)) {
961 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", mono_native_thread_id_get ());
964 thread = create_internal_thread ();
966 thread_handle = mono_thread_info_open_handle ();
967 g_assert (thread_handle);
969 tid=mono_native_thread_id_get ();
971 thread->handle = thread_handle;
972 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
973 thread->stack_ptr = &tid;
975 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
977 info = mono_thread_info_current ();
979 thread->thread_info = info;
980 thread->small_id = info->small_id;
982 current_thread = new_thread_with_internal (domain, thread);
984 if (!handle_store (current_thread, force_attach)) {
985 /* Mono is shutting down, so just wait for the end */
987 mono_thread_info_sleep (10000, NULL);
990 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
992 SET_CURRENT_OBJECT (thread);
993 mono_domain_set (domain, TRUE);
995 thread_adjust_static_data (thread);
997 init_root_domain_thread (thread, current_thread);
998 if (domain != mono_get_root_domain ())
999 set_current_thread_for_domain (domain, thread, current_thread);
1002 if (mono_thread_attach_cb) {
1006 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1009 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1011 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1014 // FIXME: Need a separate callback
1015 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1017 return current_thread;
1021 mono_thread_detach_internal (MonoInternalThread *thread)
1023 g_return_if_fail (thread != NULL);
1025 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1027 thread_cleanup (thread);
1029 SET_CURRENT_OBJECT (NULL);
1030 mono_domain_unset ();
1032 /* Don't need to CloseHandle this thread, even though we took a
1033 * reference in mono_thread_attach (), because the GC will do it
1034 * when the Thread object is finalised.
1039 mono_thread_detach (MonoThread *thread)
1042 mono_thread_detach_internal (thread->internal_thread);
1046 * mono_thread_detach_if_exiting:
1048 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1049 * This should be used at the end of embedding code which calls into managed code, and which
1050 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1053 mono_thread_detach_if_exiting (void)
1055 if (mono_thread_info_is_exiting ()) {
1056 MonoInternalThread *thread;
1058 thread = mono_thread_internal_current ();
1060 mono_thread_detach_internal (thread);
1061 mono_thread_info_detach ();
1069 MonoInternalThread *thread = mono_thread_internal_current ();
1071 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1073 thread_cleanup (thread);
1074 SET_CURRENT_OBJECT (NULL);
1075 mono_domain_unset ();
1077 /* we could add a callback here for embedders to use. */
1078 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1079 exit (mono_environment_exitcode_get ());
1080 mono_thread_info_exit ();
1084 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1086 MonoInternalThread *internal = create_internal_thread ();
1088 internal->state = ThreadState_Unstarted;
1090 InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
1094 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1097 StartInfo *start_info;
1098 MonoInternalThread *internal;
1101 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1103 if (!this_obj->internal_thread)
1104 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1105 internal = this_obj->internal_thread;
1107 LOCK_THREAD (internal);
1109 if ((internal->state & ThreadState_Unstarted) == 0) {
1110 UNLOCK_THREAD (internal);
1111 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1115 if ((internal->state & ThreadState_Aborted) != 0) {
1116 UNLOCK_THREAD (internal);
1119 /* This is freed in start_wrapper */
1120 start_info = g_new0 (StartInfo, 1);
1121 start_info->func = NULL;
1122 start_info->start_arg = NULL;
1123 start_info->delegate = start;
1124 start_info->obj = this_obj;
1125 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1127 res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
1129 UNLOCK_THREAD (internal);
1133 internal->state &= ~ThreadState_Unstarted;
1135 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1137 UNLOCK_THREAD (internal);
1138 return internal->handle;
1142 * This is called from the finalizer of the internal thread object.
1145 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1147 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1150 * Since threads keep a reference to their thread object while running, by the time this function is called,
1151 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1152 * when thread_cleanup () can be called after this.
1155 CloseHandle (thread);
1157 if (this_obj->synch_cs) {
1158 mono_mutex_t *synch_cs = this_obj->synch_cs;
1159 this_obj->synch_cs = NULL;
1160 mono_mutex_destroy (synch_cs);
1164 if (this_obj->name) {
1165 void *name = this_obj->name;
1166 this_obj->name = NULL;
1172 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1175 MonoInternalThread *thread = mono_thread_internal_current ();
1177 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1179 mono_thread_current_check_pending_interrupt ();
1182 gboolean alerted = FALSE;
1184 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1186 MONO_PREPARE_BLOCKING
1187 res = mono_thread_info_sleep (ms, &alerted);
1188 MONO_FINISH_BLOCKING
1190 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1193 MonoException* exc = mono_thread_execute_interruption ();
1195 mono_raise_exception (exc);
1207 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1212 ves_icall_System_Threading_Thread_GetDomainID (void)
1214 return mono_domain_get()->domain_id;
1218 ves_icall_System_Threading_Thread_Yield (void)
1220 return mono_thread_info_yield ();
1224 * mono_thread_get_name:
1226 * Return the name of the thread. NAME_LEN is set to the length of the name.
1227 * Return NULL if the thread has no name. The returned memory is owned by the
1231 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1235 LOCK_THREAD (this_obj);
1237 if (!this_obj->name) {
1241 *name_len = this_obj->name_len;
1242 res = g_new (gunichar2, this_obj->name_len);
1243 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1246 UNLOCK_THREAD (this_obj);
1252 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1256 LOCK_THREAD (this_obj);
1258 if (!this_obj->name)
1261 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1263 UNLOCK_THREAD (this_obj);
1269 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1271 LOCK_THREAD (this_obj);
1273 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1274 UNLOCK_THREAD (this_obj);
1276 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1279 if (this_obj->name) {
1280 g_free (this_obj->name);
1281 this_obj->name_len = 0;
1284 this_obj->name = g_new (gunichar2, mono_string_length (name));
1285 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1286 this_obj->name_len = mono_string_length (name);
1289 this_obj->name = NULL;
1292 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1294 UNLOCK_THREAD (this_obj);
1296 if (this_obj->name && this_obj->tid) {
1297 char *tname = mono_string_to_utf8 (name);
1298 mono_profiler_thread_name (this_obj->tid, tname);
1299 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1305 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1307 mono_thread_set_name_internal (this_obj, name, TRUE);
1311 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1313 return ThreadPriority_Lowest;
1317 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1321 /* If the array is already in the requested domain, we just return it,
1322 otherwise we return a copy in that domain. */
1324 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1331 if (mono_object_domain (arr) == domain)
1334 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1335 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1340 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1342 return byte_array_to_domain (arr, mono_get_root_domain ());
1346 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1348 return byte_array_to_domain (arr, mono_domain_get ());
1352 mono_thread_current (void)
1354 MonoDomain *domain = mono_domain_get ();
1355 MonoInternalThread *internal = mono_thread_internal_current ();
1356 MonoThread **current_thread_ptr;
1358 g_assert (internal);
1359 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1361 if (!*current_thread_ptr) {
1362 g_assert (domain != mono_get_root_domain ());
1363 *current_thread_ptr = new_thread_with_internal (domain, internal);
1365 return *current_thread_ptr;
1368 /* Return the thread object belonging to INTERNAL in the current domain */
1370 mono_thread_current_for_thread (MonoInternalThread *internal)
1372 MonoDomain *domain = mono_domain_get ();
1373 MonoThread **current_thread_ptr;
1375 g_assert (internal);
1376 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1378 if (!*current_thread_ptr) {
1379 g_assert (domain != mono_get_root_domain ());
1380 *current_thread_ptr = new_thread_with_internal (domain, internal);
1382 return *current_thread_ptr;
1386 mono_thread_internal_current (void)
1388 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1389 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1394 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1396 MonoInternalThread *thread = this_obj->internal_thread;
1397 HANDLE handle = thread->handle;
1398 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1401 mono_thread_current_check_pending_interrupt ();
1403 LOCK_THREAD (thread);
1405 if ((thread->state & ThreadState_Unstarted) != 0) {
1406 UNLOCK_THREAD (thread);
1408 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1412 UNLOCK_THREAD (thread);
1417 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1419 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1421 MONO_PREPARE_BLOCKING;
1422 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1423 MONO_FINISH_BLOCKING;
1425 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1427 if(ret==WAIT_OBJECT_0) {
1428 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1433 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1439 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1447 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1449 MONO_PREPARE_BLOCKING;
1451 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1453 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1454 MONO_FINISH_BLOCKING;
1456 if (ret != WAIT_IO_COMPLETION)
1459 exc = mono_thread_execute_interruption ();
1461 mono_raise_exception (exc);
1466 /* Re-calculate ms according to the time passed */
1467 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1468 if (diff_ms >= ms) {
1472 wait = ms - diff_ms;
1478 /* FIXME: exitContext isnt documented */
1479 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1485 MonoObject *waitHandle;
1486 MonoInternalThread *thread = mono_thread_internal_current ();
1488 /* Do this WaitSleepJoin check before creating objects */
1489 mono_thread_current_check_pending_interrupt ();
1491 /* We fail in managed if the array has more than 64 elements */
1492 numhandles = (guint32)mono_array_length(mono_handles);
1493 handles = g_new0(HANDLE, numhandles);
1495 for(i = 0; i < numhandles; i++) {
1496 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1497 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1504 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1506 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1508 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1512 if(ret==WAIT_FAILED) {
1513 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
1515 } else if(ret==WAIT_TIMEOUT) {
1516 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
1523 /* FIXME: exitContext isnt documented */
1524 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1526 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1527 uintptr_t numhandles;
1530 MonoObject *waitHandle;
1531 MonoInternalThread *thread = mono_thread_internal_current ();
1533 /* Do this WaitSleepJoin check before creating objects */
1534 mono_thread_current_check_pending_interrupt ();
1536 numhandles = mono_array_length(mono_handles);
1537 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1540 for(i = 0; i < numhandles; i++) {
1541 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1542 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1549 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1551 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1553 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1555 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1558 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1560 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1561 return ret - WAIT_OBJECT_0;
1563 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1564 return ret - WAIT_ABANDONED_0;
1571 /* FIXME: exitContext isnt documented */
1572 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
1575 MonoInternalThread *thread = mono_thread_internal_current ();
1577 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1583 mono_thread_current_check_pending_interrupt ();
1585 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1587 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1589 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1591 if(ret==WAIT_FAILED) {
1592 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
1594 } else if(ret==WAIT_TIMEOUT) {
1595 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
1603 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1606 MonoInternalThread *thread = mono_thread_internal_current ();
1611 mono_thread_current_check_pending_interrupt ();
1613 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1615 MONO_PREPARE_BLOCKING;
1616 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1617 MONO_FINISH_BLOCKING;
1619 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1621 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1624 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1631 mutex = CreateMutex (NULL, owned, NULL);
1633 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1635 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1643 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1644 return(ReleaseMutex (handle));
1647 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1653 *error = ERROR_SUCCESS;
1655 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1657 *error = GetLastError ();
1664 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1671 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1673 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1674 mono_string_chars (name));
1676 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1684 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1688 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1693 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1697 *error = ERROR_SUCCESS;
1699 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1701 *error = GetLastError ();
1707 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1714 event = CreateEvent (NULL, manual, initial, NULL);
1716 event = CreateEvent (NULL, manual, initial,
1717 mono_string_chars (name));
1719 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1727 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1728 return (SetEvent(handle));
1731 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1732 return (ResetEvent(handle));
1736 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1737 CloseHandle (handle);
1740 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1746 *error = ERROR_SUCCESS;
1748 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1750 *error = GetLastError ();
1756 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1758 return InterlockedIncrement (location);
1761 gint64 ves_icall_System_Threading_Interlocked_Increment_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 InterlockedIncrement64 (location);
1776 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1778 return InterlockedDecrement(location);
1781 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1783 #if SIZEOF_VOID_P == 4
1784 if (G_UNLIKELY ((size_t)location & 0x7)) {
1786 mono_interlocked_lock ();
1789 mono_interlocked_unlock ();
1793 return InterlockedDecrement64 (location);
1796 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1798 return InterlockedExchange(location, value);
1801 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1804 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1805 mono_gc_wbarrier_generic_nostore (location);
1809 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1811 return InterlockedExchangePointer(location, value);
1814 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1816 IntFloatUnion val, ret;
1819 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1825 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1827 #if SIZEOF_VOID_P == 4
1828 if (G_UNLIKELY ((size_t)location & 0x7)) {
1830 mono_interlocked_lock ();
1833 mono_interlocked_unlock ();
1837 return InterlockedExchange64 (location, value);
1841 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1843 LongDoubleUnion val, ret;
1846 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1851 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1853 return InterlockedCompareExchange(location, value, comparand);
1856 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1858 gint32 r = InterlockedCompareExchange(location, value, comparand);
1859 *success = r == comparand;
1863 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1866 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1867 mono_gc_wbarrier_generic_nostore (location);
1871 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1873 return InterlockedCompareExchangePointer(location, value, comparand);
1876 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1878 IntFloatUnion val, ret, cmp;
1881 cmp.fval = comparand;
1882 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1888 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1890 #if SIZEOF_VOID_P == 8
1891 LongDoubleUnion val, comp, ret;
1894 comp.fval = comparand;
1895 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1901 mono_interlocked_lock ();
1903 if (old == comparand)
1905 mono_interlocked_unlock ();
1912 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1914 #if SIZEOF_VOID_P == 4
1915 if (G_UNLIKELY ((size_t)location & 0x7)) {
1917 mono_interlocked_lock ();
1919 if (old == comparand)
1921 mono_interlocked_unlock ();
1925 return InterlockedCompareExchange64 (location, value, comparand);
1929 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1932 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1933 mono_gc_wbarrier_generic_nostore (location);
1938 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1941 res = InterlockedExchangePointer ((gpointer *)location, value);
1942 mono_gc_wbarrier_generic_nostore (location);
1947 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1949 return InterlockedAdd (location, value);
1953 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1955 #if SIZEOF_VOID_P == 4
1956 if (G_UNLIKELY ((size_t)location & 0x7)) {
1958 mono_interlocked_lock ();
1961 mono_interlocked_unlock ();
1965 return InterlockedAdd64 (location, value);
1969 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1971 #if SIZEOF_VOID_P == 4
1972 if (G_UNLIKELY ((size_t)location & 0x7)) {
1974 mono_interlocked_lock ();
1976 mono_interlocked_unlock ();
1980 return InterlockedRead64 (location);
1984 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1986 mono_memory_barrier ();
1990 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1992 mono_thread_clr_state (this, state);
1994 if (state & ThreadState_Background) {
1995 /* If the thread changes the background mode, the main thread has to
1996 * be notified, since it has to rebuild the list of threads to
1999 SetEvent (background_change_event);
2004 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
2006 mono_thread_set_state (this, state);
2008 if (state & ThreadState_Background) {
2009 /* If the thread changes the background mode, the main thread has to
2010 * be notified, since it has to rebuild the list of threads to
2013 SetEvent (background_change_event);
2018 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2024 state = this->state;
2026 UNLOCK_THREAD (this);
2031 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2033 MonoInternalThread *current;
2035 MonoInternalThread *thread = this_obj->internal_thread;
2037 LOCK_THREAD (thread);
2039 current = mono_thread_internal_current ();
2041 thread->thread_interrupt_requested = TRUE;
2042 throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2044 UNLOCK_THREAD (thread);
2047 abort_thread_internal (thread, TRUE, FALSE);
2051 void mono_thread_current_check_pending_interrupt ()
2053 MonoInternalThread *thread = mono_thread_internal_current ();
2054 gboolean throw = FALSE;
2056 LOCK_THREAD (thread);
2058 if (thread->thread_interrupt_requested) {
2060 thread->thread_interrupt_requested = FALSE;
2063 UNLOCK_THREAD (thread);
2066 mono_raise_exception (mono_get_exception_thread_interrupted ());
2071 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2073 LOCK_THREAD (thread);
2075 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2076 (thread->state & ThreadState_StopRequested) != 0 ||
2077 (thread->state & ThreadState_Stopped) != 0)
2079 UNLOCK_THREAD (thread);
2083 if ((thread->state & ThreadState_Unstarted) != 0) {
2084 thread->state |= ThreadState_Aborted;
2085 UNLOCK_THREAD (thread);
2089 thread->state |= ThreadState_AbortRequested;
2090 if (thread->abort_state_handle)
2091 mono_gchandle_free (thread->abort_state_handle);
2093 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2094 g_assert (thread->abort_state_handle);
2096 thread->abort_state_handle = 0;
2098 thread->abort_exc = NULL;
2100 UNLOCK_THREAD (thread);
2102 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), thread, (gsize)thread->tid));
2104 /* During shutdown, we can't wait for other threads */
2106 /* Make sure the thread is awake */
2107 mono_thread_resume (thread);
2109 abort_thread_internal (thread, TRUE, TRUE);
2113 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2115 MonoInternalThread *thread = mono_thread_internal_current ();
2116 gboolean was_aborting;
2118 LOCK_THREAD (thread);
2119 was_aborting = thread->state & ThreadState_AbortRequested;
2120 thread->state &= ~ThreadState_AbortRequested;
2121 UNLOCK_THREAD (thread);
2123 if (!was_aborting) {
2124 const char *msg = "Unable to reset abort because no abort was requested";
2125 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2128 thread->abort_exc = NULL;
2129 if (thread->abort_state_handle) {
2130 mono_gchandle_free (thread->abort_state_handle);
2131 /* This is actually not necessary - the handle
2132 only counts if the exception is set */
2133 thread->abort_state_handle = 0;
2138 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2140 LOCK_THREAD (thread);
2142 thread->state &= ~ThreadState_AbortRequested;
2144 if (thread->abort_exc) {
2145 thread->abort_exc = NULL;
2146 if (thread->abort_state_handle) {
2147 mono_gchandle_free (thread->abort_state_handle);
2148 /* This is actually not necessary - the handle
2149 only counts if the exception is set */
2150 thread->abort_state_handle = 0;
2154 UNLOCK_THREAD (thread);
2158 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2160 MonoInternalThread *thread = this_obj->internal_thread;
2161 MonoObject *state, *deserialized = NULL, *exc;
2164 if (!thread->abort_state_handle)
2167 state = mono_gchandle_get_target (thread->abort_state_handle);
2170 domain = mono_domain_get ();
2171 if (mono_object_domain (state) == domain)
2174 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2176 if (!deserialized) {
2177 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2179 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2180 mono_set_pending_exception (invalid_op_exc);
2184 return deserialized;
2188 mono_thread_suspend (MonoInternalThread *thread)
2190 LOCK_THREAD (thread);
2192 if ((thread->state & ThreadState_Unstarted) != 0 ||
2193 (thread->state & ThreadState_Aborted) != 0 ||
2194 (thread->state & ThreadState_Stopped) != 0)
2196 UNLOCK_THREAD (thread);
2200 if ((thread->state & ThreadState_Suspended) != 0 ||
2201 (thread->state & ThreadState_SuspendRequested) != 0 ||
2202 (thread->state & ThreadState_StopRequested) != 0)
2204 UNLOCK_THREAD (thread);
2208 thread->state |= ThreadState_SuspendRequested;
2210 UNLOCK_THREAD (thread);
2212 suspend_thread_internal (thread, FALSE);
2217 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2219 if (!mono_thread_suspend (this_obj->internal_thread)) {
2220 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2226 mono_thread_resume (MonoInternalThread *thread)
2228 LOCK_THREAD (thread);
2230 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2231 thread->state &= ~ThreadState_SuspendRequested;
2232 UNLOCK_THREAD (thread);
2236 if ((thread->state & ThreadState_Suspended) == 0 ||
2237 (thread->state & ThreadState_Unstarted) != 0 ||
2238 (thread->state & ThreadState_Aborted) != 0 ||
2239 (thread->state & ThreadState_Stopped) != 0)
2241 UNLOCK_THREAD (thread);
2245 return resume_thread_internal (thread);
2249 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2251 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2252 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2258 mono_threads_is_critical_method (MonoMethod *method)
2260 switch (method->wrapper_type) {
2261 case MONO_WRAPPER_RUNTIME_INVOKE:
2262 case MONO_WRAPPER_XDOMAIN_INVOKE:
2263 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2270 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2275 if (mono_threads_is_critical_method (m)) {
2276 *((gboolean*)data) = TRUE;
2283 is_running_protected_wrapper (void)
2285 gboolean found = FALSE;
2286 mono_stack_walk (find_wrapper, &found);
2290 void mono_thread_internal_stop (MonoInternalThread *thread)
2292 LOCK_THREAD (thread);
2294 if ((thread->state & ThreadState_StopRequested) != 0 ||
2295 (thread->state & ThreadState_Stopped) != 0)
2297 UNLOCK_THREAD (thread);
2301 /* Make sure the thread is awake */
2302 mono_thread_resume (thread);
2304 thread->state |= ThreadState_StopRequested;
2305 thread->state &= ~ThreadState_AbortRequested;
2307 UNLOCK_THREAD (thread);
2309 abort_thread_internal (thread, TRUE, TRUE);
2312 void mono_thread_stop (MonoThread *thread)
2314 mono_thread_internal_stop (thread->internal_thread);
2318 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2321 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2326 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2329 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2334 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2337 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2342 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2345 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2350 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2353 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2354 return (void *) tmp;
2358 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2360 volatile MonoObject *tmp;
2361 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2362 return (MonoObject *) tmp;
2366 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2369 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2374 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2377 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2382 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2384 return InterlockedRead8 (ptr);
2388 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2390 return InterlockedRead16 (ptr);
2394 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2396 return InterlockedRead (ptr);
2400 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2402 #if SIZEOF_VOID_P == 4
2403 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2405 mono_interlocked_lock ();
2406 val = *(gint64*)ptr;
2407 mono_interlocked_unlock ();
2411 return InterlockedRead64 (ptr);
2415 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2417 return InterlockedReadPointer (ptr);
2421 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2425 #if SIZEOF_VOID_P == 4
2426 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2428 mono_interlocked_lock ();
2429 val = *(double*)ptr;
2430 mono_interlocked_unlock ();
2435 u.ival = InterlockedRead64 (ptr);
2441 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2445 u.ival = InterlockedRead (ptr);
2451 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2453 return InterlockedReadPointer (ptr);
2457 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2459 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2463 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2465 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2469 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2471 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2475 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2477 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2481 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2483 mono_atomic_store_release ((volatile void **) ptr, value);
2487 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2489 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2493 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2495 mono_atomic_store_release ((volatile double *) ptr, value);
2499 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2501 mono_atomic_store_release ((volatile float *) ptr, value);
2505 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2507 InterlockedWrite8 (ptr, value);
2511 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2513 InterlockedWrite16 (ptr, value);
2517 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2519 InterlockedWrite (ptr, value);
2523 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2525 #if SIZEOF_VOID_P == 4
2526 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2527 mono_interlocked_lock ();
2528 *(gint64*)ptr = value;
2529 mono_interlocked_unlock ();
2534 InterlockedWrite64 (ptr, value);
2538 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2540 InterlockedWritePointer (ptr, value);
2544 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2548 #if SIZEOF_VOID_P == 4
2549 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2550 mono_interlocked_lock ();
2551 *(double*)ptr = value;
2552 mono_interlocked_unlock ();
2559 InterlockedWrite64 (ptr, u.ival);
2563 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2569 InterlockedWrite (ptr, u.ival);
2573 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2575 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2579 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2581 mono_threads_lock ();
2583 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2586 contexts = g_hash_table_new (NULL, NULL);
2588 context_adjust_static_data (ctx);
2589 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2590 g_hash_table_insert (contexts, gch, gch);
2592 mono_threads_unlock ();
2594 mono_profiler_context_loaded (ctx);
2598 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2601 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2602 * cleanup in exceptional circumstances, we don't actually do any
2603 * cleanup work here. We instead do this when we iterate the `contexts`
2604 * hash table. The only purpose of this finalizer, at the moment, is to
2605 * notify the profiler.
2608 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2610 mono_profiler_context_unloaded (ctx);
2614 mono_thread_init_tls (void)
2616 MONO_FAST_TLS_INIT (tls_current_object);
2617 mono_native_tls_alloc (¤t_object_key, NULL);
2620 void mono_thread_init (MonoThreadStartCB start_cb,
2621 MonoThreadAttachCB attach_cb)
2623 mono_mutex_init_recursive(&threads_mutex);
2624 mono_mutex_init_recursive(&interlocked_mutex);
2625 mono_mutex_init_recursive(&joinable_threads_mutex);
2627 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2628 g_assert(background_change_event != NULL);
2630 mono_init_static_data_info (&thread_static_info);
2631 mono_init_static_data_info (&context_static_info);
2633 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2635 mono_thread_start_cb = start_cb;
2636 mono_thread_attach_cb = attach_cb;
2638 /* Get a pseudo handle to the current process. This is just a
2639 * kludge so that wapi can build a process handle if needed.
2640 * As a pseudo handle is returned, we don't need to clean
2643 GetCurrentProcess ();
2646 void mono_thread_cleanup (void)
2648 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2649 MonoThreadInfo *info;
2651 /* The main thread must abandon any held mutexes (particularly
2652 * important for named mutexes as they are shared across
2653 * processes, see bug 74680.) This will happen when the
2654 * thread exits, but if it's not running in a subthread it
2655 * won't exit in time.
2657 info = mono_thread_info_current ();
2658 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2662 /* This stuff needs more testing, it seems one of these
2663 * critical sections can be locked when mono_thread_cleanup is
2666 mono_mutex_destroy (&threads_mutex);
2667 mono_mutex_destroy (&interlocked_mutex);
2668 mono_mutex_destroy (&delayed_free_table_mutex);
2669 mono_mutex_destroy (&small_id_mutex);
2670 CloseHandle (background_change_event);
2673 mono_native_tls_free (current_object_key);
2677 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2679 mono_thread_cleanup_fn = func;
2683 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2685 thread->internal_thread->manage_callback = func;
2688 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2690 mono_thread_notify_pending_exc_fn = func;
2694 static void print_tids (gpointer key, gpointer value, gpointer user)
2696 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2697 * sizeof(uint) and a cast to uint would overflow
2699 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2700 * print this as a pointer.
2702 g_message ("Waiting for: %p", key);
2707 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2708 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2712 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2716 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2718 MONO_PREPARE_BLOCKING;
2719 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2720 MONO_FINISH_BLOCKING;
2722 if(ret==WAIT_FAILED) {
2723 /* See the comment in build_wait_tids() */
2724 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2728 for(i=0; i<wait->num; i++)
2729 CloseHandle (wait->handles[i]);
2731 if (ret == WAIT_TIMEOUT)
2734 for(i=0; i<wait->num; i++) {
2735 gsize tid = wait->threads[i]->tid;
2738 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2739 * it can still run io-layer etc. code. So wait for it to really exit.
2740 * FIXME: This won't join threads which are not in the joinable_hash yet.
2742 mono_thread_join ((gpointer)tid);
2744 mono_threads_lock ();
2745 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2746 /* This thread must have been killed, because
2747 * it hasn't cleaned itself up. (It's just
2748 * possible that the thread exited before the
2749 * parent thread had a chance to store the
2750 * handle, and now there is another pointer to
2751 * the already-exited thread stored. In this
2752 * case, we'll just get two
2753 * mono_profiler_thread_end() calls for the
2757 mono_threads_unlock ();
2758 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2759 thread_cleanup (wait->threads[i]);
2761 mono_threads_unlock ();
2766 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2768 guint32 i, ret, count;
2770 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2772 /* Add the thread state change event, so it wakes up if a thread changes
2773 * to background mode.
2776 if (count < MAXIMUM_WAIT_OBJECTS) {
2777 wait->handles [count] = background_change_event;
2781 MONO_PREPARE_BLOCKING;
2782 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2783 MONO_FINISH_BLOCKING;
2785 if(ret==WAIT_FAILED) {
2786 /* See the comment in build_wait_tids() */
2787 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2791 for(i=0; i<wait->num; i++)
2792 CloseHandle (wait->handles[i]);
2794 if (ret == WAIT_TIMEOUT)
2797 if (ret < wait->num) {
2798 gsize tid = wait->threads[ret]->tid;
2799 mono_threads_lock ();
2800 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2801 /* See comment in wait_for_tids about thread cleanup */
2802 mono_threads_unlock ();
2803 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2804 thread_cleanup (wait->threads [ret]);
2806 mono_threads_unlock ();
2810 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2812 struct wait_data *wait=(struct wait_data *)user;
2814 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2816 MonoInternalThread *thread=(MonoInternalThread *)value;
2818 /* Ignore background threads, we abort them later */
2819 /* Do not lock here since it is not needed and the caller holds threads_lock */
2820 if (thread->state & ThreadState_Background) {
2821 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2822 return; /* just leave, ignore */
2825 if (mono_gc_is_finalizer_internal_thread (thread)) {
2826 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2830 if (thread == mono_thread_internal_current ()) {
2831 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2835 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2836 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2840 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2841 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2845 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2846 if (handle == NULL) {
2847 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2851 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2852 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2853 wait->handles[wait->num]=handle;
2854 wait->threads[wait->num]=thread;
2857 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2859 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2864 /* Just ignore the rest, we can't do anything with
2871 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2873 struct wait_data *wait=(struct wait_data *)user;
2874 MonoNativeThreadId self = mono_native_thread_id_get ();
2875 MonoInternalThread *thread = value;
2878 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2881 /* The finalizer thread is not a background thread */
2882 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
2883 && (thread->state & ThreadState_Background) != 0
2884 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
2886 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2890 /* printf ("A: %d\n", wait->num); */
2891 wait->handles[wait->num]=thread->handle;
2892 wait->threads[wait->num]=thread;
2895 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2896 mono_thread_internal_stop (thread);
2900 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
2901 && !mono_gc_is_finalizer_internal_thread (thread);
2905 * mono_threads_set_shutting_down:
2907 * Is called by a thread that wants to shut down Mono. If the runtime is already
2908 * shutting down, the calling thread is suspended/stopped, and this function never
2912 mono_threads_set_shutting_down (void)
2914 MonoInternalThread *current_thread = mono_thread_internal_current ();
2916 mono_threads_lock ();
2918 if (shutting_down) {
2919 mono_threads_unlock ();
2921 /* Make sure we're properly suspended/stopped */
2923 LOCK_THREAD (current_thread);
2925 if ((current_thread->state & ThreadState_SuspendRequested) ||
2926 (current_thread->state & ThreadState_AbortRequested) ||
2927 (current_thread->state & ThreadState_StopRequested)) {
2928 UNLOCK_THREAD (current_thread);
2929 mono_thread_execute_interruption ();
2931 current_thread->state |= ThreadState_Stopped;
2932 UNLOCK_THREAD (current_thread);
2935 /*since we're killing the thread, unset the current domain.*/
2936 mono_domain_unset ();
2938 /* Wake up other threads potentially waiting for us */
2939 mono_thread_info_exit ();
2941 shutting_down = TRUE;
2943 /* Not really a background state change, but this will
2944 * interrupt the main thread if it is waiting for all
2945 * the other threads.
2947 SetEvent (background_change_event);
2949 mono_threads_unlock ();
2953 void mono_thread_manage (void)
2955 struct wait_data wait_data;
2956 struct wait_data *wait = &wait_data;
2958 memset (wait, 0, sizeof (struct wait_data));
2959 /* join each thread that's still running */
2960 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2962 mono_threads_lock ();
2964 THREAD_DEBUG (g_message("%s: No threads", __func__));
2965 mono_threads_unlock ();
2968 mono_threads_unlock ();
2971 mono_threads_lock ();
2972 if (shutting_down) {
2973 /* somebody else is shutting down */
2974 mono_threads_unlock ();
2977 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2978 mono_g_hash_table_foreach (threads, print_tids, NULL));
2980 ResetEvent (background_change_event);
2982 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2983 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2984 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2985 mono_threads_unlock ();
2987 /* Something to wait for */
2988 wait_for_tids_or_state_change (wait, INFINITE);
2990 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2991 } while(wait->num>0);
2993 /* Mono is shutting down, so just wait for the end */
2994 if (!mono_runtime_try_shutdown ()) {
2995 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2996 mono_thread_suspend (mono_thread_internal_current ());
2997 mono_thread_execute_interruption ();
3001 * Remove everything but the finalizer thread and self.
3002 * Also abort all the background threads
3005 mono_threads_lock ();
3008 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3009 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3010 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3012 mono_threads_unlock ();
3014 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3016 /* Something to wait for */
3017 wait_for_tids (wait, INFINITE);
3019 } while (wait->num > 0);
3022 * give the subthreads a chance to really quit (this is mainly needed
3023 * to get correct user and system times from getrusage/wait/time(1)).
3024 * This could be removed if we avoid pthread_detach() and use pthread_join().
3026 mono_thread_info_yield ();
3030 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3032 MonoInternalThread *thread = (MonoInternalThread*)value;
3033 struct wait_data *wait = (struct wait_data*)user_data;
3037 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3039 * This needs no locking.
3041 if ((thread->state & ThreadState_Suspended) != 0 ||
3042 (thread->state & ThreadState_Stopped) != 0)
3045 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3046 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3050 wait->handles [wait->num] = handle;
3051 wait->threads [wait->num] = thread;
3057 * mono_thread_suspend_all_other_threads:
3059 * Suspend all managed threads except the finalizer thread and this thread. It is
3060 * not possible to resume them later.
3062 void mono_thread_suspend_all_other_threads (void)
3064 struct wait_data wait_data;
3065 struct wait_data *wait = &wait_data;
3067 MonoNativeThreadId self = mono_native_thread_id_get ();
3068 guint32 eventidx = 0;
3069 gboolean starting, finished;
3071 memset (wait, 0, sizeof (struct wait_data));
3073 * The other threads could be in an arbitrary state at this point, i.e.
3074 * they could be starting up, shutting down etc. This means that there could be
3075 * threads which are not even in the threads hash table yet.
3079 * First we set a barrier which will be checked by all threads before they
3080 * are added to the threads hash table, and they will exit if the flag is set.
3081 * This ensures that no threads could be added to the hash later.
3082 * We will use shutting_down as the barrier for now.
3084 g_assert (shutting_down);
3087 * We make multiple calls to WaitForMultipleObjects since:
3088 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3089 * - some threads could exit without becoming suspended
3094 * Make a copy of the hashtable since we can't do anything with
3095 * threads while threads_mutex is held.
3098 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3099 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3100 mono_threads_lock ();
3101 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3102 mono_threads_unlock ();
3105 /* Get the suspended events that we'll be waiting for */
3106 for (i = 0; i < wait->num; ++i) {
3107 MonoInternalThread *thread = wait->threads [i];
3109 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3110 || mono_gc_is_finalizer_internal_thread (thread)
3111 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3113 //CloseHandle (wait->handles [i]);
3114 wait->threads [i] = NULL; /* ignore this thread in next loop */
3118 LOCK_THREAD (thread);
3120 if ((thread->state & ThreadState_Suspended) != 0 ||
3121 (thread->state & ThreadState_StopRequested) != 0 ||
3122 (thread->state & ThreadState_Stopped) != 0) {
3123 UNLOCK_THREAD (thread);
3124 CloseHandle (wait->handles [i]);
3125 wait->threads [i] = NULL; /* ignore this thread in next loop */
3131 /* Convert abort requests into suspend requests */
3132 if ((thread->state & ThreadState_AbortRequested) != 0)
3133 thread->state &= ~ThreadState_AbortRequested;
3135 thread->state |= ThreadState_SuspendRequested;
3137 UNLOCK_THREAD (thread);
3139 /* Signal the thread to suspend */
3140 suspend_thread_internal (thread, TRUE);
3142 if (eventidx <= 0) {
3144 * If there are threads which are starting up, we wait until they
3145 * are suspended when they try to register in the threads hash.
3146 * This is guaranteed to finish, since the threads which can create new
3147 * threads get suspended after a while.
3148 * FIXME: The finalizer thread can still create new threads.
3150 mono_threads_lock ();
3151 if (threads_starting_up)
3152 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3155 mono_threads_unlock ();
3157 mono_thread_info_sleep (100, NULL);
3165 MonoInternalThread *thread;
3166 MonoStackFrameInfo *frames;
3167 int nframes, max_frames;
3168 int nthreads, max_threads;
3169 MonoInternalThread **threads;
3170 } ThreadDumpUserData;
3172 static gboolean thread_dump_requested;
3174 /* This needs to be async safe */
3176 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3178 ThreadDumpUserData *ud = data;
3180 if (ud->nframes < ud->max_frames) {
3181 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3188 /* This needs to be async safe */
3189 static SuspendThreadResult
3190 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3192 ThreadDumpUserData *user_data = ud;
3193 MonoInternalThread *thread = user_data->thread;
3196 /* This no longer works with remote unwinding */
3198 wapi_desc = wapi_current_thread_desc ();
3199 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3204 if (thread == mono_thread_internal_current ())
3205 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3207 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3209 return MonoResumeThread;
3213 int nthreads, max_threads;
3214 MonoInternalThread **threads;
3215 } CollectThreadsUserData;
3218 collect_thread (gpointer key, gpointer value, gpointer user)
3220 CollectThreadsUserData *ud = user;
3221 MonoInternalThread *thread = value;
3223 if (ud->nthreads < ud->max_threads)
3224 ud->threads [ud->nthreads ++] = thread;
3228 * Collect running threads into the THREADS array.
3229 * THREADS should be an array allocated on the stack.
3232 collect_threads (MonoInternalThread **thread_array, int max_threads)
3234 CollectThreadsUserData ud;
3236 memset (&ud, 0, sizeof (ud));
3237 /* This array contains refs, but its on the stack, so its ok */
3238 ud.threads = thread_array;
3239 ud.max_threads = max_threads;
3241 mono_threads_lock ();
3242 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3243 mono_threads_unlock ();
3249 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3251 GString* text = g_string_new (0);
3253 GError *error = NULL;
3256 ud->thread = thread;
3259 /* Collect frames for the thread */
3260 if (thread == mono_thread_internal_current ()) {
3261 get_thread_dump (mono_thread_info_current (), ud);
3263 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3267 * Do all the non async-safe work outside of get_thread_dump.
3270 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3272 g_string_append_printf (text, "\n\"%s\"", name);
3275 else if (thread->threadpool_thread) {
3276 g_string_append (text, "\n\"<threadpool thread>\"");
3278 g_string_append (text, "\n\"<unnamed thread>\"");
3281 for (i = 0; i < ud->nframes; ++i) {
3282 MonoStackFrameInfo *frame = &ud->frames [i];
3283 MonoMethod *method = NULL;
3285 if (frame->type == FRAME_TYPE_MANAGED)
3286 method = mono_jit_info_get_method (frame->ji);
3289 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3290 g_string_append_printf (text, " %s\n", location);
3293 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3297 fprintf (stdout, "%s", text->str);
3299 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3300 OutputDebugStringA(text->str);
3303 g_string_free (text, TRUE);
3308 mono_threads_perform_thread_dump (void)
3310 ThreadDumpUserData ud;
3311 MonoInternalThread *thread_array [128];
3312 int tindex, nthreads;
3314 if (!thread_dump_requested)
3317 printf ("Full thread dump:\n");
3319 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3320 nthreads = collect_threads (thread_array, 128);
3322 memset (&ud, 0, sizeof (ud));
3323 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3324 ud.max_frames = 256;
3326 for (tindex = 0; tindex < nthreads; ++tindex)
3327 dump_thread (thread_array [tindex], &ud);
3331 thread_dump_requested = FALSE;
3334 /* Obtain the thread dump of all threads */
3336 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames)
3338 ThreadDumpUserData ud;
3339 MonoInternalThread *thread_array [128];
3340 MonoDomain *domain = mono_domain_get ();
3341 MonoDebugSourceLocation *location;
3342 int tindex, nthreads;
3344 *out_threads = NULL;
3345 *out_stack_frames = NULL;
3347 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3348 nthreads = collect_threads (thread_array, 128);
3350 memset (&ud, 0, sizeof (ud));
3351 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3352 ud.max_frames = 256;
3354 *out_threads = mono_array_new (domain, mono_defaults.thread_class, nthreads);
3355 *out_stack_frames = mono_array_new (domain, mono_defaults.array_class, nthreads);
3357 for (tindex = 0; tindex < nthreads; ++tindex) {
3358 MonoInternalThread *thread = thread_array [tindex];
3359 MonoArray *thread_frames;
3365 /* Collect frames for the thread */
3366 if (thread == mono_thread_internal_current ()) {
3367 get_thread_dump (mono_thread_info_current (), &ud);
3369 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3372 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3374 thread_frames = mono_array_new (domain, mono_defaults.stack_frame_class, ud.nframes);
3375 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3377 for (i = 0; i < ud.nframes; ++i) {
3378 MonoStackFrameInfo *frame = &ud.frames [i];
3379 MonoMethod *method = NULL;
3380 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
3382 sf->native_offset = frame->native_offset;
3384 if (frame->type == FRAME_TYPE_MANAGED)
3385 method = mono_jit_info_get_method (frame->ji);
3388 sf->method_address = (gsize) frame->ji->code_start;
3390 MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
3392 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3394 sf->il_offset = location->il_offset;
3396 if (location && location->source_file) {
3397 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3398 sf->line = location->row;
3399 sf->column = location->column;
3401 mono_debug_free_source_location (location);
3406 mono_array_setref (thread_frames, i, sf);
3414 * mono_threads_request_thread_dump:
3416 * Ask all threads except the current to print their stacktrace to stdout.
3419 mono_threads_request_thread_dump (void)
3421 /*The new thread dump code runs out of the finalizer thread. */
3422 thread_dump_requested = TRUE;
3423 mono_gc_finalize_notify ();
3428 gint allocated; /* +1 so that refs [allocated] == NULL */
3432 typedef struct ref_stack RefStack;
3435 ref_stack_new (gint initial_size)
3439 initial_size = MAX (initial_size, 16) + 1;
3440 rs = g_new0 (RefStack, 1);
3441 rs->refs = g_new0 (gpointer, initial_size);
3442 rs->allocated = initial_size;
3447 ref_stack_destroy (gpointer ptr)
3458 ref_stack_push (RefStack *rs, gpointer ptr)
3460 g_assert (rs != NULL);
3462 if (rs->bottom >= rs->allocated) {
3463 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3464 rs->allocated <<= 1;
3465 rs->refs [rs->allocated] = NULL;
3467 rs->refs [rs->bottom++] = ptr;
3471 ref_stack_pop (RefStack *rs)
3473 if (rs == NULL || rs->bottom == 0)
3477 rs->refs [rs->bottom] = NULL;
3481 ref_stack_find (RefStack *rs, gpointer ptr)
3488 for (refs = rs->refs; refs && *refs; refs++) {
3496 * mono_thread_push_appdomain_ref:
3498 * Register that the current thread may have references to objects in domain
3499 * @domain on its stack. Each call to this function should be paired with a
3500 * call to pop_appdomain_ref.
3503 mono_thread_push_appdomain_ref (MonoDomain *domain)
3505 MonoInternalThread *thread = mono_thread_internal_current ();
3508 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3509 SPIN_LOCK (thread->lock_thread_id);
3510 if (thread->appdomain_refs == NULL)
3511 thread->appdomain_refs = ref_stack_new (16);
3512 ref_stack_push (thread->appdomain_refs, domain);
3513 SPIN_UNLOCK (thread->lock_thread_id);
3518 mono_thread_pop_appdomain_ref (void)
3520 MonoInternalThread *thread = mono_thread_internal_current ();
3523 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3524 SPIN_LOCK (thread->lock_thread_id);
3525 ref_stack_pop (thread->appdomain_refs);
3526 SPIN_UNLOCK (thread->lock_thread_id);
3531 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3534 SPIN_LOCK (thread->lock_thread_id);
3535 res = ref_stack_find (thread->appdomain_refs, domain);
3536 SPIN_UNLOCK (thread->lock_thread_id);
3541 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3543 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3546 typedef struct abort_appdomain_data {
3547 struct wait_data wait;
3549 } abort_appdomain_data;
3552 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3554 MonoInternalThread *thread = (MonoInternalThread*)value;
3555 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3556 MonoDomain *domain = data->domain;
3558 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3559 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3561 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3562 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3565 data->wait.handles [data->wait.num] = handle;
3566 data->wait.threads [data->wait.num] = thread;
3569 /* Just ignore the rest, we can't do anything with
3577 * mono_threads_abort_appdomain_threads:
3579 * Abort threads which has references to the given appdomain.
3582 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3584 #ifdef __native_client__
3588 abort_appdomain_data user_data;
3590 int orig_timeout = timeout;
3593 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3595 start_time = mono_msec_ticks ();
3597 mono_threads_lock ();
3599 user_data.domain = domain;
3600 user_data.wait.num = 0;
3601 /* This shouldn't take any locks */
3602 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3603 mono_threads_unlock ();
3605 if (user_data.wait.num > 0) {
3606 /* Abort the threads outside the threads lock */
3607 for (i = 0; i < user_data.wait.num; ++i)
3608 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3611 * We should wait for the threads either to abort, or to leave the
3612 * domain. We can't do the latter, so we wait with a timeout.
3614 wait_for_tids (&user_data.wait, 100);
3617 /* Update remaining time */
3618 timeout -= mono_msec_ticks () - start_time;
3619 start_time = mono_msec_ticks ();
3621 if (orig_timeout != -1 && timeout < 0)
3624 while (user_data.wait.num > 0);
3626 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3632 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3634 MonoInternalThread *thread = (MonoInternalThread*)value;
3635 MonoDomain *domain = (MonoDomain*)user_data;
3638 /* No locking needed here */
3639 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3641 if (thread->cached_culture_info) {
3642 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3643 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3644 if (obj && obj->vtable->domain == domain)
3645 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3651 * mono_threads_clear_cached_culture:
3653 * Clear the cached_current_culture from all threads if it is in the
3657 mono_threads_clear_cached_culture (MonoDomain *domain)
3659 mono_threads_lock ();
3660 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3661 mono_threads_unlock ();
3665 * mono_thread_get_undeniable_exception:
3667 * Return an exception which needs to be raised when leaving a catch clause.
3668 * This is used for undeniable exception propagation.
3671 mono_thread_get_undeniable_exception (void)
3673 MonoInternalThread *thread = mono_thread_internal_current ();
3675 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3677 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3678 * exception if the thread no longer references a dying appdomain.
3680 thread->abort_exc->trace_ips = NULL;
3681 thread->abort_exc->stack_trace = NULL;
3682 return thread->abort_exc;
3688 #if MONO_SMALL_CONFIG
3689 #define NUM_STATIC_DATA_IDX 4
3690 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3694 #define NUM_STATIC_DATA_IDX 8
3695 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3696 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3700 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3701 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3704 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3706 gpointer *static_data = addr;
3708 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3709 void **ptr = static_data [i];
3714 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3715 void **p = ptr + idx;
3718 mark_func ((MonoObject**)p, gc_data);
3724 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3726 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3730 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3732 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3736 * mono_alloc_static_data
3738 * Allocate memory blocks for storing threads or context static data
3741 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3743 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3746 gpointer* static_data = *static_data_ptr;
3748 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3749 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3751 if (mono_gc_user_markers_supported ()) {
3752 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3753 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3755 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3756 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3759 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3760 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3761 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3762 *static_data_ptr = static_data;
3763 static_data [0] = static_data;
3766 for (i = 1; i <= idx; ++i) {
3767 if (static_data [i])
3770 if (mono_gc_user_markers_supported ())
3771 static_data [i] = g_malloc0 (static_data_size [i]);
3773 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3774 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3775 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3780 mono_free_static_data (gpointer* static_data)
3783 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3784 gpointer p = static_data [i];
3788 * At this point, the static data pointer array is still registered with the
3789 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3790 * data. Freeing the individual arrays without first nulling their slots
3791 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3792 * such an already freed array. See bug #13813.
3794 static_data [i] = NULL;
3795 mono_memory_write_barrier ();
3796 if (mono_gc_user_markers_supported ())
3799 mono_gc_free_fixed (p);
3801 mono_gc_free_fixed (static_data);
3805 * mono_init_static_data_info
3807 * Initializes static data counters
3809 static void mono_init_static_data_info (StaticDataInfo *static_data)
3811 static_data->idx = 0;
3812 static_data->offset = 0;
3813 static_data->freelist = NULL;
3817 * mono_alloc_static_data_slot
3819 * Generates an offset for static data. static_data contains the counters
3820 * used to generate it.
3823 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3825 if (!static_data->idx && !static_data->offset) {
3827 * we use the first chunk of the first allocation also as
3828 * an array for the rest of the data
3830 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3832 static_data->offset += align - 1;
3833 static_data->offset &= ~(align - 1);
3834 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3835 static_data->idx ++;
3836 g_assert (size <= static_data_size [static_data->idx]);
3837 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3838 static_data->offset = 0;
3840 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3841 static_data->offset += size;
3846 * ensure thread static fields already allocated are valid for thread
3847 * This function is called when a thread is created or on thread attach.
3850 thread_adjust_static_data (MonoInternalThread *thread)
3852 mono_threads_lock ();
3853 if (thread_static_info.offset || thread_static_info.idx > 0) {
3854 /* get the current allocated size */
3855 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3856 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3858 mono_threads_unlock ();
3862 * LOCKING: requires that threads_mutex is held
3865 context_adjust_static_data (MonoAppContext *ctx)
3867 if (context_static_info.offset || context_static_info.idx > 0) {
3868 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3869 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3874 * LOCKING: requires that threads_mutex is held
3877 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3879 MonoInternalThread *thread = value;
3880 guint32 offset = GPOINTER_TO_UINT (user);
3882 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3886 * LOCKING: requires that threads_mutex is held
3889 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3891 uint32_t gch = GPOINTER_TO_INT (key);
3892 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3895 mono_gchandle_free (gch);
3896 return TRUE; // Remove this key/value pair
3899 guint32 offset = GPOINTER_TO_UINT (user);
3900 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3902 return FALSE; // Don't remove it
3905 static StaticDataFreeList*
3906 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3908 StaticDataFreeList* prev = NULL;
3909 StaticDataFreeList* tmp = static_data->freelist;
3911 if (tmp->size == size) {
3913 prev->next = tmp->next;
3915 static_data->freelist = tmp->next;
3924 #if SIZEOF_VOID_P == 4
3931 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3933 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3935 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3936 MonoBitSet *rb = sets [idx];
3937 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3938 offset /= sizeof (uintptr_t);
3939 /* offset is now the bitmap offset */
3940 for (int i = 0; i < numbits; ++i) {
3941 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3942 mono_bitset_set_fast (rb, offset + i);
3947 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3949 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3950 MonoBitSet *rb = sets [idx];
3951 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3952 offset /= sizeof (uintptr_t);
3953 /* offset is now the bitmap offset */
3954 for (int i = 0; i < size / sizeof (uintptr_t); i++)
3955 mono_bitset_clear_fast (rb, offset + i);
3959 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3961 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3963 StaticDataInfo *info;
3966 if (static_type == SPECIAL_STATIC_THREAD) {
3967 info = &thread_static_info;
3968 sets = thread_reference_bitmaps;
3970 info = &context_static_info;
3971 sets = context_reference_bitmaps;
3974 mono_threads_lock ();
3976 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3980 offset = item->offset;
3983 offset = mono_alloc_static_data_slot (info, size, align);
3986 update_reference_bitmap (sets, offset, bitmap, numbits);
3988 if (static_type == SPECIAL_STATIC_THREAD) {
3989 /* This can be called during startup */
3990 if (threads != NULL)
3991 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3993 if (contexts != NULL)
3994 g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3996 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3999 mono_threads_unlock ();
4005 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4007 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4009 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4010 return get_thread_static_data (thread, offset);
4012 return get_context_static_data (thread->current_appcontext, offset);
4017 mono_get_special_static_data (guint32 offset)
4019 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4028 * LOCKING: requires that threads_mutex is held
4031 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4033 MonoInternalThread *thread = value;
4034 OffsetSize *data = user;
4035 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4036 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4039 if (!thread->static_data || !thread->static_data [idx])
4041 ptr = ((char*) thread->static_data [idx]) + off;
4042 mono_gc_bzero_atomic (ptr, data->size);
4046 * LOCKING: requires that threads_mutex is held
4049 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4051 uint32_t gch = GPOINTER_TO_INT (key);
4052 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
4055 mono_gchandle_free (gch);
4056 return TRUE; // Remove this key/value pair
4059 OffsetSize *data = user;
4060 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4061 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4064 if (!ctx->static_data || !ctx->static_data [idx])
4065 return FALSE; // Don't remove this key/value pair
4067 ptr = ((char*) ctx->static_data [idx]) + off;
4068 mono_gc_bzero_atomic (ptr, data->size);
4070 return FALSE; // Don't remove this key/value pair
4074 do_free_special_slot (guint32 offset, guint32 size)
4076 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4078 StaticDataInfo *info;
4080 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4081 info = &thread_static_info;
4082 sets = thread_reference_bitmaps;
4084 info = &context_static_info;
4085 sets = context_reference_bitmaps;
4088 guint32 data_offset = offset;
4089 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4090 OffsetSize data = { data_offset, size };
4092 clear_reference_bitmap (sets, data.offset, data.size);
4094 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4095 if (threads != NULL)
4096 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4098 if (contexts != NULL)
4099 g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
4102 if (!mono_runtime_is_shutting_down ()) {
4103 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4105 item->offset = offset;
4108 item->next = info->freelist;
4109 info->freelist = item;
4114 do_free_special (gpointer key, gpointer value, gpointer data)
4116 MonoClassField *field = key;
4117 guint32 offset = GPOINTER_TO_UINT (value);
4120 size = mono_type_size (field->type, &align);
4121 do_free_special_slot (offset, size);
4125 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4127 mono_threads_lock ();
4129 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4131 mono_threads_unlock ();
4135 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4137 /* Only ever called for ThreadLocal instances */
4138 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
4140 mono_threads_lock ();
4141 do_free_special_slot (offset, size);
4142 mono_threads_unlock ();
4146 static void CALLBACK dummy_apc (ULONG_PTR param)
4152 * mono_thread_execute_interruption
4154 * Performs the operation that the requested thread state requires (abort,
4157 static MonoException*
4158 mono_thread_execute_interruption (void)
4160 MonoInternalThread *thread = mono_thread_internal_current ();
4162 LOCK_THREAD (thread);
4164 /* MonoThread::interruption_requested can only be changed with atomics */
4165 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4166 /* this will consume pending APC calls */
4168 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4170 InterlockedDecrement (&thread_interruption_requested);
4172 /* Clear the interrupted flag of the thread so it can wait again */
4173 mono_thread_info_clear_self_interrupt ();
4176 if ((thread->state & ThreadState_AbortRequested) != 0) {
4177 UNLOCK_THREAD (thread);
4178 if (thread->abort_exc == NULL) {
4180 * This might be racy, but it has to be called outside the lock
4181 * since it calls managed code.
4183 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4185 return thread->abort_exc;
4187 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4188 self_suspend_internal (thread);
4191 else if ((thread->state & ThreadState_StopRequested) != 0) {
4192 /* FIXME: do this through the JIT? */
4194 UNLOCK_THREAD (thread);
4196 mono_thread_exit ();
4198 } else if (thread->pending_exception) {
4201 exc = thread->pending_exception;
4202 thread->pending_exception = NULL;
4204 UNLOCK_THREAD (thread);
4206 } else if (thread->thread_interrupt_requested) {
4208 thread->thread_interrupt_requested = FALSE;
4209 UNLOCK_THREAD (thread);
4211 return(mono_get_exception_thread_interrupted ());
4214 UNLOCK_THREAD (thread);
4220 * mono_thread_request_interruption
4222 * A signal handler can call this method to request the interruption of a
4223 * thread. The result of the interruption will depend on the current state of
4224 * the thread. If the result is an exception that needs to be throw, it is
4225 * provided as return value.
4228 mono_thread_request_interruption (gboolean running_managed)
4230 MonoInternalThread *thread = mono_thread_internal_current ();
4232 /* The thread may already be stopping */
4237 if (thread->interrupt_on_stop &&
4238 thread->state & ThreadState_StopRequested &&
4239 thread->state & ThreadState_Background)
4243 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4245 InterlockedIncrement (&thread_interruption_requested);
4247 if (!running_managed || is_running_protected_wrapper ()) {
4248 /* Can't stop while in unmanaged code. Increase the global interruption
4249 request count. When exiting the unmanaged method the count will be
4250 checked and the thread will be interrupted. */
4252 if (mono_thread_notify_pending_exc_fn && !running_managed)
4253 /* The JIT will notify the thread about the interruption */
4254 /* This shouldn't take any locks */
4255 mono_thread_notify_pending_exc_fn (NULL);
4257 /* this will awake the thread if it is in WaitForSingleObject
4259 /* Our implementation of this function ignores the func argument */
4261 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4263 mono_thread_info_self_interrupt ();
4268 return mono_thread_execute_interruption ();
4272 /*This function should be called by a thread after it has exited all of
4273 * its handle blocks at interruption time.*/
4275 mono_thread_resume_interruption (void)
4277 MonoInternalThread *thread = mono_thread_internal_current ();
4278 gboolean still_aborting;
4280 /* The thread may already be stopping */
4284 LOCK_THREAD (thread);
4285 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4286 UNLOCK_THREAD (thread);
4288 /*This can happen if the protected block called Thread::ResetAbort*/
4289 if (!still_aborting)
4292 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4294 InterlockedIncrement (&thread_interruption_requested);
4296 mono_thread_info_self_interrupt ();
4298 return mono_thread_execute_interruption ();
4301 gboolean mono_thread_interruption_requested ()
4303 if (thread_interruption_requested) {
4304 MonoInternalThread *thread = mono_thread_internal_current ();
4305 /* The thread may already be stopping */
4307 return (thread->interruption_requested);
4312 static MonoException*
4313 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4315 MonoInternalThread *thread = mono_thread_internal_current ();
4317 /* The thread may already be stopping */
4321 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4322 MonoException* exc = mono_thread_execute_interruption ();
4330 * Performs the interruption of the current thread, if one has been requested,
4331 * and the thread is not running a protected wrapper.
4332 * Return the exception which needs to be thrown, if any.
4335 mono_thread_interruption_checkpoint (void)
4337 return mono_thread_interruption_checkpoint_request (FALSE);
4341 * Performs the interruption of the current thread, if one has been requested.
4342 * Return the exception which needs to be thrown, if any.
4345 mono_thread_force_interruption_checkpoint_noraise (void)
4347 return mono_thread_interruption_checkpoint_request (TRUE);
4351 * Performs the interruption of the current thread, if one has been requested.
4352 * Throw the exception which needs to be thrown, if any.
4355 mono_thread_force_interruption_checkpoint (void)
4359 ex = mono_thread_interruption_checkpoint_request (TRUE);
4361 mono_raise_exception (ex);
4365 * mono_thread_get_and_clear_pending_exception:
4367 * Return any pending exceptions for the current thread and clear it as a side effect.
4370 mono_thread_get_and_clear_pending_exception (void)
4372 MonoInternalThread *thread = mono_thread_internal_current ();
4374 /* The thread may already be stopping */
4378 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4379 return mono_thread_execute_interruption ();
4382 if (thread->pending_exception) {
4383 MonoException *exc = thread->pending_exception;
4385 thread->pending_exception = NULL;
4393 * mono_set_pending_exception:
4395 * Set the pending exception of the current thread to EXC.
4396 * The exception will be thrown when execution returns to managed code.
4399 mono_set_pending_exception (MonoException *exc)
4401 MonoInternalThread *thread = mono_thread_internal_current ();
4403 /* The thread may already be stopping */
4407 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4409 mono_thread_request_interruption (FALSE);
4413 * mono_thread_interruption_request_flag:
4415 * Returns the address of a flag that will be non-zero if an interruption has
4416 * been requested for a thread. The thread to interrupt may not be the current
4417 * thread, so an additional call to mono_thread_interruption_requested() or
4418 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4421 gint32* mono_thread_interruption_request_flag ()
4423 return &thread_interruption_requested;
4427 mono_thread_init_apartment_state (void)
4430 MonoInternalThread* thread = mono_thread_internal_current ();
4432 /* Positive return value indicates success, either
4433 * S_OK if this is first CoInitialize call, or
4434 * S_FALSE if CoInitialize already called, but with same
4435 * threading model. A negative value indicates failure,
4436 * probably due to trying to change the threading model.
4438 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4439 ? COINIT_APARTMENTTHREADED
4440 : COINIT_MULTITHREADED) < 0) {
4441 thread->apartment_state = ThreadApartmentState_Unknown;
4447 mono_thread_cleanup_apartment_state (void)
4450 MonoInternalThread* thread = mono_thread_internal_current ();
4452 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4459 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4461 LOCK_THREAD (thread);
4462 thread->state |= state;
4463 UNLOCK_THREAD (thread);
4467 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4469 LOCK_THREAD (thread);
4470 thread->state &= ~state;
4471 UNLOCK_THREAD (thread);
4475 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4477 gboolean ret = FALSE;
4479 LOCK_THREAD (thread);
4481 if ((thread->state & test) != 0) {
4485 UNLOCK_THREAD (thread);
4490 static gboolean has_tls_get = FALSE;
4493 mono_runtime_set_has_tls_get (gboolean val)
4499 mono_runtime_has_tls_get (void)
4505 self_interrupt_thread (void *_unused)
4507 MonoThreadInfo *info = mono_thread_info_current ();
4508 MonoException *exc = mono_thread_execute_interruption ();
4509 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4510 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. */
4511 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4515 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4519 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4523 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4525 MonoJitInfo **dest = data;
4531 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4533 MonoJitInfo *ji = NULL;
4536 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4541 MonoInternalThread *thread;
4542 gboolean install_async_abort;
4543 MonoThreadInfoInterruptToken *interrupt_token;
4546 static SuspendThreadResult
4547 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4549 AbortThreadData *data = ud;
4550 MonoInternalThread *thread = data->thread;
4551 MonoJitInfo *ji = NULL;
4552 gboolean protected_wrapper;
4553 gboolean running_managed;
4555 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4556 return MonoResumeThread;
4558 /*someone is already interrupting it*/
4559 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4560 return MonoResumeThread;
4562 InterlockedIncrement (&thread_interruption_requested);
4564 ji = mono_thread_info_get_last_managed (info);
4565 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4566 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4568 if (!protected_wrapper && running_managed) {
4569 /*We are in managed code*/
4570 /*Set the thread to call */
4571 if (data->install_async_abort)
4572 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4573 return MonoResumeThread;
4575 if (mono_thread_notify_pending_exc_fn)
4576 /* The JIT will notify the thread about the interruption */
4577 mono_thread_notify_pending_exc_fn (info);
4580 * This will cause waits to be broken.
4581 * It will also prevent the thread from entering a wait, so if the thread returns
4582 * from the wait before it receives the abort signal, it will just spin in the wait
4583 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4586 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4588 return MonoResumeThread;
4593 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4595 AbortThreadData data = { 0 };
4596 data.thread = thread;
4597 data.install_async_abort = install_async_abort;
4600 FIXME this is insanely broken, it doesn't cause interruption to happen
4601 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4603 if (thread == mono_thread_internal_current ()) {
4604 /* Do it synchronously */
4605 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4607 mono_raise_exception (exc);
4609 mono_thread_info_self_interrupt ();
4614 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_critical, &data);
4615 if (data.interrupt_token)
4616 mono_thread_info_finish_interrupt (data.interrupt_token);
4617 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4621 MonoInternalThread *thread;
4623 MonoThreadInfoInterruptToken *interrupt_token;
4624 } SuspendThreadData;
4626 static SuspendThreadResult
4627 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4629 SuspendThreadData *data = ud;
4630 MonoInternalThread *thread = data->thread;
4631 MonoJitInfo *ji = NULL;
4632 gboolean protected_wrapper;
4633 gboolean running_managed;
4635 ji = mono_thread_info_get_last_managed (info);
4636 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4637 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4639 if (running_managed && !protected_wrapper) {
4640 thread->state &= ~ThreadState_SuspendRequested;
4641 thread->state |= ThreadState_Suspended;
4642 return KeepSuspended;
4644 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4645 InterlockedIncrement (&thread_interruption_requested);
4646 if (data->interrupt)
4647 data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
4649 if (mono_thread_notify_pending_exc_fn && !running_managed)
4650 /* The JIT will notify the thread about the interruption */
4651 mono_thread_notify_pending_exc_fn (info);
4652 return MonoResumeThread;
4657 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4659 LOCK_THREAD (thread);
4660 if (thread == mono_thread_internal_current ()) {
4661 mono_thread_info_begin_self_suspend ();
4662 //XXX replace this with better named functions
4663 thread->state &= ~ThreadState_SuspendRequested;
4664 thread->state |= ThreadState_Suspended;
4665 UNLOCK_THREAD (thread);
4666 mono_thread_info_end_self_suspend ();
4668 SuspendThreadData data = { 0 };
4669 data.thread = thread;
4670 data.interrupt = interrupt;
4672 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, suspend_thread_critical, &data);
4673 if (data.interrupt_token)
4674 mono_thread_info_finish_interrupt (data.interrupt_token);
4675 UNLOCK_THREAD (thread);
4679 /*This is called with @thread synch_cs held and it must release it*/
4681 self_suspend_internal (MonoInternalThread *thread)
4683 mono_thread_info_begin_self_suspend ();
4684 thread->state &= ~ThreadState_SuspendRequested;
4685 thread->state |= ThreadState_Suspended;
4686 UNLOCK_THREAD (thread);
4687 mono_thread_info_end_self_suspend ();
4690 /*This is called with @thread synch_cs held and it must release it*/
4692 resume_thread_internal (MonoInternalThread *thread)
4694 UNLOCK_THREAD (thread);
4695 /* Awake the thread */
4696 if (!mono_thread_info_resume (thread_get_tid (thread)))
4698 LOCK_THREAD (thread);
4699 thread->state &= ~ThreadState_Suspended;
4700 UNLOCK_THREAD (thread);
4706 * mono_thread_is_foreign:
4707 * @thread: the thread to query
4709 * This function allows one to determine if a thread was created by the mono runtime and has
4710 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4712 * Returns: true if @thread was not created by the runtime.
4715 mono_thread_is_foreign (MonoThread *thread)
4717 MonoThreadInfo *info = thread->internal_thread->thread_info;
4718 return info->runtime_thread == FALSE;
4722 * mono_add_joinable_thread:
4724 * Add TID to the list of joinable threads.
4725 * LOCKING: Acquires the threads lock.
4728 mono_threads_add_joinable_thread (gpointer tid)
4732 * We cannot detach from threads because it causes problems like
4733 * 2fd16f60/r114307. So we collect them and join them when
4734 * we have time (in he finalizer thread).
4736 joinable_threads_lock ();
4737 if (!joinable_threads)
4738 joinable_threads = g_hash_table_new (NULL, NULL);
4739 g_hash_table_insert (joinable_threads, tid, tid);
4740 joinable_thread_count ++;
4741 joinable_threads_unlock ();
4743 mono_gc_finalize_notify ();
4748 * mono_threads_join_threads:
4750 * Join all joinable threads. This is called from the finalizer thread.
4751 * LOCKING: Acquires the threads lock.
4754 mono_threads_join_threads (void)
4757 GHashTableIter iter;
4764 if (!joinable_thread_count)
4768 joinable_threads_lock ();
4770 if (g_hash_table_size (joinable_threads)) {
4771 g_hash_table_iter_init (&iter, joinable_threads);
4772 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4773 thread = (pthread_t)tid;
4774 g_hash_table_remove (joinable_threads, key);
4775 joinable_thread_count --;
4778 joinable_threads_unlock ();
4780 if (thread != pthread_self ())
4781 /* This shouldn't block */
4782 pthread_join (thread, NULL);
4793 * Wait for thread TID to exit.
4794 * LOCKING: Acquires the threads lock.
4797 mono_thread_join (gpointer tid)
4801 gboolean found = FALSE;
4803 joinable_threads_lock ();
4804 if (!joinable_threads)
4805 joinable_threads = g_hash_table_new (NULL, NULL);
4806 if (g_hash_table_lookup (joinable_threads, tid)) {
4807 g_hash_table_remove (joinable_threads, tid);
4808 joinable_thread_count --;
4811 joinable_threads_unlock ();
4814 thread = (pthread_t)tid;
4815 pthread_join (thread, NULL);
4820 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4822 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4823 mono_thread_interruption_checkpoint ();
4826 static inline gboolean
4827 is_appdomainunloaded_exception (MonoClass *klass)
4829 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4831 if (!app_domain_unloaded_exception_klass)
4832 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4833 g_assert (app_domain_unloaded_exception_klass);
4835 return klass == app_domain_unloaded_exception_klass;
4838 static inline gboolean
4839 is_threadabort_exception (MonoClass *klass)
4841 return klass == mono_defaults.threadabortexception_class;
4845 mono_thread_internal_unhandled_exception (MonoObject* exc)
4847 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4848 MonoClass *klass = exc->vtable->klass;
4849 if (is_threadabort_exception (klass)) {
4850 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4851 } else if (!is_appdomainunloaded_exception (klass)) {
4852 mono_unhandled_exception (exc);
4853 if (mono_environment_exitcode_get () == 1)
4860 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
4862 mono_threads_get_thread_dump (out_threads, out_stack_traces);