2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threads-types.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/environment.h>
26 #include <mono/metadata/monitor.h>
27 #include <mono/metadata/gc-internals.h>
28 #include <mono/metadata/marshal.h>
29 #include <mono/metadata/runtime.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/mono-debug-debugger.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internals.h>
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
51 #define USE_TKILL_ON_ANDROID 1
54 #ifdef PLATFORM_ANDROID
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid, int signal);
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func)(void *);
107 typedef struct _StaticDataFreeList StaticDataFreeList;
108 struct _StaticDataFreeList {
109 StaticDataFreeList *next;
117 StaticDataFreeList *freelist;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 static void mono_threads_lock (void);
130 static void mono_threads_unlock (void);
131 static MonoCoopMutex threads_mutex;
133 /* Controls access to the 'joinable_threads' hash table */
134 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
135 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
136 static mono_mutex_t joinable_threads_mutex;
138 /* Holds current status of static data heap */
139 static StaticDataInfo thread_static_info;
140 static StaticDataInfo context_static_info;
142 /* The hash of existing threads (key is thread ID, value is
143 * MonoInternalThread*) that need joining before exit
145 static MonoGHashTable *threads=NULL;
147 /* List of app context GC handles.
148 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
150 static GHashTable *contexts = NULL;
152 /* Cleanup queue for contexts. */
153 static MonoReferenceQueue *context_queue;
156 * Threads which are starting up and they are not in the 'threads' hash yet.
157 * When handle_store is called for a thread, it will be removed from this hash table.
158 * Protected by mono_threads_lock ().
160 static MonoGHashTable *threads_starting_up = NULL;
162 /* The TLS key that holds the MonoObject assigned to each thread */
163 static MonoNativeTlsKey current_object_key;
166 /* Protected by the threads lock */
167 static GHashTable *joinable_threads;
168 static int joinable_thread_count;
170 #ifdef MONO_HAVE_FAST_TLS
171 /* we need to use both the Tls* functions and __thread because
172 * the gc needs to see all the threads
174 MONO_FAST_TLS_DECLARE(tls_current_object);
175 #define SET_CURRENT_OBJECT(x) do { \
176 MONO_FAST_TLS_SET (tls_current_object, x); \
177 mono_native_tls_set_value (current_object_key, x); \
179 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
181 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
182 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
185 /* function called at thread start */
186 static MonoThreadStartCB mono_thread_start_cb = NULL;
188 /* function called at thread attach */
189 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
191 /* function called at thread cleanup */
192 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
194 /* function called to notify the runtime about a pending exception on the current thread */
195 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
197 /* The default stack size for each thread */
198 static guint32 default_stacksize = 0;
199 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
201 static void thread_adjust_static_data (MonoInternalThread *thread);
202 static void context_adjust_static_data (MonoAppContext *ctx);
203 static void mono_free_static_data (gpointer* static_data);
204 static void mono_init_static_data_info (StaticDataInfo *static_data);
205 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
206 static gboolean mono_thread_resume (MonoInternalThread* thread);
207 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
208 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
209 static void self_suspend_internal (MonoInternalThread *thread);
211 static MonoException* mono_thread_execute_interruption (void);
212 static void ref_stack_destroy (gpointer rs);
214 /* Spin lock for InterlockedXXX 64 bit functions */
215 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
216 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
217 static mono_mutex_t interlocked_mutex;
219 /* global count of thread interruptions requested */
220 static gint32 thread_interruption_requested = 0;
222 /* Event signaled when a thread changes its background mode */
223 static HANDLE background_change_event;
225 static gboolean shutting_down = FALSE;
227 static gint32 managed_thread_id_counter = 0;
230 mono_threads_lock (void)
232 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
236 mono_threads_unlock (void)
238 mono_locks_coop_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 MonoCoopMutex *synch_cs;
354 if (thread->synch_cs != NULL) {
358 synch_cs = g_new0 (MonoCoopMutex, 1);
359 mono_coop_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_coop_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);
377 mono_coop_mutex_lock (thread->synch_cs);
381 unlock_thread (MonoInternalThread *thread)
383 mono_coop_mutex_unlock (thread->synch_cs);
387 * NOTE: this function can be called also for threads different from the current one:
388 * make sure no code called from it will ever assume it is run on the thread that is
389 * getting cleaned up.
391 static void thread_cleanup (MonoInternalThread *thread)
393 g_assert (thread != NULL);
395 if (thread->abort_state_handle) {
396 mono_gchandle_free (thread->abort_state_handle);
397 thread->abort_state_handle = 0;
399 thread->abort_exc = NULL;
400 thread->current_appcontext = NULL;
403 * This is necessary because otherwise we might have
404 * cross-domain references which will not get cleaned up when
405 * the target domain is unloaded.
407 if (thread->cached_culture_info) {
409 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
410 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
414 * thread->synch_cs can be NULL if this was called after
415 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
416 * This can happen only during shutdown.
417 * The shutting_down flag is not always set, so we can't assert on it.
419 if (thread->synch_cs)
420 LOCK_THREAD (thread);
422 thread->state |= ThreadState_Stopped;
423 thread->state &= ~ThreadState_Background;
425 if (thread->synch_cs)
426 UNLOCK_THREAD (thread);
429 An interruption request has leaked to cleanup. Adjust the global counter.
431 This can happen is the abort source thread finds the abortee (this) thread
432 in unmanaged code. If this thread never trips back to managed code or check
433 the local flag it will be left set and positively unbalance the global counter.
435 Leaving the counter unbalanced will cause a performance degradation since all threads
436 will now keep checking their local flags all the time.
438 if (InterlockedExchange (&thread->interruption_requested, 0))
439 InterlockedDecrement (&thread_interruption_requested);
441 /* if the thread is not in the hash it has been removed already */
442 if (!handle_remove (thread)) {
443 if (thread == mono_thread_internal_current ()) {
444 mono_domain_unset ();
445 mono_memory_barrier ();
447 /* This needs to be called even if handle_remove () fails */
448 if (mono_thread_cleanup_fn)
449 mono_thread_cleanup_fn (thread_get_tid (thread));
452 mono_release_type_locks (thread);
454 mono_profiler_thread_end (thread->tid);
456 if (thread == mono_thread_internal_current ()) {
458 * This will signal async signal handlers that the thread has exited.
459 * The profiler callback needs this to be set, so it cannot be done earlier.
461 mono_domain_unset ();
462 mono_memory_barrier ();
465 if (thread == mono_thread_internal_current ())
466 mono_thread_pop_appdomain_ref ();
468 thread->cached_culture_info = NULL;
470 mono_free_static_data (thread->static_data);
471 thread->static_data = NULL;
472 ref_stack_destroy (thread->appdomain_refs);
473 thread->appdomain_refs = NULL;
475 if (mono_thread_cleanup_fn)
476 mono_thread_cleanup_fn (thread_get_tid (thread));
478 if (mono_gc_is_moving ()) {
479 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
480 thread->thread_pinning_ref = NULL;
486 * A special static data offset (guint32) consists of 3 parts:
488 * [0] 6-bit index into the array of chunks.
489 * [6] 25-bit offset into the array.
490 * [31] Bit indicating thread or context static.
495 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
506 } SpecialStaticOffset;
508 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
509 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
511 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
512 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
513 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
514 (((SpecialStaticOffset *) &(x))->fields.f)
517 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
519 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
521 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
522 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
524 return ((char *) thread->static_data [idx]) + off;
528 get_context_static_data (MonoAppContext *ctx, guint32 offset)
530 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
532 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
533 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
535 return ((char *) ctx->static_data [idx]) + off;
539 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
541 static MonoClassField *current_thread_field = NULL;
545 if (!current_thread_field) {
546 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
547 g_assert (current_thread_field);
550 mono_class_vtable (domain, mono_defaults.thread_class);
551 mono_domain_lock (domain);
552 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
553 mono_domain_unlock (domain);
556 return (MonoThread **)get_thread_static_data (thread, offset);
560 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
562 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
564 g_assert (current->obj.vtable->domain == domain);
566 g_assert (!*current_thread_ptr);
567 *current_thread_ptr = current;
571 create_thread_object (MonoDomain *domain, MonoError *error)
573 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
574 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, error);
579 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal, MonoError *error)
583 thread = create_thread_object (domain, error);
584 if (!mono_error_ok (error))
587 MONO_OBJECT_SETREF (thread, internal_thread, internal);
592 static MonoInternalThread*
593 create_internal_thread (MonoError *error)
595 MonoInternalThread *thread;
598 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
599 thread = (MonoInternalThread*) mono_object_new_mature (vt, error);
600 if (!mono_error_ok (error))
603 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
604 mono_coop_mutex_init_recursive (thread->synch_cs);
606 thread->apartment_state = ThreadApartmentState_Unknown;
607 thread->managed_id = get_next_managed_thread_id ();
608 if (mono_gc_is_moving ()) {
609 thread->thread_pinning_ref = thread;
610 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
617 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
620 MonoDomain *domain = mono_get_root_domain ();
622 if (!candidate || candidate->obj.vtable->domain != domain) {
623 candidate = new_thread_with_internal (domain, thread, &error);
624 mono_error_raise_exception (&error); /* FIXME don't raise here */
626 set_current_thread_for_domain (domain, thread, candidate);
627 g_assert (!thread->root_domain_thread);
628 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
631 static guint32 WINAPI start_wrapper_internal(void *data)
633 MonoThreadInfo *info;
634 StartInfo *start_info = (StartInfo *)data;
635 guint32 (*start_func)(void *);
639 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
642 MonoInternalThread *internal = start_info->obj->internal_thread;
643 MonoObject *start_delegate = start_info->delegate;
644 MonoDomain *domain = start_info->obj->obj.vtable->domain;
646 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
648 /* We can be sure start_info->obj->tid and
649 * start_info->obj->handle have been set, because the thread
650 * was created suspended, and these values were set before the
654 info = mono_thread_info_current ();
656 internal->thread_info = info;
657 internal->small_id = info->small_id;
661 SET_CURRENT_OBJECT (internal);
663 /* Every thread references the appdomain which created it */
664 mono_thread_push_appdomain_ref (domain);
666 if (!mono_domain_set (domain, FALSE)) {
667 /* No point in raising an appdomain_unloaded exception here */
668 /* FIXME: Cleanup here */
669 mono_thread_pop_appdomain_ref ();
673 start_func = start_info->func;
674 start_arg = start_info->obj->start_obj;
676 start_arg = start_info->start_arg;
678 /* We have to do this here because mono_thread_new_init()
679 requires that root_domain_thread is set up. */
680 thread_adjust_static_data (internal);
681 init_root_domain_thread (internal, start_info->obj);
683 /* This MUST be called before any managed code can be
684 * executed, as it calls the callback function that (for the
685 * jit) sets the lmf marker.
687 mono_thread_new_init (tid, &tid, start_func);
688 internal->stack_ptr = &tid;
689 if (domain != mono_get_root_domain ())
690 set_current_thread_for_domain (domain, internal, start_info->obj);
692 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
694 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
696 /* On 2.0 profile (and higher), set explicitly since state might have been
698 if (internal->apartment_state == ThreadApartmentState_Unknown)
699 internal->apartment_state = ThreadApartmentState_MTA;
701 mono_thread_init_apartment_state ();
703 if(internal->start_notify!=NULL) {
704 /* Let the thread that called Start() know we're
707 ReleaseSemaphore (internal->start_notify, 1, NULL);
711 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
715 * Call this after calling start_notify, since the profiler callback might want
716 * to lock the thread, and the lock is held by thread_start () which waits for
719 mono_profiler_thread_start (tid);
721 /* if the name was set before starting, we didn't invoke the profiler callback */
722 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
723 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
724 mono_profiler_thread_name (internal->tid, tname);
727 /* start_func is set only for unmanaged start functions */
729 start_func (start_arg);
732 g_assert (start_delegate != NULL);
733 args [0] = start_arg;
734 /* we may want to handle the exception here. See comment below on unhandled exceptions */
735 mono_runtime_delegate_invoke (start_delegate, args, NULL);
738 /* If the thread calls ExitThread at all, this remaining code
739 * will not be executed, but the main thread will eventually
740 * call thread_cleanup() on this thread's behalf.
743 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
745 /* Do any cleanup needed for apartment state. This
746 * cannot be done in thread_cleanup since thread_cleanup could be
747 * called for a thread other than the current thread.
748 * mono_thread_cleanup_apartment_state cleans up apartment
749 * for the current thead */
750 mono_thread_cleanup_apartment_state ();
752 thread_cleanup (internal);
756 /* Remove the reference to the thread object in the TLS data,
757 * so the thread object can be finalized. This won't be
758 * reached if the thread threw an uncaught exception, so those
759 * thread handles will stay referenced :-( (This is due to
760 * missing support for scanning thread-specific data in the
761 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
764 SET_CURRENT_OBJECT (NULL);
769 static guint32 WINAPI start_wrapper(void *data)
773 /* Avoid scanning the frames above this frame during a GC */
774 mono_gc_set_stack_end ((void*)&dummy);
776 return start_wrapper_internal (data);
782 * Common thread creation code.
783 * LOCKING: Acquires the threads lock.
786 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
787 gboolean throw_on_failure)
789 HANDLE thread_handle;
790 MonoNativeThreadId tid;
791 guint32 create_flags;
794 * Join joinable threads to prevent running out of threads since the finalizer
795 * thread might be blocked/backlogged.
797 mono_threads_join_threads ();
799 mono_threads_lock ();
802 mono_threads_unlock ();
805 if (threads_starting_up == NULL) {
806 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
807 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
809 mono_g_hash_table_insert (threads_starting_up, thread, thread);
810 mono_threads_unlock ();
812 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
813 if (!internal->start_notify) {
814 mono_threads_lock ();
815 mono_g_hash_table_remove (threads_starting_up, thread);
816 mono_threads_unlock ();
817 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
823 stack_size = default_stacksize_for_thread (internal);
825 /* Create suspended, so we can do some housekeeping before the thread
828 create_flags = CREATE_SUSPENDED;
830 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
831 stack_size, create_flags, &tid);
833 if (thread_handle == NULL) {
834 /* The thread couldn't be created, so throw an exception */
835 mono_threads_lock ();
836 mono_g_hash_table_remove (threads_starting_up, thread);
837 mono_threads_unlock ();
839 if (throw_on_failure)
840 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
842 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
845 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
847 internal->handle = thread_handle;
848 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
850 internal->threadpool_thread = threadpool_thread;
851 if (threadpool_thread)
852 mono_thread_set_state (internal, ThreadState_Background);
854 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
856 /* Only store the handle when the thread is about to be
857 * launched, to avoid the main thread deadlocking while trying
858 * to clean up a thread that will never be signalled.
860 if (!handle_store (thread, FALSE))
863 mono_thread_info_resume (tid);
865 if (internal->start_notify) {
867 * Wait for the thread to set up its TLS data etc, so
868 * theres no potential race condition if someone tries
869 * to look up the data believing the thread has
872 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
874 MONO_PREPARE_BLOCKING;
875 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
876 MONO_FINISH_BLOCKING;
878 CloseHandle (internal->start_notify);
879 internal->start_notify = NULL;
882 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
887 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
889 if (mono_thread_start_cb) {
890 mono_thread_start_cb (tid, stack_start, func);
894 void mono_threads_set_default_stacksize (guint32 stacksize)
896 default_stacksize = stacksize;
899 guint32 mono_threads_get_default_stacksize (void)
901 return default_stacksize;
905 * mono_thread_create_internal:
907 * ARG should not be a GC reference.
910 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
914 MonoInternalThread *internal;
915 StartInfo *start_info;
918 thread = create_thread_object (domain, &error);
919 mono_error_raise_exception (&error); /* FIXME don't raise here */
921 internal = create_internal_thread (&error);
922 mono_error_raise_exception (&error); /* FIXME don't raise here */
924 MONO_OBJECT_SETREF (thread, internal_thread, internal);
926 start_info = g_new0 (StartInfo, 1);
927 start_info->func = (guint32 (*)(void *))func;
928 start_info->obj = thread;
929 start_info->start_arg = arg;
931 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
935 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
936 #ifndef MONO_CROSS_COMPILE
937 if (mono_check_corlib_version () == NULL)
938 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
945 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
947 mono_thread_create_internal (domain, func, arg, FALSE, 0);
951 mono_thread_attach (MonoDomain *domain)
954 MonoThread *thread = mono_thread_attach_full (domain, FALSE, &error);
955 mono_error_raise_exception (&error);
961 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach, MonoError *error)
963 MonoThreadInfo *info;
964 MonoInternalThread *thread;
965 MonoThread *current_thread;
966 HANDLE thread_handle;
967 MonoNativeThreadId tid;
969 mono_error_init (error);
971 if ((thread = mono_thread_internal_current ())) {
972 if (domain != mono_domain_get ())
973 mono_domain_set (domain, TRUE);
974 /* Already attached */
975 return mono_thread_current ();
978 if (!mono_gc_register_thread (&domain)) {
979 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", mono_native_thread_id_get ());
982 thread = create_internal_thread (error);
983 if (!mono_error_ok (error))
986 thread_handle = mono_thread_info_open_handle ();
987 g_assert (thread_handle);
989 tid=mono_native_thread_id_get ();
991 thread->handle = thread_handle;
992 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
993 thread->stack_ptr = &tid;
995 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
997 info = mono_thread_info_current ();
999 thread->thread_info = info;
1000 thread->small_id = info->small_id;
1002 current_thread = new_thread_with_internal (domain, thread, error);
1003 if (!mono_error_ok (error))
1006 if (!handle_store (current_thread, force_attach)) {
1007 /* Mono is shutting down, so just wait for the end */
1009 mono_thread_info_sleep (10000, NULL);
1012 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
1014 SET_CURRENT_OBJECT (thread);
1015 mono_domain_set (domain, TRUE);
1017 thread_adjust_static_data (thread);
1019 init_root_domain_thread (thread, current_thread);
1020 if (domain != mono_get_root_domain ())
1021 set_current_thread_for_domain (domain, thread, current_thread);
1024 if (mono_thread_attach_cb) {
1028 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1031 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1033 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1036 // FIXME: Need a separate callback
1037 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1039 return current_thread;
1043 mono_thread_detach_internal (MonoInternalThread *thread)
1045 g_return_if_fail (thread != NULL);
1047 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1049 thread_cleanup (thread);
1051 SET_CURRENT_OBJECT (NULL);
1052 mono_domain_unset ();
1054 /* Don't need to CloseHandle this thread, even though we took a
1055 * reference in mono_thread_attach (), because the GC will do it
1056 * when the Thread object is finalised.
1061 mono_thread_detach (MonoThread *thread)
1064 mono_thread_detach_internal (thread->internal_thread);
1068 * mono_thread_detach_if_exiting:
1070 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1071 * This should be used at the end of embedding code which calls into managed code, and which
1072 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1075 mono_thread_detach_if_exiting (void)
1077 if (mono_thread_info_is_exiting ()) {
1078 MonoInternalThread *thread;
1080 thread = mono_thread_internal_current ();
1082 mono_thread_detach_internal (thread);
1083 mono_thread_info_detach ();
1091 MonoInternalThread *thread = mono_thread_internal_current ();
1093 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1095 thread_cleanup (thread);
1096 SET_CURRENT_OBJECT (NULL);
1097 mono_domain_unset ();
1099 /* we could add a callback here for embedders to use. */
1100 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1101 exit (mono_environment_exitcode_get ());
1102 mono_thread_info_exit ();
1106 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1109 MonoInternalThread *internal;
1111 internal = create_internal_thread (&error);
1112 mono_error_raise_exception (&error);
1114 internal->state = ThreadState_Unstarted;
1116 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1120 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1123 StartInfo *start_info;
1124 MonoInternalThread *internal;
1127 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1129 if (!this_obj->internal_thread)
1130 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1131 internal = this_obj->internal_thread;
1133 LOCK_THREAD (internal);
1135 if ((internal->state & ThreadState_Unstarted) == 0) {
1136 UNLOCK_THREAD (internal);
1137 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1141 if ((internal->state & ThreadState_Aborted) != 0) {
1142 UNLOCK_THREAD (internal);
1145 /* This is freed in start_wrapper */
1146 start_info = g_new0 (StartInfo, 1);
1147 start_info->func = NULL;
1148 start_info->start_arg = NULL;
1149 start_info->delegate = start;
1150 start_info->obj = this_obj;
1151 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1153 res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
1155 UNLOCK_THREAD (internal);
1159 internal->state &= ~ThreadState_Unstarted;
1161 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1163 UNLOCK_THREAD (internal);
1164 return internal->handle;
1168 * This is called from the finalizer of the internal thread object.
1171 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1173 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1176 * Since threads keep a reference to their thread object while running, by the time this function is called,
1177 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1178 * when thread_cleanup () can be called after this.
1181 CloseHandle (thread);
1183 if (this_obj->synch_cs) {
1184 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1185 this_obj->synch_cs = NULL;
1186 mono_coop_mutex_destroy (synch_cs);
1190 if (this_obj->name) {
1191 void *name = this_obj->name;
1192 this_obj->name = NULL;
1198 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1201 MonoInternalThread *thread = mono_thread_internal_current ();
1203 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1205 mono_thread_current_check_pending_interrupt ();
1208 gboolean alerted = FALSE;
1210 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1212 res = mono_thread_info_sleep (ms, &alerted);
1214 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1217 MonoException* exc = mono_thread_execute_interruption ();
1219 mono_raise_exception (exc);
1231 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1236 ves_icall_System_Threading_Thread_GetDomainID (void)
1238 return mono_domain_get()->domain_id;
1242 ves_icall_System_Threading_Thread_Yield (void)
1244 return mono_thread_info_yield ();
1248 * mono_thread_get_name:
1250 * Return the name of the thread. NAME_LEN is set to the length of the name.
1251 * Return NULL if the thread has no name. The returned memory is owned by the
1255 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1259 LOCK_THREAD (this_obj);
1261 if (!this_obj->name) {
1265 *name_len = this_obj->name_len;
1266 res = g_new (gunichar2, this_obj->name_len);
1267 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1270 UNLOCK_THREAD (this_obj);
1276 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1280 LOCK_THREAD (this_obj);
1282 if (!this_obj->name)
1285 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1287 UNLOCK_THREAD (this_obj);
1293 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1295 LOCK_THREAD (this_obj);
1297 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1298 UNLOCK_THREAD (this_obj);
1300 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1303 if (this_obj->name) {
1304 g_free (this_obj->name);
1305 this_obj->name_len = 0;
1308 this_obj->name = g_new (gunichar2, mono_string_length (name));
1309 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1310 this_obj->name_len = mono_string_length (name);
1313 this_obj->name = NULL;
1316 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1318 UNLOCK_THREAD (this_obj);
1320 if (this_obj->name && this_obj->tid) {
1321 char *tname = mono_string_to_utf8 (name);
1322 mono_profiler_thread_name (this_obj->tid, tname);
1323 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1329 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1331 mono_thread_set_name_internal (this_obj, name, TRUE);
1335 * ves_icall_System_Threading_Thread_GetPriority_internal:
1336 * @param this_obj: The MonoInternalThread on which to operate.
1338 * Gets the priority of the given thread.
1339 * @return: The priority of the given thread.
1342 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1345 MonoInternalThread *internal = this_obj->internal_thread;
1347 LOCK_THREAD (internal);
1348 priority = GetThreadPriority (internal->handle) + 2;
1349 UNLOCK_THREAD (internal);
1354 * ves_icall_System_Threading_Thread_SetPriority_internal:
1355 * @param this_obj: The MonoInternalThread on which to operate.
1356 * @param priority: The priority to set.
1358 * Sets the priority of the given thread.
1361 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1363 MonoInternalThread *internal = this_obj->internal_thread;
1365 LOCK_THREAD (internal);
1366 SetThreadPriority (internal->handle, priority - 2);
1367 UNLOCK_THREAD (internal);
1370 /* If the array is already in the requested domain, we just return it,
1371 otherwise we return a copy in that domain. */
1373 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1380 if (mono_object_domain (arr) == domain)
1383 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1384 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1389 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1391 return byte_array_to_domain (arr, mono_get_root_domain ());
1395 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1397 return byte_array_to_domain (arr, mono_domain_get ());
1401 mono_thread_current (void)
1404 MonoDomain *domain = mono_domain_get ();
1405 MonoInternalThread *internal = mono_thread_internal_current ();
1406 MonoThread **current_thread_ptr;
1408 g_assert (internal);
1409 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1411 if (!*current_thread_ptr) {
1412 g_assert (domain != mono_get_root_domain ());
1413 *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
1414 mono_error_raise_exception (&error); /* FIXME don't raise here */
1416 return *current_thread_ptr;
1419 /* Return the thread object belonging to INTERNAL in the current domain */
1421 mono_thread_current_for_thread (MonoInternalThread *internal)
1424 MonoDomain *domain = mono_domain_get ();
1425 MonoThread **current_thread_ptr;
1427 g_assert (internal);
1428 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1430 if (!*current_thread_ptr) {
1431 g_assert (domain != mono_get_root_domain ());
1432 *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
1433 mono_error_raise_exception (&error); /* FIXME don't raise here */
1435 return *current_thread_ptr;
1439 mono_thread_internal_current (void)
1441 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1442 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1447 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1449 MonoInternalThread *thread = this_obj->internal_thread;
1450 HANDLE handle = thread->handle;
1451 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1454 mono_thread_current_check_pending_interrupt ();
1456 LOCK_THREAD (thread);
1458 if ((thread->state & ThreadState_Unstarted) != 0) {
1459 UNLOCK_THREAD (thread);
1461 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1465 UNLOCK_THREAD (thread);
1470 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1472 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1474 MONO_PREPARE_BLOCKING;
1475 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1476 MONO_FINISH_BLOCKING;
1478 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1480 if(ret==WAIT_OBJECT_0) {
1481 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1486 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1492 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1500 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1502 MONO_PREPARE_BLOCKING;
1504 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1506 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1507 MONO_FINISH_BLOCKING;
1509 if (ret != WAIT_IO_COMPLETION)
1512 exc = mono_thread_execute_interruption ();
1514 mono_raise_exception (exc);
1519 /* Re-calculate ms according to the time passed */
1520 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1521 if (diff_ms >= ms) {
1525 wait = ms - diff_ms;
1531 /* FIXME: exitContext isnt documented */
1532 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1538 MonoObject *waitHandle;
1539 MonoInternalThread *thread = mono_thread_internal_current ();
1541 /* Do this WaitSleepJoin check before creating objects */
1542 mono_thread_current_check_pending_interrupt ();
1544 /* We fail in managed if the array has more than 64 elements */
1545 numhandles = (guint32)mono_array_length(mono_handles);
1546 handles = g_new0(HANDLE, numhandles);
1548 for(i = 0; i < numhandles; i++) {
1549 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1550 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1557 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1559 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1561 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1565 if(ret==WAIT_FAILED) {
1566 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
1568 } else if(ret==WAIT_TIMEOUT) {
1569 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
1576 /* FIXME: exitContext isnt documented */
1577 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1579 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1580 uintptr_t numhandles;
1583 MonoObject *waitHandle;
1584 MonoInternalThread *thread = mono_thread_internal_current ();
1586 /* Do this WaitSleepJoin check before creating objects */
1587 mono_thread_current_check_pending_interrupt ();
1589 numhandles = mono_array_length(mono_handles);
1590 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1593 for(i = 0; i < numhandles; i++) {
1594 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1595 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1602 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1604 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1606 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1608 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1611 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1613 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1614 return ret - WAIT_OBJECT_0;
1616 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1617 return ret - WAIT_ABANDONED_0;
1624 /* FIXME: exitContext isnt documented */
1625 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
1628 MonoInternalThread *thread = mono_thread_internal_current ();
1630 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1636 mono_thread_current_check_pending_interrupt ();
1638 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1640 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1642 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1644 if(ret==WAIT_FAILED) {
1645 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
1647 } else if(ret==WAIT_TIMEOUT) {
1648 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
1656 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1659 MonoInternalThread *thread = mono_thread_internal_current ();
1664 mono_thread_current_check_pending_interrupt ();
1666 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1668 MONO_PREPARE_BLOCKING;
1669 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1670 MONO_FINISH_BLOCKING;
1672 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1674 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1677 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1684 mutex = CreateMutex (NULL, owned, NULL);
1686 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1688 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1696 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1697 return(ReleaseMutex (handle));
1700 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1706 *error = ERROR_SUCCESS;
1708 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1710 *error = GetLastError ();
1717 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1724 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1726 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1727 mono_string_chars (name));
1729 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1737 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1741 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1746 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1750 *error = ERROR_SUCCESS;
1752 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1754 *error = GetLastError ();
1760 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1767 event = CreateEvent (NULL, manual, initial, NULL);
1769 event = CreateEvent (NULL, manual, initial,
1770 mono_string_chars (name));
1772 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1780 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1781 return (SetEvent(handle));
1784 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1785 return (ResetEvent(handle));
1789 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1790 CloseHandle (handle);
1793 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1799 *error = ERROR_SUCCESS;
1801 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1803 *error = GetLastError ();
1809 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1811 return InterlockedIncrement (location);
1814 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1816 #if SIZEOF_VOID_P == 4
1817 if (G_UNLIKELY ((size_t)location & 0x7)) {
1819 mono_interlocked_lock ();
1822 mono_interlocked_unlock ();
1826 return InterlockedIncrement64 (location);
1829 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1831 return InterlockedDecrement(location);
1834 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1836 #if SIZEOF_VOID_P == 4
1837 if (G_UNLIKELY ((size_t)location & 0x7)) {
1839 mono_interlocked_lock ();
1842 mono_interlocked_unlock ();
1846 return InterlockedDecrement64 (location);
1849 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1851 return InterlockedExchange(location, value);
1854 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1857 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1858 mono_gc_wbarrier_generic_nostore (location);
1862 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1864 return InterlockedExchangePointer(location, value);
1867 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1869 IntFloatUnion val, ret;
1872 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1878 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1880 #if SIZEOF_VOID_P == 4
1881 if (G_UNLIKELY ((size_t)location & 0x7)) {
1883 mono_interlocked_lock ();
1886 mono_interlocked_unlock ();
1890 return InterlockedExchange64 (location, value);
1894 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1896 LongDoubleUnion val, ret;
1899 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1904 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1906 return InterlockedCompareExchange(location, value, comparand);
1909 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1911 gint32 r = InterlockedCompareExchange(location, value, comparand);
1912 *success = r == comparand;
1916 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1919 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1920 mono_gc_wbarrier_generic_nostore (location);
1924 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1926 return InterlockedCompareExchangePointer(location, value, comparand);
1929 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1931 IntFloatUnion val, ret, cmp;
1934 cmp.fval = comparand;
1935 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1941 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1943 #if SIZEOF_VOID_P == 8
1944 LongDoubleUnion val, comp, ret;
1947 comp.fval = comparand;
1948 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1954 mono_interlocked_lock ();
1956 if (old == comparand)
1958 mono_interlocked_unlock ();
1965 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1967 #if SIZEOF_VOID_P == 4
1968 if (G_UNLIKELY ((size_t)location & 0x7)) {
1970 mono_interlocked_lock ();
1972 if (old == comparand)
1974 mono_interlocked_unlock ();
1978 return InterlockedCompareExchange64 (location, value, comparand);
1982 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1985 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
1986 mono_gc_wbarrier_generic_nostore (location);
1991 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1994 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
1995 mono_gc_wbarrier_generic_nostore (location);
2000 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2002 return InterlockedAdd (location, value);
2006 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2008 #if SIZEOF_VOID_P == 4
2009 if (G_UNLIKELY ((size_t)location & 0x7)) {
2011 mono_interlocked_lock ();
2014 mono_interlocked_unlock ();
2018 return InterlockedAdd64 (location, value);
2022 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2024 #if SIZEOF_VOID_P == 4
2025 if (G_UNLIKELY ((size_t)location & 0x7)) {
2027 mono_interlocked_lock ();
2029 mono_interlocked_unlock ();
2033 return InterlockedRead64 (location);
2037 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2039 mono_memory_barrier ();
2043 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2045 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2047 if (state & ThreadState_Background) {
2048 /* If the thread changes the background mode, the main thread has to
2049 * be notified, since it has to rebuild the list of threads to
2052 SetEvent (background_change_event);
2057 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2059 mono_thread_set_state (this_obj, (MonoThreadState)state);
2061 if (state & ThreadState_Background) {
2062 /* If the thread changes the background mode, the main thread has to
2063 * be notified, since it has to rebuild the list of threads to
2066 SetEvent (background_change_event);
2071 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2075 LOCK_THREAD (this_obj);
2077 state = this_obj->state;
2079 UNLOCK_THREAD (this_obj);
2084 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2086 MonoInternalThread *current;
2088 MonoInternalThread *thread = this_obj->internal_thread;
2090 LOCK_THREAD (thread);
2092 current = mono_thread_internal_current ();
2094 thread->thread_interrupt_requested = TRUE;
2095 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2097 UNLOCK_THREAD (thread);
2100 abort_thread_internal (thread, TRUE, FALSE);
2104 void mono_thread_current_check_pending_interrupt ()
2106 MonoInternalThread *thread = mono_thread_internal_current ();
2107 gboolean throw_ = FALSE;
2109 LOCK_THREAD (thread);
2111 if (thread->thread_interrupt_requested) {
2113 thread->thread_interrupt_requested = FALSE;
2116 UNLOCK_THREAD (thread);
2119 mono_raise_exception (mono_get_exception_thread_interrupted ());
2124 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2126 LOCK_THREAD (thread);
2128 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2129 (thread->state & ThreadState_StopRequested) != 0 ||
2130 (thread->state & ThreadState_Stopped) != 0)
2132 UNLOCK_THREAD (thread);
2136 if ((thread->state & ThreadState_Unstarted) != 0) {
2137 thread->state |= ThreadState_Aborted;
2138 UNLOCK_THREAD (thread);
2142 thread->state |= ThreadState_AbortRequested;
2143 if (thread->abort_state_handle)
2144 mono_gchandle_free (thread->abort_state_handle);
2146 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2147 g_assert (thread->abort_state_handle);
2149 thread->abort_state_handle = 0;
2151 thread->abort_exc = NULL;
2153 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), thread, (gsize)thread->tid));
2155 /* During shutdown, we can't wait for other threads */
2157 /* Make sure the thread is awake */
2158 mono_thread_resume (thread);
2160 UNLOCK_THREAD (thread);
2162 abort_thread_internal (thread, TRUE, TRUE);
2166 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2168 MonoInternalThread *thread = mono_thread_internal_current ();
2169 gboolean was_aborting;
2171 LOCK_THREAD (thread);
2172 was_aborting = thread->state & ThreadState_AbortRequested;
2173 thread->state &= ~ThreadState_AbortRequested;
2174 UNLOCK_THREAD (thread);
2176 if (!was_aborting) {
2177 const char *msg = "Unable to reset abort because no abort was requested";
2178 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2181 thread->abort_exc = NULL;
2182 if (thread->abort_state_handle) {
2183 mono_gchandle_free (thread->abort_state_handle);
2184 /* This is actually not necessary - the handle
2185 only counts if the exception is set */
2186 thread->abort_state_handle = 0;
2191 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2193 LOCK_THREAD (thread);
2195 thread->state &= ~ThreadState_AbortRequested;
2197 if (thread->abort_exc) {
2198 thread->abort_exc = NULL;
2199 if (thread->abort_state_handle) {
2200 mono_gchandle_free (thread->abort_state_handle);
2201 /* This is actually not necessary - the handle
2202 only counts if the exception is set */
2203 thread->abort_state_handle = 0;
2207 UNLOCK_THREAD (thread);
2211 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2213 MonoInternalThread *thread = this_obj->internal_thread;
2214 MonoObject *state, *deserialized = NULL, *exc;
2217 if (!thread->abort_state_handle)
2220 state = mono_gchandle_get_target (thread->abort_state_handle);
2223 domain = mono_domain_get ();
2224 if (mono_object_domain (state) == domain)
2227 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2229 if (!deserialized) {
2230 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2232 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2233 mono_set_pending_exception (invalid_op_exc);
2237 return deserialized;
2241 mono_thread_suspend (MonoInternalThread *thread)
2243 LOCK_THREAD (thread);
2245 if ((thread->state & ThreadState_Unstarted) != 0 ||
2246 (thread->state & ThreadState_Aborted) != 0 ||
2247 (thread->state & ThreadState_Stopped) != 0)
2249 UNLOCK_THREAD (thread);
2253 if ((thread->state & ThreadState_Suspended) != 0 ||
2254 (thread->state & ThreadState_SuspendRequested) != 0 ||
2255 (thread->state & ThreadState_StopRequested) != 0)
2257 UNLOCK_THREAD (thread);
2261 thread->state |= ThreadState_SuspendRequested;
2263 UNLOCK_THREAD (thread);
2265 suspend_thread_internal (thread, FALSE);
2270 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2272 if (!mono_thread_suspend (this_obj->internal_thread)) {
2273 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2278 /* LOCKING: LOCK_THREAD(thread) must be held */
2280 mono_thread_resume (MonoInternalThread *thread)
2282 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2283 thread->state &= ~ThreadState_SuspendRequested;
2287 if ((thread->state & ThreadState_Suspended) == 0 ||
2288 (thread->state & ThreadState_Unstarted) != 0 ||
2289 (thread->state & ThreadState_Aborted) != 0 ||
2290 (thread->state & ThreadState_Stopped) != 0)
2295 UNLOCK_THREAD (thread);
2297 /* Awake the thread */
2298 if (!mono_thread_info_resume (thread_get_tid (thread)))
2301 LOCK_THREAD (thread);
2303 thread->state &= ~ThreadState_Suspended;
2309 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2311 if (!thread->internal_thread) {
2312 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2314 LOCK_THREAD (thread->internal_thread);
2315 if (!mono_thread_resume (thread->internal_thread))
2316 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2317 UNLOCK_THREAD (thread->internal_thread);
2322 mono_threads_is_critical_method (MonoMethod *method)
2324 switch (method->wrapper_type) {
2325 case MONO_WRAPPER_RUNTIME_INVOKE:
2326 case MONO_WRAPPER_XDOMAIN_INVOKE:
2327 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2334 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2339 if (mono_threads_is_critical_method (m)) {
2340 *((gboolean*)data) = TRUE;
2347 is_running_protected_wrapper (void)
2349 gboolean found = FALSE;
2350 mono_stack_walk (find_wrapper, &found);
2354 void mono_thread_internal_stop (MonoInternalThread *thread)
2356 LOCK_THREAD (thread);
2358 if ((thread->state & ThreadState_StopRequested) != 0 ||
2359 (thread->state & ThreadState_Stopped) != 0)
2361 UNLOCK_THREAD (thread);
2365 /* Make sure the thread is awake */
2366 mono_thread_resume (thread);
2368 thread->state |= ThreadState_StopRequested;
2369 thread->state &= ~ThreadState_AbortRequested;
2371 UNLOCK_THREAD (thread);
2373 abort_thread_internal (thread, TRUE, TRUE);
2376 void mono_thread_stop (MonoThread *thread)
2378 mono_thread_internal_stop (thread->internal_thread);
2382 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2384 gint8 tmp = *(volatile gint8 *)ptr;
2385 mono_memory_barrier ();
2390 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2392 gint16 tmp = *(volatile gint16 *)ptr;
2393 mono_memory_barrier ();
2398 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2400 gint32 tmp = *(volatile gint32 *)ptr;
2401 mono_memory_barrier ();
2406 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2408 gint64 tmp = *(volatile gint64 *)ptr;
2409 mono_memory_barrier ();
2414 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2416 volatile void *tmp = *(volatile void **)ptr;
2417 mono_memory_barrier ();
2418 return (void *) tmp;
2422 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2424 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2425 mono_memory_barrier ();
2426 return (MonoObject *) tmp;
2430 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2432 double tmp = *(volatile double *)ptr;
2433 mono_memory_barrier ();
2438 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2440 float tmp = *(volatile float *)ptr;
2441 mono_memory_barrier ();
2446 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2448 return InterlockedRead8 ((volatile gint8 *)ptr);
2452 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2454 return InterlockedRead16 ((volatile gint16 *)ptr);
2458 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2460 return InterlockedRead ((volatile gint32 *)ptr);
2464 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2466 #if SIZEOF_VOID_P == 4
2467 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2469 mono_interlocked_lock ();
2470 val = *(gint64*)ptr;
2471 mono_interlocked_unlock ();
2475 return InterlockedRead64 ((volatile gint64 *)ptr);
2479 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2481 return InterlockedReadPointer ((volatile gpointer *)ptr);
2485 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2489 #if SIZEOF_VOID_P == 4
2490 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2492 mono_interlocked_lock ();
2493 val = *(double*)ptr;
2494 mono_interlocked_unlock ();
2499 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2505 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2509 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2515 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2517 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2521 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2523 mono_memory_barrier ();
2524 *(volatile gint8 *)ptr = value;
2528 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2530 mono_memory_barrier ();
2531 *(volatile gint16 *)ptr = value;
2535 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2537 mono_memory_barrier ();
2538 *(volatile gint32 *)ptr = value;
2542 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2544 mono_memory_barrier ();
2545 *(volatile gint64 *)ptr = value;
2549 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2551 mono_memory_barrier ();
2552 *(volatile void **)ptr = value;
2556 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2558 mono_memory_barrier ();
2559 mono_gc_wbarrier_generic_store (ptr, value);
2563 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2565 mono_memory_barrier ();
2566 *(volatile double *)ptr = value;
2570 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2572 mono_memory_barrier ();
2573 *(volatile float *)ptr = value;
2577 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2579 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2583 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2585 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2589 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2591 InterlockedWrite ((volatile gint32 *)ptr, value);
2595 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2597 #if SIZEOF_VOID_P == 4
2598 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2599 mono_interlocked_lock ();
2600 *(gint64*)ptr = value;
2601 mono_interlocked_unlock ();
2606 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2610 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2612 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2616 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2620 #if SIZEOF_VOID_P == 4
2621 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2622 mono_interlocked_lock ();
2623 *(double*)ptr = value;
2624 mono_interlocked_unlock ();
2631 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2635 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2641 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2645 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2647 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2651 free_context (void *user_data)
2653 ContextStaticData *data = user_data;
2655 mono_threads_lock ();
2658 * There is no guarantee that, by the point this reference queue callback
2659 * has been invoked, the GC handle associated with the object will fail to
2660 * resolve as one might expect. So if we don't free and remove the GC
2661 * handle here, free_context_static_data_helper () could end up resolving
2662 * a GC handle to an actually-dead context which would contain a pointer
2663 * to an already-freed static data segment, resulting in a crash when
2666 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2668 mono_threads_unlock ();
2670 mono_gchandle_free (data->gc_handle);
2671 mono_free_static_data (data->static_data);
2676 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2678 mono_threads_lock ();
2680 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2683 contexts = g_hash_table_new (NULL, NULL);
2686 context_queue = mono_gc_reference_queue_new (free_context);
2688 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2689 g_hash_table_insert (contexts, gch, gch);
2692 * We use this intermediate structure to contain a duplicate pointer to
2693 * the static data because we can't rely on being able to resolve the GC
2694 * handle in the reference queue callback.
2696 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2697 data->gc_handle = GPOINTER_TO_UINT (gch);
2700 context_adjust_static_data (ctx);
2701 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2703 mono_threads_unlock ();
2705 mono_profiler_context_loaded (ctx);
2709 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2712 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2713 * cleanup in exceptional circumstances, we don't actually do any
2714 * cleanup work here. We instead do this via a reference queue.
2717 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2719 mono_profiler_context_unloaded (ctx);
2723 mono_thread_init_tls (void)
2725 MONO_FAST_TLS_INIT (tls_current_object);
2726 mono_native_tls_alloc (¤t_object_key, NULL);
2729 void mono_thread_init (MonoThreadStartCB start_cb,
2730 MonoThreadAttachCB attach_cb)
2732 mono_coop_mutex_init_recursive (&threads_mutex);
2734 mono_os_mutex_init_recursive(&interlocked_mutex);
2735 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2737 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2738 g_assert(background_change_event != NULL);
2740 mono_init_static_data_info (&thread_static_info);
2741 mono_init_static_data_info (&context_static_info);
2743 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2745 mono_thread_start_cb = start_cb;
2746 mono_thread_attach_cb = attach_cb;
2748 /* Get a pseudo handle to the current process. This is just a
2749 * kludge so that wapi can build a process handle if needed.
2750 * As a pseudo handle is returned, we don't need to clean
2753 GetCurrentProcess ();
2756 void mono_thread_cleanup (void)
2758 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2759 MonoThreadInfo *info;
2761 /* The main thread must abandon any held mutexes (particularly
2762 * important for named mutexes as they are shared across
2763 * processes, see bug 74680.) This will happen when the
2764 * thread exits, but if it's not running in a subthread it
2765 * won't exit in time.
2767 info = mono_thread_info_current ();
2768 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2772 /* This stuff needs more testing, it seems one of these
2773 * critical sections can be locked when mono_thread_cleanup is
2776 mono_coop_mutex_destroy (&threads_mutex);
2777 mono_os_mutex_destroy (&interlocked_mutex);
2778 mono_os_mutex_destroy (&delayed_free_table_mutex);
2779 mono_os_mutex_destroy (&small_id_mutex);
2780 CloseHandle (background_change_event);
2783 mono_native_tls_free (current_object_key);
2787 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2789 mono_thread_cleanup_fn = func;
2793 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2795 thread->internal_thread->manage_callback = func;
2798 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2800 mono_thread_notify_pending_exc_fn = func;
2804 static void print_tids (gpointer key, gpointer value, gpointer user)
2806 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2807 * sizeof(uint) and a cast to uint would overflow
2809 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2810 * print this as a pointer.
2812 g_message ("Waiting for: %p", key);
2817 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2818 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2822 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2826 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2828 MONO_PREPARE_BLOCKING;
2829 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2830 MONO_FINISH_BLOCKING;
2832 if(ret==WAIT_FAILED) {
2833 /* See the comment in build_wait_tids() */
2834 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2838 for(i=0; i<wait->num; i++)
2839 CloseHandle (wait->handles[i]);
2841 if (ret == WAIT_TIMEOUT)
2844 for(i=0; i<wait->num; i++) {
2845 gsize tid = wait->threads[i]->tid;
2848 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2849 * it can still run io-layer etc. code. So wait for it to really exit.
2850 * FIXME: This won't join threads which are not in the joinable_hash yet.
2852 mono_thread_join ((gpointer)tid);
2854 mono_threads_lock ();
2855 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2856 /* This thread must have been killed, because
2857 * it hasn't cleaned itself up. (It's just
2858 * possible that the thread exited before the
2859 * parent thread had a chance to store the
2860 * handle, and now there is another pointer to
2861 * the already-exited thread stored. In this
2862 * case, we'll just get two
2863 * mono_profiler_thread_end() calls for the
2867 mono_threads_unlock ();
2868 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2869 thread_cleanup (wait->threads[i]);
2871 mono_threads_unlock ();
2876 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2878 guint32 i, ret, count;
2880 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2882 /* Add the thread state change event, so it wakes up if a thread changes
2883 * to background mode.
2886 if (count < MAXIMUM_WAIT_OBJECTS) {
2887 wait->handles [count] = background_change_event;
2891 MONO_PREPARE_BLOCKING;
2892 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2893 MONO_FINISH_BLOCKING;
2895 if(ret==WAIT_FAILED) {
2896 /* See the comment in build_wait_tids() */
2897 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2901 for(i=0; i<wait->num; i++)
2902 CloseHandle (wait->handles[i]);
2904 if (ret == WAIT_TIMEOUT)
2907 if (ret < wait->num) {
2908 gsize tid = wait->threads[ret]->tid;
2909 mono_threads_lock ();
2910 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2911 /* See comment in wait_for_tids about thread cleanup */
2912 mono_threads_unlock ();
2913 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2914 thread_cleanup (wait->threads [ret]);
2916 mono_threads_unlock ();
2920 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2922 struct wait_data *wait=(struct wait_data *)user;
2924 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2926 MonoInternalThread *thread=(MonoInternalThread *)value;
2928 /* Ignore background threads, we abort them later */
2929 /* Do not lock here since it is not needed and the caller holds threads_lock */
2930 if (thread->state & ThreadState_Background) {
2931 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2932 return; /* just leave, ignore */
2935 if (mono_gc_is_finalizer_internal_thread (thread)) {
2936 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2940 if (thread == mono_thread_internal_current ()) {
2941 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2945 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2946 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2950 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2951 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2955 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2956 if (handle == NULL) {
2957 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2961 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2962 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2963 wait->handles[wait->num]=handle;
2964 wait->threads[wait->num]=thread;
2967 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2969 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2974 /* Just ignore the rest, we can't do anything with
2981 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2983 struct wait_data *wait=(struct wait_data *)user;
2984 MonoNativeThreadId self = mono_native_thread_id_get ();
2985 MonoInternalThread *thread = (MonoInternalThread *)value;
2988 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2991 /* The finalizer thread is not a background thread */
2992 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
2993 && (thread->state & ThreadState_Background) != 0
2994 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
2996 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3000 /* printf ("A: %d\n", wait->num); */
3001 wait->handles[wait->num]=thread->handle;
3002 wait->threads[wait->num]=thread;
3005 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3006 mono_thread_internal_stop (thread);
3010 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3011 && !mono_gc_is_finalizer_internal_thread (thread);
3015 * mono_threads_set_shutting_down:
3017 * Is called by a thread that wants to shut down Mono. If the runtime is already
3018 * shutting down, the calling thread is suspended/stopped, and this function never
3022 mono_threads_set_shutting_down (void)
3024 MonoInternalThread *current_thread = mono_thread_internal_current ();
3026 mono_threads_lock ();
3028 if (shutting_down) {
3029 mono_threads_unlock ();
3031 /* Make sure we're properly suspended/stopped */
3033 LOCK_THREAD (current_thread);
3035 if ((current_thread->state & ThreadState_SuspendRequested) ||
3036 (current_thread->state & ThreadState_AbortRequested) ||
3037 (current_thread->state & ThreadState_StopRequested)) {
3038 UNLOCK_THREAD (current_thread);
3039 mono_thread_execute_interruption ();
3041 current_thread->state |= ThreadState_Stopped;
3042 UNLOCK_THREAD (current_thread);
3045 /*since we're killing the thread, unset the current domain.*/
3046 mono_domain_unset ();
3048 /* Wake up other threads potentially waiting for us */
3049 mono_thread_info_exit ();
3051 shutting_down = TRUE;
3053 /* Not really a background state change, but this will
3054 * interrupt the main thread if it is waiting for all
3055 * the other threads.
3057 SetEvent (background_change_event);
3059 mono_threads_unlock ();
3063 void mono_thread_manage (void)
3065 struct wait_data wait_data;
3066 struct wait_data *wait = &wait_data;
3068 memset (wait, 0, sizeof (struct wait_data));
3069 /* join each thread that's still running */
3070 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3072 mono_threads_lock ();
3074 THREAD_DEBUG (g_message("%s: No threads", __func__));
3075 mono_threads_unlock ();
3078 mono_threads_unlock ();
3081 mono_threads_lock ();
3082 if (shutting_down) {
3083 /* somebody else is shutting down */
3084 mono_threads_unlock ();
3087 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3088 mono_g_hash_table_foreach (threads, print_tids, NULL));
3090 ResetEvent (background_change_event);
3092 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3093 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3094 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3095 mono_threads_unlock ();
3097 /* Something to wait for */
3098 wait_for_tids_or_state_change (wait, INFINITE);
3100 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3101 } while(wait->num>0);
3103 /* Mono is shutting down, so just wait for the end */
3104 if (!mono_runtime_try_shutdown ()) {
3105 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3106 mono_thread_suspend (mono_thread_internal_current ());
3107 mono_thread_execute_interruption ();
3111 * Remove everything but the finalizer thread and self.
3112 * Also abort all the background threads
3115 mono_threads_lock ();
3118 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3119 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3120 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3122 mono_threads_unlock ();
3124 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3126 /* Something to wait for */
3127 wait_for_tids (wait, INFINITE);
3129 } while (wait->num > 0);
3132 * give the subthreads a chance to really quit (this is mainly needed
3133 * to get correct user and system times from getrusage/wait/time(1)).
3134 * This could be removed if we avoid pthread_detach() and use pthread_join().
3136 mono_thread_info_yield ();
3140 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3142 MonoInternalThread *thread = (MonoInternalThread*)value;
3143 struct wait_data *wait = (struct wait_data*)user_data;
3147 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3149 * This needs no locking.
3151 if ((thread->state & ThreadState_Suspended) != 0 ||
3152 (thread->state & ThreadState_Stopped) != 0)
3155 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3156 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3160 wait->handles [wait->num] = handle;
3161 wait->threads [wait->num] = thread;
3167 * mono_thread_suspend_all_other_threads:
3169 * Suspend all managed threads except the finalizer thread and this thread. It is
3170 * not possible to resume them later.
3172 void mono_thread_suspend_all_other_threads (void)
3174 struct wait_data wait_data;
3175 struct wait_data *wait = &wait_data;
3177 MonoNativeThreadId self = mono_native_thread_id_get ();
3178 guint32 eventidx = 0;
3179 gboolean starting, finished;
3181 memset (wait, 0, sizeof (struct wait_data));
3183 * The other threads could be in an arbitrary state at this point, i.e.
3184 * they could be starting up, shutting down etc. This means that there could be
3185 * threads which are not even in the threads hash table yet.
3189 * First we set a barrier which will be checked by all threads before they
3190 * are added to the threads hash table, and they will exit if the flag is set.
3191 * This ensures that no threads could be added to the hash later.
3192 * We will use shutting_down as the barrier for now.
3194 g_assert (shutting_down);
3197 * We make multiple calls to WaitForMultipleObjects since:
3198 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3199 * - some threads could exit without becoming suspended
3204 * Make a copy of the hashtable since we can't do anything with
3205 * threads while threads_mutex is held.
3208 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3209 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3210 mono_threads_lock ();
3211 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3212 mono_threads_unlock ();
3215 /* Get the suspended events that we'll be waiting for */
3216 for (i = 0; i < wait->num; ++i) {
3217 MonoInternalThread *thread = wait->threads [i];
3219 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3220 || mono_gc_is_finalizer_internal_thread (thread)
3221 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3223 //CloseHandle (wait->handles [i]);
3224 wait->threads [i] = NULL; /* ignore this thread in next loop */
3228 LOCK_THREAD (thread);
3230 if ((thread->state & ThreadState_Suspended) != 0 ||
3231 (thread->state & ThreadState_StopRequested) != 0 ||
3232 (thread->state & ThreadState_Stopped) != 0) {
3233 UNLOCK_THREAD (thread);
3234 CloseHandle (wait->handles [i]);
3235 wait->threads [i] = NULL; /* ignore this thread in next loop */
3241 /* Convert abort requests into suspend requests */
3242 if ((thread->state & ThreadState_AbortRequested) != 0)
3243 thread->state &= ~ThreadState_AbortRequested;
3245 thread->state |= ThreadState_SuspendRequested;
3247 UNLOCK_THREAD (thread);
3249 /* Signal the thread to suspend */
3250 suspend_thread_internal (thread, TRUE);
3252 if (eventidx <= 0) {
3254 * If there are threads which are starting up, we wait until they
3255 * are suspended when they try to register in the threads hash.
3256 * This is guaranteed to finish, since the threads which can create new
3257 * threads get suspended after a while.
3258 * FIXME: The finalizer thread can still create new threads.
3260 mono_threads_lock ();
3261 if (threads_starting_up)
3262 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3265 mono_threads_unlock ();
3267 mono_thread_info_sleep (100, NULL);
3275 MonoInternalThread *thread;
3276 MonoStackFrameInfo *frames;
3277 int nframes, max_frames;
3278 int nthreads, max_threads;
3279 MonoInternalThread **threads;
3280 } ThreadDumpUserData;
3282 static gboolean thread_dump_requested;
3284 /* This needs to be async safe */
3286 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3288 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3290 if (ud->nframes < ud->max_frames) {
3291 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3298 /* This needs to be async safe */
3299 static SuspendThreadResult
3300 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3302 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3303 MonoInternalThread *thread = user_data->thread;
3306 /* This no longer works with remote unwinding */
3308 wapi_desc = wapi_current_thread_desc ();
3309 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3314 if (thread == mono_thread_internal_current ())
3315 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3317 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3319 return MonoResumeThread;
3323 int nthreads, max_threads;
3324 MonoInternalThread **threads;
3325 } CollectThreadsUserData;
3328 collect_thread (gpointer key, gpointer value, gpointer user)
3330 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3331 MonoInternalThread *thread = (MonoInternalThread *)value;
3333 if (ud->nthreads < ud->max_threads)
3334 ud->threads [ud->nthreads ++] = thread;
3338 * Collect running threads into the THREADS array.
3339 * THREADS should be an array allocated on the stack.
3342 collect_threads (MonoInternalThread **thread_array, int max_threads)
3344 CollectThreadsUserData ud;
3346 memset (&ud, 0, sizeof (ud));
3347 /* This array contains refs, but its on the stack, so its ok */
3348 ud.threads = thread_array;
3349 ud.max_threads = max_threads;
3351 mono_threads_lock ();
3352 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3353 mono_threads_unlock ();
3359 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3361 GString* text = g_string_new (0);
3363 GError *error = NULL;
3366 ud->thread = thread;
3369 /* Collect frames for the thread */
3370 if (thread == mono_thread_internal_current ()) {
3371 get_thread_dump (mono_thread_info_current (), ud);
3373 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3377 * Do all the non async-safe work outside of get_thread_dump.
3380 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3382 g_string_append_printf (text, "\n\"%s\"", name);
3385 else if (thread->threadpool_thread) {
3386 g_string_append (text, "\n\"<threadpool thread>\"");
3388 g_string_append (text, "\n\"<unnamed thread>\"");
3391 for (i = 0; i < ud->nframes; ++i) {
3392 MonoStackFrameInfo *frame = &ud->frames [i];
3393 MonoMethod *method = NULL;
3395 if (frame->type == FRAME_TYPE_MANAGED)
3396 method = mono_jit_info_get_method (frame->ji);
3399 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3400 g_string_append_printf (text, " %s\n", location);
3403 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3407 fprintf (stdout, "%s", text->str);
3409 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3410 OutputDebugStringA(text->str);
3413 g_string_free (text, TRUE);
3418 mono_threads_perform_thread_dump (void)
3420 ThreadDumpUserData ud;
3421 MonoInternalThread *thread_array [128];
3422 int tindex, nthreads;
3424 if (!thread_dump_requested)
3427 printf ("Full thread dump:\n");
3429 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3430 nthreads = collect_threads (thread_array, 128);
3432 memset (&ud, 0, sizeof (ud));
3433 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3434 ud.max_frames = 256;
3436 for (tindex = 0; tindex < nthreads; ++tindex)
3437 dump_thread (thread_array [tindex], &ud);
3441 thread_dump_requested = FALSE;
3444 /* Obtain the thread dump of all threads */
3446 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames)
3448 ThreadDumpUserData ud;
3449 MonoInternalThread *thread_array [128];
3450 MonoDomain *domain = mono_domain_get ();
3451 MonoDebugSourceLocation *location;
3452 int tindex, nthreads;
3454 *out_threads = NULL;
3455 *out_stack_frames = NULL;
3457 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3458 nthreads = collect_threads (thread_array, 128);
3460 memset (&ud, 0, sizeof (ud));
3461 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3462 ud.max_frames = 256;
3464 *out_threads = mono_array_new (domain, mono_defaults.thread_class, nthreads);
3465 *out_stack_frames = mono_array_new (domain, mono_defaults.array_class, nthreads);
3467 for (tindex = 0; tindex < nthreads; ++tindex) {
3468 MonoInternalThread *thread = thread_array [tindex];
3469 MonoArray *thread_frames;
3475 /* Collect frames for the thread */
3476 if (thread == mono_thread_internal_current ()) {
3477 get_thread_dump (mono_thread_info_current (), &ud);
3479 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3482 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3484 thread_frames = mono_array_new (domain, mono_defaults.stack_frame_class, ud.nframes);
3485 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3487 for (i = 0; i < ud.nframes; ++i) {
3488 MonoStackFrameInfo *frame = &ud.frames [i];
3489 MonoMethod *method = NULL;
3490 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
3492 sf->native_offset = frame->native_offset;
3494 if (frame->type == FRAME_TYPE_MANAGED)
3495 method = mono_jit_info_get_method (frame->ji);
3498 sf->method_address = (gsize) frame->ji->code_start;
3500 MONO_OBJECT_SETREF (sf, method, mono_method_get_object (domain, method, NULL));
3502 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3504 sf->il_offset = location->il_offset;
3506 if (location && location->source_file) {
3507 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3508 sf->line = location->row;
3509 sf->column = location->column;
3511 mono_debug_free_source_location (location);
3516 mono_array_setref (thread_frames, i, sf);
3524 * mono_threads_request_thread_dump:
3526 * Ask all threads except the current to print their stacktrace to stdout.
3529 mono_threads_request_thread_dump (void)
3531 /*The new thread dump code runs out of the finalizer thread. */
3532 thread_dump_requested = TRUE;
3533 mono_gc_finalize_notify ();
3538 gint allocated; /* +1 so that refs [allocated] == NULL */
3542 typedef struct ref_stack RefStack;
3545 ref_stack_new (gint initial_size)
3549 initial_size = MAX (initial_size, 16) + 1;
3550 rs = g_new0 (RefStack, 1);
3551 rs->refs = g_new0 (gpointer, initial_size);
3552 rs->allocated = initial_size;
3557 ref_stack_destroy (gpointer ptr)
3559 RefStack *rs = (RefStack *)ptr;
3568 ref_stack_push (RefStack *rs, gpointer ptr)
3570 g_assert (rs != NULL);
3572 if (rs->bottom >= rs->allocated) {
3573 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3574 rs->allocated <<= 1;
3575 rs->refs [rs->allocated] = NULL;
3577 rs->refs [rs->bottom++] = ptr;
3581 ref_stack_pop (RefStack *rs)
3583 if (rs == NULL || rs->bottom == 0)
3587 rs->refs [rs->bottom] = NULL;
3591 ref_stack_find (RefStack *rs, gpointer ptr)
3598 for (refs = rs->refs; refs && *refs; refs++) {
3606 * mono_thread_push_appdomain_ref:
3608 * Register that the current thread may have references to objects in domain
3609 * @domain on its stack. Each call to this function should be paired with a
3610 * call to pop_appdomain_ref.
3613 mono_thread_push_appdomain_ref (MonoDomain *domain)
3615 MonoInternalThread *thread = mono_thread_internal_current ();
3618 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3619 SPIN_LOCK (thread->lock_thread_id);
3620 if (thread->appdomain_refs == NULL)
3621 thread->appdomain_refs = ref_stack_new (16);
3622 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3623 SPIN_UNLOCK (thread->lock_thread_id);
3628 mono_thread_pop_appdomain_ref (void)
3630 MonoInternalThread *thread = mono_thread_internal_current ();
3633 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3634 SPIN_LOCK (thread->lock_thread_id);
3635 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3636 SPIN_UNLOCK (thread->lock_thread_id);
3641 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3644 SPIN_LOCK (thread->lock_thread_id);
3645 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3646 SPIN_UNLOCK (thread->lock_thread_id);
3651 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3653 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3656 typedef struct abort_appdomain_data {
3657 struct wait_data wait;
3659 } abort_appdomain_data;
3662 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3664 MonoInternalThread *thread = (MonoInternalThread*)value;
3665 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3666 MonoDomain *domain = data->domain;
3668 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3669 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3671 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3672 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3675 data->wait.handles [data->wait.num] = handle;
3676 data->wait.threads [data->wait.num] = thread;
3679 /* Just ignore the rest, we can't do anything with
3687 * mono_threads_abort_appdomain_threads:
3689 * Abort threads which has references to the given appdomain.
3692 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3694 #ifdef __native_client__
3698 abort_appdomain_data user_data;
3700 int orig_timeout = timeout;
3703 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3705 start_time = mono_msec_ticks ();
3707 mono_threads_lock ();
3709 user_data.domain = domain;
3710 user_data.wait.num = 0;
3711 /* This shouldn't take any locks */
3712 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3713 mono_threads_unlock ();
3715 if (user_data.wait.num > 0) {
3716 /* Abort the threads outside the threads lock */
3717 for (i = 0; i < user_data.wait.num; ++i)
3718 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3721 * We should wait for the threads either to abort, or to leave the
3722 * domain. We can't do the latter, so we wait with a timeout.
3724 wait_for_tids (&user_data.wait, 100);
3727 /* Update remaining time */
3728 timeout -= mono_msec_ticks () - start_time;
3729 start_time = mono_msec_ticks ();
3731 if (orig_timeout != -1 && timeout < 0)
3734 while (user_data.wait.num > 0);
3736 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3742 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3744 MonoInternalThread *thread = (MonoInternalThread*)value;
3745 MonoDomain *domain = (MonoDomain*)user_data;
3748 /* No locking needed here */
3749 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3751 if (thread->cached_culture_info) {
3752 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3753 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3754 if (obj && obj->vtable->domain == domain)
3755 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3761 * mono_threads_clear_cached_culture:
3763 * Clear the cached_current_culture from all threads if it is in the
3767 mono_threads_clear_cached_culture (MonoDomain *domain)
3769 mono_threads_lock ();
3770 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3771 mono_threads_unlock ();
3775 * mono_thread_get_undeniable_exception:
3777 * Return an exception which needs to be raised when leaving a catch clause.
3778 * This is used for undeniable exception propagation.
3781 mono_thread_get_undeniable_exception (void)
3783 MonoInternalThread *thread = mono_thread_internal_current ();
3785 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3787 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3788 * exception if the thread no longer references a dying appdomain.
3790 thread->abort_exc->trace_ips = NULL;
3791 thread->abort_exc->stack_trace = NULL;
3792 return thread->abort_exc;
3798 #if MONO_SMALL_CONFIG
3799 #define NUM_STATIC_DATA_IDX 4
3800 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3804 #define NUM_STATIC_DATA_IDX 8
3805 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3806 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3810 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3811 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3814 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3816 gpointer *static_data = (gpointer *)addr;
3818 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3819 void **ptr = (void **)static_data [i];
3824 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3825 void **p = ptr + idx;
3828 mark_func ((MonoObject**)p, gc_data);
3834 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3836 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3840 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3842 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3846 * mono_alloc_static_data
3848 * Allocate memory blocks for storing threads or context static data
3851 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3853 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3856 gpointer* static_data = *static_data_ptr;
3858 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3859 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3861 if (mono_gc_user_markers_supported ()) {
3862 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3863 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3865 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3866 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3869 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3870 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3871 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3872 *static_data_ptr = static_data;
3873 static_data [0] = static_data;
3876 for (i = 1; i <= idx; ++i) {
3877 if (static_data [i])
3880 if (mono_gc_user_markers_supported ())
3881 static_data [i] = g_malloc0 (static_data_size [i]);
3883 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3884 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3885 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3890 mono_free_static_data (gpointer* static_data)
3893 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3894 gpointer p = static_data [i];
3898 * At this point, the static data pointer array is still registered with the
3899 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3900 * data. Freeing the individual arrays without first nulling their slots
3901 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3902 * such an already freed array. See bug #13813.
3904 static_data [i] = NULL;
3905 mono_memory_write_barrier ();
3906 if (mono_gc_user_markers_supported ())
3909 mono_gc_free_fixed (p);
3911 mono_gc_free_fixed (static_data);
3915 * mono_init_static_data_info
3917 * Initializes static data counters
3919 static void mono_init_static_data_info (StaticDataInfo *static_data)
3921 static_data->idx = 0;
3922 static_data->offset = 0;
3923 static_data->freelist = NULL;
3927 * mono_alloc_static_data_slot
3929 * Generates an offset for static data. static_data contains the counters
3930 * used to generate it.
3933 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3935 if (!static_data->idx && !static_data->offset) {
3937 * we use the first chunk of the first allocation also as
3938 * an array for the rest of the data
3940 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3942 static_data->offset += align - 1;
3943 static_data->offset &= ~(align - 1);
3944 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3945 static_data->idx ++;
3946 g_assert (size <= static_data_size [static_data->idx]);
3947 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3948 static_data->offset = 0;
3950 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3951 static_data->offset += size;
3956 * ensure thread static fields already allocated are valid for thread
3957 * This function is called when a thread is created or on thread attach.
3960 thread_adjust_static_data (MonoInternalThread *thread)
3962 mono_threads_lock ();
3963 if (thread_static_info.offset || thread_static_info.idx > 0) {
3964 /* get the current allocated size */
3965 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3966 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3968 mono_threads_unlock ();
3972 * LOCKING: requires that threads_mutex is held
3975 context_adjust_static_data (MonoAppContext *ctx)
3977 if (context_static_info.offset || context_static_info.idx > 0) {
3978 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3979 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3980 ctx->data->static_data = ctx->static_data;
3985 * LOCKING: requires that threads_mutex is held
3988 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3990 MonoInternalThread *thread = (MonoInternalThread *)value;
3991 guint32 offset = GPOINTER_TO_UINT (user);
3993 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3997 * LOCKING: requires that threads_mutex is held
4000 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4002 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4007 guint32 offset = GPOINTER_TO_UINT (user);
4008 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4009 ctx->data->static_data = ctx->static_data;
4012 static StaticDataFreeList*
4013 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4015 StaticDataFreeList* prev = NULL;
4016 StaticDataFreeList* tmp = static_data->freelist;
4018 if (tmp->size == size) {
4020 prev->next = tmp->next;
4022 static_data->freelist = tmp->next;
4031 #if SIZEOF_VOID_P == 4
4038 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4040 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4042 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4043 MonoBitSet *rb = sets [idx];
4044 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4045 offset /= sizeof (uintptr_t);
4046 /* offset is now the bitmap offset */
4047 for (int i = 0; i < numbits; ++i) {
4048 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4049 mono_bitset_set_fast (rb, offset + i);
4054 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4056 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4057 MonoBitSet *rb = sets [idx];
4058 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4059 offset /= sizeof (uintptr_t);
4060 /* offset is now the bitmap offset */
4061 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4062 mono_bitset_clear_fast (rb, offset + i);
4066 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4068 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4070 StaticDataInfo *info;
4073 if (static_type == SPECIAL_STATIC_THREAD) {
4074 info = &thread_static_info;
4075 sets = thread_reference_bitmaps;
4077 info = &context_static_info;
4078 sets = context_reference_bitmaps;
4081 mono_threads_lock ();
4083 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4087 offset = item->offset;
4090 offset = mono_alloc_static_data_slot (info, size, align);
4093 update_reference_bitmap (sets, offset, bitmap, numbits);
4095 if (static_type == SPECIAL_STATIC_THREAD) {
4096 /* This can be called during startup */
4097 if (threads != NULL)
4098 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4100 if (contexts != NULL)
4101 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4103 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4106 mono_threads_unlock ();
4112 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4114 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4116 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4117 return get_thread_static_data (thread, offset);
4119 return get_context_static_data (thread->current_appcontext, offset);
4124 mono_get_special_static_data (guint32 offset)
4126 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4135 * LOCKING: requires that threads_mutex is held
4138 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4140 MonoInternalThread *thread = (MonoInternalThread *)value;
4141 OffsetSize *data = (OffsetSize *)user;
4142 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4143 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4146 if (!thread->static_data || !thread->static_data [idx])
4148 ptr = ((char*) thread->static_data [idx]) + off;
4149 mono_gc_bzero_atomic (ptr, data->size);
4153 * LOCKING: requires that threads_mutex is held
4156 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4158 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4163 OffsetSize *data = (OffsetSize *)user;
4164 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4165 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4168 if (!ctx->static_data || !ctx->static_data [idx])
4171 ptr = ((char*) ctx->static_data [idx]) + off;
4172 mono_gc_bzero_atomic (ptr, data->size);
4176 do_free_special_slot (guint32 offset, guint32 size)
4178 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4180 StaticDataInfo *info;
4182 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4183 info = &thread_static_info;
4184 sets = thread_reference_bitmaps;
4186 info = &context_static_info;
4187 sets = context_reference_bitmaps;
4190 guint32 data_offset = offset;
4191 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4192 OffsetSize data = { data_offset, size };
4194 clear_reference_bitmap (sets, data.offset, data.size);
4196 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4197 if (threads != NULL)
4198 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4200 if (contexts != NULL)
4201 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4204 if (!mono_runtime_is_shutting_down ()) {
4205 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4207 item->offset = offset;
4210 item->next = info->freelist;
4211 info->freelist = item;
4216 do_free_special (gpointer key, gpointer value, gpointer data)
4218 MonoClassField *field = (MonoClassField *)key;
4219 guint32 offset = GPOINTER_TO_UINT (value);
4222 size = mono_type_size (field->type, &align);
4223 do_free_special_slot (offset, size);
4227 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4229 mono_threads_lock ();
4231 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4233 mono_threads_unlock ();
4237 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4239 /* Only ever called for ThreadLocal instances */
4240 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
4242 mono_threads_lock ();
4243 do_free_special_slot (offset, size);
4244 mono_threads_unlock ();
4248 static void CALLBACK dummy_apc (ULONG_PTR param)
4254 * mono_thread_execute_interruption
4256 * Performs the operation that the requested thread state requires (abort,
4259 static MonoException*
4260 mono_thread_execute_interruption (void)
4262 MonoInternalThread *thread = mono_thread_internal_current ();
4264 LOCK_THREAD (thread);
4266 /* MonoThread::interruption_requested can only be changed with atomics */
4267 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4268 /* this will consume pending APC calls */
4270 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4272 InterlockedDecrement (&thread_interruption_requested);
4274 /* Clear the interrupted flag of the thread so it can wait again */
4275 mono_thread_info_clear_self_interrupt ();
4278 if ((thread->state & ThreadState_AbortRequested) != 0) {
4279 UNLOCK_THREAD (thread);
4280 if (thread->abort_exc == NULL) {
4282 * This might be racy, but it has to be called outside the lock
4283 * since it calls managed code.
4285 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4287 return thread->abort_exc;
4289 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4290 self_suspend_internal (thread);
4293 else if ((thread->state & ThreadState_StopRequested) != 0) {
4294 /* FIXME: do this through the JIT? */
4296 UNLOCK_THREAD (thread);
4298 mono_thread_exit ();
4300 } else if (thread->pending_exception) {
4303 exc = thread->pending_exception;
4304 thread->pending_exception = NULL;
4306 UNLOCK_THREAD (thread);
4308 } else if (thread->thread_interrupt_requested) {
4310 thread->thread_interrupt_requested = FALSE;
4311 UNLOCK_THREAD (thread);
4313 return(mono_get_exception_thread_interrupted ());
4316 UNLOCK_THREAD (thread);
4322 * mono_thread_request_interruption
4324 * A signal handler can call this method to request the interruption of a
4325 * thread. The result of the interruption will depend on the current state of
4326 * the thread. If the result is an exception that needs to be throw, it is
4327 * provided as return value.
4330 mono_thread_request_interruption (gboolean running_managed)
4332 MonoInternalThread *thread = mono_thread_internal_current ();
4334 /* The thread may already be stopping */
4339 if (thread->interrupt_on_stop &&
4340 thread->state & ThreadState_StopRequested &&
4341 thread->state & ThreadState_Background)
4345 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4347 InterlockedIncrement (&thread_interruption_requested);
4349 if (!running_managed || is_running_protected_wrapper ()) {
4350 /* Can't stop while in unmanaged code. Increase the global interruption
4351 request count. When exiting the unmanaged method the count will be
4352 checked and the thread will be interrupted. */
4354 if (mono_thread_notify_pending_exc_fn && !running_managed)
4355 /* The JIT will notify the thread about the interruption */
4356 /* This shouldn't take any locks */
4357 mono_thread_notify_pending_exc_fn (NULL);
4359 /* this will awake the thread if it is in WaitForSingleObject
4361 /* Our implementation of this function ignores the func argument */
4363 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4365 mono_thread_info_self_interrupt ();
4370 return mono_thread_execute_interruption ();
4374 /*This function should be called by a thread after it has exited all of
4375 * its handle blocks at interruption time.*/
4377 mono_thread_resume_interruption (void)
4379 MonoInternalThread *thread = mono_thread_internal_current ();
4380 gboolean still_aborting;
4382 /* The thread may already be stopping */
4386 LOCK_THREAD (thread);
4387 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4388 UNLOCK_THREAD (thread);
4390 /*This can happen if the protected block called Thread::ResetAbort*/
4391 if (!still_aborting)
4394 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4396 InterlockedIncrement (&thread_interruption_requested);
4398 mono_thread_info_self_interrupt ();
4400 return mono_thread_execute_interruption ();
4403 gboolean mono_thread_interruption_requested ()
4405 if (thread_interruption_requested) {
4406 MonoInternalThread *thread = mono_thread_internal_current ();
4407 /* The thread may already be stopping */
4409 return (thread->interruption_requested);
4414 static MonoException*
4415 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4417 MonoInternalThread *thread = mono_thread_internal_current ();
4419 /* The thread may already be stopping */
4423 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4424 MonoException* exc = mono_thread_execute_interruption ();
4432 * Performs the interruption of the current thread, if one has been requested,
4433 * and the thread is not running a protected wrapper.
4434 * Return the exception which needs to be thrown, if any.
4437 mono_thread_interruption_checkpoint (void)
4439 return mono_thread_interruption_checkpoint_request (FALSE);
4443 * Performs the interruption of the current thread, if one has been requested.
4444 * Return the exception which needs to be thrown, if any.
4447 mono_thread_force_interruption_checkpoint_noraise (void)
4449 return mono_thread_interruption_checkpoint_request (TRUE);
4453 * Performs the interruption of the current thread, if one has been requested.
4454 * Throw the exception which needs to be thrown, if any.
4457 mono_thread_force_interruption_checkpoint (void)
4461 ex = mono_thread_interruption_checkpoint_request (TRUE);
4463 mono_raise_exception (ex);
4467 * mono_thread_get_and_clear_pending_exception:
4469 * Return any pending exceptions for the current thread and clear it as a side effect.
4472 mono_thread_get_and_clear_pending_exception (void)
4474 MonoInternalThread *thread = mono_thread_internal_current ();
4476 /* The thread may already be stopping */
4480 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4481 return mono_thread_execute_interruption ();
4484 if (thread->pending_exception) {
4485 MonoException *exc = thread->pending_exception;
4487 thread->pending_exception = NULL;
4495 * mono_set_pending_exception:
4497 * Set the pending exception of the current thread to EXC.
4498 * The exception will be thrown when execution returns to managed code.
4501 mono_set_pending_exception (MonoException *exc)
4503 MonoInternalThread *thread = mono_thread_internal_current ();
4505 /* The thread may already be stopping */
4509 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4511 mono_thread_request_interruption (FALSE);
4515 * mono_thread_interruption_request_flag:
4517 * Returns the address of a flag that will be non-zero if an interruption has
4518 * been requested for a thread. The thread to interrupt may not be the current
4519 * thread, so an additional call to mono_thread_interruption_requested() or
4520 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4523 gint32* mono_thread_interruption_request_flag ()
4525 return &thread_interruption_requested;
4529 mono_thread_init_apartment_state (void)
4532 MonoInternalThread* thread = mono_thread_internal_current ();
4534 /* Positive return value indicates success, either
4535 * S_OK if this is first CoInitialize call, or
4536 * S_FALSE if CoInitialize already called, but with same
4537 * threading model. A negative value indicates failure,
4538 * probably due to trying to change the threading model.
4540 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4541 ? COINIT_APARTMENTTHREADED
4542 : COINIT_MULTITHREADED) < 0) {
4543 thread->apartment_state = ThreadApartmentState_Unknown;
4549 mono_thread_cleanup_apartment_state (void)
4552 MonoInternalThread* thread = mono_thread_internal_current ();
4554 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4561 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4563 LOCK_THREAD (thread);
4564 thread->state |= state;
4565 UNLOCK_THREAD (thread);
4569 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4571 LOCK_THREAD (thread);
4572 thread->state &= ~state;
4573 UNLOCK_THREAD (thread);
4577 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4579 gboolean ret = FALSE;
4581 LOCK_THREAD (thread);
4583 if ((thread->state & test) != 0) {
4587 UNLOCK_THREAD (thread);
4592 static gboolean has_tls_get = FALSE;
4595 mono_runtime_set_has_tls_get (gboolean val)
4601 mono_runtime_has_tls_get (void)
4607 self_interrupt_thread (void *_unused)
4609 MonoThreadInfo *info = mono_thread_info_current ();
4610 MonoException *exc = mono_thread_execute_interruption ();
4611 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4612 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. */
4613 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4617 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4621 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4625 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4627 MonoJitInfo **dest = (MonoJitInfo **)data;
4633 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4635 MonoJitInfo *ji = NULL;
4638 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4643 MonoInternalThread *thread;
4644 gboolean install_async_abort;
4645 MonoThreadInfoInterruptToken *interrupt_token;
4648 static SuspendThreadResult
4649 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4651 AbortThreadData *data = (AbortThreadData *)ud;
4652 MonoInternalThread *thread = data->thread;
4653 MonoJitInfo *ji = NULL;
4654 gboolean protected_wrapper;
4655 gboolean running_managed;
4657 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4658 return MonoResumeThread;
4660 /*someone is already interrupting it*/
4661 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4662 return MonoResumeThread;
4664 InterlockedIncrement (&thread_interruption_requested);
4666 ji = mono_thread_info_get_last_managed (info);
4667 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4668 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4670 if (!protected_wrapper && running_managed) {
4671 /*We are in managed code*/
4672 /*Set the thread to call */
4673 if (data->install_async_abort)
4674 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4675 return MonoResumeThread;
4677 if (mono_thread_notify_pending_exc_fn)
4678 /* The JIT will notify the thread about the interruption */
4679 mono_thread_notify_pending_exc_fn (info);
4682 * This will cause waits to be broken.
4683 * It will also prevent the thread from entering a wait, so if the thread returns
4684 * from the wait before it receives the abort signal, it will just spin in the wait
4685 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4688 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4690 return MonoResumeThread;
4695 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4697 AbortThreadData data = { 0 };
4698 data.thread = thread;
4699 data.install_async_abort = install_async_abort;
4702 FIXME this is insanely broken, it doesn't cause interruption to happen
4703 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4705 if (thread == mono_thread_internal_current ()) {
4706 /* Do it synchronously */
4707 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4709 mono_raise_exception (exc);
4711 mono_thread_info_self_interrupt ();
4716 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_critical, &data);
4717 if (data.interrupt_token)
4718 mono_thread_info_finish_interrupt (data.interrupt_token);
4719 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4723 MonoInternalThread *thread;
4725 MonoThreadInfoInterruptToken *interrupt_token;
4726 } SuspendThreadData;
4728 static SuspendThreadResult
4729 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4731 SuspendThreadData *data = (SuspendThreadData *)ud;
4732 MonoInternalThread *thread = data->thread;
4733 MonoJitInfo *ji = NULL;
4734 gboolean protected_wrapper;
4735 gboolean running_managed;
4737 ji = mono_thread_info_get_last_managed (info);
4738 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4739 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4741 if (running_managed && !protected_wrapper) {
4742 thread->state &= ~ThreadState_SuspendRequested;
4743 thread->state |= ThreadState_Suspended;
4744 return KeepSuspended;
4746 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4747 InterlockedIncrement (&thread_interruption_requested);
4748 if (data->interrupt)
4749 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4751 if (mono_thread_notify_pending_exc_fn && !running_managed)
4752 /* The JIT will notify the thread about the interruption */
4753 mono_thread_notify_pending_exc_fn (info);
4754 return MonoResumeThread;
4759 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4761 LOCK_THREAD (thread);
4762 if (thread == mono_thread_internal_current ()) {
4763 mono_thread_info_begin_self_suspend ();
4764 //XXX replace this with better named functions
4765 thread->state &= ~ThreadState_SuspendRequested;
4766 thread->state |= ThreadState_Suspended;
4767 UNLOCK_THREAD (thread);
4768 mono_thread_info_end_self_suspend ();
4770 SuspendThreadData data = { 0 };
4771 data.thread = thread;
4772 data.interrupt = interrupt;
4774 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, suspend_thread_critical, &data);
4775 if (data.interrupt_token)
4776 mono_thread_info_finish_interrupt (data.interrupt_token);
4777 UNLOCK_THREAD (thread);
4781 /*This is called with @thread synch_cs held and it must release it*/
4783 self_suspend_internal (MonoInternalThread *thread)
4785 mono_thread_info_begin_self_suspend ();
4786 thread->state &= ~ThreadState_SuspendRequested;
4787 thread->state |= ThreadState_Suspended;
4788 UNLOCK_THREAD (thread);
4789 mono_thread_info_end_self_suspend ();
4794 * mono_thread_is_foreign:
4795 * @thread: the thread to query
4797 * This function allows one to determine if a thread was created by the mono runtime and has
4798 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4800 * Returns: true if @thread was not created by the runtime.
4803 mono_thread_is_foreign (MonoThread *thread)
4805 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4806 return info->runtime_thread == FALSE;
4810 * mono_add_joinable_thread:
4812 * Add TID to the list of joinable threads.
4813 * LOCKING: Acquires the threads lock.
4816 mono_threads_add_joinable_thread (gpointer tid)
4820 * We cannot detach from threads because it causes problems like
4821 * 2fd16f60/r114307. So we collect them and join them when
4822 * we have time (in he finalizer thread).
4824 joinable_threads_lock ();
4825 if (!joinable_threads)
4826 joinable_threads = g_hash_table_new (NULL, NULL);
4827 g_hash_table_insert (joinable_threads, tid, tid);
4828 joinable_thread_count ++;
4829 joinable_threads_unlock ();
4831 mono_gc_finalize_notify ();
4836 * mono_threads_join_threads:
4838 * Join all joinable threads. This is called from the finalizer thread.
4839 * LOCKING: Acquires the threads lock.
4842 mono_threads_join_threads (void)
4845 GHashTableIter iter;
4852 if (!joinable_thread_count)
4856 joinable_threads_lock ();
4858 if (g_hash_table_size (joinable_threads)) {
4859 g_hash_table_iter_init (&iter, joinable_threads);
4860 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4861 thread = (pthread_t)tid;
4862 g_hash_table_remove (joinable_threads, key);
4863 joinable_thread_count --;
4866 joinable_threads_unlock ();
4868 if (thread != pthread_self ())
4869 /* This shouldn't block */
4870 pthread_join (thread, NULL);
4881 * Wait for thread TID to exit.
4882 * LOCKING: Acquires the threads lock.
4885 mono_thread_join (gpointer tid)
4889 gboolean found = FALSE;
4891 joinable_threads_lock ();
4892 if (!joinable_threads)
4893 joinable_threads = g_hash_table_new (NULL, NULL);
4894 if (g_hash_table_lookup (joinable_threads, tid)) {
4895 g_hash_table_remove (joinable_threads, tid);
4896 joinable_thread_count --;
4899 joinable_threads_unlock ();
4902 thread = (pthread_t)tid;
4903 pthread_join (thread, NULL);
4908 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4910 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4911 mono_thread_interruption_checkpoint ();
4914 static inline gboolean
4915 is_appdomainunloaded_exception (MonoClass *klass)
4917 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4919 if (!app_domain_unloaded_exception_klass)
4920 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4921 g_assert (app_domain_unloaded_exception_klass);
4923 return klass == app_domain_unloaded_exception_klass;
4926 static inline gboolean
4927 is_threadabort_exception (MonoClass *klass)
4929 return klass == mono_defaults.threadabortexception_class;
4933 mono_thread_internal_unhandled_exception (MonoObject* exc)
4935 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4936 MonoClass *klass = exc->vtable->klass;
4937 if (is_threadabort_exception (klass)) {
4938 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4939 } else if (!is_appdomainunloaded_exception (klass)) {
4940 mono_unhandled_exception (exc);
4941 if (mono_environment_exitcode_get () == 1)
4948 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
4950 mono_threads_get_thread_dump (out_threads, out_stack_traces);