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>
45 #include <mono/metadata/reflection-internals.h>
51 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
52 #define USE_TKILL_ON_ANDROID 1
55 #ifdef PLATFORM_ANDROID
58 #ifdef USE_TKILL_ON_ANDROID
59 extern int tkill (pid_t tid, int signal);
63 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
64 #define THREAD_DEBUG(a)
65 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
66 #define THREAD_WAIT_DEBUG(a)
67 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
68 #define LIBGC_DEBUG(a)
70 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
71 #define SPIN_LOCK(i) do { \
72 if (SPIN_TRYLOCK (i)) \
76 #define SPIN_UNLOCK(i) i = 0
78 #define LOCK_THREAD(thread) lock_thread((thread))
79 #define UNLOCK_THREAD(thread) unlock_thread((thread))
81 /* Provide this for systems with glib < 2.6 */
82 #ifndef G_GSIZE_FORMAT
83 # if GLIB_SIZEOF_LONG == 8
84 # define G_GSIZE_FORMAT "lu"
86 # define G_GSIZE_FORMAT "u"
92 guint32 (*func)(void *);
108 typedef struct _StaticDataFreeList StaticDataFreeList;
109 struct _StaticDataFreeList {
110 StaticDataFreeList *next;
118 StaticDataFreeList *freelist;
121 /* Number of cached culture objects in the MonoThread->cached_culture_info array
122 * (per-type): we use the first NUM entries for CultureInfo and the last for
123 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
125 #define NUM_CACHED_CULTURES 4
126 #define CULTURES_START_IDX 0
127 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
129 /* Controls access to the 'threads' hash table */
130 static void mono_threads_lock (void);
131 static void mono_threads_unlock (void);
132 static MonoCoopMutex threads_mutex;
134 /* Controls access to the 'joinable_threads' hash table */
135 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
136 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
137 static mono_mutex_t joinable_threads_mutex;
139 /* Holds current status of static data heap */
140 static StaticDataInfo thread_static_info;
141 static StaticDataInfo context_static_info;
143 /* The hash of existing threads (key is thread ID, value is
144 * MonoInternalThread*) that need joining before exit
146 static MonoGHashTable *threads=NULL;
148 /* List of app context GC handles.
149 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
151 static GHashTable *contexts = NULL;
153 /* Cleanup queue for contexts. */
154 static MonoReferenceQueue *context_queue;
157 * Threads which are starting up and they are not in the 'threads' hash yet.
158 * When handle_store is called for a thread, it will be removed from this hash table.
159 * Protected by mono_threads_lock ().
161 static MonoGHashTable *threads_starting_up = NULL;
163 /* The TLS key that holds the MonoObject assigned to each thread */
164 static MonoNativeTlsKey current_object_key;
167 /* Protected by the threads lock */
168 static GHashTable *joinable_threads;
169 static int joinable_thread_count;
171 #ifdef MONO_HAVE_FAST_TLS
172 /* we need to use both the Tls* functions and __thread because
173 * the gc needs to see all the threads
175 MONO_FAST_TLS_DECLARE(tls_current_object);
176 #define SET_CURRENT_OBJECT(x) do { \
177 MONO_FAST_TLS_SET (tls_current_object, x); \
178 mono_native_tls_set_value (current_object_key, x); \
180 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
182 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
183 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
186 /* function called at thread start */
187 static MonoThreadStartCB mono_thread_start_cb = NULL;
189 /* function called at thread attach */
190 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
192 /* function called at thread cleanup */
193 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
195 /* The default stack size for each thread */
196 static guint32 default_stacksize = 0;
197 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
199 static void thread_adjust_static_data (MonoInternalThread *thread);
200 static void context_adjust_static_data (MonoAppContext *ctx);
201 static void mono_free_static_data (gpointer* static_data);
202 static void mono_init_static_data_info (StaticDataInfo *static_data);
203 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
204 static gboolean mono_thread_resume (MonoInternalThread* thread);
205 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
206 static void self_abort_internal (void);
207 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
208 static void self_suspend_internal (void);
210 static MonoException* mono_thread_execute_interruption (void);
211 static void ref_stack_destroy (gpointer rs);
213 /* Spin lock for InterlockedXXX 64 bit functions */
214 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
215 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
216 static mono_mutex_t interlocked_mutex;
218 /* global count of thread interruptions requested */
219 static gint32 thread_interruption_requested = 0;
221 /* Event signaled when a thread changes its background mode */
222 static HANDLE background_change_event;
224 static gboolean shutting_down = FALSE;
226 static gint32 managed_thread_id_counter = 0;
229 mono_threads_lock (void)
231 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
235 mono_threads_unlock (void)
237 mono_locks_coop_release (&threads_mutex, ThreadsLock);
242 get_next_managed_thread_id (void)
244 return InterlockedIncrement (&managed_thread_id_counter);
248 mono_thread_get_tls_key (void)
250 return current_object_key;
254 mono_thread_get_tls_offset (void)
257 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
261 static inline MonoNativeThreadId
262 thread_get_tid (MonoInternalThread *thread)
264 /* We store the tid as a guint64 to keep the object layout constant between platforms */
265 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
268 /* handle_store() and handle_remove() manage the array of threads that
269 * still need to be waited for when the main thread exits.
271 * If handle_store() returns FALSE the thread must not be started
272 * because Mono is shutting down.
274 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
276 mono_threads_lock ();
278 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
280 if (threads_starting_up)
281 mono_g_hash_table_remove (threads_starting_up, thread);
283 if (shutting_down && !force_attach) {
284 mono_threads_unlock ();
289 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
290 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
293 /* We don't need to duplicate thread->handle, because it is
294 * only closed when the thread object is finalized by the GC.
296 g_assert (thread->internal_thread);
297 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
298 thread->internal_thread);
300 mono_threads_unlock ();
305 static gboolean handle_remove(MonoInternalThread *thread)
308 gsize tid = thread->tid;
310 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
312 mono_threads_lock ();
315 /* We have to check whether the thread object for the
316 * tid is still the same in the table because the
317 * thread might have been destroyed and the tid reused
318 * in the meantime, in which case the tid would be in
319 * the table, but with another thread object.
321 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
322 mono_g_hash_table_remove (threads, (gpointer)tid);
331 mono_threads_unlock ();
333 /* Don't close the handle here, wait for the object finalizer
334 * to do it. Otherwise, the following race condition applies:
336 * 1) Thread exits (and handle_remove() closes the handle)
338 * 2) Some other handle is reassigned the same slot
340 * 3) Another thread tries to join the first thread, and
341 * blocks waiting for the reassigned handle to be signalled
342 * (which might never happen). This is possible, because the
343 * thread calling Join() still has a reference to the first
349 static void ensure_synch_cs_set (MonoInternalThread *thread)
351 MonoCoopMutex *synch_cs;
353 if (thread->synch_cs != NULL) {
357 synch_cs = g_new0 (MonoCoopMutex, 1);
358 mono_coop_mutex_init_recursive (synch_cs);
360 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
361 synch_cs, NULL) != NULL) {
362 /* Another thread must have installed this CS */
363 mono_coop_mutex_destroy (synch_cs);
369 lock_thread (MonoInternalThread *thread)
371 if (!thread->synch_cs)
372 ensure_synch_cs_set (thread);
374 g_assert (thread->synch_cs);
376 mono_coop_mutex_lock (thread->synch_cs);
380 unlock_thread (MonoInternalThread *thread)
382 mono_coop_mutex_unlock (thread->synch_cs);
386 * NOTE: this function can be called also for threads different from the current one:
387 * make sure no code called from it will ever assume it is run on the thread that is
388 * getting cleaned up.
390 static void thread_cleanup (MonoInternalThread *thread)
392 g_assert (thread != NULL);
394 if (thread->abort_state_handle) {
395 mono_gchandle_free (thread->abort_state_handle);
396 thread->abort_state_handle = 0;
398 thread->abort_exc = NULL;
399 thread->current_appcontext = NULL;
402 * This is necessary because otherwise we might have
403 * cross-domain references which will not get cleaned up when
404 * the target domain is unloaded.
406 if (thread->cached_culture_info) {
408 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
409 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
413 * thread->synch_cs can be NULL if this was called after
414 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
415 * This can happen only during shutdown.
416 * The shutting_down flag is not always set, so we can't assert on it.
418 if (thread->synch_cs)
419 LOCK_THREAD (thread);
421 thread->state |= ThreadState_Stopped;
422 thread->state &= ~ThreadState_Background;
424 if (thread->synch_cs)
425 UNLOCK_THREAD (thread);
428 An interruption request has leaked to cleanup. Adjust the global counter.
430 This can happen is the abort source thread finds the abortee (this) thread
431 in unmanaged code. If this thread never trips back to managed code or check
432 the local flag it will be left set and positively unbalance the global counter.
434 Leaving the counter unbalanced will cause a performance degradation since all threads
435 will now keep checking their local flags all the time.
437 if (InterlockedExchange (&thread->interruption_requested, 0))
438 InterlockedDecrement (&thread_interruption_requested);
440 /* if the thread is not in the hash it has been removed already */
441 if (!handle_remove (thread)) {
442 if (thread == mono_thread_internal_current ()) {
443 mono_domain_unset ();
444 mono_memory_barrier ();
446 /* This needs to be called even if handle_remove () fails */
447 if (mono_thread_cleanup_fn)
448 mono_thread_cleanup_fn (thread_get_tid (thread));
451 mono_release_type_locks (thread);
453 mono_profiler_thread_end (thread->tid);
455 if (thread == mono_thread_internal_current ()) {
457 * This will signal async signal handlers that the thread has exited.
458 * The profiler callback needs this to be set, so it cannot be done earlier.
460 mono_domain_unset ();
461 mono_memory_barrier ();
464 if (thread == mono_thread_internal_current ())
465 mono_thread_pop_appdomain_ref ();
467 thread->cached_culture_info = NULL;
469 mono_free_static_data (thread->static_data);
470 thread->static_data = NULL;
471 ref_stack_destroy (thread->appdomain_refs);
472 thread->appdomain_refs = NULL;
474 if (mono_thread_cleanup_fn)
475 mono_thread_cleanup_fn (thread_get_tid (thread));
477 if (mono_gc_is_moving ()) {
478 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
479 thread->thread_pinning_ref = NULL;
485 * A special static data offset (guint32) consists of 3 parts:
487 * [0] 6-bit index into the array of chunks.
488 * [6] 25-bit offset into the array.
489 * [31] Bit indicating thread or context static.
494 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
505 } SpecialStaticOffset;
507 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
508 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
510 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
511 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
512 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
513 (((SpecialStaticOffset *) &(x))->fields.f)
516 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
518 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
520 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
521 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
523 return ((char *) thread->static_data [idx]) + off;
527 get_context_static_data (MonoAppContext *ctx, guint32 offset)
529 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
531 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
532 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
534 return ((char *) ctx->static_data [idx]) + off;
538 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
540 static MonoClassField *current_thread_field = NULL;
544 if (!current_thread_field) {
545 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
546 g_assert (current_thread_field);
549 mono_class_vtable (domain, mono_defaults.thread_class);
550 mono_domain_lock (domain);
551 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
552 mono_domain_unlock (domain);
555 return (MonoThread **)get_thread_static_data (thread, offset);
559 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
561 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
563 g_assert (current->obj.vtable->domain == domain);
565 g_assert (!*current_thread_ptr);
566 *current_thread_ptr = current;
570 create_thread_object (MonoDomain *domain, MonoError *error)
572 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
573 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, error);
578 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal, MonoError *error)
582 thread = create_thread_object (domain, error);
583 if (!mono_error_ok (error))
586 MONO_OBJECT_SETREF (thread, internal_thread, internal);
591 static MonoInternalThread*
592 create_internal_thread (MonoError *error)
594 MonoInternalThread *thread;
597 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
598 thread = (MonoInternalThread*) mono_object_new_mature (vt, error);
599 if (!mono_error_ok (error))
602 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
603 mono_coop_mutex_init_recursive (thread->synch_cs);
605 thread->apartment_state = ThreadApartmentState_Unknown;
606 thread->managed_id = get_next_managed_thread_id ();
607 if (mono_gc_is_moving ()) {
608 thread->thread_pinning_ref = thread;
609 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
616 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
619 MonoDomain *domain = mono_get_root_domain ();
621 if (!candidate || candidate->obj.vtable->domain != domain) {
622 candidate = new_thread_with_internal (domain, thread, &error);
623 mono_error_raise_exception (&error); /* FIXME don't raise here */
625 set_current_thread_for_domain (domain, thread, candidate);
626 g_assert (!thread->root_domain_thread);
627 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
630 static guint32 WINAPI start_wrapper_internal(void *data)
632 MonoThreadInfo *info;
633 StartInfo *start_info = (StartInfo *)data;
634 guint32 (*start_func)(void *);
638 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
641 MonoInternalThread *internal = start_info->obj->internal_thread;
642 MonoObject *start_delegate = start_info->delegate;
643 MonoDomain *domain = start_info->obj->obj.vtable->domain;
645 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
647 /* We can be sure start_info->obj->tid and
648 * start_info->obj->handle have been set, because the thread
649 * was created suspended, and these values were set before the
653 info = mono_thread_info_current ();
655 internal->thread_info = info;
656 internal->small_id = info->small_id;
660 SET_CURRENT_OBJECT (internal);
662 /* Every thread references the appdomain which created it */
663 mono_thread_push_appdomain_ref (domain);
665 if (!mono_domain_set (domain, FALSE)) {
666 /* No point in raising an appdomain_unloaded exception here */
667 /* FIXME: Cleanup here */
668 mono_thread_pop_appdomain_ref ();
672 start_func = start_info->func;
673 start_arg = start_info->obj->start_obj;
675 start_arg = start_info->start_arg;
677 /* We have to do this here because mono_thread_new_init()
678 requires that root_domain_thread is set up. */
679 thread_adjust_static_data (internal);
680 init_root_domain_thread (internal, start_info->obj);
682 /* This MUST be called before any managed code can be
683 * executed, as it calls the callback function that (for the
684 * jit) sets the lmf marker.
686 mono_thread_new_init (tid, &tid, start_func);
687 internal->stack_ptr = &tid;
688 if (domain != mono_get_root_domain ())
689 set_current_thread_for_domain (domain, internal, start_info->obj);
691 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
693 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
695 /* On 2.0 profile (and higher), set explicitly since state might have been
697 if (internal->apartment_state == ThreadApartmentState_Unknown)
698 internal->apartment_state = ThreadApartmentState_MTA;
700 mono_thread_init_apartment_state ();
702 if(internal->start_notify!=NULL) {
703 /* Let the thread that called Start() know we're
706 ReleaseSemaphore (internal->start_notify, 1, NULL);
710 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
714 * Call this after calling start_notify, since the profiler callback might want
715 * to lock the thread, and the lock is held by thread_start () which waits for
718 mono_profiler_thread_start (tid);
720 /* if the name was set before starting, we didn't invoke the profiler callback */
721 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
722 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
723 mono_profiler_thread_name (internal->tid, tname);
726 /* start_func is set only for unmanaged start functions */
728 start_func (start_arg);
731 g_assert (start_delegate != NULL);
732 args [0] = start_arg;
733 /* we may want to handle the exception here. See comment below on unhandled exceptions */
734 mono_runtime_delegate_invoke (start_delegate, args, NULL);
737 /* If the thread calls ExitThread at all, this remaining code
738 * will not be executed, but the main thread will eventually
739 * call thread_cleanup() on this thread's behalf.
742 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
744 /* Do any cleanup needed for apartment state. This
745 * cannot be done in thread_cleanup since thread_cleanup could be
746 * called for a thread other than the current thread.
747 * mono_thread_cleanup_apartment_state cleans up apartment
748 * for the current thead */
749 mono_thread_cleanup_apartment_state ();
751 thread_cleanup (internal);
755 /* Remove the reference to the thread object in the TLS data,
756 * so the thread object can be finalized. This won't be
757 * reached if the thread threw an uncaught exception, so those
758 * thread handles will stay referenced :-( (This is due to
759 * missing support for scanning thread-specific data in the
760 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
763 SET_CURRENT_OBJECT (NULL);
768 static guint32 WINAPI start_wrapper(void *data)
772 /* Avoid scanning the frames above this frame during a GC */
773 mono_gc_set_stack_end ((void*)&dummy);
775 return start_wrapper_internal (data);
781 * Common thread creation code.
782 * LOCKING: Acquires the threads lock.
785 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
786 gboolean throw_on_failure)
788 HANDLE thread_handle;
789 MonoNativeThreadId tid;
790 guint32 create_flags;
793 * Join joinable threads to prevent running out of threads since the finalizer
794 * thread might be blocked/backlogged.
796 mono_threads_join_threads ();
798 mono_threads_lock ();
801 mono_threads_unlock ();
804 if (threads_starting_up == NULL) {
805 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
806 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
808 mono_g_hash_table_insert (threads_starting_up, thread, thread);
809 mono_threads_unlock ();
811 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
812 if (!internal->start_notify) {
813 mono_threads_lock ();
814 mono_g_hash_table_remove (threads_starting_up, thread);
815 mono_threads_unlock ();
816 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
822 stack_size = default_stacksize_for_thread (internal);
824 /* Create suspended, so we can do some housekeeping before the thread
827 create_flags = CREATE_SUSPENDED;
829 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
830 stack_size, create_flags, &tid);
832 if (thread_handle == NULL) {
833 /* The thread couldn't be created, so throw an exception */
834 mono_threads_lock ();
835 mono_g_hash_table_remove (threads_starting_up, thread);
836 mono_threads_unlock ();
838 if (throw_on_failure)
839 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
841 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
844 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
846 internal->handle = thread_handle;
847 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
849 internal->threadpool_thread = threadpool_thread;
850 if (threadpool_thread)
851 mono_thread_set_state (internal, ThreadState_Background);
853 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
855 /* Only store the handle when the thread is about to be
856 * launched, to avoid the main thread deadlocking while trying
857 * to clean up a thread that will never be signalled.
859 if (!handle_store (thread, FALSE))
862 mono_thread_info_resume (tid);
864 if (internal->start_notify) {
866 * Wait for the thread to set up its TLS data etc, so
867 * theres no potential race condition if someone tries
868 * to look up the data believing the thread has
871 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));
873 MONO_PREPARE_BLOCKING;
874 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
875 MONO_FINISH_BLOCKING;
877 CloseHandle (internal->start_notify);
878 internal->start_notify = NULL;
881 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));
886 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
888 if (mono_thread_start_cb) {
889 mono_thread_start_cb (tid, stack_start, func);
893 void mono_threads_set_default_stacksize (guint32 stacksize)
895 default_stacksize = stacksize;
898 guint32 mono_threads_get_default_stacksize (void)
900 return default_stacksize;
904 * mono_thread_create_internal:
906 * ARG should not be a GC reference.
909 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
913 MonoInternalThread *internal;
914 StartInfo *start_info;
917 thread = create_thread_object (domain, &error);
918 mono_error_raise_exception (&error); /* FIXME don't raise here */
920 internal = create_internal_thread (&error);
921 mono_error_raise_exception (&error); /* FIXME don't raise here */
923 MONO_OBJECT_SETREF (thread, internal_thread, internal);
925 start_info = g_new0 (StartInfo, 1);
926 start_info->func = (guint32 (*)(void *))func;
927 start_info->obj = thread;
928 start_info->start_arg = arg;
930 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
934 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
935 #ifndef MONO_CROSS_COMPILE
936 if (mono_check_corlib_version () == NULL)
937 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
944 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
946 mono_thread_create_internal (domain, func, arg, FALSE, 0);
950 mono_thread_attach (MonoDomain *domain)
953 MonoThread *thread = mono_thread_attach_full (domain, FALSE, &error);
954 mono_error_raise_exception (&error);
960 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach, MonoError *error)
962 MonoThreadInfo *info;
963 MonoInternalThread *thread;
964 MonoThread *current_thread;
965 HANDLE thread_handle;
966 MonoNativeThreadId tid;
968 mono_error_init (error);
970 if ((thread = mono_thread_internal_current ())) {
971 if (domain != mono_domain_get ())
972 mono_domain_set (domain, TRUE);
973 /* Already attached */
974 return mono_thread_current ();
977 if (!mono_gc_register_thread (&domain)) {
978 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 ());
981 thread = create_internal_thread (error);
982 if (!mono_error_ok (error))
985 thread_handle = mono_thread_info_open_handle ();
986 g_assert (thread_handle);
988 tid=mono_native_thread_id_get ();
990 thread->handle = thread_handle;
991 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
992 thread->stack_ptr = &tid;
994 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
996 info = mono_thread_info_current ();
998 thread->thread_info = info;
999 thread->small_id = info->small_id;
1001 current_thread = new_thread_with_internal (domain, thread, error);
1002 if (!mono_error_ok (error))
1005 if (!handle_store (current_thread, force_attach)) {
1006 /* Mono is shutting down, so just wait for the end */
1008 mono_thread_info_sleep (10000, NULL);
1011 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
1013 SET_CURRENT_OBJECT (thread);
1014 mono_domain_set (domain, TRUE);
1016 thread_adjust_static_data (thread);
1018 init_root_domain_thread (thread, current_thread);
1019 if (domain != mono_get_root_domain ())
1020 set_current_thread_for_domain (domain, thread, current_thread);
1023 if (mono_thread_attach_cb) {
1027 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1030 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1032 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1035 // FIXME: Need a separate callback
1036 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1038 return current_thread;
1042 mono_thread_detach_internal (MonoInternalThread *thread)
1044 g_return_if_fail (thread != NULL);
1046 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1048 thread_cleanup (thread);
1050 SET_CURRENT_OBJECT (NULL);
1051 mono_domain_unset ();
1053 /* Don't need to CloseHandle this thread, even though we took a
1054 * reference in mono_thread_attach (), because the GC will do it
1055 * when the Thread object is finalised.
1060 mono_thread_detach (MonoThread *thread)
1063 mono_thread_detach_internal (thread->internal_thread);
1067 * mono_thread_detach_if_exiting:
1069 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1070 * This should be used at the end of embedding code which calls into managed code, and which
1071 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1074 mono_thread_detach_if_exiting (void)
1076 if (mono_thread_info_is_exiting ()) {
1077 MonoInternalThread *thread;
1079 thread = mono_thread_internal_current ();
1081 mono_thread_detach_internal (thread);
1082 mono_thread_info_detach ();
1090 MonoInternalThread *thread = mono_thread_internal_current ();
1092 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1094 thread_cleanup (thread);
1095 SET_CURRENT_OBJECT (NULL);
1096 mono_domain_unset ();
1098 /* we could add a callback here for embedders to use. */
1099 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1100 exit (mono_environment_exitcode_get ());
1101 mono_thread_info_exit ();
1105 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1108 MonoInternalThread *internal;
1110 internal = create_internal_thread (&error);
1111 mono_error_raise_exception (&error);
1113 internal->state = ThreadState_Unstarted;
1115 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1119 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1122 StartInfo *start_info;
1123 MonoInternalThread *internal;
1126 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1128 if (!this_obj->internal_thread)
1129 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1130 internal = this_obj->internal_thread;
1132 LOCK_THREAD (internal);
1134 if ((internal->state & ThreadState_Unstarted) == 0) {
1135 UNLOCK_THREAD (internal);
1136 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1140 if ((internal->state & ThreadState_Aborted) != 0) {
1141 UNLOCK_THREAD (internal);
1144 /* This is freed in start_wrapper */
1145 start_info = g_new0 (StartInfo, 1);
1146 start_info->func = NULL;
1147 start_info->start_arg = NULL;
1148 start_info->delegate = start;
1149 start_info->obj = this_obj;
1150 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1152 res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
1154 UNLOCK_THREAD (internal);
1158 internal->state &= ~ThreadState_Unstarted;
1160 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1162 UNLOCK_THREAD (internal);
1163 return internal->handle;
1167 * This is called from the finalizer of the internal thread object.
1170 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1172 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1175 * Since threads keep a reference to their thread object while running, by the time this function is called,
1176 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1177 * when thread_cleanup () can be called after this.
1180 CloseHandle (thread);
1182 if (this_obj->synch_cs) {
1183 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1184 this_obj->synch_cs = NULL;
1185 mono_coop_mutex_destroy (synch_cs);
1189 if (this_obj->name) {
1190 void *name = this_obj->name;
1191 this_obj->name = NULL;
1197 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1200 MonoInternalThread *thread = mono_thread_internal_current ();
1202 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1204 mono_thread_current_check_pending_interrupt ();
1207 gboolean alerted = FALSE;
1209 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1211 res = mono_thread_info_sleep (ms, &alerted);
1213 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1216 MonoException* exc = mono_thread_execute_interruption ();
1218 mono_raise_exception (exc);
1230 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1235 ves_icall_System_Threading_Thread_GetDomainID (void)
1237 return mono_domain_get()->domain_id;
1241 ves_icall_System_Threading_Thread_Yield (void)
1243 return mono_thread_info_yield ();
1247 * mono_thread_get_name:
1249 * Return the name of the thread. NAME_LEN is set to the length of the name.
1250 * Return NULL if the thread has no name. The returned memory is owned by the
1254 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1258 LOCK_THREAD (this_obj);
1260 if (!this_obj->name) {
1264 *name_len = this_obj->name_len;
1265 res = g_new (gunichar2, this_obj->name_len);
1266 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1269 UNLOCK_THREAD (this_obj);
1275 * mono_thread_get_name_utf8:
1277 * Return the name of the thread in UTF-8.
1278 * Return NULL if the thread has no name.
1279 * The returned memory is owned by the caller.
1282 mono_thread_get_name_utf8 (MonoThread *thread)
1287 MonoInternalThread *internal = thread->internal_thread;
1288 if (internal == NULL)
1291 LOCK_THREAD (internal);
1293 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1295 UNLOCK_THREAD (internal);
1301 * mono_thread_get_managed_id:
1303 * Return the Thread.ManagedThreadId value of `thread`.
1304 * Returns -1 if `thread` is NULL.
1307 mono_thread_get_managed_id (MonoThread *thread)
1312 MonoInternalThread *internal = thread->internal_thread;
1313 if (internal == NULL)
1316 int32_t id = internal->managed_id;
1322 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1327 mono_error_init (&error);
1329 LOCK_THREAD (this_obj);
1331 if (!this_obj->name)
1334 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1336 UNLOCK_THREAD (this_obj);
1338 mono_error_raise_exception (&error);
1344 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1346 LOCK_THREAD (this_obj);
1348 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1349 UNLOCK_THREAD (this_obj);
1351 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1354 if (this_obj->name) {
1355 g_free (this_obj->name);
1356 this_obj->name_len = 0;
1359 this_obj->name = g_new (gunichar2, mono_string_length (name));
1360 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1361 this_obj->name_len = mono_string_length (name);
1364 this_obj->name = NULL;
1367 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1369 UNLOCK_THREAD (this_obj);
1371 if (this_obj->name && this_obj->tid) {
1372 char *tname = mono_string_to_utf8 (name);
1373 mono_profiler_thread_name (this_obj->tid, tname);
1374 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1380 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1382 mono_thread_set_name_internal (this_obj, name, TRUE);
1386 * ves_icall_System_Threading_Thread_GetPriority_internal:
1387 * @param this_obj: The MonoInternalThread on which to operate.
1389 * Gets the priority of the given thread.
1390 * @return: The priority of the given thread.
1393 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1396 MonoInternalThread *internal = this_obj->internal_thread;
1398 LOCK_THREAD (internal);
1399 priority = GetThreadPriority (internal->handle) + 2;
1400 UNLOCK_THREAD (internal);
1405 * ves_icall_System_Threading_Thread_SetPriority_internal:
1406 * @param this_obj: The MonoInternalThread on which to operate.
1407 * @param priority: The priority to set.
1409 * Sets the priority of the given thread.
1412 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1414 MonoInternalThread *internal = this_obj->internal_thread;
1416 LOCK_THREAD (internal);
1417 SetThreadPriority (internal->handle, priority - 2);
1418 UNLOCK_THREAD (internal);
1421 /* If the array is already in the requested domain, we just return it,
1422 otherwise we return a copy in that domain. */
1424 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1431 if (mono_object_domain (arr) == domain)
1434 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1435 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1440 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1442 return byte_array_to_domain (arr, mono_get_root_domain ());
1446 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1448 return byte_array_to_domain (arr, mono_domain_get ());
1452 mono_thread_current (void)
1455 MonoDomain *domain = mono_domain_get ();
1456 MonoInternalThread *internal = mono_thread_internal_current ();
1457 MonoThread **current_thread_ptr;
1459 g_assert (internal);
1460 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1462 if (!*current_thread_ptr) {
1463 g_assert (domain != mono_get_root_domain ());
1464 *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
1465 mono_error_raise_exception (&error); /* FIXME don't raise here */
1467 return *current_thread_ptr;
1470 /* Return the thread object belonging to INTERNAL in the current domain */
1472 mono_thread_current_for_thread (MonoInternalThread *internal)
1475 MonoDomain *domain = mono_domain_get ();
1476 MonoThread **current_thread_ptr;
1478 g_assert (internal);
1479 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1481 if (!*current_thread_ptr) {
1482 g_assert (domain != mono_get_root_domain ());
1483 *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
1484 mono_error_raise_exception (&error); /* FIXME don't raise here */
1486 return *current_thread_ptr;
1490 mono_thread_internal_current (void)
1492 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1493 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1498 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1500 MonoInternalThread *thread = this_obj->internal_thread;
1501 HANDLE handle = thread->handle;
1502 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1505 mono_thread_current_check_pending_interrupt ();
1507 LOCK_THREAD (thread);
1509 if ((thread->state & ThreadState_Unstarted) != 0) {
1510 UNLOCK_THREAD (thread);
1512 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1516 UNLOCK_THREAD (thread);
1521 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1523 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1525 MONO_PREPARE_BLOCKING;
1526 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1527 MONO_FINISH_BLOCKING;
1529 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1531 if(ret==WAIT_OBJECT_0) {
1532 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1537 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1543 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1551 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1553 MONO_PREPARE_BLOCKING;
1555 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1557 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1558 MONO_FINISH_BLOCKING;
1560 if (ret != WAIT_IO_COMPLETION)
1563 exc = mono_thread_execute_interruption ();
1565 mono_raise_exception (exc);
1570 /* Re-calculate ms according to the time passed */
1571 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1572 if (diff_ms >= ms) {
1576 wait = ms - diff_ms;
1582 /* FIXME: exitContext isnt documented */
1583 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1589 MonoObject *waitHandle;
1590 MonoInternalThread *thread = mono_thread_internal_current ();
1592 /* Do this WaitSleepJoin check before creating objects */
1593 mono_thread_current_check_pending_interrupt ();
1595 /* We fail in managed if the array has more than 64 elements */
1596 numhandles = (guint32)mono_array_length(mono_handles);
1597 handles = g_new0(HANDLE, numhandles);
1599 for(i = 0; i < numhandles; i++) {
1600 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1601 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1608 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1610 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1612 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1616 if(ret==WAIT_FAILED) {
1617 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
1619 } else if(ret==WAIT_TIMEOUT) {
1620 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
1627 /* FIXME: exitContext isnt documented */
1628 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1630 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1631 uintptr_t numhandles;
1634 MonoObject *waitHandle;
1635 MonoInternalThread *thread = mono_thread_internal_current ();
1637 /* Do this WaitSleepJoin check before creating objects */
1638 mono_thread_current_check_pending_interrupt ();
1640 numhandles = mono_array_length(mono_handles);
1641 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1644 for(i = 0; i < numhandles; i++) {
1645 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1646 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1653 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1655 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1657 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1659 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1662 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1664 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1665 return ret - WAIT_OBJECT_0;
1667 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1668 return ret - WAIT_ABANDONED_0;
1675 /* FIXME: exitContext isnt documented */
1676 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
1679 MonoInternalThread *thread = mono_thread_internal_current ();
1681 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1687 mono_thread_current_check_pending_interrupt ();
1689 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1691 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1693 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1695 if(ret==WAIT_FAILED) {
1696 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
1698 } else if(ret==WAIT_TIMEOUT) {
1699 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
1707 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1710 MonoInternalThread *thread = mono_thread_internal_current ();
1715 mono_thread_current_check_pending_interrupt ();
1717 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1719 MONO_PREPARE_BLOCKING;
1720 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1721 MONO_FINISH_BLOCKING;
1723 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1725 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1728 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1735 mutex = CreateMutex (NULL, owned, NULL);
1737 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1739 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1747 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1748 return(ReleaseMutex (handle));
1751 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1757 *error = ERROR_SUCCESS;
1759 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1761 *error = GetLastError ();
1768 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1775 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1777 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1778 mono_string_chars (name));
1780 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1788 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1792 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1797 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1801 *error = ERROR_SUCCESS;
1803 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1805 *error = GetLastError ();
1811 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1818 event = CreateEvent (NULL, manual, initial, NULL);
1820 event = CreateEvent (NULL, manual, initial,
1821 mono_string_chars (name));
1823 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1831 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1832 return (SetEvent(handle));
1835 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1836 return (ResetEvent(handle));
1840 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1841 CloseHandle (handle);
1844 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1850 *error = ERROR_SUCCESS;
1852 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1854 *error = GetLastError ();
1860 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1862 return InterlockedIncrement (location);
1865 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1867 #if SIZEOF_VOID_P == 4
1868 if (G_UNLIKELY ((size_t)location & 0x7)) {
1870 mono_interlocked_lock ();
1873 mono_interlocked_unlock ();
1877 return InterlockedIncrement64 (location);
1880 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1882 return InterlockedDecrement(location);
1885 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1887 #if SIZEOF_VOID_P == 4
1888 if (G_UNLIKELY ((size_t)location & 0x7)) {
1890 mono_interlocked_lock ();
1893 mono_interlocked_unlock ();
1897 return InterlockedDecrement64 (location);
1900 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1902 return InterlockedExchange(location, value);
1905 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1908 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1909 mono_gc_wbarrier_generic_nostore (location);
1913 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1915 return InterlockedExchangePointer(location, value);
1918 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1920 IntFloatUnion val, ret;
1923 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1929 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1931 #if SIZEOF_VOID_P == 4
1932 if (G_UNLIKELY ((size_t)location & 0x7)) {
1934 mono_interlocked_lock ();
1937 mono_interlocked_unlock ();
1941 return InterlockedExchange64 (location, value);
1945 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1947 LongDoubleUnion val, ret;
1950 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1955 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1957 return InterlockedCompareExchange(location, value, comparand);
1960 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1962 gint32 r = InterlockedCompareExchange(location, value, comparand);
1963 *success = r == comparand;
1967 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1970 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1971 mono_gc_wbarrier_generic_nostore (location);
1975 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1977 return InterlockedCompareExchangePointer(location, value, comparand);
1980 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1982 IntFloatUnion val, ret, cmp;
1985 cmp.fval = comparand;
1986 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1992 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1994 #if SIZEOF_VOID_P == 8
1995 LongDoubleUnion val, comp, ret;
1998 comp.fval = comparand;
1999 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2005 mono_interlocked_lock ();
2007 if (old == comparand)
2009 mono_interlocked_unlock ();
2016 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2018 #if SIZEOF_VOID_P == 4
2019 if (G_UNLIKELY ((size_t)location & 0x7)) {
2021 mono_interlocked_lock ();
2023 if (old == comparand)
2025 mono_interlocked_unlock ();
2029 return InterlockedCompareExchange64 (location, value, comparand);
2033 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2036 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2037 mono_gc_wbarrier_generic_nostore (location);
2042 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2045 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2046 mono_gc_wbarrier_generic_nostore (location);
2051 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2053 return InterlockedAdd (location, value);
2057 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2059 #if SIZEOF_VOID_P == 4
2060 if (G_UNLIKELY ((size_t)location & 0x7)) {
2062 mono_interlocked_lock ();
2065 mono_interlocked_unlock ();
2069 return InterlockedAdd64 (location, value);
2073 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2075 #if SIZEOF_VOID_P == 4
2076 if (G_UNLIKELY ((size_t)location & 0x7)) {
2078 mono_interlocked_lock ();
2080 mono_interlocked_unlock ();
2084 return InterlockedRead64 (location);
2088 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2090 mono_memory_barrier ();
2094 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2096 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2098 if (state & ThreadState_Background) {
2099 /* If the thread changes the background mode, the main thread has to
2100 * be notified, since it has to rebuild the list of threads to
2103 SetEvent (background_change_event);
2108 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2110 mono_thread_set_state (this_obj, (MonoThreadState)state);
2112 if (state & ThreadState_Background) {
2113 /* If the thread changes the background mode, the main thread has to
2114 * be notified, since it has to rebuild the list of threads to
2117 SetEvent (background_change_event);
2122 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2126 LOCK_THREAD (this_obj);
2128 state = this_obj->state;
2130 UNLOCK_THREAD (this_obj);
2135 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2137 MonoInternalThread *current;
2139 MonoInternalThread *thread = this_obj->internal_thread;
2141 LOCK_THREAD (thread);
2143 current = mono_thread_internal_current ();
2145 thread->thread_interrupt_requested = TRUE;
2146 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2148 UNLOCK_THREAD (thread);
2151 async_abort_internal (thread, FALSE);
2155 void mono_thread_current_check_pending_interrupt ()
2157 MonoInternalThread *thread = mono_thread_internal_current ();
2158 gboolean throw_ = FALSE;
2160 LOCK_THREAD (thread);
2162 if (thread->thread_interrupt_requested) {
2164 thread->thread_interrupt_requested = FALSE;
2167 UNLOCK_THREAD (thread);
2170 mono_raise_exception (mono_get_exception_thread_interrupted ());
2175 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2177 LOCK_THREAD (thread);
2179 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2180 (thread->state & ThreadState_StopRequested) != 0 ||
2181 (thread->state & ThreadState_Stopped) != 0)
2183 UNLOCK_THREAD (thread);
2187 if ((thread->state & ThreadState_Unstarted) != 0) {
2188 thread->state |= ThreadState_Aborted;
2189 UNLOCK_THREAD (thread);
2193 thread->state |= ThreadState_AbortRequested;
2194 if (thread->abort_state_handle)
2195 mono_gchandle_free (thread->abort_state_handle);
2197 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2198 g_assert (thread->abort_state_handle);
2200 thread->abort_state_handle = 0;
2202 thread->abort_exc = NULL;
2204 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));
2206 /* During shutdown, we can't wait for other threads */
2208 /* Make sure the thread is awake */
2209 mono_thread_resume (thread);
2211 UNLOCK_THREAD (thread);
2213 if (thread == mono_thread_internal_current ())
2214 self_abort_internal ();
2216 async_abort_internal (thread, TRUE);
2220 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2222 MonoInternalThread *thread = mono_thread_internal_current ();
2223 gboolean was_aborting;
2225 LOCK_THREAD (thread);
2226 was_aborting = thread->state & ThreadState_AbortRequested;
2227 thread->state &= ~ThreadState_AbortRequested;
2228 UNLOCK_THREAD (thread);
2230 if (!was_aborting) {
2231 const char *msg = "Unable to reset abort because no abort was requested";
2232 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2235 thread->abort_exc = NULL;
2236 if (thread->abort_state_handle) {
2237 mono_gchandle_free (thread->abort_state_handle);
2238 /* This is actually not necessary - the handle
2239 only counts if the exception is set */
2240 thread->abort_state_handle = 0;
2245 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2247 LOCK_THREAD (thread);
2249 thread->state &= ~ThreadState_AbortRequested;
2251 if (thread->abort_exc) {
2252 thread->abort_exc = NULL;
2253 if (thread->abort_state_handle) {
2254 mono_gchandle_free (thread->abort_state_handle);
2255 /* This is actually not necessary - the handle
2256 only counts if the exception is set */
2257 thread->abort_state_handle = 0;
2261 UNLOCK_THREAD (thread);
2265 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2267 MonoInternalThread *thread = this_obj->internal_thread;
2268 MonoObject *state, *deserialized = NULL, *exc;
2271 if (!thread->abort_state_handle)
2274 state = mono_gchandle_get_target (thread->abort_state_handle);
2277 domain = mono_domain_get ();
2278 if (mono_object_domain (state) == domain)
2281 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2283 if (!deserialized) {
2284 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2286 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2287 mono_set_pending_exception (invalid_op_exc);
2291 return deserialized;
2295 mono_thread_suspend (MonoInternalThread *thread)
2297 LOCK_THREAD (thread);
2299 if ((thread->state & ThreadState_Unstarted) != 0 ||
2300 (thread->state & ThreadState_Aborted) != 0 ||
2301 (thread->state & ThreadState_Stopped) != 0)
2303 UNLOCK_THREAD (thread);
2307 if ((thread->state & ThreadState_Suspended) != 0 ||
2308 (thread->state & ThreadState_SuspendRequested) != 0 ||
2309 (thread->state & ThreadState_StopRequested) != 0)
2311 UNLOCK_THREAD (thread);
2315 thread->state |= ThreadState_SuspendRequested;
2317 if (thread == mono_thread_internal_current ()) {
2318 /* calls UNLOCK_THREAD (thread) */
2319 self_suspend_internal ();
2321 /* calls UNLOCK_THREAD (thread) */
2322 async_suspend_internal (thread, FALSE);
2329 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2331 if (!mono_thread_suspend (this_obj->internal_thread)) {
2332 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2337 /* LOCKING: LOCK_THREAD(thread) must be held */
2339 mono_thread_resume (MonoInternalThread *thread)
2341 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2342 thread->state &= ~ThreadState_SuspendRequested;
2346 if ((thread->state & ThreadState_Suspended) == 0 ||
2347 (thread->state & ThreadState_Unstarted) != 0 ||
2348 (thread->state & ThreadState_Aborted) != 0 ||
2349 (thread->state & ThreadState_Stopped) != 0)
2354 UNLOCK_THREAD (thread);
2356 /* Awake the thread */
2357 if (!mono_thread_info_resume (thread_get_tid (thread)))
2360 LOCK_THREAD (thread);
2362 thread->state &= ~ThreadState_Suspended;
2368 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2370 if (!thread->internal_thread) {
2371 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2373 LOCK_THREAD (thread->internal_thread);
2374 if (!mono_thread_resume (thread->internal_thread))
2375 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2376 UNLOCK_THREAD (thread->internal_thread);
2381 mono_threads_is_critical_method (MonoMethod *method)
2383 switch (method->wrapper_type) {
2384 case MONO_WRAPPER_RUNTIME_INVOKE:
2385 case MONO_WRAPPER_XDOMAIN_INVOKE:
2386 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2393 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2398 if (mono_threads_is_critical_method (m)) {
2399 *((gboolean*)data) = TRUE;
2406 is_running_protected_wrapper (void)
2408 gboolean found = FALSE;
2409 mono_stack_walk (find_wrapper, &found);
2413 void mono_thread_internal_stop (MonoInternalThread *thread)
2415 LOCK_THREAD (thread);
2417 if ((thread->state & ThreadState_StopRequested) != 0 ||
2418 (thread->state & ThreadState_Stopped) != 0)
2420 UNLOCK_THREAD (thread);
2424 /* Make sure the thread is awake */
2425 mono_thread_resume (thread);
2427 thread->state |= ThreadState_StopRequested;
2428 thread->state &= ~ThreadState_AbortRequested;
2430 UNLOCK_THREAD (thread);
2432 if (thread == mono_thread_internal_current ())
2433 self_abort_internal ();
2435 async_abort_internal (thread, TRUE);
2438 void mono_thread_stop (MonoThread *thread)
2440 mono_thread_internal_stop (thread->internal_thread);
2444 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2446 gint8 tmp = *(volatile gint8 *)ptr;
2447 mono_memory_barrier ();
2452 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2454 gint16 tmp = *(volatile gint16 *)ptr;
2455 mono_memory_barrier ();
2460 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2462 gint32 tmp = *(volatile gint32 *)ptr;
2463 mono_memory_barrier ();
2468 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2470 gint64 tmp = *(volatile gint64 *)ptr;
2471 mono_memory_barrier ();
2476 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2478 volatile void *tmp = *(volatile void **)ptr;
2479 mono_memory_barrier ();
2480 return (void *) tmp;
2484 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2486 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2487 mono_memory_barrier ();
2488 return (MonoObject *) tmp;
2492 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2494 double tmp = *(volatile double *)ptr;
2495 mono_memory_barrier ();
2500 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2502 float tmp = *(volatile float *)ptr;
2503 mono_memory_barrier ();
2508 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2510 return InterlockedRead8 ((volatile gint8 *)ptr);
2514 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2516 return InterlockedRead16 ((volatile gint16 *)ptr);
2520 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2522 return InterlockedRead ((volatile gint32 *)ptr);
2526 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2528 #if SIZEOF_VOID_P == 4
2529 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2531 mono_interlocked_lock ();
2532 val = *(gint64*)ptr;
2533 mono_interlocked_unlock ();
2537 return InterlockedRead64 ((volatile gint64 *)ptr);
2541 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2543 return InterlockedReadPointer ((volatile gpointer *)ptr);
2547 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2551 #if SIZEOF_VOID_P == 4
2552 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2554 mono_interlocked_lock ();
2555 val = *(double*)ptr;
2556 mono_interlocked_unlock ();
2561 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2567 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2571 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2577 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2579 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2583 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2585 mono_memory_barrier ();
2586 *(volatile gint8 *)ptr = value;
2590 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2592 mono_memory_barrier ();
2593 *(volatile gint16 *)ptr = value;
2597 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2599 mono_memory_barrier ();
2600 *(volatile gint32 *)ptr = value;
2604 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2606 mono_memory_barrier ();
2607 *(volatile gint64 *)ptr = value;
2611 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2613 mono_memory_barrier ();
2614 *(volatile void **)ptr = value;
2618 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2620 mono_memory_barrier ();
2621 mono_gc_wbarrier_generic_store (ptr, value);
2625 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2627 mono_memory_barrier ();
2628 *(volatile double *)ptr = value;
2632 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2634 mono_memory_barrier ();
2635 *(volatile float *)ptr = value;
2639 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2641 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2645 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2647 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2651 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2653 InterlockedWrite ((volatile gint32 *)ptr, value);
2657 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2659 #if SIZEOF_VOID_P == 4
2660 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2661 mono_interlocked_lock ();
2662 *(gint64*)ptr = value;
2663 mono_interlocked_unlock ();
2668 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2672 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2674 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2678 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2682 #if SIZEOF_VOID_P == 4
2683 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2684 mono_interlocked_lock ();
2685 *(double*)ptr = value;
2686 mono_interlocked_unlock ();
2693 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2697 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2703 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2707 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2709 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2713 free_context (void *user_data)
2715 ContextStaticData *data = user_data;
2717 mono_threads_lock ();
2720 * There is no guarantee that, by the point this reference queue callback
2721 * has been invoked, the GC handle associated with the object will fail to
2722 * resolve as one might expect. So if we don't free and remove the GC
2723 * handle here, free_context_static_data_helper () could end up resolving
2724 * a GC handle to an actually-dead context which would contain a pointer
2725 * to an already-freed static data segment, resulting in a crash when
2728 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2730 mono_threads_unlock ();
2732 mono_gchandle_free (data->gc_handle);
2733 mono_free_static_data (data->static_data);
2738 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2740 mono_threads_lock ();
2742 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2745 contexts = g_hash_table_new (NULL, NULL);
2748 context_queue = mono_gc_reference_queue_new (free_context);
2750 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2751 g_hash_table_insert (contexts, gch, gch);
2754 * We use this intermediate structure to contain a duplicate pointer to
2755 * the static data because we can't rely on being able to resolve the GC
2756 * handle in the reference queue callback.
2758 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2759 data->gc_handle = GPOINTER_TO_UINT (gch);
2762 context_adjust_static_data (ctx);
2763 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2765 mono_threads_unlock ();
2767 mono_profiler_context_loaded (ctx);
2771 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2774 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2775 * cleanup in exceptional circumstances, we don't actually do any
2776 * cleanup work here. We instead do this via a reference queue.
2779 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2781 mono_profiler_context_unloaded (ctx);
2785 mono_thread_init_tls (void)
2787 MONO_FAST_TLS_INIT (tls_current_object);
2788 mono_native_tls_alloc (¤t_object_key, NULL);
2791 void mono_thread_init (MonoThreadStartCB start_cb,
2792 MonoThreadAttachCB attach_cb)
2794 mono_coop_mutex_init_recursive (&threads_mutex);
2796 mono_os_mutex_init_recursive(&interlocked_mutex);
2797 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2799 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2800 g_assert(background_change_event != NULL);
2802 mono_init_static_data_info (&thread_static_info);
2803 mono_init_static_data_info (&context_static_info);
2805 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2807 mono_thread_start_cb = start_cb;
2808 mono_thread_attach_cb = attach_cb;
2810 /* Get a pseudo handle to the current process. This is just a
2811 * kludge so that wapi can build a process handle if needed.
2812 * As a pseudo handle is returned, we don't need to clean
2815 GetCurrentProcess ();
2818 void mono_thread_cleanup (void)
2820 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2821 MonoThreadInfo *info;
2823 /* The main thread must abandon any held mutexes (particularly
2824 * important for named mutexes as they are shared across
2825 * processes, see bug 74680.) This will happen when the
2826 * thread exits, but if it's not running in a subthread it
2827 * won't exit in time.
2829 info = mono_thread_info_current ();
2830 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2834 /* This stuff needs more testing, it seems one of these
2835 * critical sections can be locked when mono_thread_cleanup is
2838 mono_coop_mutex_destroy (&threads_mutex);
2839 mono_os_mutex_destroy (&interlocked_mutex);
2840 mono_os_mutex_destroy (&delayed_free_table_mutex);
2841 mono_os_mutex_destroy (&small_id_mutex);
2842 CloseHandle (background_change_event);
2845 mono_native_tls_free (current_object_key);
2849 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2851 mono_thread_cleanup_fn = func;
2855 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2857 thread->internal_thread->manage_callback = func;
2861 static void print_tids (gpointer key, gpointer value, gpointer user)
2863 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2864 * sizeof(uint) and a cast to uint would overflow
2866 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2867 * print this as a pointer.
2869 g_message ("Waiting for: %p", key);
2874 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2875 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2879 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2883 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2885 MONO_PREPARE_BLOCKING;
2886 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2887 MONO_FINISH_BLOCKING;
2889 if(ret==WAIT_FAILED) {
2890 /* See the comment in build_wait_tids() */
2891 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2895 for(i=0; i<wait->num; i++)
2896 CloseHandle (wait->handles[i]);
2898 if (ret == WAIT_TIMEOUT)
2901 for(i=0; i<wait->num; i++) {
2902 gsize tid = wait->threads[i]->tid;
2905 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2906 * it can still run io-layer etc. code. So wait for it to really exit.
2907 * FIXME: This won't join threads which are not in the joinable_hash yet.
2909 mono_thread_join ((gpointer)tid);
2911 mono_threads_lock ();
2912 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2913 /* This thread must have been killed, because
2914 * it hasn't cleaned itself up. (It's just
2915 * possible that the thread exited before the
2916 * parent thread had a chance to store the
2917 * handle, and now there is another pointer to
2918 * the already-exited thread stored. In this
2919 * case, we'll just get two
2920 * mono_profiler_thread_end() calls for the
2924 mono_threads_unlock ();
2925 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2926 thread_cleanup (wait->threads[i]);
2928 mono_threads_unlock ();
2933 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2935 guint32 i, ret, count;
2937 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2939 /* Add the thread state change event, so it wakes up if a thread changes
2940 * to background mode.
2943 if (count < MAXIMUM_WAIT_OBJECTS) {
2944 wait->handles [count] = background_change_event;
2948 MONO_PREPARE_BLOCKING;
2949 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2950 MONO_FINISH_BLOCKING;
2952 if(ret==WAIT_FAILED) {
2953 /* See the comment in build_wait_tids() */
2954 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2958 for(i=0; i<wait->num; i++)
2959 CloseHandle (wait->handles[i]);
2961 if (ret == WAIT_TIMEOUT)
2964 if (ret < wait->num) {
2965 gsize tid = wait->threads[ret]->tid;
2966 mono_threads_lock ();
2967 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2968 /* See comment in wait_for_tids about thread cleanup */
2969 mono_threads_unlock ();
2970 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2971 thread_cleanup (wait->threads [ret]);
2973 mono_threads_unlock ();
2977 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2979 struct wait_data *wait=(struct wait_data *)user;
2981 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2983 MonoInternalThread *thread=(MonoInternalThread *)value;
2985 /* Ignore background threads, we abort them later */
2986 /* Do not lock here since it is not needed and the caller holds threads_lock */
2987 if (thread->state & ThreadState_Background) {
2988 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2989 return; /* just leave, ignore */
2992 if (mono_gc_is_finalizer_internal_thread (thread)) {
2993 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2997 if (thread == mono_thread_internal_current ()) {
2998 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3002 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3003 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3007 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3008 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3012 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3013 if (handle == NULL) {
3014 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3018 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3019 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3020 wait->handles[wait->num]=handle;
3021 wait->threads[wait->num]=thread;
3024 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3026 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3031 /* Just ignore the rest, we can't do anything with
3038 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3040 struct wait_data *wait=(struct wait_data *)user;
3041 MonoNativeThreadId self = mono_native_thread_id_get ();
3042 MonoInternalThread *thread = (MonoInternalThread *)value;
3045 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
3048 /* The finalizer thread is not a background thread */
3049 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3050 && (thread->state & ThreadState_Background) != 0
3051 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3053 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3057 /* printf ("A: %d\n", wait->num); */
3058 wait->handles[wait->num]=thread->handle;
3059 wait->threads[wait->num]=thread;
3062 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3063 mono_thread_internal_stop (thread);
3067 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3068 && !mono_gc_is_finalizer_internal_thread (thread);
3072 * mono_threads_set_shutting_down:
3074 * Is called by a thread that wants to shut down Mono. If the runtime is already
3075 * shutting down, the calling thread is suspended/stopped, and this function never
3079 mono_threads_set_shutting_down (void)
3081 MonoInternalThread *current_thread = mono_thread_internal_current ();
3083 mono_threads_lock ();
3085 if (shutting_down) {
3086 mono_threads_unlock ();
3088 /* Make sure we're properly suspended/stopped */
3090 LOCK_THREAD (current_thread);
3092 if ((current_thread->state & ThreadState_SuspendRequested) ||
3093 (current_thread->state & ThreadState_AbortRequested) ||
3094 (current_thread->state & ThreadState_StopRequested)) {
3095 UNLOCK_THREAD (current_thread);
3096 mono_thread_execute_interruption ();
3098 current_thread->state |= ThreadState_Stopped;
3099 UNLOCK_THREAD (current_thread);
3102 /*since we're killing the thread, unset the current domain.*/
3103 mono_domain_unset ();
3105 /* Wake up other threads potentially waiting for us */
3106 mono_thread_info_exit ();
3108 shutting_down = TRUE;
3110 /* Not really a background state change, but this will
3111 * interrupt the main thread if it is waiting for all
3112 * the other threads.
3114 SetEvent (background_change_event);
3116 mono_threads_unlock ();
3120 void mono_thread_manage (void)
3122 struct wait_data wait_data;
3123 struct wait_data *wait = &wait_data;
3125 memset (wait, 0, sizeof (struct wait_data));
3126 /* join each thread that's still running */
3127 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3129 mono_threads_lock ();
3131 THREAD_DEBUG (g_message("%s: No threads", __func__));
3132 mono_threads_unlock ();
3135 mono_threads_unlock ();
3138 mono_threads_lock ();
3139 if (shutting_down) {
3140 /* somebody else is shutting down */
3141 mono_threads_unlock ();
3144 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3145 mono_g_hash_table_foreach (threads, print_tids, NULL));
3147 ResetEvent (background_change_event);
3149 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3150 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3151 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3152 mono_threads_unlock ();
3154 /* Something to wait for */
3155 wait_for_tids_or_state_change (wait, INFINITE);
3157 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3158 } while(wait->num>0);
3160 /* Mono is shutting down, so just wait for the end */
3161 if (!mono_runtime_try_shutdown ()) {
3162 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3163 mono_thread_suspend (mono_thread_internal_current ());
3164 mono_thread_execute_interruption ();
3168 * Remove everything but the finalizer thread and self.
3169 * Also abort all the background threads
3172 mono_threads_lock ();
3175 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3176 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3177 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3179 mono_threads_unlock ();
3181 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3183 /* Something to wait for */
3184 wait_for_tids (wait, INFINITE);
3186 } while (wait->num > 0);
3189 * give the subthreads a chance to really quit (this is mainly needed
3190 * to get correct user and system times from getrusage/wait/time(1)).
3191 * This could be removed if we avoid pthread_detach() and use pthread_join().
3193 mono_thread_info_yield ();
3197 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3199 MonoInternalThread *thread = (MonoInternalThread*)value;
3200 struct wait_data *wait = (struct wait_data*)user_data;
3204 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3206 * This needs no locking.
3208 if ((thread->state & ThreadState_Suspended) != 0 ||
3209 (thread->state & ThreadState_Stopped) != 0)
3212 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3213 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3217 wait->handles [wait->num] = handle;
3218 wait->threads [wait->num] = thread;
3224 * mono_thread_suspend_all_other_threads:
3226 * Suspend all managed threads except the finalizer thread and this thread. It is
3227 * not possible to resume them later.
3229 void mono_thread_suspend_all_other_threads (void)
3231 struct wait_data wait_data;
3232 struct wait_data *wait = &wait_data;
3234 MonoNativeThreadId self = mono_native_thread_id_get ();
3235 guint32 eventidx = 0;
3236 gboolean starting, finished;
3238 memset (wait, 0, sizeof (struct wait_data));
3240 * The other threads could be in an arbitrary state at this point, i.e.
3241 * they could be starting up, shutting down etc. This means that there could be
3242 * threads which are not even in the threads hash table yet.
3246 * First we set a barrier which will be checked by all threads before they
3247 * are added to the threads hash table, and they will exit if the flag is set.
3248 * This ensures that no threads could be added to the hash later.
3249 * We will use shutting_down as the barrier for now.
3251 g_assert (shutting_down);
3254 * We make multiple calls to WaitForMultipleObjects since:
3255 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3256 * - some threads could exit without becoming suspended
3261 * Make a copy of the hashtable since we can't do anything with
3262 * threads while threads_mutex is held.
3265 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3266 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3267 mono_threads_lock ();
3268 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3269 mono_threads_unlock ();
3272 /* Get the suspended events that we'll be waiting for */
3273 for (i = 0; i < wait->num; ++i) {
3274 MonoInternalThread *thread = wait->threads [i];
3276 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3277 || mono_gc_is_finalizer_internal_thread (thread)
3278 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3280 //CloseHandle (wait->handles [i]);
3281 wait->threads [i] = NULL; /* ignore this thread in next loop */
3285 LOCK_THREAD (thread);
3287 if ((thread->state & ThreadState_Suspended) != 0 ||
3288 (thread->state & ThreadState_StopRequested) != 0 ||
3289 (thread->state & ThreadState_Stopped) != 0) {
3290 UNLOCK_THREAD (thread);
3291 CloseHandle (wait->handles [i]);
3292 wait->threads [i] = NULL; /* ignore this thread in next loop */
3298 /* Convert abort requests into suspend requests */
3299 if ((thread->state & ThreadState_AbortRequested) != 0)
3300 thread->state &= ~ThreadState_AbortRequested;
3302 thread->state |= ThreadState_SuspendRequested;
3304 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3305 async_suspend_internal (thread, TRUE);
3307 if (eventidx <= 0) {
3309 * If there are threads which are starting up, we wait until they
3310 * are suspended when they try to register in the threads hash.
3311 * This is guaranteed to finish, since the threads which can create new
3312 * threads get suspended after a while.
3313 * FIXME: The finalizer thread can still create new threads.
3315 mono_threads_lock ();
3316 if (threads_starting_up)
3317 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3320 mono_threads_unlock ();
3322 mono_thread_info_sleep (100, NULL);
3330 MonoInternalThread *thread;
3331 MonoStackFrameInfo *frames;
3332 int nframes, max_frames;
3333 int nthreads, max_threads;
3334 MonoInternalThread **threads;
3335 } ThreadDumpUserData;
3337 static gboolean thread_dump_requested;
3339 /* This needs to be async safe */
3341 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3343 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3345 if (ud->nframes < ud->max_frames) {
3346 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3353 /* This needs to be async safe */
3354 static SuspendThreadResult
3355 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3357 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3358 MonoInternalThread *thread = user_data->thread;
3361 /* This no longer works with remote unwinding */
3363 wapi_desc = wapi_current_thread_desc ();
3364 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3369 if (thread == mono_thread_internal_current ())
3370 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3372 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3374 return MonoResumeThread;
3378 int nthreads, max_threads;
3379 MonoInternalThread **threads;
3380 } CollectThreadsUserData;
3383 collect_thread (gpointer key, gpointer value, gpointer user)
3385 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3386 MonoInternalThread *thread = (MonoInternalThread *)value;
3388 if (ud->nthreads < ud->max_threads)
3389 ud->threads [ud->nthreads ++] = thread;
3393 * Collect running threads into the THREADS array.
3394 * THREADS should be an array allocated on the stack.
3397 collect_threads (MonoInternalThread **thread_array, int max_threads)
3399 CollectThreadsUserData ud;
3401 memset (&ud, 0, sizeof (ud));
3402 /* This array contains refs, but its on the stack, so its ok */
3403 ud.threads = thread_array;
3404 ud.max_threads = max_threads;
3406 mono_threads_lock ();
3407 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3408 mono_threads_unlock ();
3414 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3416 GString* text = g_string_new (0);
3418 GError *error = NULL;
3421 ud->thread = thread;
3424 /* Collect frames for the thread */
3425 if (thread == mono_thread_internal_current ()) {
3426 get_thread_dump (mono_thread_info_current (), ud);
3428 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3432 * Do all the non async-safe work outside of get_thread_dump.
3435 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3437 g_string_append_printf (text, "\n\"%s\"", name);
3440 else if (thread->threadpool_thread) {
3441 g_string_append (text, "\n\"<threadpool thread>\"");
3443 g_string_append (text, "\n\"<unnamed thread>\"");
3446 for (i = 0; i < ud->nframes; ++i) {
3447 MonoStackFrameInfo *frame = &ud->frames [i];
3448 MonoMethod *method = NULL;
3450 if (frame->type == FRAME_TYPE_MANAGED)
3451 method = mono_jit_info_get_method (frame->ji);
3454 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3455 g_string_append_printf (text, " %s\n", location);
3458 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3462 fprintf (stdout, "%s", text->str);
3464 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3465 OutputDebugStringA(text->str);
3468 g_string_free (text, TRUE);
3473 mono_threads_perform_thread_dump (void)
3475 ThreadDumpUserData ud;
3476 MonoInternalThread *thread_array [128];
3477 int tindex, nthreads;
3479 if (!thread_dump_requested)
3482 printf ("Full thread dump:\n");
3484 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3485 nthreads = collect_threads (thread_array, 128);
3487 memset (&ud, 0, sizeof (ud));
3488 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3489 ud.max_frames = 256;
3491 for (tindex = 0; tindex < nthreads; ++tindex)
3492 dump_thread (thread_array [tindex], &ud);
3496 thread_dump_requested = FALSE;
3499 /* Obtain the thread dump of all threads */
3501 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames)
3505 ThreadDumpUserData ud;
3506 MonoInternalThread *thread_array [128];
3507 MonoDomain *domain = mono_domain_get ();
3508 MonoDebugSourceLocation *location;
3509 int tindex, nthreads;
3511 mono_error_init (&error);
3513 *out_threads = NULL;
3514 *out_stack_frames = NULL;
3516 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3517 nthreads = collect_threads (thread_array, 128);
3519 memset (&ud, 0, sizeof (ud));
3520 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3521 ud.max_frames = 256;
3523 *out_threads = mono_array_new (domain, mono_defaults.thread_class, nthreads);
3524 *out_stack_frames = mono_array_new (domain, mono_defaults.array_class, nthreads);
3526 for (tindex = 0; tindex < nthreads; ++tindex) {
3527 MonoInternalThread *thread = thread_array [tindex];
3528 MonoArray *thread_frames;
3534 /* Collect frames for the thread */
3535 if (thread == mono_thread_internal_current ()) {
3536 get_thread_dump (mono_thread_info_current (), &ud);
3538 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3541 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3543 thread_frames = mono_array_new (domain, mono_defaults.stack_frame_class, ud.nframes);
3544 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3546 for (i = 0; i < ud.nframes; ++i) {
3547 MonoStackFrameInfo *frame = &ud.frames [i];
3548 MonoMethod *method = NULL;
3549 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error);
3550 if (!mono_error_ok (&error))
3553 sf->native_offset = frame->native_offset;
3555 if (frame->type == FRAME_TYPE_MANAGED)
3556 method = mono_jit_info_get_method (frame->ji);
3559 sf->method_address = (gsize) frame->ji->code_start;
3561 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
3562 mono_error_raise_exception (&error); /* FIXME don't raise here */
3563 MONO_OBJECT_SETREF (sf, method, rm);
3565 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3567 sf->il_offset = location->il_offset;
3569 if (location && location->source_file) {
3570 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3571 sf->line = location->row;
3572 sf->column = location->column;
3574 mono_debug_free_source_location (location);
3579 mono_array_setref (thread_frames, i, sf);
3585 mono_error_raise_exception (&error); /* FIXME don't raise here */
3589 * mono_threads_request_thread_dump:
3591 * Ask all threads except the current to print their stacktrace to stdout.
3594 mono_threads_request_thread_dump (void)
3596 /*The new thread dump code runs out of the finalizer thread. */
3597 thread_dump_requested = TRUE;
3598 mono_gc_finalize_notify ();
3603 gint allocated; /* +1 so that refs [allocated] == NULL */
3607 typedef struct ref_stack RefStack;
3610 ref_stack_new (gint initial_size)
3614 initial_size = MAX (initial_size, 16) + 1;
3615 rs = g_new0 (RefStack, 1);
3616 rs->refs = g_new0 (gpointer, initial_size);
3617 rs->allocated = initial_size;
3622 ref_stack_destroy (gpointer ptr)
3624 RefStack *rs = (RefStack *)ptr;
3633 ref_stack_push (RefStack *rs, gpointer ptr)
3635 g_assert (rs != NULL);
3637 if (rs->bottom >= rs->allocated) {
3638 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3639 rs->allocated <<= 1;
3640 rs->refs [rs->allocated] = NULL;
3642 rs->refs [rs->bottom++] = ptr;
3646 ref_stack_pop (RefStack *rs)
3648 if (rs == NULL || rs->bottom == 0)
3652 rs->refs [rs->bottom] = NULL;
3656 ref_stack_find (RefStack *rs, gpointer ptr)
3663 for (refs = rs->refs; refs && *refs; refs++) {
3671 * mono_thread_push_appdomain_ref:
3673 * Register that the current thread may have references to objects in domain
3674 * @domain on its stack. Each call to this function should be paired with a
3675 * call to pop_appdomain_ref.
3678 mono_thread_push_appdomain_ref (MonoDomain *domain)
3680 MonoInternalThread *thread = mono_thread_internal_current ();
3683 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3684 SPIN_LOCK (thread->lock_thread_id);
3685 if (thread->appdomain_refs == NULL)
3686 thread->appdomain_refs = ref_stack_new (16);
3687 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3688 SPIN_UNLOCK (thread->lock_thread_id);
3693 mono_thread_pop_appdomain_ref (void)
3695 MonoInternalThread *thread = mono_thread_internal_current ();
3698 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3699 SPIN_LOCK (thread->lock_thread_id);
3700 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3701 SPIN_UNLOCK (thread->lock_thread_id);
3706 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3709 SPIN_LOCK (thread->lock_thread_id);
3710 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3711 SPIN_UNLOCK (thread->lock_thread_id);
3716 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3718 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3721 typedef struct abort_appdomain_data {
3722 struct wait_data wait;
3724 } abort_appdomain_data;
3727 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3729 MonoInternalThread *thread = (MonoInternalThread*)value;
3730 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3731 MonoDomain *domain = data->domain;
3733 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3734 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3736 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3737 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3740 data->wait.handles [data->wait.num] = handle;
3741 data->wait.threads [data->wait.num] = thread;
3744 /* Just ignore the rest, we can't do anything with
3752 * mono_threads_abort_appdomain_threads:
3754 * Abort threads which has references to the given appdomain.
3757 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3759 #ifdef __native_client__
3763 abort_appdomain_data user_data;
3765 int orig_timeout = timeout;
3768 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3770 start_time = mono_msec_ticks ();
3772 mono_threads_lock ();
3774 user_data.domain = domain;
3775 user_data.wait.num = 0;
3776 /* This shouldn't take any locks */
3777 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3778 mono_threads_unlock ();
3780 if (user_data.wait.num > 0) {
3781 /* Abort the threads outside the threads lock */
3782 for (i = 0; i < user_data.wait.num; ++i)
3783 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3786 * We should wait for the threads either to abort, or to leave the
3787 * domain. We can't do the latter, so we wait with a timeout.
3789 wait_for_tids (&user_data.wait, 100);
3792 /* Update remaining time */
3793 timeout -= mono_msec_ticks () - start_time;
3794 start_time = mono_msec_ticks ();
3796 if (orig_timeout != -1 && timeout < 0)
3799 while (user_data.wait.num > 0);
3801 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3807 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3809 MonoInternalThread *thread = (MonoInternalThread*)value;
3810 MonoDomain *domain = (MonoDomain*)user_data;
3813 /* No locking needed here */
3814 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3816 if (thread->cached_culture_info) {
3817 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3818 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3819 if (obj && obj->vtable->domain == domain)
3820 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3826 * mono_threads_clear_cached_culture:
3828 * Clear the cached_current_culture from all threads if it is in the
3832 mono_threads_clear_cached_culture (MonoDomain *domain)
3834 mono_threads_lock ();
3835 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3836 mono_threads_unlock ();
3840 * mono_thread_get_undeniable_exception:
3842 * Return an exception which needs to be raised when leaving a catch clause.
3843 * This is used for undeniable exception propagation.
3846 mono_thread_get_undeniable_exception (void)
3848 MonoInternalThread *thread = mono_thread_internal_current ();
3850 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3852 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3853 * exception if the thread no longer references a dying appdomain.
3855 thread->abort_exc->trace_ips = NULL;
3856 thread->abort_exc->stack_trace = NULL;
3857 return thread->abort_exc;
3863 #if MONO_SMALL_CONFIG
3864 #define NUM_STATIC_DATA_IDX 4
3865 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3869 #define NUM_STATIC_DATA_IDX 8
3870 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3871 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3875 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3876 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3879 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3881 gpointer *static_data = (gpointer *)addr;
3883 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3884 void **ptr = (void **)static_data [i];
3889 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3890 void **p = ptr + idx;
3893 mark_func ((MonoObject**)p, gc_data);
3899 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3901 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3905 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3907 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3911 * mono_alloc_static_data
3913 * Allocate memory blocks for storing threads or context static data
3916 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3918 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3921 gpointer* static_data = *static_data_ptr;
3923 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3924 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3926 if (mono_gc_user_markers_supported ()) {
3927 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3928 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3930 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3931 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3934 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3935 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3936 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3937 *static_data_ptr = static_data;
3938 static_data [0] = static_data;
3941 for (i = 1; i <= idx; ++i) {
3942 if (static_data [i])
3945 if (mono_gc_user_markers_supported ())
3946 static_data [i] = g_malloc0 (static_data_size [i]);
3948 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3949 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3950 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3955 mono_free_static_data (gpointer* static_data)
3958 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3959 gpointer p = static_data [i];
3963 * At this point, the static data pointer array is still registered with the
3964 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3965 * data. Freeing the individual arrays without first nulling their slots
3966 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3967 * such an already freed array. See bug #13813.
3969 static_data [i] = NULL;
3970 mono_memory_write_barrier ();
3971 if (mono_gc_user_markers_supported ())
3974 mono_gc_free_fixed (p);
3976 mono_gc_free_fixed (static_data);
3980 * mono_init_static_data_info
3982 * Initializes static data counters
3984 static void mono_init_static_data_info (StaticDataInfo *static_data)
3986 static_data->idx = 0;
3987 static_data->offset = 0;
3988 static_data->freelist = NULL;
3992 * mono_alloc_static_data_slot
3994 * Generates an offset for static data. static_data contains the counters
3995 * used to generate it.
3998 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4000 if (!static_data->idx && !static_data->offset) {
4002 * we use the first chunk of the first allocation also as
4003 * an array for the rest of the data
4005 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4007 static_data->offset += align - 1;
4008 static_data->offset &= ~(align - 1);
4009 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4010 static_data->idx ++;
4011 g_assert (size <= static_data_size [static_data->idx]);
4012 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4013 static_data->offset = 0;
4015 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4016 static_data->offset += size;
4021 * ensure thread static fields already allocated are valid for thread
4022 * This function is called when a thread is created or on thread attach.
4025 thread_adjust_static_data (MonoInternalThread *thread)
4027 mono_threads_lock ();
4028 if (thread_static_info.offset || thread_static_info.idx > 0) {
4029 /* get the current allocated size */
4030 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
4031 mono_alloc_static_data (&thread->static_data, offset, TRUE);
4033 mono_threads_unlock ();
4037 * LOCKING: requires that threads_mutex is held
4040 context_adjust_static_data (MonoAppContext *ctx)
4042 if (context_static_info.offset || context_static_info.idx > 0) {
4043 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4044 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4045 ctx->data->static_data = ctx->static_data;
4050 * LOCKING: requires that threads_mutex is held
4053 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4055 MonoInternalThread *thread = (MonoInternalThread *)value;
4056 guint32 offset = GPOINTER_TO_UINT (user);
4058 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4062 * LOCKING: requires that threads_mutex is held
4065 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4067 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4072 guint32 offset = GPOINTER_TO_UINT (user);
4073 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4074 ctx->data->static_data = ctx->static_data;
4077 static StaticDataFreeList*
4078 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4080 StaticDataFreeList* prev = NULL;
4081 StaticDataFreeList* tmp = static_data->freelist;
4083 if (tmp->size == size) {
4085 prev->next = tmp->next;
4087 static_data->freelist = tmp->next;
4096 #if SIZEOF_VOID_P == 4
4103 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4105 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4107 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4108 MonoBitSet *rb = sets [idx];
4109 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4110 offset /= sizeof (uintptr_t);
4111 /* offset is now the bitmap offset */
4112 for (int i = 0; i < numbits; ++i) {
4113 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4114 mono_bitset_set_fast (rb, offset + i);
4119 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4121 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4122 MonoBitSet *rb = sets [idx];
4123 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4124 offset /= sizeof (uintptr_t);
4125 /* offset is now the bitmap offset */
4126 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4127 mono_bitset_clear_fast (rb, offset + i);
4131 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4133 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4135 StaticDataInfo *info;
4138 if (static_type == SPECIAL_STATIC_THREAD) {
4139 info = &thread_static_info;
4140 sets = thread_reference_bitmaps;
4142 info = &context_static_info;
4143 sets = context_reference_bitmaps;
4146 mono_threads_lock ();
4148 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4152 offset = item->offset;
4155 offset = mono_alloc_static_data_slot (info, size, align);
4158 update_reference_bitmap (sets, offset, bitmap, numbits);
4160 if (static_type == SPECIAL_STATIC_THREAD) {
4161 /* This can be called during startup */
4162 if (threads != NULL)
4163 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4165 if (contexts != NULL)
4166 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4168 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4171 mono_threads_unlock ();
4177 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4179 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4181 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4182 return get_thread_static_data (thread, offset);
4184 return get_context_static_data (thread->current_appcontext, offset);
4189 mono_get_special_static_data (guint32 offset)
4191 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4200 * LOCKING: requires that threads_mutex is held
4203 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4205 MonoInternalThread *thread = (MonoInternalThread *)value;
4206 OffsetSize *data = (OffsetSize *)user;
4207 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4208 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4211 if (!thread->static_data || !thread->static_data [idx])
4213 ptr = ((char*) thread->static_data [idx]) + off;
4214 mono_gc_bzero_atomic (ptr, data->size);
4218 * LOCKING: requires that threads_mutex is held
4221 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4223 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4228 OffsetSize *data = (OffsetSize *)user;
4229 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4230 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4233 if (!ctx->static_data || !ctx->static_data [idx])
4236 ptr = ((char*) ctx->static_data [idx]) + off;
4237 mono_gc_bzero_atomic (ptr, data->size);
4241 do_free_special_slot (guint32 offset, guint32 size)
4243 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4245 StaticDataInfo *info;
4247 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4248 info = &thread_static_info;
4249 sets = thread_reference_bitmaps;
4251 info = &context_static_info;
4252 sets = context_reference_bitmaps;
4255 guint32 data_offset = offset;
4256 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4257 OffsetSize data = { data_offset, size };
4259 clear_reference_bitmap (sets, data.offset, data.size);
4261 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4262 if (threads != NULL)
4263 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4265 if (contexts != NULL)
4266 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4269 if (!mono_runtime_is_shutting_down ()) {
4270 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4272 item->offset = offset;
4275 item->next = info->freelist;
4276 info->freelist = item;
4281 do_free_special (gpointer key, gpointer value, gpointer data)
4283 MonoClassField *field = (MonoClassField *)key;
4284 guint32 offset = GPOINTER_TO_UINT (value);
4287 size = mono_type_size (field->type, &align);
4288 do_free_special_slot (offset, size);
4292 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4294 mono_threads_lock ();
4296 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4298 mono_threads_unlock ();
4302 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4304 /* Only ever called for ThreadLocal instances */
4305 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
4307 mono_threads_lock ();
4308 do_free_special_slot (offset, size);
4309 mono_threads_unlock ();
4313 static void CALLBACK dummy_apc (ULONG_PTR param)
4319 * mono_thread_execute_interruption
4321 * Performs the operation that the requested thread state requires (abort,
4324 static MonoException*
4325 mono_thread_execute_interruption (void)
4327 MonoInternalThread *thread = mono_thread_internal_current ();
4329 LOCK_THREAD (thread);
4331 /* MonoThread::interruption_requested can only be changed with atomics */
4332 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4333 /* this will consume pending APC calls */
4335 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4337 InterlockedDecrement (&thread_interruption_requested);
4339 /* Clear the interrupted flag of the thread so it can wait again */
4340 mono_thread_info_clear_self_interrupt ();
4343 if ((thread->state & ThreadState_AbortRequested) != 0) {
4344 UNLOCK_THREAD (thread);
4345 if (thread->abort_exc == NULL) {
4347 * This might be racy, but it has to be called outside the lock
4348 * since it calls managed code.
4350 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4352 return thread->abort_exc;
4354 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4355 /* calls UNLOCK_THREAD (thread) */
4356 self_suspend_internal ();
4359 else if ((thread->state & ThreadState_StopRequested) != 0) {
4360 /* FIXME: do this through the JIT? */
4362 UNLOCK_THREAD (thread);
4364 mono_thread_exit ();
4366 } else if (thread->pending_exception) {
4369 exc = thread->pending_exception;
4370 thread->pending_exception = NULL;
4372 UNLOCK_THREAD (thread);
4374 } else if (thread->thread_interrupt_requested) {
4376 thread->thread_interrupt_requested = FALSE;
4377 UNLOCK_THREAD (thread);
4379 return(mono_get_exception_thread_interrupted ());
4382 UNLOCK_THREAD (thread);
4388 * mono_thread_request_interruption
4390 * A signal handler can call this method to request the interruption of a
4391 * thread. The result of the interruption will depend on the current state of
4392 * the thread. If the result is an exception that needs to be throw, it is
4393 * provided as return value.
4396 mono_thread_request_interruption (gboolean running_managed)
4398 MonoInternalThread *thread = mono_thread_internal_current ();
4400 /* The thread may already be stopping */
4405 if (thread->interrupt_on_stop &&
4406 thread->state & ThreadState_StopRequested &&
4407 thread->state & ThreadState_Background)
4411 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4413 InterlockedIncrement (&thread_interruption_requested);
4415 if (!running_managed || is_running_protected_wrapper ()) {
4416 /* Can't stop while in unmanaged code. Increase the global interruption
4417 request count. When exiting the unmanaged method the count will be
4418 checked and the thread will be interrupted. */
4420 /* this will awake the thread if it is in WaitForSingleObject
4422 /* Our implementation of this function ignores the func argument */
4424 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4426 mono_thread_info_self_interrupt ();
4431 return mono_thread_execute_interruption ();
4435 /*This function should be called by a thread after it has exited all of
4436 * its handle blocks at interruption time.*/
4438 mono_thread_resume_interruption (void)
4440 MonoInternalThread *thread = mono_thread_internal_current ();
4441 gboolean still_aborting;
4443 /* The thread may already be stopping */
4447 LOCK_THREAD (thread);
4448 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4449 UNLOCK_THREAD (thread);
4451 /*This can happen if the protected block called Thread::ResetAbort*/
4452 if (!still_aborting)
4455 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4457 InterlockedIncrement (&thread_interruption_requested);
4459 mono_thread_info_self_interrupt ();
4461 return mono_thread_execute_interruption ();
4464 gboolean mono_thread_interruption_requested ()
4466 if (thread_interruption_requested) {
4467 MonoInternalThread *thread = mono_thread_internal_current ();
4468 /* The thread may already be stopping */
4470 return (thread->interruption_requested);
4475 static MonoException*
4476 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4478 MonoInternalThread *thread = mono_thread_internal_current ();
4480 /* The thread may already be stopping */
4484 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4485 MonoException* exc = mono_thread_execute_interruption ();
4493 * Performs the interruption of the current thread, if one has been requested,
4494 * and the thread is not running a protected wrapper.
4495 * Return the exception which needs to be thrown, if any.
4498 mono_thread_interruption_checkpoint (void)
4500 return mono_thread_interruption_checkpoint_request (FALSE);
4504 * Performs the interruption of the current thread, if one has been requested.
4505 * Return the exception which needs to be thrown, if any.
4508 mono_thread_force_interruption_checkpoint_noraise (void)
4510 return mono_thread_interruption_checkpoint_request (TRUE);
4514 * mono_thread_get_and_clear_pending_exception:
4516 * Return any pending exceptions for the current thread and clear it as a side effect.
4519 mono_thread_get_and_clear_pending_exception (void)
4521 MonoInternalThread *thread = mono_thread_internal_current ();
4523 /* The thread may already be stopping */
4527 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4528 return mono_thread_execute_interruption ();
4531 if (thread->pending_exception) {
4532 MonoException *exc = thread->pending_exception;
4534 thread->pending_exception = NULL;
4542 * mono_set_pending_exception:
4544 * Set the pending exception of the current thread to EXC.
4545 * The exception will be thrown when execution returns to managed code.
4548 mono_set_pending_exception (MonoException *exc)
4550 MonoInternalThread *thread = mono_thread_internal_current ();
4552 /* The thread may already be stopping */
4556 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4558 mono_thread_request_interruption (FALSE);
4562 * mono_thread_interruption_request_flag:
4564 * Returns the address of a flag that will be non-zero if an interruption has
4565 * been requested for a thread. The thread to interrupt may not be the current
4566 * thread, so an additional call to mono_thread_interruption_requested() or
4567 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4570 gint32* mono_thread_interruption_request_flag ()
4572 return &thread_interruption_requested;
4576 mono_thread_init_apartment_state (void)
4579 MonoInternalThread* thread = mono_thread_internal_current ();
4581 /* Positive return value indicates success, either
4582 * S_OK if this is first CoInitialize call, or
4583 * S_FALSE if CoInitialize already called, but with same
4584 * threading model. A negative value indicates failure,
4585 * probably due to trying to change the threading model.
4587 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4588 ? COINIT_APARTMENTTHREADED
4589 : COINIT_MULTITHREADED) < 0) {
4590 thread->apartment_state = ThreadApartmentState_Unknown;
4596 mono_thread_cleanup_apartment_state (void)
4599 MonoInternalThread* thread = mono_thread_internal_current ();
4601 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4608 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4610 LOCK_THREAD (thread);
4611 thread->state |= state;
4612 UNLOCK_THREAD (thread);
4616 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4618 LOCK_THREAD (thread);
4619 thread->state &= ~state;
4620 UNLOCK_THREAD (thread);
4624 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4626 gboolean ret = FALSE;
4628 LOCK_THREAD (thread);
4630 if ((thread->state & test) != 0) {
4634 UNLOCK_THREAD (thread);
4639 static gboolean has_tls_get = FALSE;
4642 mono_runtime_set_has_tls_get (gboolean val)
4648 mono_runtime_has_tls_get (void)
4654 self_interrupt_thread (void *_unused)
4656 MonoThreadInfo *info = mono_thread_info_current ();
4657 MonoException *exc = mono_thread_execute_interruption ();
4658 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4659 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. */
4660 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4664 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4668 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4672 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4674 MonoJitInfo **dest = (MonoJitInfo **)data;
4680 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4682 MonoJitInfo *ji = NULL;
4685 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4690 MonoInternalThread *thread;
4691 gboolean install_async_abort;
4692 MonoThreadInfoInterruptToken *interrupt_token;
4695 static SuspendThreadResult
4696 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4698 AbortThreadData *data = (AbortThreadData *)ud;
4699 MonoInternalThread *thread = data->thread;
4700 MonoJitInfo *ji = NULL;
4701 gboolean protected_wrapper;
4702 gboolean running_managed;
4704 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4705 return MonoResumeThread;
4707 /*someone is already interrupting it*/
4708 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4709 return MonoResumeThread;
4711 InterlockedIncrement (&thread_interruption_requested);
4713 ji = mono_thread_info_get_last_managed (info);
4714 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4715 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4717 if (!protected_wrapper && running_managed) {
4718 /*We are in managed code*/
4719 /*Set the thread to call */
4720 if (data->install_async_abort)
4721 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4722 return MonoResumeThread;
4725 * This will cause waits to be broken.
4726 * It will also prevent the thread from entering a wait, so if the thread returns
4727 * from the wait before it receives the abort signal, it will just spin in the wait
4728 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4731 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4733 return MonoResumeThread;
4738 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4740 AbortThreadData data;
4742 g_assert (thread != mono_thread_internal_current ());
4744 data.thread = thread;
4745 data.install_async_abort = install_async_abort;
4746 data.interrupt_token = NULL;
4748 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4749 if (data.interrupt_token)
4750 mono_thread_info_finish_interrupt (data.interrupt_token);
4751 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4755 self_abort_internal (void)
4759 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4760 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4762 exc = mono_thread_request_interruption (TRUE);
4764 mono_raise_exception (exc);
4766 mono_thread_info_self_interrupt ();
4770 MonoInternalThread *thread;
4772 MonoThreadInfoInterruptToken *interrupt_token;
4773 } SuspendThreadData;
4775 static SuspendThreadResult
4776 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4778 SuspendThreadData *data = (SuspendThreadData *)ud;
4779 MonoInternalThread *thread = data->thread;
4780 MonoJitInfo *ji = NULL;
4781 gboolean protected_wrapper;
4782 gboolean running_managed;
4784 ji = mono_thread_info_get_last_managed (info);
4785 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4786 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4788 if (running_managed && !protected_wrapper) {
4789 thread->state &= ~ThreadState_SuspendRequested;
4790 thread->state |= ThreadState_Suspended;
4791 return KeepSuspended;
4793 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4794 InterlockedIncrement (&thread_interruption_requested);
4795 if (data->interrupt)
4796 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4798 return MonoResumeThread;
4802 /* LOCKING: called with @thread synch_cs held, and releases it */
4804 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4806 SuspendThreadData data;
4808 g_assert (thread != mono_thread_internal_current ());
4810 data.thread = thread;
4811 data.interrupt = interrupt;
4812 data.interrupt_token = NULL;
4814 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4815 if (data.interrupt_token)
4816 mono_thread_info_finish_interrupt (data.interrupt_token);
4818 UNLOCK_THREAD (thread);
4821 /* LOCKING: called with @thread synch_cs held, and releases it */
4823 self_suspend_internal (void)
4825 MonoInternalThread *thread;
4827 thread = mono_thread_internal_current ();
4829 mono_thread_info_begin_self_suspend ();
4830 thread->state &= ~ThreadState_SuspendRequested;
4831 thread->state |= ThreadState_Suspended;
4833 UNLOCK_THREAD (thread);
4835 mono_thread_info_end_self_suspend ();
4839 * mono_thread_is_foreign:
4840 * @thread: the thread to query
4842 * This function allows one to determine if a thread was created by the mono runtime and has
4843 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4845 * Returns: TRUE if @thread was not created by the runtime.
4848 mono_thread_is_foreign (MonoThread *thread)
4850 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4851 return info->runtime_thread == FALSE;
4855 * mono_add_joinable_thread:
4857 * Add TID to the list of joinable threads.
4858 * LOCKING: Acquires the threads lock.
4861 mono_threads_add_joinable_thread (gpointer tid)
4865 * We cannot detach from threads because it causes problems like
4866 * 2fd16f60/r114307. So we collect them and join them when
4867 * we have time (in he finalizer thread).
4869 joinable_threads_lock ();
4870 if (!joinable_threads)
4871 joinable_threads = g_hash_table_new (NULL, NULL);
4872 g_hash_table_insert (joinable_threads, tid, tid);
4873 joinable_thread_count ++;
4874 joinable_threads_unlock ();
4876 mono_gc_finalize_notify ();
4881 * mono_threads_join_threads:
4883 * Join all joinable threads. This is called from the finalizer thread.
4884 * LOCKING: Acquires the threads lock.
4887 mono_threads_join_threads (void)
4890 GHashTableIter iter;
4897 if (!joinable_thread_count)
4901 joinable_threads_lock ();
4903 if (g_hash_table_size (joinable_threads)) {
4904 g_hash_table_iter_init (&iter, joinable_threads);
4905 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4906 thread = (pthread_t)tid;
4907 g_hash_table_remove (joinable_threads, key);
4908 joinable_thread_count --;
4911 joinable_threads_unlock ();
4913 if (thread != pthread_self ())
4914 /* This shouldn't block */
4915 pthread_join (thread, NULL);
4926 * Wait for thread TID to exit.
4927 * LOCKING: Acquires the threads lock.
4930 mono_thread_join (gpointer tid)
4934 gboolean found = FALSE;
4936 joinable_threads_lock ();
4937 if (!joinable_threads)
4938 joinable_threads = g_hash_table_new (NULL, NULL);
4939 if (g_hash_table_lookup (joinable_threads, tid)) {
4940 g_hash_table_remove (joinable_threads, tid);
4941 joinable_thread_count --;
4944 joinable_threads_unlock ();
4947 thread = (pthread_t)tid;
4948 pthread_join (thread, NULL);
4953 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4955 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4956 mono_thread_interruption_checkpoint ();
4959 static inline gboolean
4960 is_appdomainunloaded_exception (MonoClass *klass)
4962 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4964 if (!app_domain_unloaded_exception_klass)
4965 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4966 g_assert (app_domain_unloaded_exception_klass);
4968 return klass == app_domain_unloaded_exception_klass;
4971 static inline gboolean
4972 is_threadabort_exception (MonoClass *klass)
4974 return klass == mono_defaults.threadabortexception_class;
4978 mono_thread_internal_unhandled_exception (MonoObject* exc)
4980 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4981 MonoClass *klass = exc->vtable->klass;
4982 if (is_threadabort_exception (klass)) {
4983 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4984 } else if (!is_appdomainunloaded_exception (klass)) {
4985 mono_unhandled_exception (exc);
4986 if (mono_environment_exitcode_get () == 1)
4993 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
4995 mono_threads_get_thread_dump (out_threads, out_stack_traces);