2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threads-types.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/environment.h>
26 #include <mono/metadata/monitor.h>
27 #include <mono/metadata/gc-internal.h>
28 #include <mono/metadata/marshal.h>
29 #include <mono/metadata/runtime.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/mono-debug-debugger.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internal.h>
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
51 #define USE_TKILL_ON_ANDROID 1
54 #ifdef PLATFORM_ANDROID
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid, int signal);
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func)(void *);
107 typedef struct _StaticDataFreeList StaticDataFreeList;
108 struct _StaticDataFreeList {
109 StaticDataFreeList *next;
117 StaticDataFreeList *freelist;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 static void mono_threads_lock (void);
130 static void mono_threads_unlock (void);
131 static mono_mutex_t threads_mutex;
133 /* Controls access to the 'joinable_threads' hash table */
134 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
135 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
136 static mono_mutex_t joinable_threads_mutex;
138 /* Holds current status of static data heap */
139 static StaticDataInfo thread_static_info;
140 static StaticDataInfo context_static_info;
142 /* The hash of existing threads (key is thread ID, value is
143 * MonoInternalThread*) that need joining before exit
145 static MonoGHashTable *threads=NULL;
147 /* List of app context GC handles.
148 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
150 static GHashTable *contexts = NULL;
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__, GetCurrentThreadId ()));
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;
679 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
681 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
683 /* On 2.0 profile (and higher), set explicitly since state might have been
685 if (internal->apartment_state == ThreadApartmentState_Unknown)
686 internal->apartment_state = ThreadApartmentState_MTA;
688 mono_thread_init_apartment_state ();
690 if(internal->start_notify!=NULL) {
691 /* Let the thread that called Start() know we're
694 ReleaseSemaphore (internal->start_notify, 1, NULL);
698 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
702 * Call this after calling start_notify, since the profiler callback might want
703 * to lock the thread, and the lock is held by thread_start () which waits for
706 mono_profiler_thread_start (tid);
708 /* if the name was set before starting, we didn't invoke the profiler callback */
709 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
710 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
711 mono_profiler_thread_name (internal->tid, tname);
714 /* start_func is set only for unmanaged start functions */
716 start_func (start_arg);
719 g_assert (start_delegate != NULL);
720 args [0] = start_arg;
721 /* we may want to handle the exception here. See comment below on unhandled exceptions */
722 mono_runtime_delegate_invoke (start_delegate, args, NULL);
725 /* If the thread calls ExitThread at all, this remaining code
726 * will not be executed, but the main thread will eventually
727 * call thread_cleanup() on this thread's behalf.
730 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
732 /* Do any cleanup needed for apartment state. This
733 * cannot be done in thread_cleanup since thread_cleanup could be
734 * called for a thread other than the current thread.
735 * mono_thread_cleanup_apartment_state cleans up apartment
736 * for the current thead */
737 mono_thread_cleanup_apartment_state ();
739 thread_cleanup (internal);
743 /* Remove the reference to the thread object in the TLS data,
744 * so the thread object can be finalized. This won't be
745 * reached if the thread threw an uncaught exception, so those
746 * thread handles will stay referenced :-( (This is due to
747 * missing support for scanning thread-specific data in the
748 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
751 SET_CURRENT_OBJECT (NULL);
756 static guint32 WINAPI start_wrapper(void *data)
760 /* Avoid scanning the frames above this frame during a GC */
761 mono_gc_set_stack_end ((void*)&dummy);
763 return start_wrapper_internal (data);
769 * Common thread creation code.
770 * LOCKING: Acquires the threads lock.
773 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
774 gboolean throw_on_failure)
776 HANDLE thread_handle;
777 MonoNativeThreadId tid;
778 guint32 create_flags;
781 * Join joinable threads to prevent running out of threads since the finalizer
782 * thread might be blocked/backlogged.
784 mono_threads_join_threads ();
786 mono_threads_lock ();
789 mono_threads_unlock ();
792 if (threads_starting_up == NULL) {
793 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
794 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
796 mono_g_hash_table_insert (threads_starting_up, thread, thread);
797 mono_threads_unlock ();
799 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
800 if (!internal->start_notify) {
801 mono_threads_lock ();
802 mono_g_hash_table_remove (threads_starting_up, thread);
803 mono_threads_unlock ();
804 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
810 stack_size = default_stacksize_for_thread (internal);
812 /* Create suspended, so we can do some housekeeping before the thread
815 create_flags = CREATE_SUSPENDED;
817 MONO_PREPARE_BLOCKING;
818 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
819 stack_size, create_flags, &tid);
820 MONO_FINISH_BLOCKING;
822 if (thread_handle == NULL) {
823 /* The thread couldn't be created, so throw an exception */
824 mono_threads_lock ();
825 mono_g_hash_table_remove (threads_starting_up, thread);
826 mono_threads_unlock ();
828 if (throw_on_failure)
829 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
831 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
834 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
836 internal->handle = thread_handle;
837 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
839 internal->threadpool_thread = threadpool_thread;
840 if (threadpool_thread)
841 mono_thread_set_state (internal, ThreadState_Background);
843 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
845 /* Only store the handle when the thread is about to be
846 * launched, to avoid the main thread deadlocking while trying
847 * to clean up a thread that will never be signalled.
849 if (!handle_store (thread, FALSE))
852 MONO_PREPARE_BLOCKING;
853 mono_thread_info_resume (tid);
854 MONO_FINISH_BLOCKING;
856 if (internal->start_notify) {
858 * Wait for the thread to set up its TLS data etc, so
859 * theres no potential race condition if someone tries
860 * to look up the data believing the thread has
863 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
865 MONO_PREPARE_BLOCKING;
866 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
867 MONO_FINISH_BLOCKING;
869 CloseHandle (internal->start_notify);
870 internal->start_notify = NULL;
873 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
878 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
880 if (mono_thread_start_cb) {
881 mono_thread_start_cb (tid, stack_start, func);
885 void mono_threads_set_default_stacksize (guint32 stacksize)
887 default_stacksize = stacksize;
890 guint32 mono_threads_get_default_stacksize (void)
892 return default_stacksize;
896 * mono_thread_create_internal:
898 * ARG should not be a GC reference.
901 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
904 MonoInternalThread *internal;
905 StartInfo *start_info;
908 thread = create_thread_object (domain);
909 internal = create_internal_thread ();
910 MONO_OBJECT_SETREF (thread, internal_thread, internal);
912 start_info = g_new0 (StartInfo, 1);
913 start_info->func = func;
914 start_info->obj = thread;
915 start_info->start_arg = arg;
917 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
921 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
922 if (mono_check_corlib_version () == NULL)
923 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
929 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
931 mono_thread_create_internal (domain, func, arg, FALSE, 0);
935 mono_thread_attach (MonoDomain *domain)
937 return mono_thread_attach_full (domain, FALSE);
941 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
943 MonoThreadInfo *info;
944 MonoInternalThread *thread;
945 MonoThread *current_thread;
946 HANDLE thread_handle;
949 if ((thread = mono_thread_internal_current ())) {
950 if (domain != mono_domain_get ())
951 mono_domain_set (domain, TRUE);
952 /* Already attached */
953 return mono_thread_current ();
956 if (!mono_gc_register_thread (&domain)) {
957 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ());
960 thread = create_internal_thread ();
962 thread_handle = mono_thread_info_open_handle ();
963 g_assert (thread_handle);
965 tid=GetCurrentThreadId ();
967 thread->handle = thread_handle;
969 thread->stack_ptr = &tid;
971 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
973 info = mono_thread_info_current ();
975 thread->thread_info = info;
976 thread->small_id = info->small_id;
978 current_thread = new_thread_with_internal (domain, thread);
980 if (!handle_store (current_thread, force_attach)) {
981 /* Mono is shutting down, so just wait for the end */
986 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
988 SET_CURRENT_OBJECT (thread);
989 mono_domain_set (domain, TRUE);
991 thread_adjust_static_data (thread);
993 init_root_domain_thread (thread, current_thread);
994 if (domain != mono_get_root_domain ())
995 set_current_thread_for_domain (domain, thread, current_thread);
998 if (mono_thread_attach_cb) {
1002 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1005 mono_thread_attach_cb (tid, &tid);
1007 mono_thread_attach_cb (tid, staddr + stsize);
1010 // FIXME: Need a separate callback
1011 mono_profiler_thread_start (tid);
1013 return current_thread;
1017 mono_thread_detach_internal (MonoInternalThread *thread)
1019 g_return_if_fail (thread != NULL);
1021 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1023 thread_cleanup (thread);
1025 SET_CURRENT_OBJECT (NULL);
1026 mono_domain_unset ();
1028 /* Don't need to CloseHandle this thread, even though we took a
1029 * reference in mono_thread_attach (), because the GC will do it
1030 * when the Thread object is finalised.
1035 mono_thread_detach (MonoThread *thread)
1038 mono_thread_detach_internal (thread->internal_thread);
1042 * mono_thread_detach_if_exiting:
1044 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1045 * This should be used at the end of embedding code which calls into managed code, and which
1046 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1049 mono_thread_detach_if_exiting (void)
1051 if (mono_thread_info_is_exiting ()) {
1052 MonoInternalThread *thread;
1054 thread = mono_thread_internal_current ();
1056 mono_thread_detach_internal (thread);
1057 mono_thread_info_detach ();
1065 MonoInternalThread *thread = mono_thread_internal_current ();
1067 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1069 thread_cleanup (thread);
1070 SET_CURRENT_OBJECT (NULL);
1071 mono_domain_unset ();
1073 /* we could add a callback here for embedders to use. */
1074 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1075 exit (mono_environment_exitcode_get ());
1076 mono_thread_info_exit ();
1080 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1082 MonoInternalThread *internal = create_internal_thread ();
1084 internal->state = ThreadState_Unstarted;
1086 InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
1090 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1093 StartInfo *start_info;
1094 MonoInternalThread *internal;
1097 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1099 if (!this_obj->internal_thread)
1100 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1101 internal = this_obj->internal_thread;
1103 LOCK_THREAD (internal);
1105 if ((internal->state & ThreadState_Unstarted) == 0) {
1106 UNLOCK_THREAD (internal);
1107 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1111 if ((internal->state & ThreadState_Aborted) != 0) {
1112 UNLOCK_THREAD (internal);
1115 /* This is freed in start_wrapper */
1116 start_info = g_new0 (StartInfo, 1);
1117 start_info->func = NULL;
1118 start_info->start_arg = NULL;
1119 start_info->delegate = start;
1120 start_info->obj = this_obj;
1121 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1123 res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
1125 UNLOCK_THREAD (internal);
1129 internal->state &= ~ThreadState_Unstarted;
1131 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1133 UNLOCK_THREAD (internal);
1134 return internal->handle;
1138 * This is called from the finalizer of the internal thread object.
1141 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1143 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1146 * Since threads keep a reference to their thread object while running, by the time this function is called,
1147 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1148 * when thread_cleanup () can be called after this.
1151 CloseHandle (thread);
1153 if (this_obj->synch_cs) {
1154 mono_mutex_t *synch_cs = this_obj->synch_cs;
1155 this_obj->synch_cs = NULL;
1156 mono_mutex_destroy (synch_cs);
1160 if (this_obj->name) {
1161 void *name = this_obj->name;
1162 this_obj->name = NULL;
1168 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1171 MonoInternalThread *thread = mono_thread_internal_current ();
1173 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1175 mono_thread_current_check_pending_interrupt ();
1178 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1180 MONO_PREPARE_BLOCKING;
1181 res = SleepEx(ms,TRUE);
1182 MONO_FINISH_BLOCKING;
1184 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1186 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1187 MonoException* exc = mono_thread_execute_interruption ();
1189 mono_raise_exception (exc);
1201 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1206 ves_icall_System_Threading_Thread_GetDomainID (void)
1208 return mono_domain_get()->domain_id;
1212 ves_icall_System_Threading_Thread_Yield (void)
1214 return mono_thread_info_yield ();
1218 * mono_thread_get_name:
1220 * Return the name of the thread. NAME_LEN is set to the length of the name.
1221 * Return NULL if the thread has no name. The returned memory is owned by the
1225 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1229 LOCK_THREAD (this_obj);
1231 if (!this_obj->name) {
1235 *name_len = this_obj->name_len;
1236 res = g_new (gunichar2, this_obj->name_len);
1237 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1240 UNLOCK_THREAD (this_obj);
1246 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1250 LOCK_THREAD (this_obj);
1252 if (!this_obj->name)
1255 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1257 UNLOCK_THREAD (this_obj);
1263 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1265 LOCK_THREAD (this_obj);
1267 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1268 UNLOCK_THREAD (this_obj);
1270 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1273 if (this_obj->name) {
1274 g_free (this_obj->name);
1275 this_obj->name_len = 0;
1278 this_obj->name = g_new (gunichar2, mono_string_length (name));
1279 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1280 this_obj->name_len = mono_string_length (name);
1283 this_obj->name = NULL;
1286 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1288 UNLOCK_THREAD (this_obj);
1290 if (this_obj->name && this_obj->tid) {
1291 char *tname = mono_string_to_utf8 (name);
1292 mono_profiler_thread_name (this_obj->tid, tname);
1293 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1299 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1301 mono_thread_set_name_internal (this_obj, name, TRUE);
1305 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
1307 return ThreadPriority_Lowest;
1311 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1315 /* If the array is already in the requested domain, we just return it,
1316 otherwise we return a copy in that domain. */
1318 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1325 if (mono_object_domain (arr) == domain)
1328 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1329 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1334 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1336 return byte_array_to_domain (arr, mono_get_root_domain ());
1340 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1342 return byte_array_to_domain (arr, mono_domain_get ());
1346 mono_thread_current (void)
1348 MonoDomain *domain = mono_domain_get ();
1349 MonoInternalThread *internal = mono_thread_internal_current ();
1350 MonoThread **current_thread_ptr;
1352 g_assert (internal);
1353 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1355 if (!*current_thread_ptr) {
1356 g_assert (domain != mono_get_root_domain ());
1357 *current_thread_ptr = new_thread_with_internal (domain, internal);
1359 return *current_thread_ptr;
1363 mono_thread_internal_current (void)
1365 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1366 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1371 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1373 MonoInternalThread *thread = this_obj->internal_thread;
1374 HANDLE handle = thread->handle;
1375 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1378 mono_thread_current_check_pending_interrupt ();
1380 LOCK_THREAD (thread);
1382 if ((thread->state & ThreadState_Unstarted) != 0) {
1383 UNLOCK_THREAD (thread);
1385 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1389 UNLOCK_THREAD (thread);
1394 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1396 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1398 MONO_PREPARE_BLOCKING;
1399 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1400 MONO_FINISH_BLOCKING;
1402 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1404 if(ret==WAIT_OBJECT_0) {
1405 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1410 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1416 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1424 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1426 MONO_PREPARE_BLOCKING;
1428 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1430 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1431 MONO_FINISH_BLOCKING;
1433 if (ret != WAIT_IO_COMPLETION)
1436 exc = mono_thread_execute_interruption ();
1438 mono_raise_exception (exc);
1443 /* Re-calculate ms according to the time passed */
1444 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1445 if (diff_ms >= ms) {
1449 wait = ms - diff_ms;
1455 /* FIXME: exitContext isnt documented */
1456 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1462 MonoObject *waitHandle;
1463 MonoInternalThread *thread = mono_thread_internal_current ();
1465 /* Do this WaitSleepJoin check before creating objects */
1466 mono_thread_current_check_pending_interrupt ();
1468 /* We fail in managed if the array has more than 64 elements */
1469 numhandles = (guint32)mono_array_length(mono_handles);
1470 handles = g_new0(HANDLE, numhandles);
1472 for(i = 0; i < numhandles; i++) {
1473 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1474 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1481 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1483 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1485 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1489 if(ret==WAIT_FAILED) {
1490 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1492 } else if(ret==WAIT_TIMEOUT) {
1493 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1500 /* FIXME: exitContext isnt documented */
1501 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1503 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1504 uintptr_t numhandles;
1507 MonoObject *waitHandle;
1508 MonoInternalThread *thread = mono_thread_internal_current ();
1510 /* Do this WaitSleepJoin check before creating objects */
1511 mono_thread_current_check_pending_interrupt ();
1513 numhandles = mono_array_length(mono_handles);
1514 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1517 for(i = 0; i < numhandles; i++) {
1518 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1519 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1526 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1528 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1530 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1532 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1535 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1537 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1538 return ret - WAIT_OBJECT_0;
1540 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1541 return ret - WAIT_ABANDONED_0;
1548 /* FIXME: exitContext isnt documented */
1549 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
1552 MonoInternalThread *thread = mono_thread_internal_current ();
1554 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1560 mono_thread_current_check_pending_interrupt ();
1562 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1564 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1566 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1568 if(ret==WAIT_FAILED) {
1569 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1571 } else if(ret==WAIT_TIMEOUT) {
1572 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1580 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1583 MonoInternalThread *thread = mono_thread_internal_current ();
1588 mono_thread_current_check_pending_interrupt ();
1590 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1592 MONO_PREPARE_BLOCKING;
1593 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1594 MONO_FINISH_BLOCKING;
1596 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1598 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1601 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1608 mutex = CreateMutex (NULL, owned, NULL);
1610 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1612 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1620 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1621 return(ReleaseMutex (handle));
1624 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1630 *error = ERROR_SUCCESS;
1632 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1634 *error = GetLastError ();
1641 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1648 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1650 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1651 mono_string_chars (name));
1653 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1661 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1665 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1670 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1674 *error = ERROR_SUCCESS;
1676 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1678 *error = GetLastError ();
1684 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1691 event = CreateEvent (NULL, manual, initial, NULL);
1693 event = CreateEvent (NULL, manual, initial,
1694 mono_string_chars (name));
1696 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1704 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1705 return (SetEvent(handle));
1708 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1709 return (ResetEvent(handle));
1713 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1714 CloseHandle (handle);
1717 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1723 *error = ERROR_SUCCESS;
1725 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1727 *error = GetLastError ();
1733 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1735 return InterlockedIncrement (location);
1738 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1740 #if SIZEOF_VOID_P == 4
1741 if (G_UNLIKELY ((size_t)location & 0x7)) {
1743 mono_interlocked_lock ();
1746 mono_interlocked_unlock ();
1750 return InterlockedIncrement64 (location);
1753 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1755 return InterlockedDecrement(location);
1758 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1760 #if SIZEOF_VOID_P == 4
1761 if (G_UNLIKELY ((size_t)location & 0x7)) {
1763 mono_interlocked_lock ();
1766 mono_interlocked_unlock ();
1770 return InterlockedDecrement64 (location);
1773 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1775 return InterlockedExchange(location, value);
1778 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1781 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1782 mono_gc_wbarrier_generic_nostore (location);
1786 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1788 return InterlockedExchangePointer(location, value);
1791 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1793 IntFloatUnion val, ret;
1796 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1802 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1804 #if SIZEOF_VOID_P == 4
1805 if (G_UNLIKELY ((size_t)location & 0x7)) {
1807 mono_interlocked_lock ();
1810 mono_interlocked_unlock ();
1814 return InterlockedExchange64 (location, value);
1818 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1820 LongDoubleUnion val, ret;
1823 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1828 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1830 return InterlockedCompareExchange(location, value, comparand);
1833 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1835 gint32 r = InterlockedCompareExchange(location, value, comparand);
1836 *success = r == comparand;
1840 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1843 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1844 mono_gc_wbarrier_generic_nostore (location);
1848 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1850 return InterlockedCompareExchangePointer(location, value, comparand);
1853 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1855 IntFloatUnion val, ret, cmp;
1858 cmp.fval = comparand;
1859 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1865 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1867 #if SIZEOF_VOID_P == 8
1868 LongDoubleUnion val, comp, ret;
1871 comp.fval = comparand;
1872 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1878 mono_interlocked_lock ();
1880 if (old == comparand)
1882 mono_interlocked_unlock ();
1889 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1891 #if SIZEOF_VOID_P == 4
1892 if (G_UNLIKELY ((size_t)location & 0x7)) {
1894 mono_interlocked_lock ();
1896 if (old == comparand)
1898 mono_interlocked_unlock ();
1902 return InterlockedCompareExchange64 (location, value, comparand);
1906 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1909 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1910 mono_gc_wbarrier_generic_nostore (location);
1915 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1918 res = InterlockedExchangePointer ((gpointer *)location, value);
1919 mono_gc_wbarrier_generic_nostore (location);
1924 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1926 return InterlockedAdd (location, value);
1930 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1932 #if SIZEOF_VOID_P == 4
1933 if (G_UNLIKELY ((size_t)location & 0x7)) {
1935 mono_interlocked_lock ();
1938 mono_interlocked_unlock ();
1942 return InterlockedAdd64 (location, value);
1946 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1948 #if SIZEOF_VOID_P == 4
1949 if (G_UNLIKELY ((size_t)location & 0x7)) {
1951 mono_interlocked_lock ();
1953 mono_interlocked_unlock ();
1957 return InterlockedRead64 (location);
1961 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1963 mono_memory_barrier ();
1967 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1969 mono_thread_clr_state (this, state);
1971 if (state & ThreadState_Background) {
1972 /* If the thread changes the background mode, the main thread has to
1973 * be notified, since it has to rebuild the list of threads to
1976 SetEvent (background_change_event);
1981 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1983 mono_thread_set_state (this, state);
1985 if (state & ThreadState_Background) {
1986 /* If the thread changes the background mode, the main thread has to
1987 * be notified, since it has to rebuild the list of threads to
1990 SetEvent (background_change_event);
1995 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2001 state = this->state;
2003 UNLOCK_THREAD (this);
2008 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2010 MonoInternalThread *current;
2012 MonoInternalThread *thread = this_obj->internal_thread;
2014 LOCK_THREAD (thread);
2016 current = mono_thread_internal_current ();
2018 thread->thread_interrupt_requested = TRUE;
2019 throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2021 UNLOCK_THREAD (thread);
2024 abort_thread_internal (thread, TRUE, FALSE);
2028 void mono_thread_current_check_pending_interrupt ()
2030 MonoInternalThread *thread = mono_thread_internal_current ();
2031 gboolean throw = FALSE;
2033 LOCK_THREAD (thread);
2035 if (thread->thread_interrupt_requested) {
2037 thread->thread_interrupt_requested = FALSE;
2040 UNLOCK_THREAD (thread);
2043 mono_raise_exception (mono_get_exception_thread_interrupted ());
2048 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2050 LOCK_THREAD (thread);
2052 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2053 (thread->state & ThreadState_StopRequested) != 0 ||
2054 (thread->state & ThreadState_Stopped) != 0)
2056 UNLOCK_THREAD (thread);
2060 if ((thread->state & ThreadState_Unstarted) != 0) {
2061 thread->state |= ThreadState_Aborted;
2062 UNLOCK_THREAD (thread);
2066 thread->state |= ThreadState_AbortRequested;
2067 if (thread->abort_state_handle)
2068 mono_gchandle_free (thread->abort_state_handle);
2070 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2071 g_assert (thread->abort_state_handle);
2073 thread->abort_state_handle = 0;
2075 thread->abort_exc = NULL;
2077 UNLOCK_THREAD (thread);
2079 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2081 /* During shutdown, we can't wait for other threads */
2083 /* Make sure the thread is awake */
2084 mono_thread_resume (thread);
2086 abort_thread_internal (thread, TRUE, TRUE);
2090 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2092 MonoInternalThread *thread = mono_thread_internal_current ();
2093 gboolean was_aborting;
2095 LOCK_THREAD (thread);
2096 was_aborting = thread->state & ThreadState_AbortRequested;
2097 thread->state &= ~ThreadState_AbortRequested;
2098 UNLOCK_THREAD (thread);
2100 if (!was_aborting) {
2101 const char *msg = "Unable to reset abort because no abort was requested";
2102 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2105 thread->abort_exc = NULL;
2106 if (thread->abort_state_handle) {
2107 mono_gchandle_free (thread->abort_state_handle);
2108 /* This is actually not necessary - the handle
2109 only counts if the exception is set */
2110 thread->abort_state_handle = 0;
2115 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2117 LOCK_THREAD (thread);
2119 thread->state &= ~ThreadState_AbortRequested;
2121 if (thread->abort_exc) {
2122 thread->abort_exc = NULL;
2123 if (thread->abort_state_handle) {
2124 mono_gchandle_free (thread->abort_state_handle);
2125 /* This is actually not necessary - the handle
2126 only counts if the exception is set */
2127 thread->abort_state_handle = 0;
2131 UNLOCK_THREAD (thread);
2135 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2137 MonoInternalThread *thread = this_obj->internal_thread;
2138 MonoObject *state, *deserialized = NULL, *exc;
2141 if (!thread->abort_state_handle)
2144 state = mono_gchandle_get_target (thread->abort_state_handle);
2147 domain = mono_domain_get ();
2148 if (mono_object_domain (state) == domain)
2151 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2153 if (!deserialized) {
2154 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2156 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2157 mono_set_pending_exception (invalid_op_exc);
2161 return deserialized;
2165 mono_thread_suspend (MonoInternalThread *thread)
2167 LOCK_THREAD (thread);
2169 if ((thread->state & ThreadState_Unstarted) != 0 ||
2170 (thread->state & ThreadState_Aborted) != 0 ||
2171 (thread->state & ThreadState_Stopped) != 0)
2173 UNLOCK_THREAD (thread);
2177 if ((thread->state & ThreadState_Suspended) != 0 ||
2178 (thread->state & ThreadState_SuspendRequested) != 0 ||
2179 (thread->state & ThreadState_StopRequested) != 0)
2181 UNLOCK_THREAD (thread);
2185 thread->state |= ThreadState_SuspendRequested;
2187 UNLOCK_THREAD (thread);
2189 suspend_thread_internal (thread, FALSE);
2194 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2196 if (!mono_thread_suspend (this_obj->internal_thread)) {
2197 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2203 mono_thread_resume (MonoInternalThread *thread)
2205 LOCK_THREAD (thread);
2207 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2208 thread->state &= ~ThreadState_SuspendRequested;
2209 UNLOCK_THREAD (thread);
2213 if ((thread->state & ThreadState_Suspended) == 0 ||
2214 (thread->state & ThreadState_Unstarted) != 0 ||
2215 (thread->state & ThreadState_Aborted) != 0 ||
2216 (thread->state & ThreadState_Stopped) != 0)
2218 UNLOCK_THREAD (thread);
2222 return resume_thread_internal (thread);
2226 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2228 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2229 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2235 mono_threads_is_critical_method (MonoMethod *method)
2237 switch (method->wrapper_type) {
2238 case MONO_WRAPPER_RUNTIME_INVOKE:
2239 case MONO_WRAPPER_XDOMAIN_INVOKE:
2240 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2247 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2252 if (mono_threads_is_critical_method (m)) {
2253 *((gboolean*)data) = TRUE;
2260 is_running_protected_wrapper (void)
2262 gboolean found = FALSE;
2263 mono_stack_walk (find_wrapper, &found);
2267 void mono_thread_internal_stop (MonoInternalThread *thread)
2269 LOCK_THREAD (thread);
2271 if ((thread->state & ThreadState_StopRequested) != 0 ||
2272 (thread->state & ThreadState_Stopped) != 0)
2274 UNLOCK_THREAD (thread);
2278 /* Make sure the thread is awake */
2279 mono_thread_resume (thread);
2281 thread->state |= ThreadState_StopRequested;
2282 thread->state &= ~ThreadState_AbortRequested;
2284 UNLOCK_THREAD (thread);
2286 abort_thread_internal (thread, TRUE, TRUE);
2289 void mono_thread_stop (MonoThread *thread)
2291 mono_thread_internal_stop (thread->internal_thread);
2295 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2298 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2303 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2306 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2311 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2314 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2319 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2322 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2327 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2330 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2331 return (void *) tmp;
2335 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2337 volatile MonoObject *tmp;
2338 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2339 return (MonoObject *) tmp;
2343 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2346 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2351 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2354 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2359 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2361 return InterlockedRead8 (ptr);
2365 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2367 return InterlockedRead16 (ptr);
2371 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2373 return InterlockedRead (ptr);
2377 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2379 #if SIZEOF_VOID_P == 4
2380 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2382 mono_interlocked_lock ();
2383 val = *(gint64*)ptr;
2384 mono_interlocked_unlock ();
2388 return InterlockedRead64 (ptr);
2392 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2394 return InterlockedReadPointer (ptr);
2398 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2402 #if SIZEOF_VOID_P == 4
2403 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2405 mono_interlocked_lock ();
2406 val = *(double*)ptr;
2407 mono_interlocked_unlock ();
2412 u.ival = InterlockedRead64 (ptr);
2418 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2422 u.ival = InterlockedRead (ptr);
2428 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2430 return InterlockedReadPointer (ptr);
2434 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2436 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2440 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2442 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2446 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2448 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2452 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2454 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2458 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2460 mono_atomic_store_release ((volatile void **) ptr, value);
2464 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2466 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2470 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2472 mono_atomic_store_release ((volatile double *) ptr, value);
2476 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2478 mono_atomic_store_release ((volatile float *) ptr, value);
2482 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2484 InterlockedWrite8 (ptr, value);
2488 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2490 InterlockedWrite16 (ptr, value);
2494 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2496 InterlockedWrite (ptr, value);
2500 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2502 #if SIZEOF_VOID_P == 4
2503 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2504 mono_interlocked_lock ();
2505 *(gint64*)ptr = value;
2506 mono_interlocked_unlock ();
2511 InterlockedWrite64 (ptr, value);
2515 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2517 InterlockedWritePointer (ptr, value);
2521 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2525 #if SIZEOF_VOID_P == 4
2526 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2527 mono_interlocked_lock ();
2528 *(double*)ptr = value;
2529 mono_interlocked_unlock ();
2536 InterlockedWrite64 (ptr, u.ival);
2540 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2546 InterlockedWrite (ptr, u.ival);
2550 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2552 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2556 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2558 mono_threads_lock ();
2560 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2563 contexts = g_hash_table_new (NULL, NULL);
2565 context_adjust_static_data (ctx);
2566 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2567 g_hash_table_insert (contexts, gch, gch);
2569 mono_threads_unlock ();
2571 mono_profiler_context_loaded (ctx);
2575 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2578 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2579 * cleanup in exceptional circumstances, we don't actually do any
2580 * cleanup work here. We instead do this when we iterate the `contexts`
2581 * hash table. The only purpose of this finalizer, at the moment, is to
2582 * notify the profiler.
2585 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2587 mono_profiler_context_unloaded (ctx);
2591 mono_thread_init_tls (void)
2593 MONO_FAST_TLS_INIT (tls_current_object);
2594 mono_native_tls_alloc (¤t_object_key, NULL);
2597 void mono_thread_init (MonoThreadStartCB start_cb,
2598 MonoThreadAttachCB attach_cb)
2600 mono_mutex_init_recursive(&threads_mutex);
2601 mono_mutex_init_recursive(&interlocked_mutex);
2602 mono_mutex_init_recursive(&joinable_threads_mutex);
2604 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2605 g_assert(background_change_event != NULL);
2607 mono_init_static_data_info (&thread_static_info);
2608 mono_init_static_data_info (&context_static_info);
2610 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2612 mono_thread_start_cb = start_cb;
2613 mono_thread_attach_cb = attach_cb;
2615 /* Get a pseudo handle to the current process. This is just a
2616 * kludge so that wapi can build a process handle if needed.
2617 * As a pseudo handle is returned, we don't need to clean
2620 GetCurrentProcess ();
2623 void mono_thread_cleanup (void)
2625 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2626 MonoThreadInfo *info;
2628 /* The main thread must abandon any held mutexes (particularly
2629 * important for named mutexes as they are shared across
2630 * processes, see bug 74680.) This will happen when the
2631 * thread exits, but if it's not running in a subthread it
2632 * won't exit in time.
2634 info = mono_thread_info_current ();
2635 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2639 /* This stuff needs more testing, it seems one of these
2640 * critical sections can be locked when mono_thread_cleanup is
2643 mono_mutex_destroy (&threads_mutex);
2644 mono_mutex_destroy (&interlocked_mutex);
2645 mono_mutex_destroy (&delayed_free_table_mutex);
2646 mono_mutex_destroy (&small_id_mutex);
2647 CloseHandle (background_change_event);
2650 mono_native_tls_free (current_object_key);
2654 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2656 mono_thread_cleanup_fn = func;
2660 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2662 thread->internal_thread->manage_callback = func;
2665 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2667 mono_thread_notify_pending_exc_fn = func;
2671 static void print_tids (gpointer key, gpointer value, gpointer user)
2673 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2674 * sizeof(uint) and a cast to uint would overflow
2676 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2677 * print this as a pointer.
2679 g_message ("Waiting for: %p", key);
2684 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2685 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2689 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2693 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2695 MONO_PREPARE_BLOCKING;
2696 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2697 MONO_FINISH_BLOCKING;
2699 if(ret==WAIT_FAILED) {
2700 /* See the comment in build_wait_tids() */
2701 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2705 for(i=0; i<wait->num; i++)
2706 CloseHandle (wait->handles[i]);
2708 if (ret == WAIT_TIMEOUT)
2711 for(i=0; i<wait->num; i++) {
2712 gsize tid = wait->threads[i]->tid;
2715 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2716 * it can still run io-layer etc. code. So wait for it to really exit.
2717 * FIXME: This won't join threads which are not in the joinable_hash yet.
2719 mono_thread_join ((gpointer)tid);
2721 mono_threads_lock ();
2722 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2723 /* This thread must have been killed, because
2724 * it hasn't cleaned itself up. (It's just
2725 * possible that the thread exited before the
2726 * parent thread had a chance to store the
2727 * handle, and now there is another pointer to
2728 * the already-exited thread stored. In this
2729 * case, we'll just get two
2730 * mono_profiler_thread_end() calls for the
2734 mono_threads_unlock ();
2735 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2736 thread_cleanup (wait->threads[i]);
2738 mono_threads_unlock ();
2743 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2745 guint32 i, ret, count;
2747 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2749 /* Add the thread state change event, so it wakes up if a thread changes
2750 * to background mode.
2753 if (count < MAXIMUM_WAIT_OBJECTS) {
2754 wait->handles [count] = background_change_event;
2758 MONO_PREPARE_BLOCKING;
2759 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2760 MONO_FINISH_BLOCKING;
2762 if(ret==WAIT_FAILED) {
2763 /* See the comment in build_wait_tids() */
2764 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2768 for(i=0; i<wait->num; i++)
2769 CloseHandle (wait->handles[i]);
2771 if (ret == WAIT_TIMEOUT)
2774 if (ret < wait->num) {
2775 gsize tid = wait->threads[ret]->tid;
2776 mono_threads_lock ();
2777 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2778 /* See comment in wait_for_tids about thread cleanup */
2779 mono_threads_unlock ();
2780 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2781 thread_cleanup (wait->threads [ret]);
2783 mono_threads_unlock ();
2787 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2789 struct wait_data *wait=(struct wait_data *)user;
2791 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2793 MonoInternalThread *thread=(MonoInternalThread *)value;
2795 /* Ignore background threads, we abort them later */
2796 /* Do not lock here since it is not needed and the caller holds threads_lock */
2797 if (thread->state & ThreadState_Background) {
2798 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2799 return; /* just leave, ignore */
2802 if (mono_gc_is_finalizer_internal_thread (thread)) {
2803 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2807 if (thread == mono_thread_internal_current ()) {
2808 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2812 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2813 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2817 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2818 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2822 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2823 if (handle == NULL) {
2824 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2828 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2829 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2830 wait->handles[wait->num]=handle;
2831 wait->threads[wait->num]=thread;
2834 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2836 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2841 /* Just ignore the rest, we can't do anything with
2848 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2850 struct wait_data *wait=(struct wait_data *)user;
2851 gsize self = GetCurrentThreadId ();
2852 MonoInternalThread *thread = value;
2855 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2858 /* The finalizer thread is not a background thread */
2859 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2860 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2862 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2866 /* printf ("A: %d\n", wait->num); */
2867 wait->handles[wait->num]=thread->handle;
2868 wait->threads[wait->num]=thread;
2871 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2872 mono_thread_internal_stop (thread);
2876 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2880 * mono_threads_set_shutting_down:
2882 * Is called by a thread that wants to shut down Mono. If the runtime is already
2883 * shutting down, the calling thread is suspended/stopped, and this function never
2887 mono_threads_set_shutting_down (void)
2889 MonoInternalThread *current_thread = mono_thread_internal_current ();
2891 mono_threads_lock ();
2893 if (shutting_down) {
2894 mono_threads_unlock ();
2896 /* Make sure we're properly suspended/stopped */
2898 LOCK_THREAD (current_thread);
2900 if ((current_thread->state & ThreadState_SuspendRequested) ||
2901 (current_thread->state & ThreadState_AbortRequested) ||
2902 (current_thread->state & ThreadState_StopRequested)) {
2903 UNLOCK_THREAD (current_thread);
2904 mono_thread_execute_interruption ();
2906 current_thread->state |= ThreadState_Stopped;
2907 UNLOCK_THREAD (current_thread);
2910 /*since we're killing the thread, unset the current domain.*/
2911 mono_domain_unset ();
2913 /* Wake up other threads potentially waiting for us */
2914 mono_thread_info_exit ();
2916 shutting_down = TRUE;
2918 /* Not really a background state change, but this will
2919 * interrupt the main thread if it is waiting for all
2920 * the other threads.
2922 SetEvent (background_change_event);
2924 mono_threads_unlock ();
2928 void mono_thread_manage (void)
2930 struct wait_data wait_data;
2931 struct wait_data *wait = &wait_data;
2933 memset (wait, 0, sizeof (struct wait_data));
2934 /* join each thread that's still running */
2935 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2937 mono_threads_lock ();
2939 THREAD_DEBUG (g_message("%s: No threads", __func__));
2940 mono_threads_unlock ();
2943 mono_threads_unlock ();
2946 mono_threads_lock ();
2947 if (shutting_down) {
2948 /* somebody else is shutting down */
2949 mono_threads_unlock ();
2952 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2953 mono_g_hash_table_foreach (threads, print_tids, NULL));
2955 ResetEvent (background_change_event);
2957 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2958 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2959 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2960 mono_threads_unlock ();
2962 /* Something to wait for */
2963 wait_for_tids_or_state_change (wait, INFINITE);
2965 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2966 } while(wait->num>0);
2968 /* Mono is shutting down, so just wait for the end */
2969 if (!mono_runtime_try_shutdown ()) {
2970 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2971 mono_thread_suspend (mono_thread_internal_current ());
2972 mono_thread_execute_interruption ();
2976 * Remove everything but the finalizer thread and self.
2977 * Also abort all the background threads
2980 mono_threads_lock ();
2983 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2984 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2985 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2987 mono_threads_unlock ();
2989 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2991 /* Something to wait for */
2992 wait_for_tids (wait, INFINITE);
2994 } while (wait->num > 0);
2997 * give the subthreads a chance to really quit (this is mainly needed
2998 * to get correct user and system times from getrusage/wait/time(1)).
2999 * This could be removed if we avoid pthread_detach() and use pthread_join().
3001 mono_thread_info_yield ();
3004 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3006 MonoInternalThread *thread=(MonoInternalThread *)value;
3008 if(thread->tid != (gsize)user) {
3009 /*TerminateThread (thread->handle, -1);*/
3013 void mono_thread_abort_all_other_threads (void)
3015 gsize self = GetCurrentThreadId ();
3017 mono_threads_lock ();
3018 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3019 mono_g_hash_table_size (threads));
3020 mono_g_hash_table_foreach (threads, print_tids, NULL));
3022 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3024 mono_threads_unlock ();
3028 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3030 MonoInternalThread *thread = (MonoInternalThread*)value;
3031 struct wait_data *wait = (struct wait_data*)user_data;
3035 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3037 * This needs no locking.
3039 if ((thread->state & ThreadState_Suspended) != 0 ||
3040 (thread->state & ThreadState_Stopped) != 0)
3043 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3044 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3048 wait->handles [wait->num] = handle;
3049 wait->threads [wait->num] = thread;
3055 * mono_thread_suspend_all_other_threads:
3057 * Suspend all managed threads except the finalizer thread and this thread. It is
3058 * not possible to resume them later.
3060 void mono_thread_suspend_all_other_threads (void)
3062 struct wait_data wait_data;
3063 struct wait_data *wait = &wait_data;
3065 gsize self = GetCurrentThreadId ();
3066 guint32 eventidx = 0;
3067 gboolean starting, finished;
3069 memset (wait, 0, sizeof (struct wait_data));
3071 * The other threads could be in an arbitrary state at this point, i.e.
3072 * they could be starting up, shutting down etc. This means that there could be
3073 * threads which are not even in the threads hash table yet.
3077 * First we set a barrier which will be checked by all threads before they
3078 * are added to the threads hash table, and they will exit if the flag is set.
3079 * This ensures that no threads could be added to the hash later.
3080 * We will use shutting_down as the barrier for now.
3082 g_assert (shutting_down);
3085 * We make multiple calls to WaitForMultipleObjects since:
3086 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3087 * - some threads could exit without becoming suspended
3092 * Make a copy of the hashtable since we can't do anything with
3093 * threads while threads_mutex is held.
3096 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3097 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3098 mono_threads_lock ();
3099 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3100 mono_threads_unlock ();
3103 /* Get the suspended events that we'll be waiting for */
3104 for (i = 0; i < wait->num; ++i) {
3105 MonoInternalThread *thread = wait->threads [i];
3107 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3108 //CloseHandle (wait->handles [i]);
3109 wait->threads [i] = NULL; /* ignore this thread in next loop */
3113 LOCK_THREAD (thread);
3115 if ((thread->state & ThreadState_Suspended) != 0 ||
3116 (thread->state & ThreadState_StopRequested) != 0 ||
3117 (thread->state & ThreadState_Stopped) != 0) {
3118 UNLOCK_THREAD (thread);
3119 CloseHandle (wait->handles [i]);
3120 wait->threads [i] = NULL; /* ignore this thread in next loop */
3126 /* Convert abort requests into suspend requests */
3127 if ((thread->state & ThreadState_AbortRequested) != 0)
3128 thread->state &= ~ThreadState_AbortRequested;
3130 thread->state |= ThreadState_SuspendRequested;
3132 UNLOCK_THREAD (thread);
3134 /* Signal the thread to suspend */
3135 suspend_thread_internal (thread, TRUE);
3137 if (eventidx <= 0) {
3139 * If there are threads which are starting up, we wait until they
3140 * are suspended when they try to register in the threads hash.
3141 * This is guaranteed to finish, since the threads which can create new
3142 * threads get suspended after a while.
3143 * FIXME: The finalizer thread can still create new threads.
3145 mono_threads_lock ();
3146 if (threads_starting_up)
3147 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3150 mono_threads_unlock ();
3159 static gboolean thread_dump_requested;
3161 static G_GNUC_UNUSED gboolean
3162 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3164 GString *p = (GString*)data;
3165 MonoMethod *method = NULL;
3166 if (frame->type == FRAME_TYPE_MANAGED)
3167 method = mono_jit_info_get_method (frame->ji);
3170 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3171 g_string_append_printf (p, " %s\n", location);
3174 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3179 static SuspendThreadResult
3180 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3182 MonoInternalThread *thread = ud;
3183 GString* text = g_string_new (0);
3185 GError *error = NULL;
3188 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3190 g_string_append_printf (text, "\n\"%s\"", name);
3193 else if (thread->threadpool_thread)
3194 g_string_append (text, "\n\"<threadpool thread>\"");
3196 g_string_append (text, "\n\"<unnamed thread>\"");
3199 /* This no longer works with remote unwinding */
3201 wapi_desc = wapi_current_thread_desc ();
3202 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3207 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, text);
3209 fprintf (stdout, "%s", text->str);
3211 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3212 OutputDebugStringA(text->str);
3215 g_string_free (text, TRUE);
3217 return MonoResumeThread;
3221 dump_thread (gpointer key, gpointer value, gpointer user)
3223 MonoInternalThread *thread = (MonoInternalThread *)value;
3225 if (thread == mono_thread_internal_current ())
3229 FIXME This still can hang if we stop a thread during malloc.
3230 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3231 that takes a callback and runs it with the target suspended.
3232 We probably should loop a bit around trying to get it to either managed code
3235 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, print_thread_dump, thread);
3239 mono_threads_perform_thread_dump (void)
3241 if (!thread_dump_requested)
3244 printf ("Full thread dump:\n");
3246 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3247 something needs then in the process.
3249 mono_loader_lock ();
3250 mono_domain_lock (mono_get_root_domain ());
3252 mono_threads_lock ();
3253 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3254 mono_threads_unlock ();
3256 mono_domain_unlock (mono_get_root_domain ());
3257 mono_loader_unlock ();
3259 thread_dump_requested = FALSE;
3263 * mono_threads_request_thread_dump:
3265 * Ask all threads except the current to print their stacktrace to stdout.
3268 mono_threads_request_thread_dump (void)
3270 /*The new thread dump code runs out of the finalizer thread. */
3271 thread_dump_requested = TRUE;
3272 mono_gc_finalize_notify ();
3277 gint allocated; /* +1 so that refs [allocated] == NULL */
3281 typedef struct ref_stack RefStack;
3284 ref_stack_new (gint initial_size)
3288 initial_size = MAX (initial_size, 16) + 1;
3289 rs = g_new0 (RefStack, 1);
3290 rs->refs = g_new0 (gpointer, initial_size);
3291 rs->allocated = initial_size;
3296 ref_stack_destroy (gpointer ptr)
3307 ref_stack_push (RefStack *rs, gpointer ptr)
3309 g_assert (rs != NULL);
3311 if (rs->bottom >= rs->allocated) {
3312 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3313 rs->allocated <<= 1;
3314 rs->refs [rs->allocated] = NULL;
3316 rs->refs [rs->bottom++] = ptr;
3320 ref_stack_pop (RefStack *rs)
3322 if (rs == NULL || rs->bottom == 0)
3326 rs->refs [rs->bottom] = NULL;
3330 ref_stack_find (RefStack *rs, gpointer ptr)
3337 for (refs = rs->refs; refs && *refs; refs++) {
3345 * mono_thread_push_appdomain_ref:
3347 * Register that the current thread may have references to objects in domain
3348 * @domain on its stack. Each call to this function should be paired with a
3349 * call to pop_appdomain_ref.
3352 mono_thread_push_appdomain_ref (MonoDomain *domain)
3354 MonoInternalThread *thread = mono_thread_internal_current ();
3357 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3358 SPIN_LOCK (thread->lock_thread_id);
3359 if (thread->appdomain_refs == NULL)
3360 thread->appdomain_refs = ref_stack_new (16);
3361 ref_stack_push (thread->appdomain_refs, domain);
3362 SPIN_UNLOCK (thread->lock_thread_id);
3367 mono_thread_pop_appdomain_ref (void)
3369 MonoInternalThread *thread = mono_thread_internal_current ();
3372 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3373 SPIN_LOCK (thread->lock_thread_id);
3374 ref_stack_pop (thread->appdomain_refs);
3375 SPIN_UNLOCK (thread->lock_thread_id);
3380 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3383 SPIN_LOCK (thread->lock_thread_id);
3384 res = ref_stack_find (thread->appdomain_refs, domain);
3385 SPIN_UNLOCK (thread->lock_thread_id);
3390 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3392 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3395 typedef struct abort_appdomain_data {
3396 struct wait_data wait;
3398 } abort_appdomain_data;
3401 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3403 MonoInternalThread *thread = (MonoInternalThread*)value;
3404 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3405 MonoDomain *domain = data->domain;
3407 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3408 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3410 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3411 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3414 data->wait.handles [data->wait.num] = handle;
3415 data->wait.threads [data->wait.num] = thread;
3418 /* Just ignore the rest, we can't do anything with
3426 * mono_threads_abort_appdomain_threads:
3428 * Abort threads which has references to the given appdomain.
3431 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3433 #ifdef __native_client__
3437 abort_appdomain_data user_data;
3439 int orig_timeout = timeout;
3442 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3444 start_time = mono_msec_ticks ();
3446 mono_threads_lock ();
3448 user_data.domain = domain;
3449 user_data.wait.num = 0;
3450 /* This shouldn't take any locks */
3451 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3452 mono_threads_unlock ();
3454 if (user_data.wait.num > 0) {
3455 /* Abort the threads outside the threads lock */
3456 for (i = 0; i < user_data.wait.num; ++i)
3457 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3460 * We should wait for the threads either to abort, or to leave the
3461 * domain. We can't do the latter, so we wait with a timeout.
3463 wait_for_tids (&user_data.wait, 100);
3466 /* Update remaining time */
3467 timeout -= mono_msec_ticks () - start_time;
3468 start_time = mono_msec_ticks ();
3470 if (orig_timeout != -1 && timeout < 0)
3473 while (user_data.wait.num > 0);
3475 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3481 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3483 MonoInternalThread *thread = (MonoInternalThread*)value;
3484 MonoDomain *domain = (MonoDomain*)user_data;
3487 /* No locking needed here */
3488 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3490 if (thread->cached_culture_info) {
3491 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3492 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3493 if (obj && obj->vtable->domain == domain)
3494 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3500 * mono_threads_clear_cached_culture:
3502 * Clear the cached_current_culture from all threads if it is in the
3506 mono_threads_clear_cached_culture (MonoDomain *domain)
3508 mono_threads_lock ();
3509 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3510 mono_threads_unlock ();
3514 * mono_thread_get_undeniable_exception:
3516 * Return an exception which needs to be raised when leaving a catch clause.
3517 * This is used for undeniable exception propagation.
3520 mono_thread_get_undeniable_exception (void)
3522 MonoInternalThread *thread = mono_thread_internal_current ();
3524 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3526 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3527 * exception if the thread no longer references a dying appdomain.
3529 thread->abort_exc->trace_ips = NULL;
3530 thread->abort_exc->stack_trace = NULL;
3531 return thread->abort_exc;
3537 #if MONO_SMALL_CONFIG
3538 #define NUM_STATIC_DATA_IDX 4
3539 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3543 #define NUM_STATIC_DATA_IDX 8
3544 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3545 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3549 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3550 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3553 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3555 gpointer *static_data = addr;
3557 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3558 void **ptr = static_data [i];
3563 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3564 void **p = ptr + idx;
3567 mark_func ((MonoObject**)p, gc_data);
3573 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3575 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3579 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3581 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3585 * mono_alloc_static_data
3587 * Allocate memory blocks for storing threads or context static data
3590 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3592 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3595 gpointer* static_data = *static_data_ptr;
3597 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3598 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3600 if (mono_gc_user_markers_supported ()) {
3601 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3602 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3604 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3605 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3608 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3609 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3610 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3611 *static_data_ptr = static_data;
3612 static_data [0] = static_data;
3615 for (i = 1; i <= idx; ++i) {
3616 if (static_data [i])
3619 if (mono_gc_user_markers_supported ())
3620 static_data [i] = g_malloc0 (static_data_size [i]);
3622 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3623 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3624 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3629 mono_free_static_data (gpointer* static_data)
3632 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3633 gpointer p = static_data [i];
3637 * At this point, the static data pointer array is still registered with the
3638 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3639 * data. Freeing the individual arrays without first nulling their slots
3640 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3641 * such an already freed array. See bug #13813.
3643 static_data [i] = NULL;
3644 mono_memory_write_barrier ();
3645 if (mono_gc_user_markers_supported ())
3648 mono_gc_free_fixed (p);
3650 mono_gc_free_fixed (static_data);
3654 * mono_init_static_data_info
3656 * Initializes static data counters
3658 static void mono_init_static_data_info (StaticDataInfo *static_data)
3660 static_data->idx = 0;
3661 static_data->offset = 0;
3662 static_data->freelist = NULL;
3666 * mono_alloc_static_data_slot
3668 * Generates an offset for static data. static_data contains the counters
3669 * used to generate it.
3672 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3674 if (!static_data->idx && !static_data->offset) {
3676 * we use the first chunk of the first allocation also as
3677 * an array for the rest of the data
3679 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3681 static_data->offset += align - 1;
3682 static_data->offset &= ~(align - 1);
3683 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3684 static_data->idx ++;
3685 g_assert (size <= static_data_size [static_data->idx]);
3686 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3687 static_data->offset = 0;
3689 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3690 static_data->offset += size;
3695 * ensure thread static fields already allocated are valid for thread
3696 * This function is called when a thread is created or on thread attach.
3699 thread_adjust_static_data (MonoInternalThread *thread)
3701 mono_threads_lock ();
3702 if (thread_static_info.offset || thread_static_info.idx > 0) {
3703 /* get the current allocated size */
3704 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3705 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3707 mono_threads_unlock ();
3711 * LOCKING: requires that threads_mutex is held
3714 context_adjust_static_data (MonoAppContext *ctx)
3716 if (context_static_info.offset || context_static_info.idx > 0) {
3717 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3718 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3723 * LOCKING: requires that threads_mutex is held
3726 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3728 MonoInternalThread *thread = value;
3729 guint32 offset = GPOINTER_TO_UINT (user);
3731 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3735 * LOCKING: requires that threads_mutex is held
3738 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3740 uint32_t gch = GPOINTER_TO_INT (key);
3741 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3744 mono_gchandle_free (gch);
3745 return TRUE; // Remove this key/value pair
3748 guint32 offset = GPOINTER_TO_UINT (user);
3749 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3751 return FALSE; // Don't remove it
3754 static StaticDataFreeList*
3755 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3757 StaticDataFreeList* prev = NULL;
3758 StaticDataFreeList* tmp = static_data->freelist;
3760 if (tmp->size == size) {
3762 prev->next = tmp->next;
3764 static_data->freelist = tmp->next;
3773 #if SIZEOF_VOID_P == 4
3780 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3782 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3784 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3785 MonoBitSet *rb = sets [idx];
3786 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3787 offset /= sizeof (uintptr_t);
3788 /* offset is now the bitmap offset */
3789 for (int i = 0; i < numbits; ++i) {
3790 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3791 mono_bitset_set_fast (rb, offset + i);
3796 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3798 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3799 MonoBitSet *rb = sets [idx];
3800 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3801 offset /= sizeof (uintptr_t);
3802 /* offset is now the bitmap offset */
3803 for (int i = 0; i < size / sizeof (uintptr_t); i++)
3804 mono_bitset_clear_fast (rb, offset + i);
3808 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3810 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3812 StaticDataInfo *info;
3815 if (static_type == SPECIAL_STATIC_THREAD) {
3816 info = &thread_static_info;
3817 sets = thread_reference_bitmaps;
3819 info = &context_static_info;
3820 sets = context_reference_bitmaps;
3823 mono_threads_lock ();
3825 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3829 offset = item->offset;
3832 offset = mono_alloc_static_data_slot (info, size, align);
3835 update_reference_bitmap (sets, offset, bitmap, numbits);
3837 if (static_type == SPECIAL_STATIC_THREAD) {
3838 /* This can be called during startup */
3839 if (threads != NULL)
3840 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3842 if (contexts != NULL)
3843 g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3845 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3848 mono_threads_unlock ();
3854 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3856 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3858 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3859 return get_thread_static_data (thread, offset);
3861 return get_context_static_data (thread->current_appcontext, offset);
3866 mono_get_special_static_data (guint32 offset)
3868 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3877 * LOCKING: requires that threads_mutex is held
3880 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3882 MonoInternalThread *thread = value;
3883 OffsetSize *data = user;
3884 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3885 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3888 if (!thread->static_data || !thread->static_data [idx])
3890 ptr = ((char*) thread->static_data [idx]) + off;
3891 mono_gc_bzero_atomic (ptr, data->size);
3895 * LOCKING: requires that threads_mutex is held
3898 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3900 uint32_t gch = GPOINTER_TO_INT (key);
3901 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3904 mono_gchandle_free (gch);
3905 return TRUE; // Remove this key/value pair
3908 OffsetSize *data = user;
3909 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3910 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3913 if (!ctx->static_data || !ctx->static_data [idx])
3914 return FALSE; // Don't remove this key/value pair
3916 ptr = ((char*) ctx->static_data [idx]) + off;
3917 mono_gc_bzero_atomic (ptr, data->size);
3919 return FALSE; // Don't remove this key/value pair
3923 do_free_special_slot (guint32 offset, guint32 size)
3925 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3927 StaticDataInfo *info;
3929 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3930 info = &thread_static_info;
3931 sets = thread_reference_bitmaps;
3933 info = &context_static_info;
3934 sets = context_reference_bitmaps;
3937 guint32 data_offset = offset;
3938 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
3939 OffsetSize data = { data_offset, size };
3941 clear_reference_bitmap (sets, data.offset, data.size);
3943 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3944 if (threads != NULL)
3945 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3947 if (contexts != NULL)
3948 g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
3951 if (!mono_runtime_is_shutting_down ()) {
3952 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
3954 item->offset = offset;
3957 item->next = info->freelist;
3958 info->freelist = item;
3963 do_free_special (gpointer key, gpointer value, gpointer data)
3965 MonoClassField *field = key;
3966 guint32 offset = GPOINTER_TO_UINT (value);
3969 size = mono_type_size (field->type, &align);
3970 do_free_special_slot (offset, size);
3974 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3976 mono_threads_lock ();
3978 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3980 mono_threads_unlock ();
3984 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3986 /* Only ever called for ThreadLocal instances */
3987 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
3989 mono_threads_lock ();
3990 do_free_special_slot (offset, size);
3991 mono_threads_unlock ();
3995 static void CALLBACK dummy_apc (ULONG_PTR param)
4001 * mono_thread_execute_interruption
4003 * Performs the operation that the requested thread state requires (abort,
4006 static MonoException*
4007 mono_thread_execute_interruption (void)
4009 MonoInternalThread *thread = mono_thread_internal_current ();
4011 LOCK_THREAD (thread);
4013 /* MonoThread::interruption_requested can only be changed with atomics */
4014 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4015 /* this will consume pending APC calls */
4017 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4019 InterlockedDecrement (&thread_interruption_requested);
4021 /* Clear the interrupted flag of the thread so it can wait again */
4022 mono_thread_info_clear_self_interrupt ();
4025 if ((thread->state & ThreadState_AbortRequested) != 0) {
4026 UNLOCK_THREAD (thread);
4027 if (thread->abort_exc == NULL) {
4029 * This might be racy, but it has to be called outside the lock
4030 * since it calls managed code.
4032 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4034 return thread->abort_exc;
4036 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4037 self_suspend_internal (thread);
4040 else if ((thread->state & ThreadState_StopRequested) != 0) {
4041 /* FIXME: do this through the JIT? */
4043 UNLOCK_THREAD (thread);
4045 mono_thread_exit ();
4047 } else if (thread->pending_exception) {
4050 exc = thread->pending_exception;
4051 thread->pending_exception = NULL;
4053 UNLOCK_THREAD (thread);
4055 } else if (thread->thread_interrupt_requested) {
4057 thread->thread_interrupt_requested = FALSE;
4058 UNLOCK_THREAD (thread);
4060 return(mono_get_exception_thread_interrupted ());
4063 UNLOCK_THREAD (thread);
4069 * mono_thread_request_interruption
4071 * A signal handler can call this method to request the interruption of a
4072 * thread. The result of the interruption will depend on the current state of
4073 * the thread. If the result is an exception that needs to be throw, it is
4074 * provided as return value.
4077 mono_thread_request_interruption (gboolean running_managed)
4079 MonoInternalThread *thread = mono_thread_internal_current ();
4081 /* The thread may already be stopping */
4086 if (thread->interrupt_on_stop &&
4087 thread->state & ThreadState_StopRequested &&
4088 thread->state & ThreadState_Background)
4092 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4094 InterlockedIncrement (&thread_interruption_requested);
4096 if (!running_managed || is_running_protected_wrapper ()) {
4097 /* Can't stop while in unmanaged code. Increase the global interruption
4098 request count. When exiting the unmanaged method the count will be
4099 checked and the thread will be interrupted. */
4101 if (mono_thread_notify_pending_exc_fn && !running_managed)
4102 /* The JIT will notify the thread about the interruption */
4103 /* This shouldn't take any locks */
4104 mono_thread_notify_pending_exc_fn (NULL);
4106 /* this will awake the thread if it is in WaitForSingleObject
4108 /* Our implementation of this function ignores the func argument */
4110 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4112 mono_thread_info_self_interrupt ();
4117 return mono_thread_execute_interruption ();
4121 /*This function should be called by a thread after it has exited all of
4122 * its handle blocks at interruption time.*/
4124 mono_thread_resume_interruption (void)
4126 MonoInternalThread *thread = mono_thread_internal_current ();
4127 gboolean still_aborting;
4129 /* The thread may already be stopping */
4133 LOCK_THREAD (thread);
4134 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4135 UNLOCK_THREAD (thread);
4137 /*This can happen if the protected block called Thread::ResetAbort*/
4138 if (!still_aborting)
4141 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4143 InterlockedIncrement (&thread_interruption_requested);
4145 mono_thread_info_self_interrupt ();
4147 return mono_thread_execute_interruption ();
4150 gboolean mono_thread_interruption_requested ()
4152 if (thread_interruption_requested) {
4153 MonoInternalThread *thread = mono_thread_internal_current ();
4154 /* The thread may already be stopping */
4156 return (thread->interruption_requested);
4161 static MonoException*
4162 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4164 MonoInternalThread *thread = mono_thread_internal_current ();
4166 /* The thread may already be stopping */
4170 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4171 MonoException* exc = mono_thread_execute_interruption ();
4179 * Performs the interruption of the current thread, if one has been requested,
4180 * and the thread is not running a protected wrapper.
4181 * Return the exception which needs to be thrown, if any.
4184 mono_thread_interruption_checkpoint (void)
4186 return mono_thread_interruption_checkpoint_request (FALSE);
4190 * Performs the interruption of the current thread, if one has been requested.
4191 * Return the exception which needs to be thrown, if any.
4194 mono_thread_force_interruption_checkpoint_noraise (void)
4196 return mono_thread_interruption_checkpoint_request (TRUE);
4200 * Performs the interruption of the current thread, if one has been requested.
4201 * Throw the exception which needs to be thrown, if any.
4204 mono_thread_force_interruption_checkpoint (void)
4208 ex = mono_thread_interruption_checkpoint_request (TRUE);
4210 mono_raise_exception (ex);
4214 * mono_thread_get_and_clear_pending_exception:
4216 * Return any pending exceptions for the current thread and clear it as a side effect.
4219 mono_thread_get_and_clear_pending_exception (void)
4221 MonoInternalThread *thread = mono_thread_internal_current ();
4223 /* The thread may already be stopping */
4227 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4228 return mono_thread_execute_interruption ();
4231 if (thread->pending_exception) {
4232 MonoException *exc = thread->pending_exception;
4234 thread->pending_exception = NULL;
4242 * mono_set_pending_exception:
4244 * Set the pending exception of the current thread to EXC.
4245 * The exception will be thrown when execution returns to managed code.
4248 mono_set_pending_exception (MonoException *exc)
4250 MonoInternalThread *thread = mono_thread_internal_current ();
4252 /* The thread may already be stopping */
4256 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4258 mono_thread_request_interruption (FALSE);
4262 * mono_thread_interruption_request_flag:
4264 * Returns the address of a flag that will be non-zero if an interruption has
4265 * been requested for a thread. The thread to interrupt may not be the current
4266 * thread, so an additional call to mono_thread_interruption_requested() or
4267 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4270 gint32* mono_thread_interruption_request_flag ()
4272 return &thread_interruption_requested;
4276 mono_thread_init_apartment_state (void)
4279 MonoInternalThread* thread = mono_thread_internal_current ();
4281 /* Positive return value indicates success, either
4282 * S_OK if this is first CoInitialize call, or
4283 * S_FALSE if CoInitialize already called, but with same
4284 * threading model. A negative value indicates failure,
4285 * probably due to trying to change the threading model.
4287 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4288 ? COINIT_APARTMENTTHREADED
4289 : COINIT_MULTITHREADED) < 0) {
4290 thread->apartment_state = ThreadApartmentState_Unknown;
4296 mono_thread_cleanup_apartment_state (void)
4299 MonoInternalThread* thread = mono_thread_internal_current ();
4301 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4308 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4310 LOCK_THREAD (thread);
4311 thread->state |= state;
4312 UNLOCK_THREAD (thread);
4316 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4318 LOCK_THREAD (thread);
4319 thread->state &= ~state;
4320 UNLOCK_THREAD (thread);
4324 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4326 gboolean ret = FALSE;
4328 LOCK_THREAD (thread);
4330 if ((thread->state & test) != 0) {
4334 UNLOCK_THREAD (thread);
4339 static gboolean has_tls_get = FALSE;
4342 mono_runtime_set_has_tls_get (gboolean val)
4348 mono_runtime_has_tls_get (void)
4354 self_interrupt_thread (void *_unused)
4356 MonoThreadInfo *info = mono_thread_info_current ();
4357 MonoException *exc = mono_thread_execute_interruption ();
4358 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4359 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. */
4360 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4364 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4368 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4372 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4374 MonoJitInfo **dest = data;
4380 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4382 MonoJitInfo *ji = NULL;
4385 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4390 MonoInternalThread *thread;
4391 gboolean install_async_abort;
4392 MonoThreadInfoInterruptToken *interrupt_token;
4395 static SuspendThreadResult
4396 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4398 AbortThreadData *data = ud;
4399 MonoInternalThread *thread = data->thread;
4400 MonoJitInfo *ji = NULL;
4401 gboolean protected_wrapper;
4402 gboolean running_managed;
4404 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4405 return MonoResumeThread;
4407 /*someone is already interrupting it*/
4408 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4409 return MonoResumeThread;
4411 InterlockedIncrement (&thread_interruption_requested);
4413 ji = mono_thread_info_get_last_managed (info);
4414 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4415 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4417 if (!protected_wrapper && running_managed) {
4418 /*We are in managed code*/
4419 /*Set the thread to call */
4420 if (data->install_async_abort)
4421 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4422 return MonoResumeThread;
4424 if (mono_thread_notify_pending_exc_fn)
4425 /* The JIT will notify the thread about the interruption */
4426 mono_thread_notify_pending_exc_fn (info);
4429 * This will cause waits to be broken.
4430 * It will also prevent the thread from entering a wait, so if the thread returns
4431 * from the wait before it receives the abort signal, it will just spin in the wait
4432 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4435 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4437 return MonoResumeThread;
4442 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4444 AbortThreadData data = { 0 };
4445 data.thread = thread;
4446 data.install_async_abort = install_async_abort;
4449 FIXME this is insanely broken, it doesn't cause interruption to happen
4450 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4452 if (thread == mono_thread_internal_current ()) {
4453 /* Do it synchronously */
4454 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4456 mono_raise_exception (exc);
4458 mono_thread_info_self_interrupt ();
4463 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_critical, &data);
4464 if (data.interrupt_token)
4465 mono_thread_info_finish_interrupt (data.interrupt_token);
4466 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4470 MonoInternalThread *thread;
4472 MonoThreadInfoInterruptToken *interrupt_token;
4473 } SuspendThreadData;
4475 static SuspendThreadResult
4476 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4478 SuspendThreadData *data = ud;
4479 MonoInternalThread *thread = data->thread;
4480 MonoJitInfo *ji = NULL;
4481 gboolean protected_wrapper;
4482 gboolean running_managed;
4484 ji = mono_thread_info_get_last_managed (info);
4485 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4486 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4488 if (running_managed && !protected_wrapper) {
4489 thread->state &= ~ThreadState_SuspendRequested;
4490 thread->state |= ThreadState_Suspended;
4491 return KeepSuspended;
4493 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4494 InterlockedIncrement (&thread_interruption_requested);
4495 if (data->interrupt)
4496 data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
4498 if (mono_thread_notify_pending_exc_fn && !running_managed)
4499 /* The JIT will notify the thread about the interruption */
4500 mono_thread_notify_pending_exc_fn (info);
4501 return MonoResumeThread;
4506 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4508 LOCK_THREAD (thread);
4509 if (thread == mono_thread_internal_current ()) {
4510 mono_thread_info_begin_self_suspend ();
4511 //XXX replace this with better named functions
4512 thread->state &= ~ThreadState_SuspendRequested;
4513 thread->state |= ThreadState_Suspended;
4514 UNLOCK_THREAD (thread);
4515 mono_thread_info_end_self_suspend ();
4517 SuspendThreadData data = { 0 };
4518 data.thread = thread;
4519 data.interrupt = interrupt;
4521 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, suspend_thread_critical, &data);
4522 if (data.interrupt_token)
4523 mono_thread_info_finish_interrupt (data.interrupt_token);
4524 UNLOCK_THREAD (thread);
4528 /*This is called with @thread synch_cs held and it must release it*/
4530 self_suspend_internal (MonoInternalThread *thread)
4532 mono_thread_info_begin_self_suspend ();
4533 thread->state &= ~ThreadState_SuspendRequested;
4534 thread->state |= ThreadState_Suspended;
4535 UNLOCK_THREAD (thread);
4536 mono_thread_info_end_self_suspend ();
4539 /*This is called with @thread synch_cs held and it must release it*/
4541 resume_thread_internal (MonoInternalThread *thread)
4543 UNLOCK_THREAD (thread);
4544 /* Awake the thread */
4545 if (!mono_thread_info_resume (thread_get_tid (thread)))
4547 LOCK_THREAD (thread);
4548 thread->state &= ~ThreadState_Suspended;
4549 UNLOCK_THREAD (thread);
4555 * mono_thread_is_foreign:
4556 * @thread: the thread to query
4558 * This function allows one to determine if a thread was created by the mono runtime and has
4559 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4561 * Returns: true if @thread was not created by the runtime.
4564 mono_thread_is_foreign (MonoThread *thread)
4566 MonoThreadInfo *info = thread->internal_thread->thread_info;
4567 return info->runtime_thread == FALSE;
4571 * mono_add_joinable_thread:
4573 * Add TID to the list of joinable threads.
4574 * LOCKING: Acquires the threads lock.
4577 mono_threads_add_joinable_thread (gpointer tid)
4581 * We cannot detach from threads because it causes problems like
4582 * 2fd16f60/r114307. So we collect them and join them when
4583 * we have time (in he finalizer thread).
4585 joinable_threads_lock ();
4586 if (!joinable_threads)
4587 joinable_threads = g_hash_table_new (NULL, NULL);
4588 g_hash_table_insert (joinable_threads, tid, tid);
4589 joinable_thread_count ++;
4590 joinable_threads_unlock ();
4592 mono_gc_finalize_notify ();
4597 * mono_threads_join_threads:
4599 * Join all joinable threads. This is called from the finalizer thread.
4600 * LOCKING: Acquires the threads lock.
4603 mono_threads_join_threads (void)
4606 GHashTableIter iter;
4613 if (!joinable_thread_count)
4617 joinable_threads_lock ();
4619 if (g_hash_table_size (joinable_threads)) {
4620 g_hash_table_iter_init (&iter, joinable_threads);
4621 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4622 thread = (pthread_t)tid;
4623 g_hash_table_remove (joinable_threads, key);
4624 joinable_thread_count --;
4627 joinable_threads_unlock ();
4629 if (thread != pthread_self ())
4630 /* This shouldn't block */
4631 pthread_join (thread, NULL);
4642 * Wait for thread TID to exit.
4643 * LOCKING: Acquires the threads lock.
4646 mono_thread_join (gpointer tid)
4650 gboolean found = FALSE;
4652 joinable_threads_lock ();
4653 if (!joinable_threads)
4654 joinable_threads = g_hash_table_new (NULL, NULL);
4655 if (g_hash_table_lookup (joinable_threads, tid)) {
4656 g_hash_table_remove (joinable_threads, tid);
4657 joinable_thread_count --;
4660 joinable_threads_unlock ();
4663 thread = (pthread_t)tid;
4664 pthread_join (thread, NULL);
4669 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4671 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4672 mono_thread_interruption_checkpoint ();
4675 static inline gboolean
4676 is_appdomainunloaded_exception (MonoClass *klass)
4678 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4680 if (!app_domain_unloaded_exception_klass)
4681 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4682 g_assert (app_domain_unloaded_exception_klass);
4684 return klass == app_domain_unloaded_exception_klass;
4687 static inline gboolean
4688 is_threadabort_exception (MonoClass *klass)
4690 return klass == mono_defaults.threadabortexception_class;
4694 mono_thread_internal_unhandled_exception (MonoObject* exc)
4696 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4697 MonoClass *klass = exc->vtable->klass;
4698 if (is_threadabort_exception (klass)) {
4699 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4700 } else if (!is_appdomainunloaded_exception (klass)) {
4701 mono_unhandled_exception (exc);
4702 if (mono_environment_exitcode_get () == 1)