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)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/threads.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internals.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/hazard-pointer.h>
41 #include <mono/utils/mono-tls.h>
42 #include <mono/utils/atomic.h>
43 #include <mono/utils/mono-memory-model.h>
45 #include <mono/metadata/gc-internals.h>
46 #include <mono/metadata/reflection-internals.h>
52 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
53 #define USE_TKILL_ON_ANDROID 1
56 #ifdef PLATFORM_ANDROID
59 #ifdef USE_TKILL_ON_ANDROID
60 extern int tkill (pid_t tid, int signal);
64 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_DEBUG(a)
66 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
67 #define THREAD_WAIT_DEBUG(a)
68 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
69 #define LIBGC_DEBUG(a)
71 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
72 #define SPIN_LOCK(i) do { \
73 if (SPIN_TRYLOCK (i)) \
77 #define SPIN_UNLOCK(i) i = 0
79 #define LOCK_THREAD(thread) lock_thread((thread))
80 #define UNLOCK_THREAD(thread) unlock_thread((thread))
82 /* Provide this for systems with glib < 2.6 */
83 #ifndef G_GSIZE_FORMAT
84 # if GLIB_SIZEOF_LONG == 8
85 # define G_GSIZE_FORMAT "lu"
87 # define G_GSIZE_FORMAT "u"
93 guint32 (*func)(void *);
109 typedef struct _StaticDataFreeList StaticDataFreeList;
110 struct _StaticDataFreeList {
111 StaticDataFreeList *next;
119 StaticDataFreeList *freelist;
122 /* Number of cached culture objects in the MonoThread->cached_culture_info array
123 * (per-type): we use the first NUM entries for CultureInfo and the last for
124 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
126 #define NUM_CACHED_CULTURES 4
127 #define CULTURES_START_IDX 0
128 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
130 /* Controls access to the 'threads' hash table */
131 static void mono_threads_lock (void);
132 static void mono_threads_unlock (void);
133 static MonoCoopMutex threads_mutex;
135 /* Controls access to the 'joinable_threads' hash table */
136 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
137 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
138 static mono_mutex_t joinable_threads_mutex;
140 /* Holds current status of static data heap */
141 static StaticDataInfo thread_static_info;
142 static StaticDataInfo context_static_info;
144 /* The hash of existing threads (key is thread ID, value is
145 * MonoInternalThread*) that need joining before exit
147 static MonoGHashTable *threads=NULL;
149 /* List of app context GC handles.
150 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
152 static GHashTable *contexts = NULL;
154 /* Cleanup queue for contexts. */
155 static MonoReferenceQueue *context_queue;
158 * Threads which are starting up and they are not in the 'threads' hash yet.
159 * When handle_store is called for a thread, it will be removed from this hash table.
160 * Protected by mono_threads_lock ().
162 static MonoGHashTable *threads_starting_up = NULL;
164 /* The TLS key that holds the MonoObject assigned to each thread */
165 static MonoNativeTlsKey current_object_key;
168 /* Protected by the threads lock */
169 static GHashTable *joinable_threads;
170 static int joinable_thread_count;
172 #ifdef MONO_HAVE_FAST_TLS
173 /* we need to use both the Tls* functions and __thread because
174 * the gc needs to see all the threads
176 MONO_FAST_TLS_DECLARE(tls_current_object);
177 #define SET_CURRENT_OBJECT(x) do { \
178 MONO_FAST_TLS_SET (tls_current_object, x); \
179 mono_native_tls_set_value (current_object_key, x); \
181 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
183 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
184 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
187 /* function called at thread start */
188 static MonoThreadStartCB mono_thread_start_cb = NULL;
190 /* function called at thread attach */
191 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
193 /* function called at thread cleanup */
194 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
196 /* The default stack size for each thread */
197 static guint32 default_stacksize = 0;
198 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
200 static void thread_adjust_static_data (MonoInternalThread *thread);
201 static void context_adjust_static_data (MonoAppContext *ctx);
202 static void mono_free_static_data (gpointer* static_data);
203 static void mono_init_static_data_info (StaticDataInfo *static_data);
204 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
205 static gboolean mono_thread_resume (MonoInternalThread* thread);
206 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
207 static void self_abort_internal (void);
208 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
209 static void self_suspend_internal (void);
211 static MonoException* mono_thread_execute_interruption (void);
212 static void ref_stack_destroy (gpointer rs);
214 /* Spin lock for InterlockedXXX 64 bit functions */
215 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
216 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
217 static mono_mutex_t interlocked_mutex;
219 /* global count of thread interruptions requested */
220 static gint32 thread_interruption_requested = 0;
222 /* Event signaled when a thread changes its background mode */
223 static HANDLE background_change_event;
225 static gboolean shutting_down = FALSE;
227 static gint32 managed_thread_id_counter = 0;
229 /* Class lazy loading functions */
230 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
233 mono_threads_lock (void)
235 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
239 mono_threads_unlock (void)
241 mono_locks_coop_release (&threads_mutex, ThreadsLock);
246 get_next_managed_thread_id (void)
248 return InterlockedIncrement (&managed_thread_id_counter);
252 mono_thread_get_tls_key (void)
254 return current_object_key;
258 mono_thread_get_tls_offset (void)
263 if (current_object_key)
264 offset = current_object_key;
266 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
271 static inline MonoNativeThreadId
272 thread_get_tid (MonoInternalThread *thread)
274 /* We store the tid as a guint64 to keep the object layout constant between platforms */
275 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
278 /* handle_store() and handle_remove() manage the array of threads that
279 * still need to be waited for when the main thread exits.
281 * If handle_store() returns FALSE the thread must not be started
282 * because Mono is shutting down.
284 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
286 mono_threads_lock ();
288 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
290 if (threads_starting_up)
291 mono_g_hash_table_remove (threads_starting_up, thread);
293 if (shutting_down && !force_attach) {
294 mono_threads_unlock ();
299 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
300 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
303 /* We don't need to duplicate thread->handle, because it is
304 * only closed when the thread object is finalized by the GC.
306 g_assert (thread->internal_thread);
307 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
308 thread->internal_thread);
310 mono_threads_unlock ();
315 static gboolean handle_remove(MonoInternalThread *thread)
318 gsize tid = thread->tid;
320 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
322 mono_threads_lock ();
325 /* We have to check whether the thread object for the
326 * tid is still the same in the table because the
327 * thread might have been destroyed and the tid reused
328 * in the meantime, in which case the tid would be in
329 * the table, but with another thread object.
331 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
332 mono_g_hash_table_remove (threads, (gpointer)tid);
341 mono_threads_unlock ();
343 /* Don't close the handle here, wait for the object finalizer
344 * to do it. Otherwise, the following race condition applies:
346 * 1) Thread exits (and handle_remove() closes the handle)
348 * 2) Some other handle is reassigned the same slot
350 * 3) Another thread tries to join the first thread, and
351 * blocks waiting for the reassigned handle to be signalled
352 * (which might never happen). This is possible, because the
353 * thread calling Join() still has a reference to the first
359 static void ensure_synch_cs_set (MonoInternalThread *thread)
361 MonoCoopMutex *synch_cs;
363 if (thread->synch_cs != NULL) {
367 synch_cs = g_new0 (MonoCoopMutex, 1);
368 mono_coop_mutex_init_recursive (synch_cs);
370 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
371 synch_cs, NULL) != NULL) {
372 /* Another thread must have installed this CS */
373 mono_coop_mutex_destroy (synch_cs);
379 lock_thread (MonoInternalThread *thread)
381 if (!thread->synch_cs)
382 ensure_synch_cs_set (thread);
384 g_assert (thread->synch_cs);
386 mono_coop_mutex_lock (thread->synch_cs);
390 unlock_thread (MonoInternalThread *thread)
392 mono_coop_mutex_unlock (thread->synch_cs);
396 * NOTE: this function can be called also for threads different from the current one:
397 * make sure no code called from it will ever assume it is run on the thread that is
398 * getting cleaned up.
400 static void thread_cleanup (MonoInternalThread *thread)
402 g_assert (thread != NULL);
404 if (thread->abort_state_handle) {
405 mono_gchandle_free (thread->abort_state_handle);
406 thread->abort_state_handle = 0;
408 thread->abort_exc = NULL;
409 thread->current_appcontext = NULL;
412 * This is necessary because otherwise we might have
413 * cross-domain references which will not get cleaned up when
414 * the target domain is unloaded.
416 if (thread->cached_culture_info) {
418 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
419 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
423 * thread->synch_cs can be NULL if this was called after
424 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
425 * This can happen only during shutdown.
426 * The shutting_down flag is not always set, so we can't assert on it.
428 if (thread->synch_cs)
429 LOCK_THREAD (thread);
431 thread->state |= ThreadState_Stopped;
432 thread->state &= ~ThreadState_Background;
434 if (thread->synch_cs)
435 UNLOCK_THREAD (thread);
438 An interruption request has leaked to cleanup. Adjust the global counter.
440 This can happen is the abort source thread finds the abortee (this) thread
441 in unmanaged code. If this thread never trips back to managed code or check
442 the local flag it will be left set and positively unbalance the global counter.
444 Leaving the counter unbalanced will cause a performance degradation since all threads
445 will now keep checking their local flags all the time.
447 if (InterlockedExchange (&thread->interruption_requested, 0))
448 InterlockedDecrement (&thread_interruption_requested);
450 /* if the thread is not in the hash it has been removed already */
451 if (!handle_remove (thread)) {
452 if (thread == mono_thread_internal_current ()) {
453 mono_domain_unset ();
454 mono_memory_barrier ();
456 /* This needs to be called even if handle_remove () fails */
457 if (mono_thread_cleanup_fn)
458 mono_thread_cleanup_fn (thread_get_tid (thread));
461 mono_release_type_locks (thread);
463 /* Can happen when we attach the profiler helper thread in order to heapshot. */
464 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
465 mono_profiler_thread_end (thread->tid);
467 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
469 if (thread == mono_thread_internal_current ()) {
471 * This will signal async signal handlers that the thread has exited.
472 * The profiler callback needs this to be set, so it cannot be done earlier.
474 mono_domain_unset ();
475 mono_memory_barrier ();
478 if (thread == mono_thread_internal_current ())
479 mono_thread_pop_appdomain_ref ();
481 thread->cached_culture_info = NULL;
483 mono_free_static_data (thread->static_data);
484 thread->static_data = NULL;
485 ref_stack_destroy (thread->appdomain_refs);
486 thread->appdomain_refs = NULL;
488 if (mono_thread_cleanup_fn)
489 mono_thread_cleanup_fn (thread_get_tid (thread));
491 if (mono_gc_is_moving ()) {
492 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
493 thread->thread_pinning_ref = NULL;
499 * A special static data offset (guint32) consists of 3 parts:
501 * [0] 6-bit index into the array of chunks.
502 * [6] 25-bit offset into the array.
503 * [31] Bit indicating thread or context static.
508 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
519 } SpecialStaticOffset;
521 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
522 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
524 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
525 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
526 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
527 (((SpecialStaticOffset *) &(x))->fields.f)
530 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
532 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
534 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
535 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
537 return ((char *) thread->static_data [idx]) + off;
541 get_context_static_data (MonoAppContext *ctx, guint32 offset)
543 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
545 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
546 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
548 return ((char *) ctx->static_data [idx]) + off;
552 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
554 static MonoClassField *current_thread_field = NULL;
558 if (!current_thread_field) {
559 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
560 g_assert (current_thread_field);
563 mono_class_vtable (domain, mono_defaults.thread_class);
564 mono_domain_lock (domain);
565 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
566 mono_domain_unlock (domain);
569 return (MonoThread **)get_thread_static_data (thread, offset);
573 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
575 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
577 g_assert (current->obj.vtable->domain == domain);
579 g_assert (!*current_thread_ptr);
580 *current_thread_ptr = current;
584 create_thread_object (MonoDomain *domain, MonoError *error)
586 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
587 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, error);
592 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal, MonoError *error)
596 thread = create_thread_object (domain, error);
597 if (!mono_error_ok (error))
600 MONO_OBJECT_SETREF (thread, internal_thread, internal);
605 static MonoInternalThread*
606 create_internal_thread (MonoError *error)
608 MonoInternalThread *thread;
611 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
612 thread = (MonoInternalThread*) mono_object_new_mature (vt, error);
613 if (!mono_error_ok (error))
616 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
617 mono_coop_mutex_init_recursive (thread->synch_cs);
619 thread->apartment_state = ThreadApartmentState_Unknown;
620 thread->managed_id = get_next_managed_thread_id ();
621 if (mono_gc_is_moving ()) {
622 thread->thread_pinning_ref = thread;
623 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
630 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate, MonoError *error)
632 MonoDomain *domain = mono_get_root_domain ();
634 mono_error_init (error);
635 if (!candidate || candidate->obj.vtable->domain != domain) {
636 candidate = new_thread_with_internal (domain, thread, error);
637 return_val_if_nok (error, FALSE);
639 set_current_thread_for_domain (domain, thread, candidate);
640 g_assert (!thread->root_domain_thread);
641 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
645 static guint32 WINAPI start_wrapper_internal(void *data)
648 MonoThreadInfo *info;
649 StartInfo *start_info = (StartInfo *)data;
650 guint32 (*start_func)(void *);
654 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
657 MonoInternalThread *internal = start_info->obj->internal_thread;
658 MonoObject *start_delegate = start_info->delegate;
659 MonoDomain *domain = start_info->obj->obj.vtable->domain;
661 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
663 /* We can be sure start_info->obj->tid and
664 * start_info->obj->handle have been set, because the thread
665 * was created suspended, and these values were set before the
669 info = mono_thread_info_current ();
671 internal->thread_info = info;
672 internal->small_id = info->small_id;
676 SET_CURRENT_OBJECT (internal);
678 /* Every thread references the appdomain which created it */
679 mono_thread_push_appdomain_ref (domain);
681 if (!mono_domain_set (domain, FALSE)) {
682 /* No point in raising an appdomain_unloaded exception here */
683 /* FIXME: Cleanup here */
684 mono_thread_pop_appdomain_ref ();
688 start_func = start_info->func;
689 start_arg = start_info->obj->start_obj;
691 start_arg = start_info->start_arg;
693 /* We have to do this here because mono_thread_new_init()
694 requires that root_domain_thread is set up. */
695 thread_adjust_static_data (internal);
696 init_root_domain_thread (internal, start_info->obj, &error);
697 mono_error_raise_exception (&error); /* FIXME don't raise here */
699 /* This MUST be called before any managed code can be
700 * executed, as it calls the callback function that (for the
701 * jit) sets the lmf marker.
703 mono_thread_new_init (tid, &tid, start_func);
704 internal->stack_ptr = &tid;
705 if (domain != mono_get_root_domain ())
706 set_current_thread_for_domain (domain, internal, start_info->obj);
708 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
710 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
712 /* On 2.0 profile (and higher), set explicitly since state might have been
714 if (internal->apartment_state == ThreadApartmentState_Unknown)
715 internal->apartment_state = ThreadApartmentState_MTA;
717 mono_thread_init_apartment_state ();
719 if(internal->start_notify!=NULL) {
720 /* Let the thread that called Start() know we're
723 ReleaseSemaphore (internal->start_notify, 1, NULL);
727 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
731 * Call this after calling start_notify, since the profiler callback might want
732 * to lock the thread, and the lock is held by thread_start () which waits for
735 mono_profiler_thread_start (tid);
737 /* if the name was set before starting, we didn't invoke the profiler callback */
738 if (internal->name) {
739 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
740 mono_profiler_thread_name (internal->tid, tname);
741 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
745 /* start_func is set only for unmanaged start functions */
747 start_func (start_arg);
750 g_assert (start_delegate != NULL);
751 args [0] = start_arg;
752 /* we may want to handle the exception here. See comment below on unhandled exceptions */
753 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
754 mono_error_raise_exception (&error); /* FIXME don't raise here */
757 /* If the thread calls ExitThread at all, this remaining code
758 * will not be executed, but the main thread will eventually
759 * call thread_cleanup() on this thread's behalf.
762 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
764 /* Do any cleanup needed for apartment state. This
765 * cannot be done in thread_cleanup since thread_cleanup could be
766 * called for a thread other than the current thread.
767 * mono_thread_cleanup_apartment_state cleans up apartment
768 * for the current thead */
769 mono_thread_cleanup_apartment_state ();
771 thread_cleanup (internal);
775 /* Remove the reference to the thread object in the TLS data,
776 * so the thread object can be finalized. This won't be
777 * reached if the thread threw an uncaught exception, so those
778 * thread handles will stay referenced :-( (This is due to
779 * missing support for scanning thread-specific data in the
780 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
783 SET_CURRENT_OBJECT (NULL);
788 static guint32 WINAPI start_wrapper(void *data)
792 /* Avoid scanning the frames above this frame during a GC */
793 mono_gc_set_stack_end ((void*)&dummy);
795 return start_wrapper_internal (data);
801 * Common thread creation code.
802 * LOCKING: Acquires the threads lock.
805 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
808 HANDLE thread_handle;
809 MonoNativeThreadId tid;
810 guint32 create_flags;
813 * Join joinable threads to prevent running out of threads since the finalizer
814 * thread might be blocked/backlogged.
816 mono_threads_join_threads ();
818 mono_error_init (error);
820 mono_threads_lock ();
823 mono_threads_unlock ();
826 if (threads_starting_up == NULL) {
827 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
828 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
830 mono_g_hash_table_insert (threads_starting_up, thread, thread);
831 mono_threads_unlock ();
833 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
834 if (!internal->start_notify) {
835 mono_threads_lock ();
836 mono_g_hash_table_remove (threads_starting_up, thread);
837 mono_threads_unlock ();
838 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
844 stack_size = default_stacksize_for_thread (internal);
846 /* Create suspended, so we can do some housekeeping before the thread
849 create_flags = CREATE_SUSPENDED;
851 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
852 stack_size, create_flags, &tid);
854 if (thread_handle == NULL) {
855 /* The thread couldn't be created, so set an exception */
856 mono_threads_lock ();
857 mono_g_hash_table_remove (threads_starting_up, thread);
858 mono_threads_unlock ();
860 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
863 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
865 internal->handle = thread_handle;
866 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
868 internal->threadpool_thread = threadpool_thread;
869 if (threadpool_thread)
870 mono_thread_set_state (internal, ThreadState_Background);
872 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
874 /* Only store the handle when the thread is about to be
875 * launched, to avoid the main thread deadlocking while trying
876 * to clean up a thread that will never be signalled.
878 if (!handle_store (thread, FALSE))
881 mono_thread_info_resume (tid);
883 if (internal->start_notify) {
885 * Wait for the thread to set up its TLS data etc, so
886 * theres no potential race condition if someone tries
887 * to look up the data believing the thread has
890 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));
893 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
896 CloseHandle (internal->start_notify);
897 internal->start_notify = NULL;
900 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));
905 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
907 if (mono_thread_start_cb) {
908 mono_thread_start_cb (tid, stack_start, func);
912 void mono_threads_set_default_stacksize (guint32 stacksize)
914 default_stacksize = stacksize;
917 guint32 mono_threads_get_default_stacksize (void)
919 return default_stacksize;
923 * mono_thread_create_internal:
925 * ARG should not be a GC reference.
928 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
931 MonoInternalThread *internal;
932 StartInfo *start_info;
935 mono_error_init (error);
937 thread = create_thread_object (domain, error);
938 return_val_if_nok (error, NULL);
940 internal = create_internal_thread (error);
941 return_val_if_nok (error, NULL);
943 MONO_OBJECT_SETREF (thread, internal_thread, internal);
945 start_info = g_new0 (StartInfo, 1);
946 start_info->func = (guint32 (*)(void *))func;
947 start_info->obj = thread;
948 start_info->start_arg = arg;
950 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, error);
951 return_val_if_nok (error, NULL);
953 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
954 #ifndef MONO_CROSS_COMPILE
955 if (mono_check_corlib_version () == NULL)
956 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
963 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
966 if (!mono_thread_create_checked (domain, func, arg, &error))
967 mono_error_cleanup (&error);
971 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
973 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
977 mono_thread_attach (MonoDomain *domain)
980 MonoThread *thread = mono_thread_attach_full (domain, FALSE, &error);
981 mono_error_raise_exception (&error);
987 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach, MonoError *error)
989 MonoThreadInfo *info;
990 MonoInternalThread *thread;
991 MonoThread *current_thread;
992 HANDLE thread_handle;
993 MonoNativeThreadId tid;
995 mono_error_init (error);
997 if ((thread = mono_thread_internal_current ())) {
998 if (domain != mono_domain_get ())
999 mono_domain_set (domain, TRUE);
1000 /* Already attached */
1001 return mono_thread_current ();
1004 if (!mono_gc_register_thread (&domain)) {
1005 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 ());
1008 thread = create_internal_thread (error);
1009 if (!mono_error_ok (error))
1012 thread_handle = mono_thread_info_open_handle ();
1013 g_assert (thread_handle);
1015 tid=mono_native_thread_id_get ();
1017 thread->handle = thread_handle;
1018 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
1019 thread->stack_ptr = &tid;
1021 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
1023 info = mono_thread_info_current ();
1025 thread->thread_info = info;
1026 thread->small_id = info->small_id;
1028 current_thread = new_thread_with_internal (domain, thread, error);
1029 if (!mono_error_ok (error))
1032 if (!handle_store (current_thread, force_attach)) {
1033 /* Mono is shutting down, so just wait for the end */
1035 mono_thread_info_sleep (10000, NULL);
1038 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
1040 SET_CURRENT_OBJECT (thread);
1041 mono_domain_set (domain, TRUE);
1043 thread_adjust_static_data (thread);
1045 init_root_domain_thread (thread, current_thread, error);
1046 return_val_if_nok (error, NULL);
1048 if (domain != mono_get_root_domain ())
1049 set_current_thread_for_domain (domain, thread, current_thread);
1052 if (mono_thread_attach_cb) {
1056 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1059 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1061 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1064 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1065 if (!info->tools_thread)
1066 // FIXME: Need a separate callback
1067 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1069 return current_thread;
1073 mono_thread_detach_internal (MonoInternalThread *thread)
1075 g_return_if_fail (thread != NULL);
1077 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1079 thread_cleanup (thread);
1081 SET_CURRENT_OBJECT (NULL);
1082 mono_domain_unset ();
1084 /* Don't need to CloseHandle this thread, even though we took a
1085 * reference in mono_thread_attach (), because the GC will do it
1086 * when the Thread object is finalised.
1091 mono_thread_detach (MonoThread *thread)
1094 mono_thread_detach_internal (thread->internal_thread);
1098 * mono_thread_detach_if_exiting:
1100 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1101 * This should be used at the end of embedding code which calls into managed code, and which
1102 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1105 mono_thread_detach_if_exiting (void)
1107 if (mono_thread_info_is_exiting ()) {
1108 MonoInternalThread *thread;
1110 thread = mono_thread_internal_current ();
1112 mono_thread_detach_internal (thread);
1113 mono_thread_info_detach ();
1121 MonoInternalThread *thread = mono_thread_internal_current ();
1123 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1125 thread_cleanup (thread);
1126 SET_CURRENT_OBJECT (NULL);
1127 mono_domain_unset ();
1129 /* we could add a callback here for embedders to use. */
1130 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1131 exit (mono_environment_exitcode_get ());
1132 mono_thread_info_exit ();
1136 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1139 MonoInternalThread *internal;
1141 internal = create_internal_thread (&error);
1142 mono_error_raise_exception (&error);
1144 internal->state = ThreadState_Unstarted;
1146 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1150 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1154 StartInfo *start_info;
1155 MonoInternalThread *internal;
1158 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1160 if (!this_obj->internal_thread)
1161 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1162 internal = this_obj->internal_thread;
1164 LOCK_THREAD (internal);
1166 if ((internal->state & ThreadState_Unstarted) == 0) {
1167 UNLOCK_THREAD (internal);
1168 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1172 if ((internal->state & ThreadState_Aborted) != 0) {
1173 UNLOCK_THREAD (internal);
1176 /* This is freed in start_wrapper */
1177 start_info = g_new0 (StartInfo, 1);
1178 start_info->func = NULL;
1179 start_info->start_arg = NULL;
1180 start_info->delegate = start;
1181 start_info->obj = this_obj;
1182 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1184 res = create_thread (this_obj, internal, start_info, FALSE, 0, &error);
1186 mono_error_cleanup (&error);
1187 UNLOCK_THREAD (internal);
1191 internal->state &= ~ThreadState_Unstarted;
1193 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1195 UNLOCK_THREAD (internal);
1196 return internal->handle;
1200 * This is called from the finalizer of the internal thread object.
1203 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1205 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1208 * Since threads keep a reference to their thread object while running, by the time this function is called,
1209 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1210 * when thread_cleanup () can be called after this.
1213 CloseHandle (thread);
1215 if (this_obj->synch_cs) {
1216 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1217 this_obj->synch_cs = NULL;
1218 mono_coop_mutex_destroy (synch_cs);
1222 if (this_obj->name) {
1223 void *name = this_obj->name;
1224 this_obj->name = NULL;
1230 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1233 MonoInternalThread *thread = mono_thread_internal_current ();
1235 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1237 mono_thread_current_check_pending_interrupt ();
1240 gboolean alerted = FALSE;
1242 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1244 res = mono_thread_info_sleep (ms, &alerted);
1246 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1249 MonoException* exc = mono_thread_execute_interruption ();
1251 mono_raise_exception (exc);
1263 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1268 ves_icall_System_Threading_Thread_GetDomainID (void)
1270 return mono_domain_get()->domain_id;
1274 ves_icall_System_Threading_Thread_Yield (void)
1276 return mono_thread_info_yield ();
1280 * mono_thread_get_name:
1282 * Return the name of the thread. NAME_LEN is set to the length of the name.
1283 * Return NULL if the thread has no name. The returned memory is owned by the
1287 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1291 LOCK_THREAD (this_obj);
1293 if (!this_obj->name) {
1297 *name_len = this_obj->name_len;
1298 res = g_new (gunichar2, this_obj->name_len);
1299 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1302 UNLOCK_THREAD (this_obj);
1308 * mono_thread_get_name_utf8:
1310 * Return the name of the thread in UTF-8.
1311 * Return NULL if the thread has no name.
1312 * The returned memory is owned by the caller.
1315 mono_thread_get_name_utf8 (MonoThread *thread)
1320 MonoInternalThread *internal = thread->internal_thread;
1321 if (internal == NULL)
1324 LOCK_THREAD (internal);
1326 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1328 UNLOCK_THREAD (internal);
1334 * mono_thread_get_managed_id:
1336 * Return the Thread.ManagedThreadId value of `thread`.
1337 * Returns -1 if `thread` is NULL.
1340 mono_thread_get_managed_id (MonoThread *thread)
1345 MonoInternalThread *internal = thread->internal_thread;
1346 if (internal == NULL)
1349 int32_t id = internal->managed_id;
1355 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1360 mono_error_init (&error);
1362 LOCK_THREAD (this_obj);
1364 if (!this_obj->name)
1367 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1369 UNLOCK_THREAD (this_obj);
1371 mono_error_raise_exception (&error);
1377 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1379 LOCK_THREAD (this_obj);
1381 mono_error_init (error);
1383 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1384 UNLOCK_THREAD (this_obj);
1386 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1389 if (this_obj->name) {
1390 g_free (this_obj->name);
1391 this_obj->name_len = 0;
1394 this_obj->name = g_new (gunichar2, mono_string_length (name));
1395 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1396 this_obj->name_len = mono_string_length (name);
1399 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1402 this_obj->name = NULL;
1405 UNLOCK_THREAD (this_obj);
1407 if (this_obj->name && this_obj->tid) {
1408 char *tname = mono_string_to_utf8 (name);
1409 mono_profiler_thread_name (this_obj->tid, tname);
1410 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1416 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1419 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1420 mono_error_set_pending_exception (&error);
1424 * ves_icall_System_Threading_Thread_GetPriority_internal:
1425 * @param this_obj: The MonoInternalThread on which to operate.
1427 * Gets the priority of the given thread.
1428 * @return: The priority of the given thread.
1431 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1434 MonoInternalThread *internal = this_obj->internal_thread;
1436 LOCK_THREAD (internal);
1437 priority = GetThreadPriority (internal->handle) + 2;
1438 UNLOCK_THREAD (internal);
1443 * ves_icall_System_Threading_Thread_SetPriority_internal:
1444 * @param this_obj: The MonoInternalThread on which to operate.
1445 * @param priority: The priority to set.
1447 * Sets the priority of the given thread.
1450 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1452 MonoInternalThread *internal = this_obj->internal_thread;
1454 LOCK_THREAD (internal);
1455 SetThreadPriority (internal->handle, priority - 2);
1456 UNLOCK_THREAD (internal);
1459 /* If the array is already in the requested domain, we just return it,
1460 otherwise we return a copy in that domain. */
1462 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1466 mono_error_init (error);
1470 if (mono_object_domain (arr) == domain)
1473 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1474 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1479 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1482 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1483 mono_error_set_pending_exception (&error);
1488 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1491 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1492 mono_error_set_pending_exception (&error);
1497 mono_thread_current (void)
1500 MonoDomain *domain = mono_domain_get ();
1501 MonoInternalThread *internal = mono_thread_internal_current ();
1502 MonoThread **current_thread_ptr;
1504 g_assert (internal);
1505 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1507 if (!*current_thread_ptr) {
1508 g_assert (domain != mono_get_root_domain ());
1509 *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
1510 mono_error_raise_exception (&error); /* FIXME don't raise here */
1512 return *current_thread_ptr;
1515 /* Return the thread object belonging to INTERNAL in the current domain */
1517 mono_thread_current_for_thread (MonoInternalThread *internal)
1520 MonoDomain *domain = mono_domain_get ();
1521 MonoThread **current_thread_ptr;
1523 g_assert (internal);
1524 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1526 if (!*current_thread_ptr) {
1527 g_assert (domain != mono_get_root_domain ());
1528 *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
1529 mono_error_raise_exception (&error); /* FIXME don't raise here */
1531 return *current_thread_ptr;
1535 mono_thread_internal_current (void)
1537 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1538 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1543 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1545 MonoInternalThread *thread = this_obj->internal_thread;
1546 HANDLE handle = thread->handle;
1547 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1550 mono_thread_current_check_pending_interrupt ();
1552 LOCK_THREAD (thread);
1554 if ((thread->state & ThreadState_Unstarted) != 0) {
1555 UNLOCK_THREAD (thread);
1557 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1561 UNLOCK_THREAD (thread);
1566 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1568 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1571 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1574 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1576 if(ret==WAIT_OBJECT_0) {
1577 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1582 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1588 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1596 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1600 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1602 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1605 if (ret != WAIT_IO_COMPLETION)
1608 exc = mono_thread_execute_interruption ();
1610 mono_raise_exception (exc);
1615 /* Re-calculate ms according to the time passed */
1616 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1617 if (diff_ms >= ms) {
1621 wait = ms - diff_ms;
1627 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1633 MonoObject *waitHandle;
1634 MonoInternalThread *thread = mono_thread_internal_current ();
1636 /* Do this WaitSleepJoin check before creating objects */
1637 mono_thread_current_check_pending_interrupt ();
1639 /* We fail in managed if the array has more than 64 elements */
1640 numhandles = (guint32)mono_array_length(mono_handles);
1641 handles = g_new0(HANDLE, numhandles);
1643 for(i = 0; i < numhandles; i++) {
1644 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1645 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1652 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1654 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1656 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1660 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1661 return ret == WAIT_FAILED ? 0x7fffffff : ret;
1664 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1666 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1667 uintptr_t numhandles;
1670 MonoObject *waitHandle;
1671 MonoInternalThread *thread = mono_thread_internal_current ();
1673 /* Do this WaitSleepJoin check before creating objects */
1674 mono_thread_current_check_pending_interrupt ();
1676 numhandles = mono_array_length(mono_handles);
1677 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1680 for(i = 0; i < numhandles; i++) {
1681 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1682 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1689 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1691 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1693 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1695 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1698 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1700 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1701 return ret - WAIT_OBJECT_0;
1703 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1704 return ret - WAIT_ABANDONED_0;
1707 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1708 return ret == WAIT_FAILED ? 0x7fffffff : ret;
1712 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1715 MonoInternalThread *thread = mono_thread_internal_current ();
1717 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1723 mono_thread_current_check_pending_interrupt ();
1725 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1727 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1729 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1731 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1732 return ret == WAIT_FAILED ? 0x7fffffff : ret;
1736 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1739 MonoInternalThread *thread = mono_thread_internal_current ();
1744 mono_thread_current_check_pending_interrupt ();
1746 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1749 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1752 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1754 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1755 return ret == WAIT_FAILED ? 0x7fffffff : ret;
1758 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1765 mutex = CreateMutex (NULL, owned, NULL);
1767 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1769 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1777 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1778 return(ReleaseMutex (handle));
1781 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1787 *error = ERROR_SUCCESS;
1789 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1791 *error = GetLastError ();
1798 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1805 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1807 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1808 mono_string_chars (name));
1810 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1818 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1822 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1827 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1831 *error = ERROR_SUCCESS;
1833 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1835 *error = GetLastError ();
1841 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1848 event = CreateEvent (NULL, manual, initial, NULL);
1850 event = CreateEvent (NULL, manual, initial,
1851 mono_string_chars (name));
1853 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1861 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1862 return (SetEvent(handle));
1865 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1866 return (ResetEvent(handle));
1870 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1871 CloseHandle (handle);
1874 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1880 *error = ERROR_SUCCESS;
1882 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1884 *error = GetLastError ();
1890 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1892 return InterlockedIncrement (location);
1895 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1897 #if SIZEOF_VOID_P == 4
1898 if (G_UNLIKELY ((size_t)location & 0x7)) {
1900 mono_interlocked_lock ();
1903 mono_interlocked_unlock ();
1907 return InterlockedIncrement64 (location);
1910 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1912 return InterlockedDecrement(location);
1915 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1917 #if SIZEOF_VOID_P == 4
1918 if (G_UNLIKELY ((size_t)location & 0x7)) {
1920 mono_interlocked_lock ();
1923 mono_interlocked_unlock ();
1927 return InterlockedDecrement64 (location);
1930 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1932 return InterlockedExchange(location, value);
1935 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1938 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1939 mono_gc_wbarrier_generic_nostore (location);
1943 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1945 return InterlockedExchangePointer(location, value);
1948 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1950 IntFloatUnion val, ret;
1953 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1959 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1961 #if SIZEOF_VOID_P == 4
1962 if (G_UNLIKELY ((size_t)location & 0x7)) {
1964 mono_interlocked_lock ();
1967 mono_interlocked_unlock ();
1971 return InterlockedExchange64 (location, value);
1975 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1977 LongDoubleUnion val, ret;
1980 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1985 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1987 return InterlockedCompareExchange(location, value, comparand);
1990 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1992 gint32 r = InterlockedCompareExchange(location, value, comparand);
1993 *success = r == comparand;
1997 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
2000 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
2001 mono_gc_wbarrier_generic_nostore (location);
2005 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
2007 return InterlockedCompareExchangePointer(location, value, comparand);
2010 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2012 IntFloatUnion val, ret, cmp;
2015 cmp.fval = comparand;
2016 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2022 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2024 #if SIZEOF_VOID_P == 8
2025 LongDoubleUnion val, comp, ret;
2028 comp.fval = comparand;
2029 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2035 mono_interlocked_lock ();
2037 if (old == comparand)
2039 mono_interlocked_unlock ();
2046 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2048 #if SIZEOF_VOID_P == 4
2049 if (G_UNLIKELY ((size_t)location & 0x7)) {
2051 mono_interlocked_lock ();
2053 if (old == comparand)
2055 mono_interlocked_unlock ();
2059 return InterlockedCompareExchange64 (location, value, comparand);
2063 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2066 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2067 mono_gc_wbarrier_generic_nostore (location);
2072 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2075 MONO_CHECK_NULL (location, NULL);
2076 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2077 mono_gc_wbarrier_generic_nostore (location);
2082 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2084 return InterlockedAdd (location, value);
2088 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2090 #if SIZEOF_VOID_P == 4
2091 if (G_UNLIKELY ((size_t)location & 0x7)) {
2093 mono_interlocked_lock ();
2096 mono_interlocked_unlock ();
2100 return InterlockedAdd64 (location, value);
2104 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2106 #if SIZEOF_VOID_P == 4
2107 if (G_UNLIKELY ((size_t)location & 0x7)) {
2109 mono_interlocked_lock ();
2111 mono_interlocked_unlock ();
2115 return InterlockedRead64 (location);
2119 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2121 mono_memory_barrier ();
2125 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2127 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2129 if (state & ThreadState_Background) {
2130 /* If the thread changes the background mode, the main thread has to
2131 * be notified, since it has to rebuild the list of threads to
2134 SetEvent (background_change_event);
2139 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2141 mono_thread_set_state (this_obj, (MonoThreadState)state);
2143 if (state & ThreadState_Background) {
2144 /* If the thread changes the background mode, the main thread has to
2145 * be notified, since it has to rebuild the list of threads to
2148 SetEvent (background_change_event);
2153 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2157 LOCK_THREAD (this_obj);
2159 state = this_obj->state;
2161 UNLOCK_THREAD (this_obj);
2166 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2168 MonoInternalThread *current;
2170 MonoInternalThread *thread = this_obj->internal_thread;
2172 LOCK_THREAD (thread);
2174 current = mono_thread_internal_current ();
2176 thread->thread_interrupt_requested = TRUE;
2177 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2179 UNLOCK_THREAD (thread);
2182 async_abort_internal (thread, FALSE);
2186 void mono_thread_current_check_pending_interrupt ()
2188 MonoInternalThread *thread = mono_thread_internal_current ();
2189 gboolean throw_ = FALSE;
2191 LOCK_THREAD (thread);
2193 if (thread->thread_interrupt_requested) {
2195 thread->thread_interrupt_requested = FALSE;
2198 UNLOCK_THREAD (thread);
2201 mono_raise_exception (mono_get_exception_thread_interrupted ());
2206 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2208 LOCK_THREAD (thread);
2210 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2211 (thread->state & ThreadState_StopRequested) != 0 ||
2212 (thread->state & ThreadState_Stopped) != 0)
2214 UNLOCK_THREAD (thread);
2218 if ((thread->state & ThreadState_Unstarted) != 0) {
2219 thread->state |= ThreadState_Aborted;
2220 UNLOCK_THREAD (thread);
2224 thread->state |= ThreadState_AbortRequested;
2225 if (thread->abort_state_handle)
2226 mono_gchandle_free (thread->abort_state_handle);
2228 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2229 g_assert (thread->abort_state_handle);
2231 thread->abort_state_handle = 0;
2233 thread->abort_exc = NULL;
2235 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));
2237 /* During shutdown, we can't wait for other threads */
2239 /* Make sure the thread is awake */
2240 mono_thread_resume (thread);
2242 UNLOCK_THREAD (thread);
2244 if (thread == mono_thread_internal_current ())
2245 self_abort_internal ();
2247 async_abort_internal (thread, TRUE);
2251 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2253 MonoInternalThread *thread = mono_thread_internal_current ();
2254 gboolean was_aborting;
2256 LOCK_THREAD (thread);
2257 was_aborting = thread->state & ThreadState_AbortRequested;
2258 thread->state &= ~ThreadState_AbortRequested;
2259 UNLOCK_THREAD (thread);
2261 if (!was_aborting) {
2262 const char *msg = "Unable to reset abort because no abort was requested";
2263 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2266 thread->abort_exc = NULL;
2267 if (thread->abort_state_handle) {
2268 mono_gchandle_free (thread->abort_state_handle);
2269 /* This is actually not necessary - the handle
2270 only counts if the exception is set */
2271 thread->abort_state_handle = 0;
2276 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2278 LOCK_THREAD (thread);
2280 thread->state &= ~ThreadState_AbortRequested;
2282 if (thread->abort_exc) {
2283 thread->abort_exc = NULL;
2284 if (thread->abort_state_handle) {
2285 mono_gchandle_free (thread->abort_state_handle);
2286 /* This is actually not necessary - the handle
2287 only counts if the exception is set */
2288 thread->abort_state_handle = 0;
2292 UNLOCK_THREAD (thread);
2296 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2299 MonoInternalThread *thread = this_obj->internal_thread;
2300 MonoObject *state, *deserialized = NULL;
2303 if (!thread->abort_state_handle)
2306 state = mono_gchandle_get_target (thread->abort_state_handle);
2309 domain = mono_domain_get ();
2310 if (mono_object_domain (state) == domain)
2313 deserialized = mono_object_xdomain_representation (state, domain, &error);
2315 if (!deserialized) {
2316 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2317 if (!is_ok (&error)) {
2318 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2319 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2321 mono_set_pending_exception (invalid_op_exc);
2325 return deserialized;
2329 mono_thread_suspend (MonoInternalThread *thread)
2331 LOCK_THREAD (thread);
2333 if ((thread->state & ThreadState_Unstarted) != 0 ||
2334 (thread->state & ThreadState_Aborted) != 0 ||
2335 (thread->state & ThreadState_Stopped) != 0)
2337 UNLOCK_THREAD (thread);
2341 if ((thread->state & ThreadState_Suspended) != 0 ||
2342 (thread->state & ThreadState_SuspendRequested) != 0 ||
2343 (thread->state & ThreadState_StopRequested) != 0)
2345 UNLOCK_THREAD (thread);
2349 thread->state |= ThreadState_SuspendRequested;
2351 if (thread == mono_thread_internal_current ()) {
2352 /* calls UNLOCK_THREAD (thread) */
2353 self_suspend_internal ();
2355 /* calls UNLOCK_THREAD (thread) */
2356 async_suspend_internal (thread, FALSE);
2363 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2365 if (!mono_thread_suspend (this_obj->internal_thread)) {
2366 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2371 /* LOCKING: LOCK_THREAD(thread) must be held */
2373 mono_thread_resume (MonoInternalThread *thread)
2375 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2376 thread->state &= ~ThreadState_SuspendRequested;
2380 if ((thread->state & ThreadState_Suspended) == 0 ||
2381 (thread->state & ThreadState_Unstarted) != 0 ||
2382 (thread->state & ThreadState_Aborted) != 0 ||
2383 (thread->state & ThreadState_Stopped) != 0)
2388 UNLOCK_THREAD (thread);
2390 /* Awake the thread */
2391 if (!mono_thread_info_resume (thread_get_tid (thread)))
2394 LOCK_THREAD (thread);
2396 thread->state &= ~ThreadState_Suspended;
2402 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2404 if (!thread->internal_thread) {
2405 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2407 LOCK_THREAD (thread->internal_thread);
2408 if (!mono_thread_resume (thread->internal_thread))
2409 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2410 UNLOCK_THREAD (thread->internal_thread);
2415 mono_threads_is_critical_method (MonoMethod *method)
2417 switch (method->wrapper_type) {
2418 case MONO_WRAPPER_RUNTIME_INVOKE:
2419 case MONO_WRAPPER_XDOMAIN_INVOKE:
2420 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2427 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2432 if (mono_threads_is_critical_method (m)) {
2433 *((gboolean*)data) = TRUE;
2440 is_running_protected_wrapper (void)
2442 gboolean found = FALSE;
2443 mono_stack_walk (find_wrapper, &found);
2447 void mono_thread_internal_stop (MonoInternalThread *thread)
2449 LOCK_THREAD (thread);
2451 if ((thread->state & ThreadState_StopRequested) != 0 ||
2452 (thread->state & ThreadState_Stopped) != 0)
2454 UNLOCK_THREAD (thread);
2458 /* Make sure the thread is awake */
2459 mono_thread_resume (thread);
2461 thread->state |= ThreadState_StopRequested;
2462 thread->state &= ~ThreadState_AbortRequested;
2464 UNLOCK_THREAD (thread);
2466 if (thread == mono_thread_internal_current ())
2467 self_abort_internal ();
2469 async_abort_internal (thread, TRUE);
2472 void mono_thread_stop (MonoThread *thread)
2474 mono_thread_internal_stop (thread->internal_thread);
2478 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2480 gint8 tmp = *(volatile gint8 *)ptr;
2481 mono_memory_barrier ();
2486 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2488 gint16 tmp = *(volatile gint16 *)ptr;
2489 mono_memory_barrier ();
2494 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2496 gint32 tmp = *(volatile gint32 *)ptr;
2497 mono_memory_barrier ();
2502 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2504 gint64 tmp = *(volatile gint64 *)ptr;
2505 mono_memory_barrier ();
2510 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2512 volatile void *tmp = *(volatile void **)ptr;
2513 mono_memory_barrier ();
2514 return (void *) tmp;
2518 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2520 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2521 mono_memory_barrier ();
2522 return (MonoObject *) tmp;
2526 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2528 double tmp = *(volatile double *)ptr;
2529 mono_memory_barrier ();
2534 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2536 float tmp = *(volatile float *)ptr;
2537 mono_memory_barrier ();
2542 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2544 return InterlockedRead8 ((volatile gint8 *)ptr);
2548 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2550 return InterlockedRead16 ((volatile gint16 *)ptr);
2554 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2556 return InterlockedRead ((volatile gint32 *)ptr);
2560 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2562 #if SIZEOF_VOID_P == 4
2563 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2565 mono_interlocked_lock ();
2566 val = *(gint64*)ptr;
2567 mono_interlocked_unlock ();
2571 return InterlockedRead64 ((volatile gint64 *)ptr);
2575 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2577 return InterlockedReadPointer ((volatile gpointer *)ptr);
2581 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2585 #if SIZEOF_VOID_P == 4
2586 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2588 mono_interlocked_lock ();
2589 val = *(double*)ptr;
2590 mono_interlocked_unlock ();
2595 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2601 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2605 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2611 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2613 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2617 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2619 mono_memory_barrier ();
2620 *(volatile gint8 *)ptr = value;
2624 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2626 mono_memory_barrier ();
2627 *(volatile gint16 *)ptr = value;
2631 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2633 mono_memory_barrier ();
2634 *(volatile gint32 *)ptr = value;
2638 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2640 mono_memory_barrier ();
2641 *(volatile gint64 *)ptr = value;
2645 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2647 mono_memory_barrier ();
2648 *(volatile void **)ptr = value;
2652 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2654 mono_memory_barrier ();
2655 mono_gc_wbarrier_generic_store (ptr, value);
2659 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2661 mono_memory_barrier ();
2662 *(volatile double *)ptr = value;
2666 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2668 mono_memory_barrier ();
2669 *(volatile float *)ptr = value;
2673 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2675 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2679 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2681 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2685 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2687 InterlockedWrite ((volatile gint32 *)ptr, value);
2691 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2693 #if SIZEOF_VOID_P == 4
2694 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2695 mono_interlocked_lock ();
2696 *(gint64*)ptr = value;
2697 mono_interlocked_unlock ();
2702 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2706 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2708 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2712 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2716 #if SIZEOF_VOID_P == 4
2717 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2718 mono_interlocked_lock ();
2719 *(double*)ptr = value;
2720 mono_interlocked_unlock ();
2727 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2731 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2737 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2741 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2743 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2747 free_context (void *user_data)
2749 ContextStaticData *data = user_data;
2751 mono_threads_lock ();
2754 * There is no guarantee that, by the point this reference queue callback
2755 * has been invoked, the GC handle associated with the object will fail to
2756 * resolve as one might expect. So if we don't free and remove the GC
2757 * handle here, free_context_static_data_helper () could end up resolving
2758 * a GC handle to an actually-dead context which would contain a pointer
2759 * to an already-freed static data segment, resulting in a crash when
2762 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2764 mono_threads_unlock ();
2766 mono_gchandle_free (data->gc_handle);
2767 mono_free_static_data (data->static_data);
2772 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2774 mono_threads_lock ();
2776 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2779 contexts = g_hash_table_new (NULL, NULL);
2782 context_queue = mono_gc_reference_queue_new (free_context);
2784 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2785 g_hash_table_insert (contexts, gch, gch);
2788 * We use this intermediate structure to contain a duplicate pointer to
2789 * the static data because we can't rely on being able to resolve the GC
2790 * handle in the reference queue callback.
2792 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2793 data->gc_handle = GPOINTER_TO_UINT (gch);
2796 context_adjust_static_data (ctx);
2797 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2799 mono_threads_unlock ();
2801 mono_profiler_context_loaded (ctx);
2805 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2808 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2809 * cleanup in exceptional circumstances, we don't actually do any
2810 * cleanup work here. We instead do this via a reference queue.
2813 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2815 mono_profiler_context_unloaded (ctx);
2819 mono_thread_init_tls (void)
2821 MONO_FAST_TLS_INIT (tls_current_object);
2822 mono_native_tls_alloc (¤t_object_key, NULL);
2825 void mono_thread_init (MonoThreadStartCB start_cb,
2826 MonoThreadAttachCB attach_cb)
2828 mono_coop_mutex_init_recursive (&threads_mutex);
2830 mono_os_mutex_init_recursive(&interlocked_mutex);
2831 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2833 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2834 g_assert(background_change_event != NULL);
2836 mono_init_static_data_info (&thread_static_info);
2837 mono_init_static_data_info (&context_static_info);
2839 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2841 mono_thread_start_cb = start_cb;
2842 mono_thread_attach_cb = attach_cb;
2844 /* Get a pseudo handle to the current process. This is just a
2845 * kludge so that wapi can build a process handle if needed.
2846 * As a pseudo handle is returned, we don't need to clean
2849 GetCurrentProcess ();
2852 void mono_thread_cleanup (void)
2854 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2855 MonoThreadInfo *info;
2857 /* The main thread must abandon any held mutexes (particularly
2858 * important for named mutexes as they are shared across
2859 * processes, see bug 74680.) This will happen when the
2860 * thread exits, but if it's not running in a subthread it
2861 * won't exit in time.
2863 info = mono_thread_info_current ();
2864 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2868 /* This stuff needs more testing, it seems one of these
2869 * critical sections can be locked when mono_thread_cleanup is
2872 mono_coop_mutex_destroy (&threads_mutex);
2873 mono_os_mutex_destroy (&interlocked_mutex);
2874 mono_os_mutex_destroy (&delayed_free_table_mutex);
2875 mono_os_mutex_destroy (&small_id_mutex);
2876 CloseHandle (background_change_event);
2879 mono_native_tls_free (current_object_key);
2883 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2885 mono_thread_cleanup_fn = func;
2889 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2891 thread->internal_thread->manage_callback = func;
2895 static void print_tids (gpointer key, gpointer value, gpointer user)
2897 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2898 * sizeof(uint) and a cast to uint would overflow
2900 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2901 * print this as a pointer.
2903 g_message ("Waiting for: %p", key);
2908 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2909 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2913 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2917 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2920 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2923 if(ret==WAIT_FAILED) {
2924 /* See the comment in build_wait_tids() */
2925 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2929 for(i=0; i<wait->num; i++)
2930 CloseHandle (wait->handles[i]);
2932 if (ret == WAIT_TIMEOUT)
2935 for(i=0; i<wait->num; i++) {
2936 gsize tid = wait->threads[i]->tid;
2939 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2940 * it can still run io-layer etc. code. So wait for it to really exit.
2941 * FIXME: This won't join threads which are not in the joinable_hash yet.
2943 mono_thread_join ((gpointer)tid);
2945 mono_threads_lock ();
2946 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2947 /* This thread must have been killed, because
2948 * it hasn't cleaned itself up. (It's just
2949 * possible that the thread exited before the
2950 * parent thread had a chance to store the
2951 * handle, and now there is another pointer to
2952 * the already-exited thread stored. In this
2953 * case, we'll just get two
2954 * mono_profiler_thread_end() calls for the
2958 mono_threads_unlock ();
2959 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2960 thread_cleanup (wait->threads[i]);
2962 mono_threads_unlock ();
2967 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2969 guint32 i, ret, count;
2971 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2973 /* Add the thread state change event, so it wakes up if a thread changes
2974 * to background mode.
2977 if (count < MAXIMUM_WAIT_OBJECTS) {
2978 wait->handles [count] = background_change_event;
2983 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2986 if(ret==WAIT_FAILED) {
2987 /* See the comment in build_wait_tids() */
2988 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2992 for(i=0; i<wait->num; i++)
2993 CloseHandle (wait->handles[i]);
2995 if (ret == WAIT_TIMEOUT)
2998 if (ret < wait->num) {
2999 gsize tid = wait->threads[ret]->tid;
3000 mono_threads_lock ();
3001 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3002 /* See comment in wait_for_tids about thread cleanup */
3003 mono_threads_unlock ();
3004 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3005 thread_cleanup (wait->threads [ret]);
3007 mono_threads_unlock ();
3011 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3013 struct wait_data *wait=(struct wait_data *)user;
3015 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
3017 MonoInternalThread *thread=(MonoInternalThread *)value;
3019 /* Ignore background threads, we abort them later */
3020 /* Do not lock here since it is not needed and the caller holds threads_lock */
3021 if (thread->state & ThreadState_Background) {
3022 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3023 return; /* just leave, ignore */
3026 if (mono_gc_is_finalizer_internal_thread (thread)) {
3027 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3031 if (thread == mono_thread_internal_current ()) {
3032 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3036 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3037 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3041 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3042 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3046 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3047 if (handle == NULL) {
3048 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3052 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3053 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3054 wait->handles[wait->num]=handle;
3055 wait->threads[wait->num]=thread;
3058 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3060 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3065 /* Just ignore the rest, we can't do anything with
3072 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3074 struct wait_data *wait=(struct wait_data *)user;
3075 MonoNativeThreadId self = mono_native_thread_id_get ();
3076 MonoInternalThread *thread = (MonoInternalThread *)value;
3079 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
3082 /* The finalizer thread is not a background thread */
3083 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3084 && (thread->state & ThreadState_Background) != 0
3085 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3087 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3091 wait->handles[wait->num] = handle;
3092 wait->threads[wait->num] = thread;
3095 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3096 mono_thread_internal_stop (thread);
3100 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3101 && !mono_gc_is_finalizer_internal_thread (thread);
3105 * mono_threads_set_shutting_down:
3107 * Is called by a thread that wants to shut down Mono. If the runtime is already
3108 * shutting down, the calling thread is suspended/stopped, and this function never
3112 mono_threads_set_shutting_down (void)
3114 MonoInternalThread *current_thread = mono_thread_internal_current ();
3116 mono_threads_lock ();
3118 if (shutting_down) {
3119 mono_threads_unlock ();
3121 /* Make sure we're properly suspended/stopped */
3123 LOCK_THREAD (current_thread);
3125 if ((current_thread->state & ThreadState_SuspendRequested) ||
3126 (current_thread->state & ThreadState_AbortRequested) ||
3127 (current_thread->state & ThreadState_StopRequested)) {
3128 UNLOCK_THREAD (current_thread);
3129 mono_thread_execute_interruption ();
3131 current_thread->state |= ThreadState_Stopped;
3132 UNLOCK_THREAD (current_thread);
3135 /*since we're killing the thread, unset the current domain.*/
3136 mono_domain_unset ();
3138 /* Wake up other threads potentially waiting for us */
3139 mono_thread_info_exit ();
3141 shutting_down = TRUE;
3143 /* Not really a background state change, but this will
3144 * interrupt the main thread if it is waiting for all
3145 * the other threads.
3147 SetEvent (background_change_event);
3149 mono_threads_unlock ();
3153 void mono_thread_manage (void)
3155 struct wait_data wait_data;
3156 struct wait_data *wait = &wait_data;
3158 memset (wait, 0, sizeof (struct wait_data));
3159 /* join each thread that's still running */
3160 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3162 mono_threads_lock ();
3164 THREAD_DEBUG (g_message("%s: No threads", __func__));
3165 mono_threads_unlock ();
3168 mono_threads_unlock ();
3171 mono_threads_lock ();
3172 if (shutting_down) {
3173 /* somebody else is shutting down */
3174 mono_threads_unlock ();
3177 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3178 mono_g_hash_table_foreach (threads, print_tids, NULL));
3180 ResetEvent (background_change_event);
3182 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3183 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3184 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3185 mono_threads_unlock ();
3187 /* Something to wait for */
3188 wait_for_tids_or_state_change (wait, INFINITE);
3190 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3191 } while(wait->num>0);
3193 /* Mono is shutting down, so just wait for the end */
3194 if (!mono_runtime_try_shutdown ()) {
3195 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3196 mono_thread_suspend (mono_thread_internal_current ());
3197 mono_thread_execute_interruption ();
3201 * Remove everything but the finalizer thread and self.
3202 * Also abort all the background threads
3205 mono_threads_lock ();
3208 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3209 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3210 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3212 mono_threads_unlock ();
3214 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3216 /* Something to wait for */
3217 wait_for_tids (wait, INFINITE);
3219 } while (wait->num > 0);
3222 * give the subthreads a chance to really quit (this is mainly needed
3223 * to get correct user and system times from getrusage/wait/time(1)).
3224 * This could be removed if we avoid pthread_detach() and use pthread_join().
3226 mono_thread_info_yield ();
3230 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3232 MonoInternalThread *thread = (MonoInternalThread*)value;
3233 struct wait_data *wait = (struct wait_data*)user_data;
3237 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3239 * This needs no locking.
3241 if ((thread->state & ThreadState_Suspended) != 0 ||
3242 (thread->state & ThreadState_Stopped) != 0)
3245 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3246 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3250 wait->handles [wait->num] = handle;
3251 wait->threads [wait->num] = thread;
3257 * mono_thread_suspend_all_other_threads:
3259 * Suspend all managed threads except the finalizer thread and this thread. It is
3260 * not possible to resume them later.
3262 void mono_thread_suspend_all_other_threads (void)
3264 struct wait_data wait_data;
3265 struct wait_data *wait = &wait_data;
3267 MonoNativeThreadId self = mono_native_thread_id_get ();
3268 guint32 eventidx = 0;
3269 gboolean starting, finished;
3271 memset (wait, 0, sizeof (struct wait_data));
3273 * The other threads could be in an arbitrary state at this point, i.e.
3274 * they could be starting up, shutting down etc. This means that there could be
3275 * threads which are not even in the threads hash table yet.
3279 * First we set a barrier which will be checked by all threads before they
3280 * are added to the threads hash table, and they will exit if the flag is set.
3281 * This ensures that no threads could be added to the hash later.
3282 * We will use shutting_down as the barrier for now.
3284 g_assert (shutting_down);
3287 * We make multiple calls to WaitForMultipleObjects since:
3288 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3289 * - some threads could exit without becoming suspended
3294 * Make a copy of the hashtable since we can't do anything with
3295 * threads while threads_mutex is held.
3298 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3299 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3300 mono_threads_lock ();
3301 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3302 mono_threads_unlock ();
3305 /* Get the suspended events that we'll be waiting for */
3306 for (i = 0; i < wait->num; ++i) {
3307 MonoInternalThread *thread = wait->threads [i];
3309 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3310 || mono_gc_is_finalizer_internal_thread (thread)
3311 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3313 //CloseHandle (wait->handles [i]);
3314 wait->threads [i] = NULL; /* ignore this thread in next loop */
3318 LOCK_THREAD (thread);
3320 if ((thread->state & ThreadState_Suspended) != 0 ||
3321 (thread->state & ThreadState_StopRequested) != 0 ||
3322 (thread->state & ThreadState_Stopped) != 0) {
3323 UNLOCK_THREAD (thread);
3324 CloseHandle (wait->handles [i]);
3325 wait->threads [i] = NULL; /* ignore this thread in next loop */
3331 /* Convert abort requests into suspend requests */
3332 if ((thread->state & ThreadState_AbortRequested) != 0)
3333 thread->state &= ~ThreadState_AbortRequested;
3335 thread->state |= ThreadState_SuspendRequested;
3337 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3338 async_suspend_internal (thread, TRUE);
3340 if (eventidx <= 0) {
3342 * If there are threads which are starting up, we wait until they
3343 * are suspended when they try to register in the threads hash.
3344 * This is guaranteed to finish, since the threads which can create new
3345 * threads get suspended after a while.
3346 * FIXME: The finalizer thread can still create new threads.
3348 mono_threads_lock ();
3349 if (threads_starting_up)
3350 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3353 mono_threads_unlock ();
3355 mono_thread_info_sleep (100, NULL);
3363 MonoInternalThread *thread;
3364 MonoStackFrameInfo *frames;
3365 int nframes, max_frames;
3366 int nthreads, max_threads;
3367 MonoInternalThread **threads;
3368 } ThreadDumpUserData;
3370 static gboolean thread_dump_requested;
3372 /* This needs to be async safe */
3374 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3376 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3378 if (ud->nframes < ud->max_frames) {
3379 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3386 /* This needs to be async safe */
3387 static SuspendThreadResult
3388 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3390 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3391 MonoInternalThread *thread = user_data->thread;
3394 /* This no longer works with remote unwinding */
3396 wapi_desc = wapi_current_thread_desc ();
3397 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3402 if (thread == mono_thread_internal_current ())
3403 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3405 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3407 return MonoResumeThread;
3411 int nthreads, max_threads;
3412 MonoInternalThread **threads;
3413 } CollectThreadsUserData;
3416 collect_thread (gpointer key, gpointer value, gpointer user)
3418 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3419 MonoInternalThread *thread = (MonoInternalThread *)value;
3421 if (ud->nthreads < ud->max_threads)
3422 ud->threads [ud->nthreads ++] = thread;
3426 * Collect running threads into the THREADS array.
3427 * THREADS should be an array allocated on the stack.
3430 collect_threads (MonoInternalThread **thread_array, int max_threads)
3432 CollectThreadsUserData ud;
3434 memset (&ud, 0, sizeof (ud));
3435 /* This array contains refs, but its on the stack, so its ok */
3436 ud.threads = thread_array;
3437 ud.max_threads = max_threads;
3439 mono_threads_lock ();
3440 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3441 mono_threads_unlock ();
3447 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3449 GString* text = g_string_new (0);
3451 GError *error = NULL;
3454 ud->thread = thread;
3457 /* Collect frames for the thread */
3458 if (thread == mono_thread_internal_current ()) {
3459 get_thread_dump (mono_thread_info_current (), ud);
3461 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3465 * Do all the non async-safe work outside of get_thread_dump.
3468 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3470 g_string_append_printf (text, "\n\"%s\"", name);
3473 else if (thread->threadpool_thread) {
3474 g_string_append (text, "\n\"<threadpool thread>\"");
3476 g_string_append (text, "\n\"<unnamed thread>\"");
3479 for (i = 0; i < ud->nframes; ++i) {
3480 MonoStackFrameInfo *frame = &ud->frames [i];
3481 MonoMethod *method = NULL;
3483 if (frame->type == FRAME_TYPE_MANAGED)
3484 method = mono_jit_info_get_method (frame->ji);
3487 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3488 g_string_append_printf (text, " %s\n", location);
3491 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3495 fprintf (stdout, "%s", text->str);
3497 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3498 OutputDebugStringA(text->str);
3501 g_string_free (text, TRUE);
3506 mono_threads_perform_thread_dump (void)
3508 ThreadDumpUserData ud;
3509 MonoInternalThread *thread_array [128];
3510 int tindex, nthreads;
3512 if (!thread_dump_requested)
3515 printf ("Full thread dump:\n");
3517 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3518 nthreads = collect_threads (thread_array, 128);
3520 memset (&ud, 0, sizeof (ud));
3521 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3522 ud.max_frames = 256;
3524 for (tindex = 0; tindex < nthreads; ++tindex)
3525 dump_thread (thread_array [tindex], &ud);
3529 thread_dump_requested = FALSE;
3532 /* Obtain the thread dump of all threads */
3534 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames)
3538 ThreadDumpUserData ud;
3539 MonoInternalThread *thread_array [128];
3540 MonoDomain *domain = mono_domain_get ();
3541 MonoDebugSourceLocation *location;
3542 int tindex, nthreads;
3544 mono_error_init (&error);
3546 *out_threads = NULL;
3547 *out_stack_frames = NULL;
3549 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3550 nthreads = collect_threads (thread_array, 128);
3552 memset (&ud, 0, sizeof (ud));
3553 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3554 ud.max_frames = 256;
3556 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, &error);
3557 if (!is_ok (&error))
3559 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, &error);
3560 if (!is_ok (&error))
3563 for (tindex = 0; tindex < nthreads; ++tindex) {
3564 MonoInternalThread *thread = thread_array [tindex];
3565 MonoArray *thread_frames;
3571 /* Collect frames for the thread */
3572 if (thread == mono_thread_internal_current ()) {
3573 get_thread_dump (mono_thread_info_current (), &ud);
3575 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3578 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3580 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, &error);
3581 if (!is_ok (&error))
3583 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3585 for (i = 0; i < ud.nframes; ++i) {
3586 MonoStackFrameInfo *frame = &ud.frames [i];
3587 MonoMethod *method = NULL;
3588 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error);
3589 if (!mono_error_ok (&error))
3592 sf->native_offset = frame->native_offset;
3594 if (frame->type == FRAME_TYPE_MANAGED)
3595 method = mono_jit_info_get_method (frame->ji);
3598 sf->method_address = (gsize) frame->ji->code_start;
3600 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
3601 mono_error_raise_exception (&error); /* FIXME don't raise here */
3602 MONO_OBJECT_SETREF (sf, method, rm);
3604 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3606 sf->il_offset = location->il_offset;
3608 if (location && location->source_file) {
3609 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3610 sf->line = location->row;
3611 sf->column = location->column;
3613 mono_debug_free_source_location (location);
3618 mono_array_setref (thread_frames, i, sf);
3624 mono_error_raise_exception (&error); /* FIXME don't raise here */
3628 * mono_threads_request_thread_dump:
3630 * Ask all threads except the current to print their stacktrace to stdout.
3633 mono_threads_request_thread_dump (void)
3635 /*The new thread dump code runs out of the finalizer thread. */
3636 thread_dump_requested = TRUE;
3637 mono_gc_finalize_notify ();
3642 gint allocated; /* +1 so that refs [allocated] == NULL */
3646 typedef struct ref_stack RefStack;
3649 ref_stack_new (gint initial_size)
3653 initial_size = MAX (initial_size, 16) + 1;
3654 rs = g_new0 (RefStack, 1);
3655 rs->refs = g_new0 (gpointer, initial_size);
3656 rs->allocated = initial_size;
3661 ref_stack_destroy (gpointer ptr)
3663 RefStack *rs = (RefStack *)ptr;
3672 ref_stack_push (RefStack *rs, gpointer ptr)
3674 g_assert (rs != NULL);
3676 if (rs->bottom >= rs->allocated) {
3677 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3678 rs->allocated <<= 1;
3679 rs->refs [rs->allocated] = NULL;
3681 rs->refs [rs->bottom++] = ptr;
3685 ref_stack_pop (RefStack *rs)
3687 if (rs == NULL || rs->bottom == 0)
3691 rs->refs [rs->bottom] = NULL;
3695 ref_stack_find (RefStack *rs, gpointer ptr)
3702 for (refs = rs->refs; refs && *refs; refs++) {
3710 * mono_thread_push_appdomain_ref:
3712 * Register that the current thread may have references to objects in domain
3713 * @domain on its stack. Each call to this function should be paired with a
3714 * call to pop_appdomain_ref.
3717 mono_thread_push_appdomain_ref (MonoDomain *domain)
3719 MonoInternalThread *thread = mono_thread_internal_current ();
3722 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3723 SPIN_LOCK (thread->lock_thread_id);
3724 if (thread->appdomain_refs == NULL)
3725 thread->appdomain_refs = ref_stack_new (16);
3726 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3727 SPIN_UNLOCK (thread->lock_thread_id);
3732 mono_thread_pop_appdomain_ref (void)
3734 MonoInternalThread *thread = mono_thread_internal_current ();
3737 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3738 SPIN_LOCK (thread->lock_thread_id);
3739 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3740 SPIN_UNLOCK (thread->lock_thread_id);
3745 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3748 SPIN_LOCK (thread->lock_thread_id);
3749 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3750 SPIN_UNLOCK (thread->lock_thread_id);
3755 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3757 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3760 typedef struct abort_appdomain_data {
3761 struct wait_data wait;
3763 } abort_appdomain_data;
3766 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3768 MonoInternalThread *thread = (MonoInternalThread*)value;
3769 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3770 MonoDomain *domain = data->domain;
3772 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3773 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3775 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3776 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3779 data->wait.handles [data->wait.num] = handle;
3780 data->wait.threads [data->wait.num] = thread;
3783 /* Just ignore the rest, we can't do anything with
3791 * mono_threads_abort_appdomain_threads:
3793 * Abort threads which has references to the given appdomain.
3796 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3798 #ifdef __native_client__
3802 abort_appdomain_data user_data;
3804 int orig_timeout = timeout;
3807 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3809 start_time = mono_msec_ticks ();
3811 mono_threads_lock ();
3813 user_data.domain = domain;
3814 user_data.wait.num = 0;
3815 /* This shouldn't take any locks */
3816 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3817 mono_threads_unlock ();
3819 if (user_data.wait.num > 0) {
3820 /* Abort the threads outside the threads lock */
3821 for (i = 0; i < user_data.wait.num; ++i)
3822 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3825 * We should wait for the threads either to abort, or to leave the
3826 * domain. We can't do the latter, so we wait with a timeout.
3828 wait_for_tids (&user_data.wait, 100);
3831 /* Update remaining time */
3832 timeout -= mono_msec_ticks () - start_time;
3833 start_time = mono_msec_ticks ();
3835 if (orig_timeout != -1 && timeout < 0)
3838 while (user_data.wait.num > 0);
3840 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3846 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3848 MonoInternalThread *thread = (MonoInternalThread*)value;
3849 MonoDomain *domain = (MonoDomain*)user_data;
3852 /* No locking needed here */
3853 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3855 if (thread->cached_culture_info) {
3856 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3857 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3858 if (obj && obj->vtable->domain == domain)
3859 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3865 * mono_threads_clear_cached_culture:
3867 * Clear the cached_current_culture from all threads if it is in the
3871 mono_threads_clear_cached_culture (MonoDomain *domain)
3873 mono_threads_lock ();
3874 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3875 mono_threads_unlock ();
3879 * mono_thread_get_undeniable_exception:
3881 * Return an exception which needs to be raised when leaving a catch clause.
3882 * This is used for undeniable exception propagation.
3885 mono_thread_get_undeniable_exception (void)
3887 MonoInternalThread *thread = mono_thread_internal_current ();
3889 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3891 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3892 * exception if the thread no longer references a dying appdomain.
3894 thread->abort_exc->trace_ips = NULL;
3895 thread->abort_exc->stack_trace = NULL;
3896 return thread->abort_exc;
3902 #if MONO_SMALL_CONFIG
3903 #define NUM_STATIC_DATA_IDX 4
3904 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3908 #define NUM_STATIC_DATA_IDX 8
3909 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3910 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3914 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3915 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3918 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3920 gpointer *static_data = (gpointer *)addr;
3922 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3923 void **ptr = (void **)static_data [i];
3928 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3929 void **p = ptr + idx;
3932 mark_func ((MonoObject**)p, gc_data);
3938 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3940 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3944 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3946 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3950 * mono_alloc_static_data
3952 * Allocate memory blocks for storing threads or context static data
3955 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3957 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3960 gpointer* static_data = *static_data_ptr;
3962 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3963 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3965 if (mono_gc_user_markers_supported ()) {
3966 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3967 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3969 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3970 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3973 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3974 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3975 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3976 *static_data_ptr = static_data;
3977 static_data [0] = static_data;
3980 for (i = 1; i <= idx; ++i) {
3981 if (static_data [i])
3984 if (mono_gc_user_markers_supported ())
3985 static_data [i] = g_malloc0 (static_data_size [i]);
3987 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3988 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3989 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3994 mono_free_static_data (gpointer* static_data)
3997 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3998 gpointer p = static_data [i];
4002 * At this point, the static data pointer array is still registered with the
4003 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4004 * data. Freeing the individual arrays without first nulling their slots
4005 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4006 * such an already freed array. See bug #13813.
4008 static_data [i] = NULL;
4009 mono_memory_write_barrier ();
4010 if (mono_gc_user_markers_supported ())
4013 mono_gc_free_fixed (p);
4015 mono_gc_free_fixed (static_data);
4019 * mono_init_static_data_info
4021 * Initializes static data counters
4023 static void mono_init_static_data_info (StaticDataInfo *static_data)
4025 static_data->idx = 0;
4026 static_data->offset = 0;
4027 static_data->freelist = NULL;
4031 * mono_alloc_static_data_slot
4033 * Generates an offset for static data. static_data contains the counters
4034 * used to generate it.
4037 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4039 if (!static_data->idx && !static_data->offset) {
4041 * we use the first chunk of the first allocation also as
4042 * an array for the rest of the data
4044 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4046 static_data->offset += align - 1;
4047 static_data->offset &= ~(align - 1);
4048 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4049 static_data->idx ++;
4050 g_assert (size <= static_data_size [static_data->idx]);
4051 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4052 static_data->offset = 0;
4054 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4055 static_data->offset += size;
4060 * ensure thread static fields already allocated are valid for thread
4061 * This function is called when a thread is created or on thread attach.
4064 thread_adjust_static_data (MonoInternalThread *thread)
4066 mono_threads_lock ();
4067 if (thread_static_info.offset || thread_static_info.idx > 0) {
4068 /* get the current allocated size */
4069 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
4070 mono_alloc_static_data (&thread->static_data, offset, TRUE);
4072 mono_threads_unlock ();
4076 * LOCKING: requires that threads_mutex is held
4079 context_adjust_static_data (MonoAppContext *ctx)
4081 if (context_static_info.offset || context_static_info.idx > 0) {
4082 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4083 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4084 ctx->data->static_data = ctx->static_data;
4089 * LOCKING: requires that threads_mutex is held
4092 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4094 MonoInternalThread *thread = (MonoInternalThread *)value;
4095 guint32 offset = GPOINTER_TO_UINT (user);
4097 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4101 * LOCKING: requires that threads_mutex is held
4104 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4106 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4111 guint32 offset = GPOINTER_TO_UINT (user);
4112 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4113 ctx->data->static_data = ctx->static_data;
4116 static StaticDataFreeList*
4117 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4119 StaticDataFreeList* prev = NULL;
4120 StaticDataFreeList* tmp = static_data->freelist;
4122 if (tmp->size == size) {
4124 prev->next = tmp->next;
4126 static_data->freelist = tmp->next;
4135 #if SIZEOF_VOID_P == 4
4142 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4144 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4146 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4147 MonoBitSet *rb = sets [idx];
4148 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4149 offset /= sizeof (uintptr_t);
4150 /* offset is now the bitmap offset */
4151 for (int i = 0; i < numbits; ++i) {
4152 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4153 mono_bitset_set_fast (rb, offset + i);
4158 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4160 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4161 MonoBitSet *rb = sets [idx];
4162 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4163 offset /= sizeof (uintptr_t);
4164 /* offset is now the bitmap offset */
4165 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4166 mono_bitset_clear_fast (rb, offset + i);
4170 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4172 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4174 StaticDataInfo *info;
4177 if (static_type == SPECIAL_STATIC_THREAD) {
4178 info = &thread_static_info;
4179 sets = thread_reference_bitmaps;
4181 info = &context_static_info;
4182 sets = context_reference_bitmaps;
4185 mono_threads_lock ();
4187 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4191 offset = item->offset;
4194 offset = mono_alloc_static_data_slot (info, size, align);
4197 update_reference_bitmap (sets, offset, bitmap, numbits);
4199 if (static_type == SPECIAL_STATIC_THREAD) {
4200 /* This can be called during startup */
4201 if (threads != NULL)
4202 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4204 if (contexts != NULL)
4205 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4207 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4210 mono_threads_unlock ();
4216 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4218 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4220 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4221 return get_thread_static_data (thread, offset);
4223 return get_context_static_data (thread->current_appcontext, offset);
4228 mono_get_special_static_data (guint32 offset)
4230 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4239 * LOCKING: requires that threads_mutex is held
4242 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4244 MonoInternalThread *thread = (MonoInternalThread *)value;
4245 OffsetSize *data = (OffsetSize *)user;
4246 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4247 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4250 if (!thread->static_data || !thread->static_data [idx])
4252 ptr = ((char*) thread->static_data [idx]) + off;
4253 mono_gc_bzero_atomic (ptr, data->size);
4257 * LOCKING: requires that threads_mutex is held
4260 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4262 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4267 OffsetSize *data = (OffsetSize *)user;
4268 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4269 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4272 if (!ctx->static_data || !ctx->static_data [idx])
4275 ptr = ((char*) ctx->static_data [idx]) + off;
4276 mono_gc_bzero_atomic (ptr, data->size);
4280 do_free_special_slot (guint32 offset, guint32 size)
4282 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4284 StaticDataInfo *info;
4286 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4287 info = &thread_static_info;
4288 sets = thread_reference_bitmaps;
4290 info = &context_static_info;
4291 sets = context_reference_bitmaps;
4294 guint32 data_offset = offset;
4295 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4296 OffsetSize data = { data_offset, size };
4298 clear_reference_bitmap (sets, data.offset, data.size);
4300 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4301 if (threads != NULL)
4302 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4304 if (contexts != NULL)
4305 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4308 if (!mono_runtime_is_shutting_down ()) {
4309 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4311 item->offset = offset;
4314 item->next = info->freelist;
4315 info->freelist = item;
4320 do_free_special (gpointer key, gpointer value, gpointer data)
4322 MonoClassField *field = (MonoClassField *)key;
4323 guint32 offset = GPOINTER_TO_UINT (value);
4326 size = mono_type_size (field->type, &align);
4327 do_free_special_slot (offset, size);
4331 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4333 mono_threads_lock ();
4335 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4337 mono_threads_unlock ();
4341 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4343 /* Only ever called for ThreadLocal instances */
4344 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
4346 mono_threads_lock ();
4347 do_free_special_slot (offset, size);
4348 mono_threads_unlock ();
4352 static void CALLBACK dummy_apc (ULONG_PTR param)
4358 * mono_thread_execute_interruption
4360 * Performs the operation that the requested thread state requires (abort,
4363 static MonoException*
4364 mono_thread_execute_interruption (void)
4366 MonoInternalThread *thread = mono_thread_internal_current ();
4367 MonoThread *sys_thread = mono_thread_current ();
4369 LOCK_THREAD (thread);
4371 /* MonoThread::interruption_requested can only be changed with atomics */
4372 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4373 /* this will consume pending APC calls */
4375 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4377 InterlockedDecrement (&thread_interruption_requested);
4379 /* Clear the interrupted flag of the thread so it can wait again */
4380 mono_thread_info_clear_self_interrupt ();
4383 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4384 if (sys_thread->pending_exception) {
4387 exc = sys_thread->pending_exception;
4388 sys_thread->pending_exception = NULL;
4390 UNLOCK_THREAD (thread);
4392 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4393 UNLOCK_THREAD (thread);
4394 g_assert (sys_thread->pending_exception == NULL);
4395 if (thread->abort_exc == NULL) {
4397 * This might be racy, but it has to be called outside the lock
4398 * since it calls managed code.
4400 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4402 return thread->abort_exc;
4404 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4405 /* calls UNLOCK_THREAD (thread) */
4406 self_suspend_internal ();
4409 else if ((thread->state & ThreadState_StopRequested) != 0) {
4410 /* FIXME: do this through the JIT? */
4412 UNLOCK_THREAD (thread);
4414 mono_thread_exit ();
4416 } else if (thread->thread_interrupt_requested) {
4418 thread->thread_interrupt_requested = FALSE;
4419 UNLOCK_THREAD (thread);
4421 return(mono_get_exception_thread_interrupted ());
4424 UNLOCK_THREAD (thread);
4430 * mono_thread_request_interruption
4432 * A signal handler can call this method to request the interruption of a
4433 * thread. The result of the interruption will depend on the current state of
4434 * the thread. If the result is an exception that needs to be throw, it is
4435 * provided as return value.
4438 mono_thread_request_interruption (gboolean running_managed)
4440 MonoInternalThread *thread = mono_thread_internal_current ();
4442 /* The thread may already be stopping */
4447 if (thread->interrupt_on_stop &&
4448 thread->state & ThreadState_StopRequested &&
4449 thread->state & ThreadState_Background)
4453 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4455 InterlockedIncrement (&thread_interruption_requested);
4457 if (!running_managed || is_running_protected_wrapper ()) {
4458 /* Can't stop while in unmanaged code. Increase the global interruption
4459 request count. When exiting the unmanaged method the count will be
4460 checked and the thread will be interrupted. */
4462 /* this will awake the thread if it is in WaitForSingleObject
4464 /* Our implementation of this function ignores the func argument */
4466 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4468 mono_thread_info_self_interrupt ();
4473 return mono_thread_execute_interruption ();
4477 /*This function should be called by a thread after it has exited all of
4478 * its handle blocks at interruption time.*/
4480 mono_thread_resume_interruption (void)
4482 MonoInternalThread *thread = mono_thread_internal_current ();
4483 gboolean still_aborting;
4485 /* The thread may already be stopping */
4489 LOCK_THREAD (thread);
4490 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4491 UNLOCK_THREAD (thread);
4493 /*This can happen if the protected block called Thread::ResetAbort*/
4494 if (!still_aborting)
4497 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4499 InterlockedIncrement (&thread_interruption_requested);
4501 mono_thread_info_self_interrupt ();
4503 return mono_thread_execute_interruption ();
4506 gboolean mono_thread_interruption_requested ()
4508 if (thread_interruption_requested) {
4509 MonoInternalThread *thread = mono_thread_internal_current ();
4510 /* The thread may already be stopping */
4512 return (thread->interruption_requested);
4517 static MonoException*
4518 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4520 MonoInternalThread *thread = mono_thread_internal_current ();
4522 /* The thread may already be stopping */
4526 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4527 MonoException* exc = mono_thread_execute_interruption ();
4535 * Performs the interruption of the current thread, if one has been requested,
4536 * and the thread is not running a protected wrapper.
4537 * Return the exception which needs to be thrown, if any.
4540 mono_thread_interruption_checkpoint (void)
4542 return mono_thread_interruption_checkpoint_request (FALSE);
4546 * Performs the interruption of the current thread, if one has been requested.
4547 * Return the exception which needs to be thrown, if any.
4550 mono_thread_force_interruption_checkpoint_noraise (void)
4552 return mono_thread_interruption_checkpoint_request (TRUE);
4556 * mono_set_pending_exception:
4558 * Set the pending exception of the current thread to EXC.
4559 * The exception will be thrown when execution returns to managed code.
4562 mono_set_pending_exception (MonoException *exc)
4564 MonoThread *thread = mono_thread_current ();
4566 /* The thread may already be stopping */
4570 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4572 mono_thread_request_interruption (FALSE);
4576 * mono_thread_interruption_request_flag:
4578 * Returns the address of a flag that will be non-zero if an interruption has
4579 * been requested for a thread. The thread to interrupt may not be the current
4580 * thread, so an additional call to mono_thread_interruption_requested() or
4581 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4584 gint32* mono_thread_interruption_request_flag ()
4586 return &thread_interruption_requested;
4590 mono_thread_init_apartment_state (void)
4593 MonoInternalThread* thread = mono_thread_internal_current ();
4595 /* Positive return value indicates success, either
4596 * S_OK if this is first CoInitialize call, or
4597 * S_FALSE if CoInitialize already called, but with same
4598 * threading model. A negative value indicates failure,
4599 * probably due to trying to change the threading model.
4601 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4602 ? COINIT_APARTMENTTHREADED
4603 : COINIT_MULTITHREADED) < 0) {
4604 thread->apartment_state = ThreadApartmentState_Unknown;
4610 mono_thread_cleanup_apartment_state (void)
4613 MonoInternalThread* thread = mono_thread_internal_current ();
4615 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4622 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4624 LOCK_THREAD (thread);
4625 thread->state |= state;
4626 UNLOCK_THREAD (thread);
4630 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4632 LOCK_THREAD (thread);
4633 thread->state &= ~state;
4634 UNLOCK_THREAD (thread);
4638 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4640 gboolean ret = FALSE;
4642 LOCK_THREAD (thread);
4644 if ((thread->state & test) != 0) {
4648 UNLOCK_THREAD (thread);
4653 static gboolean has_tls_get = FALSE;
4656 mono_runtime_set_has_tls_get (gboolean val)
4662 mono_runtime_has_tls_get (void)
4668 self_interrupt_thread (void *_unused)
4670 MonoThreadInfo *info = mono_thread_info_current ();
4671 MonoException *exc = mono_thread_execute_interruption ();
4672 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4673 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. */
4674 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4678 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4682 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4686 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4688 MonoJitInfo **dest = (MonoJitInfo **)data;
4694 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4696 MonoJitInfo *ji = NULL;
4701 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4702 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4703 * where we hold runtime locks.
4705 if (!mono_threads_is_coop_enabled ())
4706 mono_thread_info_set_is_async_context (TRUE);
4707 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4708 if (!mono_threads_is_coop_enabled ())
4709 mono_thread_info_set_is_async_context (FALSE);
4714 MonoInternalThread *thread;
4715 gboolean install_async_abort;
4716 MonoThreadInfoInterruptToken *interrupt_token;
4719 static SuspendThreadResult
4720 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4722 AbortThreadData *data = (AbortThreadData *)ud;
4723 MonoInternalThread *thread = data->thread;
4724 MonoJitInfo *ji = NULL;
4725 gboolean protected_wrapper;
4726 gboolean running_managed;
4728 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4729 return MonoResumeThread;
4731 /*someone is already interrupting it*/
4732 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4733 return MonoResumeThread;
4735 InterlockedIncrement (&thread_interruption_requested);
4737 ji = mono_thread_info_get_last_managed (info);
4738 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4739 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4741 if (!protected_wrapper && running_managed) {
4742 /*We are in managed code*/
4743 /*Set the thread to call */
4744 if (data->install_async_abort)
4745 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4746 return MonoResumeThread;
4749 * This will cause waits to be broken.
4750 * It will also prevent the thread from entering a wait, so if the thread returns
4751 * from the wait before it receives the abort signal, it will just spin in the wait
4752 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4755 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4757 return MonoResumeThread;
4762 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4764 AbortThreadData data;
4766 g_assert (thread != mono_thread_internal_current ());
4768 data.thread = thread;
4769 data.install_async_abort = install_async_abort;
4770 data.interrupt_token = NULL;
4772 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4773 if (data.interrupt_token)
4774 mono_thread_info_finish_interrupt (data.interrupt_token);
4775 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4779 self_abort_internal (void)
4783 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4784 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4786 exc = mono_thread_request_interruption (TRUE);
4788 mono_raise_exception (exc);
4790 mono_thread_info_self_interrupt ();
4794 MonoInternalThread *thread;
4796 MonoThreadInfoInterruptToken *interrupt_token;
4797 } SuspendThreadData;
4799 static SuspendThreadResult
4800 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4802 SuspendThreadData *data = (SuspendThreadData *)ud;
4803 MonoInternalThread *thread = data->thread;
4804 MonoJitInfo *ji = NULL;
4805 gboolean protected_wrapper;
4806 gboolean running_managed;
4808 ji = mono_thread_info_get_last_managed (info);
4809 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4810 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4812 if (running_managed && !protected_wrapper) {
4813 thread->state &= ~ThreadState_SuspendRequested;
4814 thread->state |= ThreadState_Suspended;
4815 return KeepSuspended;
4817 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4818 InterlockedIncrement (&thread_interruption_requested);
4819 if (data->interrupt)
4820 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4822 return MonoResumeThread;
4826 /* LOCKING: called with @thread synch_cs held, and releases it */
4828 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4830 SuspendThreadData data;
4832 g_assert (thread != mono_thread_internal_current ());
4834 data.thread = thread;
4835 data.interrupt = interrupt;
4836 data.interrupt_token = NULL;
4838 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4839 if (data.interrupt_token)
4840 mono_thread_info_finish_interrupt (data.interrupt_token);
4842 UNLOCK_THREAD (thread);
4845 /* LOCKING: called with @thread synch_cs held, and releases it */
4847 self_suspend_internal (void)
4849 MonoInternalThread *thread;
4851 thread = mono_thread_internal_current ();
4853 mono_thread_info_begin_self_suspend ();
4854 thread->state &= ~ThreadState_SuspendRequested;
4855 thread->state |= ThreadState_Suspended;
4857 UNLOCK_THREAD (thread);
4859 mono_thread_info_end_self_suspend ();
4863 * mono_thread_is_foreign:
4864 * @thread: the thread to query
4866 * This function allows one to determine if a thread was created by the mono runtime and has
4867 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4869 * Returns: TRUE if @thread was not created by the runtime.
4872 mono_thread_is_foreign (MonoThread *thread)
4874 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4875 return info->runtime_thread == FALSE;
4879 * mono_add_joinable_thread:
4881 * Add TID to the list of joinable threads.
4882 * LOCKING: Acquires the threads lock.
4885 mono_threads_add_joinable_thread (gpointer tid)
4889 * We cannot detach from threads because it causes problems like
4890 * 2fd16f60/r114307. So we collect them and join them when
4891 * we have time (in he finalizer thread).
4893 joinable_threads_lock ();
4894 if (!joinable_threads)
4895 joinable_threads = g_hash_table_new (NULL, NULL);
4896 g_hash_table_insert (joinable_threads, tid, tid);
4897 joinable_thread_count ++;
4898 joinable_threads_unlock ();
4900 mono_gc_finalize_notify ();
4905 * mono_threads_join_threads:
4907 * Join all joinable threads. This is called from the finalizer thread.
4908 * LOCKING: Acquires the threads lock.
4911 mono_threads_join_threads (void)
4914 GHashTableIter iter;
4921 if (!joinable_thread_count)
4925 joinable_threads_lock ();
4927 if (g_hash_table_size (joinable_threads)) {
4928 g_hash_table_iter_init (&iter, joinable_threads);
4929 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4930 thread = (pthread_t)tid;
4931 g_hash_table_remove (joinable_threads, key);
4932 joinable_thread_count --;
4935 joinable_threads_unlock ();
4937 if (thread != pthread_self ())
4938 /* This shouldn't block */
4939 pthread_join (thread, NULL);
4950 * Wait for thread TID to exit.
4951 * LOCKING: Acquires the threads lock.
4954 mono_thread_join (gpointer tid)
4958 gboolean found = FALSE;
4960 joinable_threads_lock ();
4961 if (!joinable_threads)
4962 joinable_threads = g_hash_table_new (NULL, NULL);
4963 if (g_hash_table_lookup (joinable_threads, tid)) {
4964 g_hash_table_remove (joinable_threads, tid);
4965 joinable_thread_count --;
4968 joinable_threads_unlock ();
4971 thread = (pthread_t)tid;
4972 pthread_join (thread, NULL);
4977 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4979 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4980 mono_thread_interruption_checkpoint ();
4983 static inline gboolean
4984 is_appdomainunloaded_exception (MonoClass *klass)
4986 return klass == mono_class_get_appdomain_unloaded_exception_class ();
4989 static inline gboolean
4990 is_threadabort_exception (MonoClass *klass)
4992 return klass == mono_defaults.threadabortexception_class;
4996 mono_thread_internal_unhandled_exception (MonoObject* exc)
4998 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4999 MonoClass *klass = exc->vtable->klass;
5000 if (is_threadabort_exception (klass)) {
5001 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5002 } else if (!is_appdomainunloaded_exception (klass)) {
5003 mono_unhandled_exception (exc);
5004 if (mono_environment_exitcode_get () == 1)
5011 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5013 mono_threads_get_thread_dump (out_threads, out_stack_traces);