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/mono-threads-coop.h>
41 #include <mono/utils/hazard-pointer.h>
42 #include <mono/utils/mono-tls.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/mono-threads-coop.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/os-event.h>
48 #include <mono/utils/mono-threads-debug.h>
49 #include <mono/metadata/w32handle.h>
50 #include <mono/metadata/w32event.h>
51 #include <mono/metadata/w32mutex.h>
53 #include <mono/metadata/gc-internals.h>
54 #include <mono/metadata/reflection-internals.h>
55 #include <mono/metadata/abi-details.h>
61 #if defined(HOST_WIN32)
65 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
66 #define USE_TKILL_ON_ANDROID 1
69 #ifdef PLATFORM_ANDROID
72 #ifdef USE_TKILL_ON_ANDROID
73 extern int tkill (pid_t tid, int signal);
77 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
78 #define THREAD_DEBUG(a)
79 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
80 #define THREAD_WAIT_DEBUG(a)
81 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
82 #define LIBGC_DEBUG(a)
84 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
85 #define SPIN_LOCK(i) do { \
86 if (SPIN_TRYLOCK (i)) \
90 #define SPIN_UNLOCK(i) i = 0
92 #define LOCK_THREAD(thread) lock_thread((thread))
93 #define UNLOCK_THREAD(thread) unlock_thread((thread))
105 typedef struct _StaticDataFreeList StaticDataFreeList;
106 struct _StaticDataFreeList {
107 StaticDataFreeList *next;
115 StaticDataFreeList *freelist;
118 /* Number of cached culture objects in the MonoThread->cached_culture_info array
119 * (per-type): we use the first NUM entries for CultureInfo and the last for
120 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
122 #define NUM_CACHED_CULTURES 4
123 #define CULTURES_START_IDX 0
124 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
126 /* Controls access to the 'threads' hash table */
127 static void mono_threads_lock (void);
128 static void mono_threads_unlock (void);
129 static MonoCoopMutex threads_mutex;
131 /* Controls access to the 'joinable_threads' hash table */
132 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
133 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
134 static mono_mutex_t joinable_threads_mutex;
136 /* Holds current status of static data heap */
137 static StaticDataInfo thread_static_info;
138 static StaticDataInfo context_static_info;
140 /* The hash of existing threads (key is thread ID, value is
141 * MonoInternalThread*) that need joining before exit
143 static MonoGHashTable *threads=NULL;
145 /* List of app context GC handles.
146 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
148 static GHashTable *contexts = NULL;
150 /* Cleanup queue for contexts. */
151 static MonoReferenceQueue *context_queue;
154 * Threads which are starting up and they are not in the 'threads' hash yet.
155 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
156 * Protected by mono_threads_lock ().
158 static MonoGHashTable *threads_starting_up = NULL;
161 /* Protected by the threads lock */
162 static GHashTable *joinable_threads;
163 static int joinable_thread_count;
165 #define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
166 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
168 /* function called at thread start */
169 static MonoThreadStartCB mono_thread_start_cb = NULL;
171 /* function called at thread attach */
172 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
174 /* function called at thread cleanup */
175 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
177 /* The default stack size for each thread */
178 static guint32 default_stacksize = 0;
179 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
181 static void context_adjust_static_data (MonoAppContext *ctx);
182 static void mono_free_static_data (gpointer* static_data);
183 static void mono_init_static_data_info (StaticDataInfo *static_data);
184 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
185 static gboolean mono_thread_resume (MonoInternalThread* thread);
186 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
187 static void self_abort_internal (MonoError *error);
188 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
189 static void self_suspend_internal (void);
191 static MonoException* mono_thread_execute_interruption (void);
192 static void ref_stack_destroy (gpointer rs);
194 /* Spin lock for InterlockedXXX 64 bit functions */
195 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
196 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
197 static mono_mutex_t interlocked_mutex;
199 /* global count of thread interruptions requested */
200 static gint32 thread_interruption_requested = 0;
202 /* Event signaled when a thread changes its background mode */
203 static MonoOSEvent background_change_event;
205 static gboolean shutting_down = FALSE;
207 static gint32 managed_thread_id_counter = 0;
209 /* Class lazy loading functions */
210 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
213 mono_threads_lock (void)
215 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
219 mono_threads_unlock (void)
221 mono_locks_coop_release (&threads_mutex, ThreadsLock);
226 get_next_managed_thread_id (void)
228 return InterlockedIncrement (&managed_thread_id_counter);
231 static inline MonoNativeThreadId
232 thread_get_tid (MonoInternalThread *thread)
234 /* We store the tid as a guint64 to keep the object layout constant between platforms */
235 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
238 static void ensure_synch_cs_set (MonoInternalThread *thread)
240 MonoCoopMutex *synch_cs;
242 if (thread->synch_cs != NULL) {
246 synch_cs = g_new0 (MonoCoopMutex, 1);
247 mono_coop_mutex_init_recursive (synch_cs);
249 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
250 synch_cs, NULL) != NULL) {
251 /* Another thread must have installed this CS */
252 mono_coop_mutex_destroy (synch_cs);
258 lock_thread (MonoInternalThread *thread)
260 if (!thread->synch_cs)
261 ensure_synch_cs_set (thread);
263 g_assert (thread->synch_cs);
265 mono_coop_mutex_lock (thread->synch_cs);
269 unlock_thread (MonoInternalThread *thread)
271 mono_coop_mutex_unlock (thread->synch_cs);
274 static inline gboolean
275 is_appdomainunloaded_exception (MonoClass *klass)
277 return klass == mono_class_get_appdomain_unloaded_exception_class ();
280 static inline gboolean
281 is_threadabort_exception (MonoClass *klass)
283 return klass == mono_defaults.threadabortexception_class;
287 * A special static data offset (guint32) consists of 3 parts:
289 * [0] 6-bit index into the array of chunks.
290 * [6] 25-bit offset into the array.
291 * [31] Bit indicating thread or context static.
296 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
307 } SpecialStaticOffset;
309 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
310 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
312 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
313 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
314 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
315 (((SpecialStaticOffset *) &(x))->fields.f)
318 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
320 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
322 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
323 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
325 return ((char *) thread->static_data [idx]) + off;
329 get_context_static_data (MonoAppContext *ctx, guint32 offset)
331 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
333 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
334 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
336 return ((char *) ctx->static_data [idx]) + off;
340 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
342 static MonoClassField *current_thread_field = NULL;
346 if (!current_thread_field) {
347 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
348 g_assert (current_thread_field);
351 mono_class_vtable (domain, mono_defaults.thread_class);
352 mono_domain_lock (domain);
353 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
354 mono_domain_unlock (domain);
357 return (MonoThread **)get_thread_static_data (thread, offset);
361 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
363 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
365 g_assert (current->obj.vtable->domain == domain);
367 g_assert (!*current_thread_ptr);
368 *current_thread_ptr = current;
372 create_thread_object (MonoDomain *domain, MonoInternalThread *internal)
378 vtable = mono_class_vtable (domain, mono_defaults.thread_class);
381 thread = (MonoThread*)mono_object_new_mature (vtable, &error);
382 /* only possible failure mode is OOM, from which we don't expect to recover. */
383 mono_error_assert_ok (&error);
385 MONO_OBJECT_SETREF (thread, internal_thread, internal);
390 static MonoInternalThread*
391 create_internal_thread_object (void)
394 MonoInternalThread *thread;
397 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
398 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
399 /* only possible failure mode is OOM, from which we don't exect to recover */
400 mono_error_assert_ok (&error);
402 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
403 mono_coop_mutex_init_recursive (thread->synch_cs);
405 thread->apartment_state = ThreadApartmentState_Unknown;
406 thread->managed_id = get_next_managed_thread_id ();
407 if (mono_gc_is_moving ()) {
408 thread->thread_pinning_ref = thread;
409 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
412 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
414 thread->suspended = g_new0 (MonoOSEvent, 1);
415 mono_os_event_init (thread->suspended, TRUE);
421 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
425 g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
426 g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
427 g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
432 g_assert (internal->native_handle);
434 res = SetThreadPriority (internal->native_handle, priority - 2);
436 g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
437 #else /* HOST_WIN32 */
440 struct sched_param param;
443 tid = thread_get_tid (internal);
445 res = pthread_getschedparam (tid, &policy, ¶m);
447 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
449 #ifdef _POSIX_PRIORITY_SCHEDULING
452 /* Necessary to get valid priority range */
454 min = sched_get_priority_min (policy);
455 max = sched_get_priority_max (policy);
457 if (max > 0 && min >= 0 && max > min) {
458 double srange, drange, sposition, dposition;
459 srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
461 sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
462 dposition = (sposition / srange) * drange;
463 param.sched_priority = (int)(dposition + min);
470 param.sched_priority = 50;
476 param.sched_priority = 0;
479 g_error ("%s: unknown policy %d", __func__, policy);
483 res = pthread_setschedparam (tid, policy, ¶m);
486 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
489 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
491 #endif /* HOST_WIN32 */
495 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
498 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
500 MonoThreadInfo *info;
501 MonoInternalThread *internal;
502 MonoDomain *domain, *root_domain;
506 info = mono_thread_info_current ();
508 internal = thread->internal_thread;
509 internal->handle = mono_threads_open_thread_handle (info->handle);
511 internal->native_handle = OpenThread (THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId ());
513 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
514 internal->thread_info = info;
515 internal->small_id = info->small_id;
516 internal->stack_ptr = stack_ptr;
518 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
520 SET_CURRENT_OBJECT (internal);
522 domain = mono_object_domain (thread);
524 mono_thread_push_appdomain_ref (domain);
525 if (!mono_domain_set (domain, force_domain)) {
526 mono_thread_pop_appdomain_ref ();
530 mono_threads_lock ();
532 if (threads_starting_up)
533 mono_g_hash_table_remove (threads_starting_up, thread);
535 if (shutting_down && !force_attach) {
536 mono_threads_unlock ();
541 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
542 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
545 /* We don't need to duplicate thread->handle, because it is
546 * only closed when the thread object is finalized by the GC. */
547 mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
549 /* We have to do this here because mono_thread_start_cb
550 * requires that root_domain_thread is set up. */
551 if (thread_static_info.offset || thread_static_info.idx > 0) {
552 /* get the current allocated size */
553 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
554 mono_alloc_static_data (&internal->static_data, offset, TRUE);
557 mono_threads_unlock ();
559 root_domain = mono_get_root_domain ();
561 g_assert (!internal->root_domain_thread);
562 if (domain != root_domain)
563 MONO_OBJECT_SETREF (internal, root_domain_thread, create_thread_object (root_domain, internal));
565 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
567 if (domain != root_domain)
568 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
570 set_current_thread_for_domain (domain, internal, thread);
572 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
580 MonoObject *start_delegate;
581 MonoObject *start_delegate_arg;
582 MonoThreadStart start_func;
583 gpointer start_func_arg;
585 MonoCoopSem registered;
588 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
591 MonoThreadStart start_func;
592 void *start_func_arg;
595 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
599 MonoInternalThread *internal;
600 MonoObject *start_delegate;
601 MonoObject *start_delegate_arg;
604 thread = start_info->thread;
605 internal = thread->internal_thread;
606 domain = mono_object_domain (start_info->thread);
608 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
610 if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
611 start_info->failed = TRUE;
613 mono_coop_sem_post (&start_info->registered);
615 if (InterlockedDecrement (&start_info->ref) == 0) {
616 mono_coop_sem_destroy (&start_info->registered);
623 mono_thread_internal_set_priority (internal, internal->priority);
627 start_delegate = start_info->start_delegate;
628 start_delegate_arg = start_info->start_delegate_arg;
629 start_func = start_info->start_func;
630 start_func_arg = start_info->start_func_arg;
632 /* This MUST be called before any managed code can be
633 * executed, as it calls the callback function that (for the
634 * jit) sets the lmf marker.
637 if (mono_thread_start_cb)
638 mono_thread_start_cb (tid, stack_ptr, start_func);
640 /* On 2.0 profile (and higher), set explicitly since state might have been
642 if (internal->apartment_state == ThreadApartmentState_Unknown)
643 internal->apartment_state = ThreadApartmentState_MTA;
645 mono_thread_init_apartment_state ();
647 /* Let the thread that called Start() know we're ready */
648 mono_coop_sem_post (&start_info->registered);
650 if (InterlockedDecrement (&start_info->ref) == 0) {
651 mono_coop_sem_destroy (&start_info->registered);
655 /* start_info is not valid anymore */
659 * Call this after calling start_notify, since the profiler callback might want
660 * to lock the thread, and the lock is held by thread_start () which waits for
663 mono_profiler_thread_start (tid);
665 /* if the name was set before starting, we didn't invoke the profiler callback */
666 if (internal->name) {
667 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
668 mono_profiler_thread_name (internal->tid, tname);
669 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
673 /* start_func is set only for unmanaged start functions */
675 start_func (start_func_arg);
679 g_assert (start_delegate != NULL);
681 /* we may want to handle the exception here. See comment below on unhandled exceptions */
682 args [0] = (gpointer) start_delegate_arg;
683 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
685 if (!mono_error_ok (&error)) {
686 MonoException *ex = mono_error_convert_to_exception (&error);
688 g_assert (ex != NULL);
689 MonoClass *klass = mono_object_get_class (&ex->object);
690 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
691 !is_threadabort_exception (klass)) {
692 mono_unhandled_exception (&ex->object);
693 mono_invoke_unhandled_exception_hook (&ex->object);
694 g_assert_not_reached ();
697 mono_error_cleanup (&error);
701 /* If the thread calls ExitThread at all, this remaining code
702 * will not be executed, but the main thread will eventually
703 * call mono_thread_detach_internal() on this thread's behalf.
706 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
708 /* Do any cleanup needed for apartment state. This
709 * cannot be done in mono_thread_detach_internal since
710 * mono_thread_detach_internal could be called for a
711 * thread other than the current thread.
712 * mono_thread_cleanup_apartment_state cleans up apartment
713 * for the current thead */
714 mono_thread_cleanup_apartment_state ();
716 mono_thread_detach_internal (internal);
723 static gsize WINAPI start_wrapper(void *data)
725 volatile gsize dummy;
727 return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
733 * Common thread creation code.
734 * LOCKING: Acquires the threads lock.
737 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
738 gboolean threadpool_thread, guint32 stack_size, MonoError *error)
740 StartInfo *start_info = NULL;
741 MonoThreadHandle *thread_handle;
742 MonoNativeThreadId tid;
744 gsize stack_set_size;
747 g_assert (!start_func && !start_func_arg);
749 g_assert (!start_delegate);
752 * Join joinable threads to prevent running out of threads since the finalizer
753 * thread might be blocked/backlogged.
755 mono_threads_join_threads ();
757 mono_error_init (error);
759 mono_threads_lock ();
761 mono_threads_unlock ();
764 if (threads_starting_up == NULL) {
765 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
766 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
768 mono_g_hash_table_insert (threads_starting_up, thread, thread);
769 mono_threads_unlock ();
771 internal->threadpool_thread = threadpool_thread;
772 if (threadpool_thread)
773 mono_thread_set_state (internal, ThreadState_Background);
775 start_info = g_new0 (StartInfo, 1);
777 start_info->thread = thread;
778 start_info->start_delegate = start_delegate;
779 start_info->start_delegate_arg = thread->start_obj;
780 start_info->start_func = start_func;
781 start_info->start_func_arg = start_func_arg;
782 start_info->failed = FALSE;
783 mono_coop_sem_init (&start_info->registered, 0);
786 stack_set_size = default_stacksize_for_thread (internal);
790 thread_handle = mono_threads_create_thread (start_wrapper, start_info, &stack_set_size, &tid);
792 if (thread_handle == NULL) {
793 /* The thread couldn't be created, so set an exception */
794 mono_threads_lock ();
795 mono_g_hash_table_remove (threads_starting_up, thread);
796 mono_threads_unlock ();
797 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
798 /* ref is not going to be decremented in start_wrapper_internal */
799 InterlockedDecrement (&start_info->ref);
804 internal->stack_size = (int) stack_set_size;
806 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
809 * Wait for the thread to set up its TLS data etc, so
810 * theres no potential race condition if someone tries
811 * to look up the data believing the thread has
815 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
817 mono_threads_close_thread_handle (thread_handle);
819 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));
821 ret = !start_info->failed;
824 if (InterlockedDecrement (&start_info->ref) == 0) {
825 mono_coop_sem_destroy (&start_info->registered);
832 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
834 if (mono_thread_start_cb) {
835 mono_thread_start_cb (tid, stack_start, func);
839 void mono_threads_set_default_stacksize (guint32 stacksize)
841 default_stacksize = stacksize;
844 guint32 mono_threads_get_default_stacksize (void)
846 return default_stacksize;
850 * mono_thread_create_internal:
852 * ARG should not be a GC reference.
855 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
858 MonoInternalThread *internal;
861 mono_error_init (error);
863 internal = create_internal_thread_object ();
865 thread = create_thread_object (domain, internal);
867 LOCK_THREAD (internal);
869 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
870 return_val_if_nok (error, NULL);
872 UNLOCK_THREAD (internal);
878 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
881 if (!mono_thread_create_checked (domain, func, arg, &error))
882 mono_error_cleanup (&error);
886 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
888 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
892 mono_thread_attach (MonoDomain *domain)
894 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
900 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
902 MonoInternalThread *internal;
904 MonoNativeThreadId tid;
907 if (mono_thread_internal_current_is_attached ()) {
908 if (domain != mono_domain_get ())
909 mono_domain_set (domain, TRUE);
910 /* Already attached */
911 return mono_thread_current ();
914 if (!mono_gc_register_thread (&domain)) {
915 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 ());
918 tid=mono_native_thread_id_get ();
920 internal = create_internal_thread_object ();
922 thread = create_thread_object (domain, internal);
924 if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
925 /* Mono is shutting down, so just wait for the end */
927 mono_thread_info_sleep (10000, NULL);
930 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
932 if (mono_thread_attach_cb) {
936 mono_thread_info_get_stack_bounds (&staddr, &stsize);
939 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
941 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
944 /* Can happen when we attach the profiler helper thread in order to heapshot. */
945 if (!mono_thread_info_current ()->tools_thread)
946 // FIXME: Need a separate callback
947 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
953 mono_thread_detach_internal (MonoInternalThread *thread)
957 g_assert (thread != NULL);
959 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
962 mono_w32mutex_abandon ();
965 if (thread->abort_state_handle) {
966 mono_gchandle_free (thread->abort_state_handle);
967 thread->abort_state_handle = 0;
970 thread->abort_exc = NULL;
971 thread->current_appcontext = NULL;
974 * This is necessary because otherwise we might have
975 * cross-domain references which will not get cleaned up when
976 * the target domain is unloaded.
978 if (thread->cached_culture_info) {
980 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
981 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
985 * thread->synch_cs can be NULL if this was called after
986 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
987 * This can happen only during shutdown.
988 * The shutting_down flag is not always set, so we can't assert on it.
990 if (thread->synch_cs)
991 LOCK_THREAD (thread);
993 thread->state |= ThreadState_Stopped;
994 thread->state &= ~ThreadState_Background;
996 if (thread->synch_cs)
997 UNLOCK_THREAD (thread);
1000 An interruption request has leaked to cleanup. Adjust the global counter.
1002 This can happen is the abort source thread finds the abortee (this) thread
1003 in unmanaged code. If this thread never trips back to managed code or check
1004 the local flag it will be left set and positively unbalance the global counter.
1006 Leaving the counter unbalanced will cause a performance degradation since all threads
1007 will now keep checking their local flags all the time.
1009 if (InterlockedExchange (&thread->interruption_requested, 0) != 0)
1010 InterlockedDecrement (&thread_interruption_requested);
1012 mono_threads_lock ();
1016 } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
1017 /* We have to check whether the thread object for the
1018 * tid is still the same in the table because the
1019 * thread might have been destroyed and the tid reused
1020 * in the meantime, in which case the tid would be in
1021 * the table, but with another thread object.
1025 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
1029 mono_threads_unlock ();
1031 /* Don't close the handle here, wait for the object finalizer
1032 * to do it. Otherwise, the following race condition applies:
1034 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
1036 * 2) Some other handle is reassigned the same slot
1038 * 3) Another thread tries to join the first thread, and
1039 * blocks waiting for the reassigned handle to be signalled
1040 * (which might never happen). This is possible, because the
1041 * thread calling Join() still has a reference to the first
1045 /* if the thread is not in the hash it has been removed already */
1047 mono_domain_unset ();
1048 mono_memory_barrier ();
1050 if (mono_thread_cleanup_fn)
1051 mono_thread_cleanup_fn (thread_get_tid (thread));
1056 mono_release_type_locks (thread);
1058 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1059 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
1060 mono_profiler_thread_end (thread->tid);
1062 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1065 * This will signal async signal handlers that the thread has exited.
1066 * The profiler callback needs this to be set, so it cannot be done earlier.
1068 mono_domain_unset ();
1069 mono_memory_barrier ();
1071 if (thread == mono_thread_internal_current ())
1072 mono_thread_pop_appdomain_ref ();
1074 thread->cached_culture_info = NULL;
1076 mono_free_static_data (thread->static_data);
1077 thread->static_data = NULL;
1078 ref_stack_destroy (thread->appdomain_refs);
1079 thread->appdomain_refs = NULL;
1081 g_assert (thread->suspended);
1082 mono_os_event_destroy (thread->suspended);
1083 g_free (thread->suspended);
1084 thread->suspended = NULL;
1086 if (mono_thread_cleanup_fn)
1087 mono_thread_cleanup_fn (thread_get_tid (thread));
1089 mono_memory_barrier ();
1091 if (mono_gc_is_moving ()) {
1092 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
1093 thread->thread_pinning_ref = NULL;
1097 SET_CURRENT_OBJECT (NULL);
1098 mono_domain_unset ();
1100 /* Don't need to close the handle to this thread, even though we took a
1101 * reference in mono_thread_attach (), because the GC will do it
1102 * when the Thread object is finalised.
1107 mono_thread_detach (MonoThread *thread)
1110 mono_thread_detach_internal (thread->internal_thread);
1114 * mono_thread_detach_if_exiting:
1116 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1117 * This should be used at the end of embedding code which calls into managed code, and which
1118 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1121 mono_thread_detach_if_exiting (void)
1123 if (mono_thread_info_is_exiting ()) {
1124 MonoInternalThread *thread;
1126 thread = mono_thread_internal_current ();
1128 mono_thread_detach_internal (thread);
1129 mono_thread_info_detach ();
1137 mono_thread_internal_current_is_attached (void)
1139 MonoInternalThread *internal;
1141 internal = GET_CURRENT_OBJECT ();
1149 mono_thread_exit (void)
1151 MonoInternalThread *thread = mono_thread_internal_current ();
1153 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1155 mono_thread_detach_internal (thread);
1157 /* we could add a callback here for embedders to use. */
1158 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1159 exit (mono_environment_exitcode_get ());
1161 mono_thread_info_exit (0);
1165 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1167 MonoInternalThread *internal;
1169 internal = create_internal_thread_object ();
1171 internal->state = ThreadState_Unstarted;
1173 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1177 ves_icall_System_Threading_Thread_GetCurrentThread (void)
1179 return mono_thread_current ();
1183 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1187 MonoInternalThread *internal;
1190 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1192 if (!this_obj->internal_thread)
1193 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1194 internal = this_obj->internal_thread;
1196 LOCK_THREAD (internal);
1198 if ((internal->state & ThreadState_Unstarted) == 0) {
1199 UNLOCK_THREAD (internal);
1200 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1204 if ((internal->state & ThreadState_Aborted) != 0) {
1205 UNLOCK_THREAD (internal);
1209 res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1211 mono_error_cleanup (&error);
1212 UNLOCK_THREAD (internal);
1216 internal->state &= ~ThreadState_Unstarted;
1218 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1220 UNLOCK_THREAD (internal);
1221 return internal->handle;
1225 * This is called from the finalizer of the internal thread object.
1228 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj)
1230 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle));
1233 * Since threads keep a reference to their thread object while running, by
1234 * the time this function is called, the thread has already exited/detached,
1235 * i.e. mono_thread_detach_internal () has ran. The exception is during
1236 * shutdown, when mono_thread_detach_internal () can be called after this.
1238 if (this_obj->handle) {
1239 mono_threads_close_thread_handle (this_obj->handle);
1240 this_obj->handle = NULL;
1244 CloseHandle (this_obj->native_handle);
1247 if (this_obj->synch_cs) {
1248 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1249 this_obj->synch_cs = NULL;
1250 mono_coop_mutex_destroy (synch_cs);
1254 if (this_obj->name) {
1255 void *name = this_obj->name;
1256 this_obj->name = NULL;
1262 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1265 MonoInternalThread *thread = mono_thread_internal_current ();
1267 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1269 if (mono_thread_current_check_pending_interrupt ())
1273 gboolean alerted = FALSE;
1275 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1277 res = mono_thread_info_sleep (ms, &alerted);
1279 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1282 MonoException* exc = mono_thread_execute_interruption ();
1284 mono_raise_exception (exc);
1286 // FIXME: !MONO_INFINITE_WAIT
1287 if (ms != MONO_INFINITE_WAIT)
1296 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1301 ves_icall_System_Threading_Thread_GetDomainID (void)
1303 return mono_domain_get()->domain_id;
1307 ves_icall_System_Threading_Thread_Yield (void)
1309 return mono_thread_info_yield ();
1313 * mono_thread_get_name:
1315 * Return the name of the thread. NAME_LEN is set to the length of the name.
1316 * Return NULL if the thread has no name. The returned memory is owned by the
1320 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1324 LOCK_THREAD (this_obj);
1326 if (!this_obj->name) {
1330 *name_len = this_obj->name_len;
1331 res = g_new (gunichar2, this_obj->name_len);
1332 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1335 UNLOCK_THREAD (this_obj);
1341 * mono_thread_get_name_utf8:
1343 * Return the name of the thread in UTF-8.
1344 * Return NULL if the thread has no name.
1345 * The returned memory is owned by the caller.
1348 mono_thread_get_name_utf8 (MonoThread *thread)
1353 MonoInternalThread *internal = thread->internal_thread;
1354 if (internal == NULL)
1357 LOCK_THREAD (internal);
1359 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1361 UNLOCK_THREAD (internal);
1367 * mono_thread_get_managed_id:
1369 * Return the Thread.ManagedThreadId value of `thread`.
1370 * Returns -1 if `thread` is NULL.
1373 mono_thread_get_managed_id (MonoThread *thread)
1378 MonoInternalThread *internal = thread->internal_thread;
1379 if (internal == NULL)
1382 int32_t id = internal->managed_id;
1388 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1393 mono_error_init (&error);
1395 LOCK_THREAD (this_obj);
1397 if (!this_obj->name)
1400 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1402 UNLOCK_THREAD (this_obj);
1404 if (mono_error_set_pending_exception (&error))
1411 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1413 LOCK_THREAD (this_obj);
1415 mono_error_init (error);
1417 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1418 UNLOCK_THREAD (this_obj);
1420 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1423 if (this_obj->name) {
1424 g_free (this_obj->name);
1425 this_obj->name_len = 0;
1428 this_obj->name = g_new (gunichar2, mono_string_length (name));
1429 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1430 this_obj->name_len = mono_string_length (name);
1433 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1436 this_obj->name = NULL;
1439 UNLOCK_THREAD (this_obj);
1441 if (this_obj->name && this_obj->tid) {
1442 char *tname = mono_string_to_utf8_checked (name, error);
1443 return_if_nok (error);
1444 mono_profiler_thread_name (this_obj->tid, tname);
1445 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1451 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1454 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1455 mono_error_set_pending_exception (&error);
1459 * ves_icall_System_Threading_Thread_GetPriority_internal:
1460 * @param this_obj: The MonoInternalThread on which to operate.
1462 * Gets the priority of the given thread.
1463 * @return: The priority of the given thread.
1466 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1469 MonoInternalThread *internal = this_obj->internal_thread;
1471 LOCK_THREAD (internal);
1472 priority = internal->priority;
1473 UNLOCK_THREAD (internal);
1479 * ves_icall_System_Threading_Thread_SetPriority_internal:
1480 * @param this_obj: The MonoInternalThread on which to operate.
1481 * @param priority: The priority to set.
1483 * Sets the priority of the given thread.
1486 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1488 MonoInternalThread *internal = this_obj->internal_thread;
1490 LOCK_THREAD (internal);
1491 internal->priority = priority;
1492 if (internal->thread_info != NULL)
1493 mono_thread_internal_set_priority (internal, priority);
1494 UNLOCK_THREAD (internal);
1497 /* If the array is already in the requested domain, we just return it,
1498 otherwise we return a copy in that domain. */
1500 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1504 mono_error_init (error);
1508 if (mono_object_domain (arr) == domain)
1511 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1512 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1517 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1520 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1521 mono_error_set_pending_exception (&error);
1526 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1529 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1530 mono_error_set_pending_exception (&error);
1535 mono_thread_current (void)
1537 MonoDomain *domain = mono_domain_get ();
1538 MonoInternalThread *internal = mono_thread_internal_current ();
1539 MonoThread **current_thread_ptr;
1541 g_assert (internal);
1542 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1544 if (!*current_thread_ptr) {
1545 g_assert (domain != mono_get_root_domain ());
1546 *current_thread_ptr = create_thread_object (domain, internal);
1548 return *current_thread_ptr;
1551 /* Return the thread object belonging to INTERNAL in the current domain */
1553 mono_thread_current_for_thread (MonoInternalThread *internal)
1555 MonoDomain *domain = mono_domain_get ();
1556 MonoThread **current_thread_ptr;
1558 g_assert (internal);
1559 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1561 if (!*current_thread_ptr) {
1562 g_assert (domain != mono_get_root_domain ());
1563 *current_thread_ptr = create_thread_object (domain, internal);
1565 return *current_thread_ptr;
1569 mono_thread_internal_current (void)
1571 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1572 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1576 static MonoThreadInfoWaitRet
1577 mono_join_uninterrupted (MonoThreadHandle* thread_to_join, gint32 ms, MonoError *error)
1580 MonoThreadInfoWaitRet ret;
1585 mono_error_init (error);
1587 start = (ms == -1) ? 0 : mono_msec_ticks ();
1590 ret = mono_thread_info_wait_one_handle (thread_to_join, ms, TRUE);
1593 if (ret != MONO_THREAD_INFO_WAIT_RET_ALERTED)
1596 exc = mono_thread_execute_interruption ();
1598 mono_error_set_exception_instance (error, exc);
1605 /* Re-calculate ms according to the time passed */
1606 diff_ms = (gint32)(mono_msec_ticks () - start);
1607 if (diff_ms >= ms) {
1608 ret = MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1611 wait = ms - diff_ms;
1618 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1620 MonoInternalThread *thread = this_obj->internal_thread;
1621 MonoThreadHandle *handle = thread->handle;
1622 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1626 if (mono_thread_current_check_pending_interrupt ())
1629 LOCK_THREAD (thread);
1631 if ((thread->state & ThreadState_Unstarted) != 0) {
1632 UNLOCK_THREAD (thread);
1634 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1638 UNLOCK_THREAD (thread);
1641 ms=MONO_INFINITE_WAIT;
1643 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1645 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1647 ret=mono_join_uninterrupted (handle, ms, &error);
1649 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1651 mono_error_set_pending_exception (&error);
1653 if(ret==MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
1654 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1659 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1664 #define MANAGED_WAIT_FAILED 0x7fffffff
1667 map_native_wait_result_to_managed (MonoW32HandleWaitRet val, gsize numobjects)
1669 if (val >= MONO_W32HANDLE_WAIT_RET_SUCCESS_0 && val < MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + numobjects) {
1670 return WAIT_OBJECT_0 + (val - MONO_W32HANDLE_WAIT_RET_SUCCESS_0);
1671 } else if (val >= MONO_W32HANDLE_WAIT_RET_ABANDONED_0 && val < MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + numobjects) {
1672 return WAIT_ABANDONED_0 + (val - MONO_W32HANDLE_WAIT_RET_ABANDONED_0);
1673 } else if (val == MONO_W32HANDLE_WAIT_RET_ALERTED) {
1674 return WAIT_IO_COMPLETION;
1675 } else if (val == MONO_W32HANDLE_WAIT_RET_TIMEOUT) {
1676 return WAIT_TIMEOUT;
1677 } else if (val == MONO_W32HANDLE_WAIT_RET_FAILED) {
1678 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1679 return MANAGED_WAIT_FAILED;
1681 g_error ("%s: unknown val value %d", __func__, val);
1685 static MonoW32HandleWaitRet
1686 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1689 MonoW32HandleWaitRet ret;
1694 mono_error_init (error);
1696 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1700 if (numhandles != 1)
1701 ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE), numhandles);
1703 ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], ms, TRUE), 1);
1705 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
1706 ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, wait, TRUE);
1707 #endif /* HOST_WIN32 */
1710 if (ret != MONO_W32HANDLE_WAIT_RET_ALERTED)
1713 exc = mono_thread_execute_interruption ();
1715 mono_error_set_exception_instance (error, exc);
1722 /* Re-calculate ms according to the time passed */
1723 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1724 if (diff_ms >= ms) {
1725 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1728 wait = ms - diff_ms;
1734 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1739 MonoW32HandleWaitRet ret;
1741 MonoObject *waitHandle;
1742 MonoInternalThread *thread = mono_thread_internal_current ();
1744 /* Do this WaitSleepJoin check before creating objects */
1745 if (mono_thread_current_check_pending_interrupt ())
1746 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1748 /* We fail in managed if the array has more than 64 elements */
1749 numhandles = (guint32)mono_array_length(mono_handles);
1750 handles = g_new0(HANDLE, numhandles);
1752 for(i = 0; i < numhandles; i++) {
1753 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1754 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1758 ms=MONO_INFINITE_WAIT;
1761 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1763 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1765 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1769 mono_error_set_pending_exception (&error);
1771 return map_native_wait_result_to_managed (ret, numhandles);
1774 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1777 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1778 uintptr_t numhandles;
1779 MonoW32HandleWaitRet ret;
1781 MonoObject *waitHandle;
1782 MonoInternalThread *thread = mono_thread_internal_current ();
1784 /* Do this WaitSleepJoin check before creating objects */
1785 if (mono_thread_current_check_pending_interrupt ())
1786 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1788 numhandles = mono_array_length(mono_handles);
1789 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1790 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1792 for(i = 0; i < numhandles; i++) {
1793 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1794 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1798 ms=MONO_INFINITE_WAIT;
1801 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1803 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1805 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1807 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1809 mono_error_set_pending_exception (&error);
1811 return map_native_wait_result_to_managed (ret, numhandles);
1814 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1817 MonoW32HandleWaitRet ret;
1818 MonoInternalThread *thread = mono_thread_internal_current ();
1820 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1823 ms=MONO_INFINITE_WAIT;
1826 if (mono_thread_current_check_pending_interrupt ())
1827 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1829 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1831 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1833 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1835 mono_error_set_pending_exception (&error);
1836 return map_native_wait_result_to_managed (ret, 1);
1840 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1842 MonoW32HandleWaitRet ret;
1843 MonoInternalThread *thread = mono_thread_internal_current ();
1846 ms = MONO_INFINITE_WAIT;
1848 if (mono_thread_current_check_pending_interrupt ())
1849 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1851 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1855 ret = mono_w32handle_convert_wait_ret (SignalObjectAndWait (toSignal, toWait, ms, TRUE), 1);
1857 ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE);
1861 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1863 return map_native_wait_result_to_managed (ret, 1);
1866 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1868 return InterlockedIncrement (location);
1871 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1873 #if SIZEOF_VOID_P == 4
1874 if (G_UNLIKELY ((size_t)location & 0x7)) {
1876 mono_interlocked_lock ();
1879 mono_interlocked_unlock ();
1883 return InterlockedIncrement64 (location);
1886 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1888 return InterlockedDecrement(location);
1891 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1893 #if SIZEOF_VOID_P == 4
1894 if (G_UNLIKELY ((size_t)location & 0x7)) {
1896 mono_interlocked_lock ();
1899 mono_interlocked_unlock ();
1903 return InterlockedDecrement64 (location);
1906 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1908 return InterlockedExchange(location, value);
1911 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1914 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1915 mono_gc_wbarrier_generic_nostore (location);
1919 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1921 return InterlockedExchangePointer(location, value);
1924 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1926 IntFloatUnion val, ret;
1929 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1935 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1937 #if SIZEOF_VOID_P == 4
1938 if (G_UNLIKELY ((size_t)location & 0x7)) {
1940 mono_interlocked_lock ();
1943 mono_interlocked_unlock ();
1947 return InterlockedExchange64 (location, value);
1951 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1953 LongDoubleUnion val, ret;
1956 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1961 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1963 return InterlockedCompareExchange(location, value, comparand);
1966 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1968 gint32 r = InterlockedCompareExchange(location, value, comparand);
1969 *success = r == comparand;
1973 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1976 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1977 mono_gc_wbarrier_generic_nostore (location);
1981 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1983 return InterlockedCompareExchangePointer(location, value, comparand);
1986 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1988 IntFloatUnion val, ret, cmp;
1991 cmp.fval = comparand;
1992 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1998 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2000 #if SIZEOF_VOID_P == 8
2001 LongDoubleUnion val, comp, ret;
2004 comp.fval = comparand;
2005 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2011 mono_interlocked_lock ();
2013 if (old == comparand)
2015 mono_interlocked_unlock ();
2022 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2024 #if SIZEOF_VOID_P == 4
2025 if (G_UNLIKELY ((size_t)location & 0x7)) {
2027 mono_interlocked_lock ();
2029 if (old == comparand)
2031 mono_interlocked_unlock ();
2035 return InterlockedCompareExchange64 (location, value, comparand);
2039 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2042 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2043 mono_gc_wbarrier_generic_nostore (location);
2048 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2051 MONO_CHECK_NULL (location, NULL);
2052 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2053 mono_gc_wbarrier_generic_nostore (location);
2058 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2060 return InterlockedAdd (location, value);
2064 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2066 #if SIZEOF_VOID_P == 4
2067 if (G_UNLIKELY ((size_t)location & 0x7)) {
2069 mono_interlocked_lock ();
2072 mono_interlocked_unlock ();
2076 return InterlockedAdd64 (location, value);
2080 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2082 #if SIZEOF_VOID_P == 4
2083 if (G_UNLIKELY ((size_t)location & 0x7)) {
2085 mono_interlocked_lock ();
2087 mono_interlocked_unlock ();
2091 return InterlockedRead64 (location);
2095 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2097 mono_memory_barrier ();
2101 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2103 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2105 if (state & ThreadState_Background) {
2106 /* If the thread changes the background mode, the main thread has to
2107 * be notified, since it has to rebuild the list of threads to
2110 mono_os_event_set (&background_change_event);
2115 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2117 mono_thread_set_state (this_obj, (MonoThreadState)state);
2119 if (state & ThreadState_Background) {
2120 /* If the thread changes the background mode, the main thread has to
2121 * be notified, since it has to rebuild the list of threads to
2124 mono_os_event_set (&background_change_event);
2129 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2133 LOCK_THREAD (this_obj);
2135 state = this_obj->state;
2137 UNLOCK_THREAD (this_obj);
2142 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2144 MonoInternalThread *current;
2146 MonoInternalThread *thread = this_obj->internal_thread;
2148 LOCK_THREAD (thread);
2150 current = mono_thread_internal_current ();
2152 thread->thread_interrupt_requested = TRUE;
2153 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2155 UNLOCK_THREAD (thread);
2158 async_abort_internal (thread, FALSE);
2163 * mono_thread_current_check_pending_interrupt:
2165 * Checks if there's a interruption request and set the pending exception if so.
2167 * @returns true if a pending exception was set
2170 mono_thread_current_check_pending_interrupt (void)
2172 MonoInternalThread *thread = mono_thread_internal_current ();
2173 gboolean throw_ = FALSE;
2175 LOCK_THREAD (thread);
2177 if (thread->thread_interrupt_requested) {
2179 thread->thread_interrupt_requested = FALSE;
2182 UNLOCK_THREAD (thread);
2185 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2190 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2192 LOCK_THREAD (thread);
2194 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2195 (thread->state & ThreadState_StopRequested) != 0 ||
2196 (thread->state & ThreadState_Stopped) != 0)
2198 UNLOCK_THREAD (thread);
2202 if ((thread->state & ThreadState_Unstarted) != 0) {
2203 thread->state |= ThreadState_Aborted;
2204 UNLOCK_THREAD (thread);
2208 thread->state |= ThreadState_AbortRequested;
2209 if (thread->abort_state_handle)
2210 mono_gchandle_free (thread->abort_state_handle);
2212 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2213 g_assert (thread->abort_state_handle);
2215 thread->abort_state_handle = 0;
2217 thread->abort_exc = NULL;
2219 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));
2221 /* During shutdown, we can't wait for other threads */
2223 /* Make sure the thread is awake */
2224 mono_thread_resume (thread);
2226 UNLOCK_THREAD (thread);
2231 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2233 if (!request_thread_abort (thread, state))
2236 if (thread == mono_thread_internal_current ()) {
2238 self_abort_internal (&error);
2239 mono_error_set_pending_exception (&error);
2241 async_abort_internal (thread, TRUE);
2246 * mono_thread_internal_abort:
2248 * Request thread @thread to be aborted.
2250 * @thread MUST NOT be the current thread.
2253 mono_thread_internal_abort (MonoInternalThread *thread)
2255 g_assert (thread != mono_thread_internal_current ());
2257 if (!request_thread_abort (thread, NULL))
2259 async_abort_internal (thread, TRUE);
2263 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2265 MonoInternalThread *thread = mono_thread_internal_current ();
2266 gboolean was_aborting;
2268 LOCK_THREAD (thread);
2269 was_aborting = thread->state & ThreadState_AbortRequested;
2270 thread->state &= ~ThreadState_AbortRequested;
2271 UNLOCK_THREAD (thread);
2273 if (!was_aborting) {
2274 const char *msg = "Unable to reset abort because no abort was requested";
2275 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2279 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2280 thread->abort_exc = NULL;
2281 if (thread->abort_state_handle) {
2282 mono_gchandle_free (thread->abort_state_handle);
2283 /* This is actually not necessary - the handle
2284 only counts if the exception is set */
2285 thread->abort_state_handle = 0;
2290 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2292 LOCK_THREAD (thread);
2294 thread->state &= ~ThreadState_AbortRequested;
2296 if (thread->abort_exc) {
2297 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2298 thread->abort_exc = NULL;
2299 if (thread->abort_state_handle) {
2300 mono_gchandle_free (thread->abort_state_handle);
2301 /* This is actually not necessary - the handle
2302 only counts if the exception is set */
2303 thread->abort_state_handle = 0;
2307 UNLOCK_THREAD (thread);
2311 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2314 MonoInternalThread *thread = this_obj->internal_thread;
2315 MonoObject *state, *deserialized = NULL;
2318 if (!thread->abort_state_handle)
2321 state = mono_gchandle_get_target (thread->abort_state_handle);
2324 domain = mono_domain_get ();
2325 if (mono_object_domain (state) == domain)
2328 deserialized = mono_object_xdomain_representation (state, domain, &error);
2330 if (!deserialized) {
2331 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2332 if (!is_ok (&error)) {
2333 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2334 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2336 mono_set_pending_exception (invalid_op_exc);
2340 return deserialized;
2344 mono_thread_suspend (MonoInternalThread *thread)
2346 LOCK_THREAD (thread);
2348 if ((thread->state & ThreadState_Unstarted) != 0 ||
2349 (thread->state & ThreadState_Aborted) != 0 ||
2350 (thread->state & ThreadState_Stopped) != 0)
2352 UNLOCK_THREAD (thread);
2356 if ((thread->state & ThreadState_Suspended) != 0 ||
2357 (thread->state & ThreadState_SuspendRequested) != 0 ||
2358 (thread->state & ThreadState_StopRequested) != 0)
2360 UNLOCK_THREAD (thread);
2364 thread->state |= ThreadState_SuspendRequested;
2365 mono_os_event_reset (thread->suspended);
2367 if (thread == mono_thread_internal_current ()) {
2368 /* calls UNLOCK_THREAD (thread) */
2369 self_suspend_internal ();
2371 /* calls UNLOCK_THREAD (thread) */
2372 async_suspend_internal (thread, FALSE);
2379 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2381 if (!mono_thread_suspend (this_obj->internal_thread)) {
2382 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2387 /* LOCKING: LOCK_THREAD(thread) must be held */
2389 mono_thread_resume (MonoInternalThread *thread)
2391 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2392 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread));
2393 thread->state &= ~ThreadState_SuspendRequested;
2394 mono_os_event_set (thread->suspended);
2398 if ((thread->state & ThreadState_Suspended) == 0 ||
2399 (thread->state & ThreadState_Unstarted) != 0 ||
2400 (thread->state & ThreadState_Aborted) != 0 ||
2401 (thread->state & ThreadState_Stopped) != 0)
2403 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread));
2407 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread));
2409 mono_os_event_set (thread->suspended);
2411 if (!thread->self_suspended) {
2412 UNLOCK_THREAD (thread);
2414 /* Awake the thread */
2415 if (!mono_thread_info_resume (thread_get_tid (thread)))
2418 LOCK_THREAD (thread);
2421 thread->state &= ~ThreadState_Suspended;
2427 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2429 if (!thread->internal_thread) {
2430 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2432 LOCK_THREAD (thread->internal_thread);
2433 if (!mono_thread_resume (thread->internal_thread))
2434 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2435 UNLOCK_THREAD (thread->internal_thread);
2440 mono_threads_is_critical_method (MonoMethod *method)
2442 switch (method->wrapper_type) {
2443 case MONO_WRAPPER_RUNTIME_INVOKE:
2444 case MONO_WRAPPER_XDOMAIN_INVOKE:
2445 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2452 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2457 if (mono_threads_is_critical_method (m)) {
2458 *((gboolean*)data) = TRUE;
2465 is_running_protected_wrapper (void)
2467 gboolean found = FALSE;
2468 mono_stack_walk (find_wrapper, &found);
2473 request_thread_stop (MonoInternalThread *thread)
2475 LOCK_THREAD (thread);
2477 if ((thread->state & ThreadState_StopRequested) != 0 ||
2478 (thread->state & ThreadState_Stopped) != 0)
2480 UNLOCK_THREAD (thread);
2484 /* Make sure the thread is awake */
2485 mono_thread_resume (thread);
2487 thread->state |= ThreadState_StopRequested;
2488 thread->state &= ~ThreadState_AbortRequested;
2490 UNLOCK_THREAD (thread);
2495 * mono_thread_internal_stop:
2497 * Request thread @thread to stop.
2499 * @thread MUST NOT be the current thread.
2502 mono_thread_internal_stop (MonoInternalThread *thread)
2504 g_assert (thread != mono_thread_internal_current ());
2506 if (!request_thread_stop (thread))
2509 async_abort_internal (thread, TRUE);
2512 void mono_thread_stop (MonoThread *thread)
2514 MonoInternalThread *internal = thread->internal_thread;
2516 if (!request_thread_stop (internal))
2519 if (internal == mono_thread_internal_current ()) {
2521 self_abort_internal (&error);
2523 This function is part of the embeding API and has no way to return the exception
2524 to be thrown. So what we do is keep the old behavior and raise the exception.
2526 mono_error_raise_exception (&error); /* OK to throw, see note */
2528 async_abort_internal (internal, TRUE);
2533 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2535 gint8 tmp = *(volatile gint8 *)ptr;
2536 mono_memory_barrier ();
2541 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2543 gint16 tmp = *(volatile gint16 *)ptr;
2544 mono_memory_barrier ();
2549 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2551 gint32 tmp = *(volatile gint32 *)ptr;
2552 mono_memory_barrier ();
2557 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2559 gint64 tmp = *(volatile gint64 *)ptr;
2560 mono_memory_barrier ();
2565 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2567 volatile void *tmp = *(volatile void **)ptr;
2568 mono_memory_barrier ();
2569 return (void *) tmp;
2573 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2575 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2576 mono_memory_barrier ();
2577 return (MonoObject *) tmp;
2581 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2583 double tmp = *(volatile double *)ptr;
2584 mono_memory_barrier ();
2589 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2591 float tmp = *(volatile float *)ptr;
2592 mono_memory_barrier ();
2597 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2599 return InterlockedRead8 ((volatile gint8 *)ptr);
2603 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2605 return InterlockedRead16 ((volatile gint16 *)ptr);
2609 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2611 return InterlockedRead ((volatile gint32 *)ptr);
2615 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2617 #if SIZEOF_VOID_P == 4
2618 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2620 mono_interlocked_lock ();
2621 val = *(gint64*)ptr;
2622 mono_interlocked_unlock ();
2626 return InterlockedRead64 ((volatile gint64 *)ptr);
2630 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2632 return InterlockedReadPointer ((volatile gpointer *)ptr);
2636 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2640 #if SIZEOF_VOID_P == 4
2641 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2643 mono_interlocked_lock ();
2644 val = *(double*)ptr;
2645 mono_interlocked_unlock ();
2650 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2656 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2660 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2666 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2668 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2672 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2674 mono_memory_barrier ();
2675 *(volatile gint8 *)ptr = value;
2679 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2681 mono_memory_barrier ();
2682 *(volatile gint16 *)ptr = value;
2686 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2688 mono_memory_barrier ();
2689 *(volatile gint32 *)ptr = value;
2693 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2695 mono_memory_barrier ();
2696 *(volatile gint64 *)ptr = value;
2700 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2702 mono_memory_barrier ();
2703 *(volatile void **)ptr = value;
2707 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2709 mono_memory_barrier ();
2710 mono_gc_wbarrier_generic_store (ptr, value);
2714 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2716 mono_memory_barrier ();
2717 *(volatile double *)ptr = value;
2721 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2723 mono_memory_barrier ();
2724 *(volatile float *)ptr = value;
2728 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2730 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2734 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2736 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2740 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2742 InterlockedWrite ((volatile gint32 *)ptr, value);
2746 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2748 #if SIZEOF_VOID_P == 4
2749 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2750 mono_interlocked_lock ();
2751 *(gint64*)ptr = value;
2752 mono_interlocked_unlock ();
2757 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2761 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2763 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2767 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2771 #if SIZEOF_VOID_P == 4
2772 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2773 mono_interlocked_lock ();
2774 *(double*)ptr = value;
2775 mono_interlocked_unlock ();
2782 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2786 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2792 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2796 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2798 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2802 free_context (void *user_data)
2804 ContextStaticData *data = user_data;
2806 mono_threads_lock ();
2809 * There is no guarantee that, by the point this reference queue callback
2810 * has been invoked, the GC handle associated with the object will fail to
2811 * resolve as one might expect. So if we don't free and remove the GC
2812 * handle here, free_context_static_data_helper () could end up resolving
2813 * a GC handle to an actually-dead context which would contain a pointer
2814 * to an already-freed static data segment, resulting in a crash when
2817 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2819 mono_threads_unlock ();
2821 mono_gchandle_free (data->gc_handle);
2822 mono_free_static_data (data->static_data);
2827 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2829 mono_threads_lock ();
2831 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2834 contexts = g_hash_table_new (NULL, NULL);
2837 context_queue = mono_gc_reference_queue_new (free_context);
2839 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2840 g_hash_table_insert (contexts, gch, gch);
2843 * We use this intermediate structure to contain a duplicate pointer to
2844 * the static data because we can't rely on being able to resolve the GC
2845 * handle in the reference queue callback.
2847 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2848 data->gc_handle = GPOINTER_TO_UINT (gch);
2851 context_adjust_static_data (ctx);
2852 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2854 mono_threads_unlock ();
2856 mono_profiler_context_loaded (ctx);
2860 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2863 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2864 * cleanup in exceptional circumstances, we don't actually do any
2865 * cleanup work here. We instead do this via a reference queue.
2868 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2870 mono_profiler_context_unloaded (ctx);
2873 void mono_thread_init (MonoThreadStartCB start_cb,
2874 MonoThreadAttachCB attach_cb)
2876 mono_coop_mutex_init_recursive (&threads_mutex);
2878 mono_os_mutex_init_recursive(&interlocked_mutex);
2879 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2881 mono_os_event_init (&background_change_event, FALSE);
2883 mono_init_static_data_info (&thread_static_info);
2884 mono_init_static_data_info (&context_static_info);
2886 mono_thread_start_cb = start_cb;
2887 mono_thread_attach_cb = attach_cb;
2890 void mono_thread_cleanup (void)
2892 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
2893 /* The main thread must abandon any held mutexes (particularly
2894 * important for named mutexes as they are shared across
2895 * processes, see bug 74680.) This will happen when the
2896 * thread exits, but if it's not running in a subthread it
2897 * won't exit in time.
2899 mono_w32mutex_abandon ();
2903 /* This stuff needs more testing, it seems one of these
2904 * critical sections can be locked when mono_thread_cleanup is
2907 mono_coop_mutex_destroy (&threads_mutex);
2908 mono_os_mutex_destroy (&interlocked_mutex);
2909 mono_os_mutex_destroy (&delayed_free_table_mutex);
2910 mono_os_mutex_destroy (&small_id_mutex);
2911 mono_os_event_destroy (&background_change_event);
2916 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2918 mono_thread_cleanup_fn = func;
2922 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2924 thread->internal_thread->manage_callback = func;
2928 static void print_tids (gpointer key, gpointer value, gpointer user)
2930 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2931 * sizeof(uint) and a cast to uint would overflow
2933 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2934 * print this as a pointer.
2936 g_message ("Waiting for: %p", key);
2941 MonoThreadHandle *handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2942 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2947 wait_for_tids (struct wait_data *wait, guint32 timeout, gboolean check_state_change)
2950 MonoThreadInfoWaitRet ret;
2952 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2954 /* Add the thread state change event, so it wakes
2955 * up if a thread changes to background mode. */
2958 if (check_state_change)
2959 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, &background_change_event, FALSE, timeout, TRUE);
2961 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, NULL, TRUE, timeout, TRUE);
2964 if (ret == MONO_THREAD_INFO_WAIT_RET_FAILED) {
2965 /* See the comment in build_wait_tids() */
2966 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2970 for( i = 0; i < wait->num; i++)
2971 mono_threads_close_thread_handle (wait->handles [i]);
2973 if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT)
2976 if (ret < wait->num) {
2977 MonoInternalThread *internal;
2979 internal = wait->threads [ret];
2981 mono_threads_lock ();
2982 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
2983 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
2984 mono_threads_unlock ();
2988 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2990 struct wait_data *wait=(struct wait_data *)user;
2992 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS - 1) {
2993 MonoInternalThread *thread=(MonoInternalThread *)value;
2995 /* Ignore background threads, we abort them later */
2996 /* Do not lock here since it is not needed and the caller holds threads_lock */
2997 if (thread->state & ThreadState_Background) {
2998 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2999 return; /* just leave, ignore */
3002 if (mono_gc_is_finalizer_internal_thread (thread)) {
3003 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3007 if (thread == mono_thread_internal_current ()) {
3008 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3012 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3013 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3017 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3018 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3022 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3023 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3024 wait->handles[wait->num]=mono_threads_open_thread_handle (thread->handle);
3025 wait->threads[wait->num]=thread;
3028 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3030 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3035 /* Just ignore the rest, we can't do anything with
3042 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3044 struct wait_data *wait=(struct wait_data *)user;
3045 MonoNativeThreadId self = mono_native_thread_id_get ();
3046 MonoInternalThread *thread = (MonoInternalThread *)value;
3048 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3051 /* The finalizer thread is not a background thread */
3052 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3053 && (thread->state & ThreadState_Background) != 0
3054 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3056 wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
3057 wait->threads[wait->num] = thread;
3060 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3061 mono_thread_internal_abort (thread);
3065 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3066 && !mono_gc_is_finalizer_internal_thread (thread);
3070 * mono_threads_set_shutting_down:
3072 * Is called by a thread that wants to shut down Mono. If the runtime is already
3073 * shutting down, the calling thread is suspended/stopped, and this function never
3077 mono_threads_set_shutting_down (void)
3079 MonoInternalThread *current_thread = mono_thread_internal_current ();
3081 mono_threads_lock ();
3083 if (shutting_down) {
3084 mono_threads_unlock ();
3086 /* Make sure we're properly suspended/stopped */
3088 LOCK_THREAD (current_thread);
3090 if ((current_thread->state & ThreadState_SuspendRequested) ||
3091 (current_thread->state & ThreadState_AbortRequested) ||
3092 (current_thread->state & ThreadState_StopRequested)) {
3093 UNLOCK_THREAD (current_thread);
3094 mono_thread_execute_interruption ();
3096 current_thread->state |= ThreadState_Stopped;
3097 UNLOCK_THREAD (current_thread);
3100 /*since we're killing the thread, detach it.*/
3101 mono_thread_detach_internal (current_thread);
3103 /* Wake up other threads potentially waiting for us */
3104 mono_thread_info_exit (0);
3106 shutting_down = TRUE;
3108 /* Not really a background state change, but this will
3109 * interrupt the main thread if it is waiting for all
3110 * the other threads.
3112 mono_os_event_set (&background_change_event);
3114 mono_threads_unlock ();
3118 void mono_thread_manage (void)
3120 struct wait_data wait_data;
3121 struct wait_data *wait = &wait_data;
3123 memset (wait, 0, sizeof (struct wait_data));
3124 /* join each thread that's still running */
3125 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3127 mono_threads_lock ();
3129 THREAD_DEBUG (g_message("%s: No threads", __func__));
3130 mono_threads_unlock ();
3133 mono_threads_unlock ();
3136 mono_threads_lock ();
3137 if (shutting_down) {
3138 /* somebody else is shutting down */
3139 mono_threads_unlock ();
3142 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3143 mono_g_hash_table_foreach (threads, print_tids, NULL));
3145 mono_os_event_reset (&background_change_event);
3147 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3148 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3149 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3150 mono_threads_unlock ();
3152 /* Something to wait for */
3153 wait_for_tids (wait, MONO_INFINITE_WAIT, TRUE);
3154 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3155 } while(wait->num>0);
3157 /* Mono is shutting down, so just wait for the end */
3158 if (!mono_runtime_try_shutdown ()) {
3159 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3160 mono_thread_suspend (mono_thread_internal_current ());
3161 mono_thread_execute_interruption ();
3165 * Remove everything but the finalizer thread and self.
3166 * Also abort all the background threads
3169 mono_threads_lock ();
3172 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3173 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3174 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3176 mono_threads_unlock ();
3178 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3179 if (wait->num > 0) {
3180 /* Something to wait for */
3181 wait_for_tids (wait, MONO_INFINITE_WAIT, FALSE);
3183 } while (wait->num > 0);
3186 * give the subthreads a chance to really quit (this is mainly needed
3187 * to get correct user and system times from getrusage/wait/time(1)).
3188 * This could be removed if we avoid pthread_detach() and use pthread_join().
3190 mono_thread_info_yield ();
3194 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3196 MonoInternalThread *thread = (MonoInternalThread*)value;
3197 struct wait_data *wait = (struct wait_data*)user_data;
3200 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3202 * This needs no locking.
3204 if ((thread->state & ThreadState_Suspended) != 0 ||
3205 (thread->state & ThreadState_Stopped) != 0)
3208 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3209 wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle);
3210 wait->threads [wait->num] = thread;
3216 * mono_thread_suspend_all_other_threads:
3218 * Suspend all managed threads except the finalizer thread and this thread. It is
3219 * not possible to resume them later.
3221 void mono_thread_suspend_all_other_threads (void)
3223 struct wait_data wait_data;
3224 struct wait_data *wait = &wait_data;
3226 MonoNativeThreadId self = mono_native_thread_id_get ();
3227 guint32 eventidx = 0;
3228 gboolean starting, finished;
3230 memset (wait, 0, sizeof (struct wait_data));
3232 * The other threads could be in an arbitrary state at this point, i.e.
3233 * they could be starting up, shutting down etc. This means that there could be
3234 * threads which are not even in the threads hash table yet.
3238 * First we set a barrier which will be checked by all threads before they
3239 * are added to the threads hash table, and they will exit if the flag is set.
3240 * This ensures that no threads could be added to the hash later.
3241 * We will use shutting_down as the barrier for now.
3243 g_assert (shutting_down);
3246 * We make multiple calls to WaitForMultipleObjects since:
3247 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3248 * - some threads could exit without becoming suspended
3253 * Make a copy of the hashtable since we can't do anything with
3254 * threads while threads_mutex is held.
3257 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3258 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3259 mono_threads_lock ();
3260 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3261 mono_threads_unlock ();
3264 /* Get the suspended events that we'll be waiting for */
3265 for (i = 0; i < wait->num; ++i) {
3266 MonoInternalThread *thread = wait->threads [i];
3268 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3269 || mono_gc_is_finalizer_internal_thread (thread)
3270 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3272 mono_threads_close_thread_handle (wait->handles [i]);
3273 wait->threads [i] = NULL;
3277 LOCK_THREAD (thread);
3279 if ((thread->state & ThreadState_Suspended) != 0 ||
3280 (thread->state & ThreadState_StopRequested) != 0 ||
3281 (thread->state & ThreadState_Stopped) != 0) {
3282 UNLOCK_THREAD (thread);
3283 mono_threads_close_thread_handle (wait->handles [i]);
3284 wait->threads [i] = NULL;
3290 /* Convert abort requests into suspend requests */
3291 if ((thread->state & ThreadState_AbortRequested) != 0)
3292 thread->state &= ~ThreadState_AbortRequested;
3294 thread->state |= ThreadState_SuspendRequested;
3295 mono_os_event_reset (thread->suspended);
3297 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3298 async_suspend_internal (thread, TRUE);
3300 mono_threads_close_thread_handle (wait->handles [i]);
3301 wait->threads [i] = NULL;
3303 if (eventidx <= 0) {
3305 * If there are threads which are starting up, we wait until they
3306 * are suspended when they try to register in the threads hash.
3307 * This is guaranteed to finish, since the threads which can create new
3308 * threads get suspended after a while.
3309 * FIXME: The finalizer thread can still create new threads.
3311 mono_threads_lock ();
3312 if (threads_starting_up)
3313 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3316 mono_threads_unlock ();
3318 mono_thread_info_sleep (100, NULL);
3326 MonoInternalThread *thread;
3327 MonoStackFrameInfo *frames;
3328 int nframes, max_frames;
3329 int nthreads, max_threads;
3330 MonoInternalThread **threads;
3331 } ThreadDumpUserData;
3333 static gboolean thread_dump_requested;
3335 /* This needs to be async safe */
3337 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3339 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3341 if (ud->nframes < ud->max_frames) {
3342 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3349 /* This needs to be async safe */
3350 static SuspendThreadResult
3351 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3353 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3354 MonoInternalThread *thread = user_data->thread;
3357 /* This no longer works with remote unwinding */
3358 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3359 mono_thread_internal_describe (thread, text);
3360 g_string_append (text, "\n");
3363 if (thread == mono_thread_internal_current ())
3364 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3366 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3368 return MonoResumeThread;
3372 int nthreads, max_threads;
3373 MonoInternalThread **threads;
3374 } CollectThreadsUserData;
3377 collect_thread (gpointer key, gpointer value, gpointer user)
3379 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3380 MonoInternalThread *thread = (MonoInternalThread *)value;
3382 if (ud->nthreads < ud->max_threads)
3383 ud->threads [ud->nthreads ++] = thread;
3387 * Collect running threads into the THREADS array.
3388 * THREADS should be an array allocated on the stack.
3391 collect_threads (MonoInternalThread **thread_array, int max_threads)
3393 CollectThreadsUserData ud;
3395 memset (&ud, 0, sizeof (ud));
3396 /* This array contains refs, but its on the stack, so its ok */
3397 ud.threads = thread_array;
3398 ud.max_threads = max_threads;
3400 mono_threads_lock ();
3401 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3402 mono_threads_unlock ();
3408 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3410 GString* text = g_string_new (0);
3412 GError *error = NULL;
3415 ud->thread = thread;
3418 /* Collect frames for the thread */
3419 if (thread == mono_thread_internal_current ()) {
3420 get_thread_dump (mono_thread_info_current (), ud);
3422 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3426 * Do all the non async-safe work outside of get_thread_dump.
3429 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3431 g_string_append_printf (text, "\n\"%s\"", name);
3434 else if (thread->threadpool_thread) {
3435 g_string_append (text, "\n\"<threadpool thread>\"");
3437 g_string_append (text, "\n\"<unnamed thread>\"");
3440 for (i = 0; i < ud->nframes; ++i) {
3441 MonoStackFrameInfo *frame = &ud->frames [i];
3442 MonoMethod *method = NULL;
3444 if (frame->type == FRAME_TYPE_MANAGED)
3445 method = mono_jit_info_get_method (frame->ji);
3448 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3449 g_string_append_printf (text, " %s\n", location);
3452 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3456 fprintf (stdout, "%s", text->str);
3458 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3459 OutputDebugStringA(text->str);
3462 g_string_free (text, TRUE);
3467 mono_threads_perform_thread_dump (void)
3469 ThreadDumpUserData ud;
3470 MonoInternalThread *thread_array [128];
3471 int tindex, nthreads;
3473 if (!thread_dump_requested)
3476 printf ("Full thread dump:\n");
3478 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3479 nthreads = collect_threads (thread_array, 128);
3481 memset (&ud, 0, sizeof (ud));
3482 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3483 ud.max_frames = 256;
3485 for (tindex = 0; tindex < nthreads; ++tindex)
3486 dump_thread (thread_array [tindex], &ud);
3490 thread_dump_requested = FALSE;
3493 /* Obtain the thread dump of all threads */
3495 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3498 ThreadDumpUserData ud;
3499 MonoInternalThread *thread_array [128];
3500 MonoDomain *domain = mono_domain_get ();
3501 MonoDebugSourceLocation *location;
3502 int tindex, nthreads;
3504 mono_error_init (error);
3506 *out_threads = NULL;
3507 *out_stack_frames = NULL;
3509 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3510 nthreads = collect_threads (thread_array, 128);
3512 memset (&ud, 0, sizeof (ud));
3513 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3514 ud.max_frames = 256;
3516 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3519 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3523 for (tindex = 0; tindex < nthreads; ++tindex) {
3524 MonoInternalThread *thread = thread_array [tindex];
3525 MonoArray *thread_frames;
3531 /* Collect frames for the thread */
3532 if (thread == mono_thread_internal_current ()) {
3533 get_thread_dump (mono_thread_info_current (), &ud);
3535 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3538 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3540 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3543 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3545 for (i = 0; i < ud.nframes; ++i) {
3546 MonoStackFrameInfo *frame = &ud.frames [i];
3547 MonoMethod *method = NULL;
3548 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3552 sf->native_offset = frame->native_offset;
3554 if (frame->type == FRAME_TYPE_MANAGED)
3555 method = mono_jit_info_get_method (frame->ji);
3558 sf->method_address = (gsize) frame->ji->code_start;
3560 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3563 MONO_OBJECT_SETREF (sf, method, rm);
3565 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3567 sf->il_offset = location->il_offset;
3569 if (location && location->source_file) {
3570 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3571 sf->line = location->row;
3572 sf->column = location->column;
3574 mono_debug_free_source_location (location);
3579 mono_array_setref (thread_frames, i, sf);
3585 return is_ok (error);
3589 * mono_threads_request_thread_dump:
3591 * Ask all threads except the current to print their stacktrace to stdout.
3594 mono_threads_request_thread_dump (void)
3596 /*The new thread dump code runs out of the finalizer thread. */
3597 thread_dump_requested = TRUE;
3598 mono_gc_finalize_notify ();
3603 gint allocated; /* +1 so that refs [allocated] == NULL */
3607 typedef struct ref_stack RefStack;
3610 ref_stack_new (gint initial_size)
3614 initial_size = MAX (initial_size, 16) + 1;
3615 rs = g_new0 (RefStack, 1);
3616 rs->refs = g_new0 (gpointer, initial_size);
3617 rs->allocated = initial_size;
3622 ref_stack_destroy (gpointer ptr)
3624 RefStack *rs = (RefStack *)ptr;
3633 ref_stack_push (RefStack *rs, gpointer ptr)
3635 g_assert (rs != NULL);
3637 if (rs->bottom >= rs->allocated) {
3638 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3639 rs->allocated <<= 1;
3640 rs->refs [rs->allocated] = NULL;
3642 rs->refs [rs->bottom++] = ptr;
3646 ref_stack_pop (RefStack *rs)
3648 if (rs == NULL || rs->bottom == 0)
3652 rs->refs [rs->bottom] = NULL;
3656 ref_stack_find (RefStack *rs, gpointer ptr)
3663 for (refs = rs->refs; refs && *refs; refs++) {
3671 * mono_thread_push_appdomain_ref:
3673 * Register that the current thread may have references to objects in domain
3674 * @domain on its stack. Each call to this function should be paired with a
3675 * call to pop_appdomain_ref.
3678 mono_thread_push_appdomain_ref (MonoDomain *domain)
3680 MonoInternalThread *thread = mono_thread_internal_current ();
3683 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3684 SPIN_LOCK (thread->lock_thread_id);
3685 if (thread->appdomain_refs == NULL)
3686 thread->appdomain_refs = ref_stack_new (16);
3687 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3688 SPIN_UNLOCK (thread->lock_thread_id);
3693 mono_thread_pop_appdomain_ref (void)
3695 MonoInternalThread *thread = mono_thread_internal_current ();
3698 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3699 SPIN_LOCK (thread->lock_thread_id);
3700 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3701 SPIN_UNLOCK (thread->lock_thread_id);
3706 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3709 SPIN_LOCK (thread->lock_thread_id);
3710 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3711 SPIN_UNLOCK (thread->lock_thread_id);
3716 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3718 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3721 typedef struct abort_appdomain_data {
3722 struct wait_data wait;
3724 } abort_appdomain_data;
3727 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3729 MonoInternalThread *thread = (MonoInternalThread*)value;
3730 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3731 MonoDomain *domain = data->domain;
3733 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3734 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3736 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3737 data->wait.handles [data->wait.num] = mono_threads_open_thread_handle (thread->handle);
3738 data->wait.threads [data->wait.num] = thread;
3741 /* Just ignore the rest, we can't do anything with
3749 * mono_threads_abort_appdomain_threads:
3751 * Abort threads which has references to the given appdomain.
3754 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3756 #ifdef __native_client__
3760 abort_appdomain_data user_data;
3762 int orig_timeout = timeout;
3765 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3767 start_time = mono_msec_ticks ();
3769 mono_threads_lock ();
3771 user_data.domain = domain;
3772 user_data.wait.num = 0;
3773 /* This shouldn't take any locks */
3774 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3775 mono_threads_unlock ();
3777 if (user_data.wait.num > 0) {
3778 /* Abort the threads outside the threads lock */
3779 for (i = 0; i < user_data.wait.num; ++i)
3780 mono_thread_internal_abort (user_data.wait.threads [i]);
3783 * We should wait for the threads either to abort, or to leave the
3784 * domain. We can't do the latter, so we wait with a timeout.
3786 wait_for_tids (&user_data.wait, 100, FALSE);
3789 /* Update remaining time */
3790 timeout -= mono_msec_ticks () - start_time;
3791 start_time = mono_msec_ticks ();
3793 if (orig_timeout != -1 && timeout < 0)
3796 while (user_data.wait.num > 0);
3798 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3804 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3806 MonoInternalThread *thread = (MonoInternalThread*)value;
3807 MonoDomain *domain = (MonoDomain*)user_data;
3810 /* No locking needed here */
3811 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3813 if (thread->cached_culture_info) {
3814 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3815 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3816 if (obj && obj->vtable->domain == domain)
3817 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3823 * mono_threads_clear_cached_culture:
3825 * Clear the cached_current_culture from all threads if it is in the
3829 mono_threads_clear_cached_culture (MonoDomain *domain)
3831 mono_threads_lock ();
3832 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3833 mono_threads_unlock ();
3837 * mono_thread_get_undeniable_exception:
3839 * Return an exception which needs to be raised when leaving a catch clause.
3840 * This is used for undeniable exception propagation.
3843 mono_thread_get_undeniable_exception (void)
3845 MonoInternalThread *thread = mono_thread_internal_current ();
3847 if (!(thread && thread->abort_exc && !is_running_protected_wrapper ()))
3850 // We don't want to have our exception effect calls made by
3851 // the catching block
3853 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
3857 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3858 * exception if the thread no longer references a dying appdomain.
3860 thread->abort_exc->trace_ips = NULL;
3861 thread->abort_exc->stack_trace = NULL;
3862 return thread->abort_exc;
3865 #if MONO_SMALL_CONFIG
3866 #define NUM_STATIC_DATA_IDX 4
3867 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3871 #define NUM_STATIC_DATA_IDX 8
3872 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3873 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3877 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3878 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3881 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3883 gpointer *static_data = (gpointer *)addr;
3885 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3886 void **ptr = (void **)static_data [i];
3891 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3892 void **p = ptr + idx;
3895 mark_func ((MonoObject**)p, gc_data);
3901 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3903 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3907 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3909 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3913 * mono_alloc_static_data
3915 * Allocate memory blocks for storing threads or context static data
3918 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3920 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3923 gpointer* static_data = *static_data_ptr;
3925 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3926 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3928 if (mono_gc_user_markers_supported ()) {
3929 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3930 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3932 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3933 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3936 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3937 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3938 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3939 *static_data_ptr = static_data;
3940 static_data [0] = static_data;
3943 for (i = 1; i <= idx; ++i) {
3944 if (static_data [i])
3947 if (mono_gc_user_markers_supported ())
3948 static_data [i] = g_malloc0 (static_data_size [i]);
3950 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3951 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3952 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3957 mono_free_static_data (gpointer* static_data)
3960 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3961 gpointer p = static_data [i];
3965 * At this point, the static data pointer array is still registered with the
3966 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3967 * data. Freeing the individual arrays without first nulling their slots
3968 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3969 * such an already freed array. See bug #13813.
3971 static_data [i] = NULL;
3972 mono_memory_write_barrier ();
3973 if (mono_gc_user_markers_supported ())
3976 mono_gc_free_fixed (p);
3978 mono_gc_free_fixed (static_data);
3982 * mono_init_static_data_info
3984 * Initializes static data counters
3986 static void mono_init_static_data_info (StaticDataInfo *static_data)
3988 static_data->idx = 0;
3989 static_data->offset = 0;
3990 static_data->freelist = NULL;
3994 * mono_alloc_static_data_slot
3996 * Generates an offset for static data. static_data contains the counters
3997 * used to generate it.
4000 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4002 if (!static_data->idx && !static_data->offset) {
4004 * we use the first chunk of the first allocation also as
4005 * an array for the rest of the data
4007 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4009 static_data->offset += align - 1;
4010 static_data->offset &= ~(align - 1);
4011 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4012 static_data->idx ++;
4013 g_assert (size <= static_data_size [static_data->idx]);
4014 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4015 static_data->offset = 0;
4017 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4018 static_data->offset += size;
4023 * LOCKING: requires that threads_mutex is held
4026 context_adjust_static_data (MonoAppContext *ctx)
4028 if (context_static_info.offset || context_static_info.idx > 0) {
4029 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4030 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4031 ctx->data->static_data = ctx->static_data;
4036 * LOCKING: requires that threads_mutex is held
4039 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4041 MonoInternalThread *thread = (MonoInternalThread *)value;
4042 guint32 offset = GPOINTER_TO_UINT (user);
4044 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4048 * LOCKING: requires that threads_mutex is held
4051 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4053 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4058 guint32 offset = GPOINTER_TO_UINT (user);
4059 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4060 ctx->data->static_data = ctx->static_data;
4063 static StaticDataFreeList*
4064 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4066 StaticDataFreeList* prev = NULL;
4067 StaticDataFreeList* tmp = static_data->freelist;
4069 if (tmp->size == size) {
4071 prev->next = tmp->next;
4073 static_data->freelist = tmp->next;
4082 #if SIZEOF_VOID_P == 4
4089 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4091 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4093 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4094 MonoBitSet *rb = sets [idx];
4095 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4096 offset /= sizeof (uintptr_t);
4097 /* offset is now the bitmap offset */
4098 for (int i = 0; i < numbits; ++i) {
4099 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4100 mono_bitset_set_fast (rb, offset + i);
4105 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4107 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4108 MonoBitSet *rb = sets [idx];
4109 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4110 offset /= sizeof (uintptr_t);
4111 /* offset is now the bitmap offset */
4112 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4113 mono_bitset_clear_fast (rb, offset + i);
4117 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4119 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4121 StaticDataInfo *info;
4124 if (static_type == SPECIAL_STATIC_THREAD) {
4125 info = &thread_static_info;
4126 sets = thread_reference_bitmaps;
4128 info = &context_static_info;
4129 sets = context_reference_bitmaps;
4132 mono_threads_lock ();
4134 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4138 offset = item->offset;
4141 offset = mono_alloc_static_data_slot (info, size, align);
4144 update_reference_bitmap (sets, offset, bitmap, numbits);
4146 if (static_type == SPECIAL_STATIC_THREAD) {
4147 /* This can be called during startup */
4148 if (threads != NULL)
4149 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4151 if (contexts != NULL)
4152 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4154 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4157 mono_threads_unlock ();
4163 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4165 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4167 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4168 return get_thread_static_data (thread, offset);
4170 return get_context_static_data (thread->current_appcontext, offset);
4175 mono_get_special_static_data (guint32 offset)
4177 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4186 * LOCKING: requires that threads_mutex is held
4189 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4191 MonoInternalThread *thread = (MonoInternalThread *)value;
4192 OffsetSize *data = (OffsetSize *)user;
4193 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4194 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4197 if (!thread->static_data || !thread->static_data [idx])
4199 ptr = ((char*) thread->static_data [idx]) + off;
4200 mono_gc_bzero_atomic (ptr, data->size);
4204 * LOCKING: requires that threads_mutex is held
4207 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4209 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4214 OffsetSize *data = (OffsetSize *)user;
4215 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4216 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4219 if (!ctx->static_data || !ctx->static_data [idx])
4222 ptr = ((char*) ctx->static_data [idx]) + off;
4223 mono_gc_bzero_atomic (ptr, data->size);
4227 do_free_special_slot (guint32 offset, guint32 size)
4229 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4231 StaticDataInfo *info;
4233 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4234 info = &thread_static_info;
4235 sets = thread_reference_bitmaps;
4237 info = &context_static_info;
4238 sets = context_reference_bitmaps;
4241 guint32 data_offset = offset;
4242 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4243 OffsetSize data = { data_offset, size };
4245 clear_reference_bitmap (sets, data.offset, data.size);
4247 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4248 if (threads != NULL)
4249 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4251 if (contexts != NULL)
4252 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4255 if (!mono_runtime_is_shutting_down ()) {
4256 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4258 item->offset = offset;
4261 item->next = info->freelist;
4262 info->freelist = item;
4267 do_free_special (gpointer key, gpointer value, gpointer data)
4269 MonoClassField *field = (MonoClassField *)key;
4270 guint32 offset = GPOINTER_TO_UINT (value);
4273 size = mono_type_size (field->type, &align);
4274 do_free_special_slot (offset, size);
4278 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4280 mono_threads_lock ();
4282 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4284 mono_threads_unlock ();
4288 static void CALLBACK dummy_apc (ULONG_PTR param)
4294 * mono_thread_execute_interruption
4296 * Performs the operation that the requested thread state requires (abort,
4299 static MonoException*
4300 mono_thread_execute_interruption (void)
4302 MonoInternalThread *thread = mono_thread_internal_current ();
4303 MonoThread *sys_thread = mono_thread_current ();
4305 LOCK_THREAD (thread);
4307 /* MonoThread::interruption_requested can only be changed with atomics */
4308 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4309 /* this will consume pending APC calls */
4311 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4313 InterlockedDecrement (&thread_interruption_requested);
4315 /* Clear the interrupted flag of the thread so it can wait again */
4316 mono_thread_info_clear_self_interrupt ();
4319 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4320 if (sys_thread->pending_exception) {
4323 exc = sys_thread->pending_exception;
4324 sys_thread->pending_exception = NULL;
4326 UNLOCK_THREAD (thread);
4328 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4329 UNLOCK_THREAD (thread);
4330 g_assert (sys_thread->pending_exception == NULL);
4331 if (thread->abort_exc == NULL) {
4333 * This might be racy, but it has to be called outside the lock
4334 * since it calls managed code.
4336 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4338 return thread->abort_exc;
4340 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4341 /* calls UNLOCK_THREAD (thread) */
4342 self_suspend_internal ();
4345 else if ((thread->state & ThreadState_StopRequested) != 0) {
4346 /* FIXME: do this through the JIT? */
4348 UNLOCK_THREAD (thread);
4350 mono_thread_exit ();
4352 } else if (thread->thread_interrupt_requested) {
4354 thread->thread_interrupt_requested = FALSE;
4355 UNLOCK_THREAD (thread);
4357 return(mono_get_exception_thread_interrupted ());
4360 UNLOCK_THREAD (thread);
4366 * mono_thread_request_interruption
4368 * A signal handler can call this method to request the interruption of a
4369 * thread. The result of the interruption will depend on the current state of
4370 * the thread. If the result is an exception that needs to be throw, it is
4371 * provided as return value.
4374 mono_thread_request_interruption (gboolean running_managed)
4376 MonoInternalThread *thread = mono_thread_internal_current ();
4378 /* The thread may already be stopping */
4383 if (thread->interrupt_on_stop &&
4384 thread->state & ThreadState_StopRequested &&
4385 thread->state & ThreadState_Background)
4388 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4390 InterlockedIncrement (&thread_interruption_requested);
4392 if (!running_managed || is_running_protected_wrapper ()) {
4393 /* Can't stop while in unmanaged code. Increase the global interruption
4394 request count. When exiting the unmanaged method the count will be
4395 checked and the thread will be interrupted. */
4397 /* this will awake the thread if it is in WaitForSingleObject
4399 /* Our implementation of this function ignores the func argument */
4401 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
4403 mono_thread_info_self_interrupt ();
4408 return mono_thread_execute_interruption ();
4412 /*This function should be called by a thread after it has exited all of
4413 * its handle blocks at interruption time.*/
4415 mono_thread_resume_interruption (void)
4417 MonoInternalThread *thread = mono_thread_internal_current ();
4418 gboolean still_aborting;
4420 /* The thread may already be stopping */
4424 LOCK_THREAD (thread);
4425 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4426 UNLOCK_THREAD (thread);
4428 /*This can happen if the protected block called Thread::ResetAbort*/
4429 if (!still_aborting)
4432 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4434 InterlockedIncrement (&thread_interruption_requested);
4436 mono_thread_info_self_interrupt ();
4438 return mono_thread_execute_interruption ();
4441 gboolean mono_thread_interruption_requested ()
4443 if (thread_interruption_requested) {
4444 MonoInternalThread *thread = mono_thread_internal_current ();
4445 /* The thread may already be stopping */
4447 return (thread->interruption_requested);
4452 static MonoException*
4453 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4455 MonoInternalThread *thread = mono_thread_internal_current ();
4457 /* The thread may already be stopping */
4460 if (!thread->interruption_requested)
4462 if (!bypass_abort_protection && is_running_protected_wrapper ())
4465 return mono_thread_execute_interruption ();
4469 * Performs the interruption of the current thread, if one has been requested,
4470 * and the thread is not running a protected wrapper.
4471 * Return the exception which needs to be thrown, if any.
4474 mono_thread_interruption_checkpoint (void)
4476 return mono_thread_interruption_checkpoint_request (FALSE);
4480 * Performs the interruption of the current thread, if one has been requested.
4481 * Return the exception which needs to be thrown, if any.
4484 mono_thread_force_interruption_checkpoint_noraise (void)
4486 return mono_thread_interruption_checkpoint_request (TRUE);
4490 * mono_set_pending_exception:
4492 * Set the pending exception of the current thread to EXC.
4493 * The exception will be thrown when execution returns to managed code.
4496 mono_set_pending_exception (MonoException *exc)
4498 MonoThread *thread = mono_thread_current ();
4500 /* The thread may already be stopping */
4504 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4506 mono_thread_request_interruption (FALSE);
4510 * mono_thread_interruption_request_flag:
4512 * Returns the address of a flag that will be non-zero if an interruption has
4513 * been requested for a thread. The thread to interrupt may not be the current
4514 * thread, so an additional call to mono_thread_interruption_requested() or
4515 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4518 gint32* mono_thread_interruption_request_flag ()
4520 return &thread_interruption_requested;
4524 mono_thread_init_apartment_state (void)
4527 MonoInternalThread* thread = mono_thread_internal_current ();
4529 /* Positive return value indicates success, either
4530 * S_OK if this is first CoInitialize call, or
4531 * S_FALSE if CoInitialize already called, but with same
4532 * threading model. A negative value indicates failure,
4533 * probably due to trying to change the threading model.
4535 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4536 ? COINIT_APARTMENTTHREADED
4537 : COINIT_MULTITHREADED) < 0) {
4538 thread->apartment_state = ThreadApartmentState_Unknown;
4544 mono_thread_cleanup_apartment_state (void)
4547 MonoInternalThread* thread = mono_thread_internal_current ();
4549 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4556 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4558 LOCK_THREAD (thread);
4559 thread->state |= state;
4560 UNLOCK_THREAD (thread);
4564 * mono_thread_test_and_set_state:
4566 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4568 * Returns TRUE is @set was OR'd in.
4571 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4573 LOCK_THREAD (thread);
4575 if ((thread->state & test) != 0) {
4576 UNLOCK_THREAD (thread);
4580 thread->state |= set;
4581 UNLOCK_THREAD (thread);
4587 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4589 LOCK_THREAD (thread);
4590 thread->state &= ~state;
4591 UNLOCK_THREAD (thread);
4595 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4597 gboolean ret = FALSE;
4599 LOCK_THREAD (thread);
4601 if ((thread->state & test) != 0) {
4605 UNLOCK_THREAD (thread);
4611 self_interrupt_thread (void *_unused)
4614 MonoThreadInfo *info;
4616 exc = mono_thread_execute_interruption ();
4618 if (mono_threads_is_coop_enabled ()) {
4619 /* We can return from an async call in coop, as
4620 * it's simply called when exiting the safepoint */
4624 g_error ("%s: we can't resume from an async call", __func__);
4627 info = mono_thread_info_current ();
4629 /* We must use _with_context since we didn't trampoline into the runtime */
4630 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. */
4634 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4638 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4642 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4644 MonoJitInfo **dest = (MonoJitInfo **)data;
4650 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4652 MonoJitInfo *ji = NULL;
4657 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4658 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4659 * where we hold runtime locks.
4661 if (!mono_threads_is_coop_enabled ())
4662 mono_thread_info_set_is_async_context (TRUE);
4663 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4664 if (!mono_threads_is_coop_enabled ())
4665 mono_thread_info_set_is_async_context (FALSE);
4670 MonoInternalThread *thread;
4671 gboolean install_async_abort;
4672 MonoThreadInfoInterruptToken *interrupt_token;
4675 static SuspendThreadResult
4676 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4678 AbortThreadData *data = (AbortThreadData *)ud;
4679 MonoInternalThread *thread = data->thread;
4680 MonoJitInfo *ji = NULL;
4681 gboolean protected_wrapper;
4682 gboolean running_managed;
4684 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4685 return MonoResumeThread;
4688 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4689 The protected block code will give them a chance when appropriate.
4691 if (thread->abort_protected_block_count)
4692 return MonoResumeThread;
4694 /*someone is already interrupting it*/
4695 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4696 return MonoResumeThread;
4698 InterlockedIncrement (&thread_interruption_requested);
4700 ji = mono_thread_info_get_last_managed (info);
4701 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4702 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4704 if (!protected_wrapper && running_managed) {
4705 /*We are in managed code*/
4706 /*Set the thread to call */
4707 if (data->install_async_abort)
4708 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4709 return MonoResumeThread;
4712 * This will cause waits to be broken.
4713 * It will also prevent the thread from entering a wait, so if the thread returns
4714 * from the wait before it receives the abort signal, it will just spin in the wait
4715 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4718 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4720 return MonoResumeThread;
4725 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4727 AbortThreadData data;
4729 g_assert (thread != mono_thread_internal_current ());
4731 data.thread = thread;
4732 data.install_async_abort = install_async_abort;
4733 data.interrupt_token = NULL;
4735 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4736 if (data.interrupt_token)
4737 mono_thread_info_finish_interrupt (data.interrupt_token);
4738 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4742 self_abort_internal (MonoError *error)
4746 mono_error_init (error);
4748 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4749 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4752 Self aborts ignore the protected block logic and raise the TAE regardless. This is verified by one of the tests in mono/tests/abort-cctor.cs.
4754 exc = mono_thread_request_interruption (TRUE);
4756 mono_error_set_exception_instance (error, exc);
4758 mono_thread_info_self_interrupt ();
4762 MonoInternalThread *thread;
4764 MonoThreadInfoInterruptToken *interrupt_token;
4765 } SuspendThreadData;
4767 static SuspendThreadResult
4768 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4770 SuspendThreadData *data = (SuspendThreadData *)ud;
4771 MonoInternalThread *thread = data->thread;
4772 MonoJitInfo *ji = NULL;
4773 gboolean protected_wrapper;
4774 gboolean running_managed;
4776 ji = mono_thread_info_get_last_managed (info);
4777 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4778 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4780 if (running_managed && !protected_wrapper) {
4781 if (mono_threads_is_coop_enabled ()) {
4782 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4783 return MonoResumeThread;
4785 thread->state &= ~ThreadState_SuspendRequested;
4786 thread->state |= ThreadState_Suspended;
4787 return KeepSuspended;
4790 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4791 InterlockedIncrement (&thread_interruption_requested);
4792 if (data->interrupt)
4793 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4795 return MonoResumeThread;
4799 /* LOCKING: called with @thread synch_cs held, and releases it */
4801 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4803 SuspendThreadData data;
4805 g_assert (thread != mono_thread_internal_current ());
4807 // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4809 thread->self_suspended = FALSE;
4811 data.thread = thread;
4812 data.interrupt = interrupt;
4813 data.interrupt_token = NULL;
4815 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4816 if (data.interrupt_token)
4817 mono_thread_info_finish_interrupt (data.interrupt_token);
4819 UNLOCK_THREAD (thread);
4822 /* LOCKING: called with @thread synch_cs held, and releases it */
4824 self_suspend_internal (void)
4826 MonoInternalThread *thread;
4828 MonoOSEventWaitRet res;
4830 thread = mono_thread_internal_current ();
4832 // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4834 thread->self_suspended = TRUE;
4836 thread->state &= ~ThreadState_SuspendRequested;
4837 thread->state |= ThreadState_Suspended;
4839 UNLOCK_THREAD (thread);
4841 event = thread->suspended;
4844 res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT);
4845 g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
4850 * mono_thread_is_foreign:
4851 * @thread: the thread to query
4853 * This function allows one to determine if a thread was created by the mono runtime and has
4854 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4856 * Returns: TRUE if @thread was not created by the runtime.
4859 mono_thread_is_foreign (MonoThread *thread)
4861 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4862 return info->runtime_thread == FALSE;
4866 * mono_add_joinable_thread:
4868 * Add TID to the list of joinable threads.
4869 * LOCKING: Acquires the threads lock.
4872 mono_threads_add_joinable_thread (gpointer tid)
4876 * We cannot detach from threads because it causes problems like
4877 * 2fd16f60/r114307. So we collect them and join them when
4878 * we have time (in he finalizer thread).
4880 joinable_threads_lock ();
4881 if (!joinable_threads)
4882 joinable_threads = g_hash_table_new (NULL, NULL);
4883 g_hash_table_insert (joinable_threads, tid, tid);
4884 joinable_thread_count ++;
4885 joinable_threads_unlock ();
4887 mono_gc_finalize_notify ();
4892 * mono_threads_join_threads:
4894 * Join all joinable threads. This is called from the finalizer thread.
4895 * LOCKING: Acquires the threads lock.
4898 mono_threads_join_threads (void)
4901 GHashTableIter iter;
4908 if (!joinable_thread_count)
4912 joinable_threads_lock ();
4914 if (g_hash_table_size (joinable_threads)) {
4915 g_hash_table_iter_init (&iter, joinable_threads);
4916 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4917 thread = (pthread_t)tid;
4918 g_hash_table_remove (joinable_threads, key);
4919 joinable_thread_count --;
4922 joinable_threads_unlock ();
4924 if (thread != pthread_self ()) {
4926 /* This shouldn't block */
4927 mono_native_thread_join (thread);
4940 * Wait for thread TID to exit.
4941 * LOCKING: Acquires the threads lock.
4944 mono_thread_join (gpointer tid)
4948 gboolean found = FALSE;
4950 joinable_threads_lock ();
4951 if (!joinable_threads)
4952 joinable_threads = g_hash_table_new (NULL, NULL);
4953 if (g_hash_table_lookup (joinable_threads, tid)) {
4954 g_hash_table_remove (joinable_threads, tid);
4955 joinable_thread_count --;
4958 joinable_threads_unlock ();
4961 thread = (pthread_t)tid;
4963 mono_native_thread_join (thread);
4969 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4971 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4972 mono_thread_interruption_checkpoint ();
4976 mono_thread_internal_unhandled_exception (MonoObject* exc)
4978 MonoClass *klass = exc->vtable->klass;
4979 if (is_threadabort_exception (klass)) {
4980 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4981 } else if (!is_appdomainunloaded_exception (klass)
4982 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4983 mono_unhandled_exception (exc);
4984 if (mono_environment_exitcode_get () == 1) {
4985 mono_environment_exitcode_set (255);
4986 mono_invoke_unhandled_exception_hook (exc);
4987 g_assert_not_reached ();
4993 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
4996 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
4997 mono_error_set_pending_exception (&error);
5001 * mono_threads_attach_coop: called by native->managed wrappers
5005 * - @return: the original domain which needs to be restored, or NULL.
5008 * - @dummy: contains the original domain
5009 * - @return: a cookie containing current MonoThreadInfo*.
5012 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5015 gboolean fresh_thread = FALSE;
5018 /* Happens when called from AOTed code which is only used in the root domain. */
5019 domain = mono_get_root_domain ();
5024 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5025 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5026 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5027 * we're only responsible for making the cookie. */
5028 if (mono_threads_is_coop_enabled ()) {
5029 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5030 fresh_thread = !info || !mono_thread_info_is_live (info);
5033 if (!mono_thread_internal_current ()) {
5034 mono_thread_attach_full (domain, FALSE);
5037 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5040 orig = mono_domain_get ();
5042 mono_domain_set (domain, TRUE);
5044 if (!mono_threads_is_coop_enabled ())
5045 return orig != domain ? orig : NULL;
5049 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5050 * return the right cookie. */
5051 return mono_threads_enter_gc_unsafe_region_cookie ();
5054 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5055 return mono_threads_enter_gc_unsafe_region (dummy);
5060 * mono_threads_detach_coop: called by native->managed wrappers
5063 * - @cookie: the original domain which needs to be restored, or NULL.
5067 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5068 * - @dummy: contains the original domain
5071 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5073 MonoDomain *domain, *orig;
5075 if (!mono_threads_is_coop_enabled ()) {
5076 orig = (MonoDomain*) cookie;
5078 mono_domain_set (orig, TRUE);
5080 orig = (MonoDomain*) *dummy;
5082 domain = mono_domain_get ();
5085 /* it won't do anything if cookie is NULL
5086 * thread state RUNNING -> (RUNNING|BLOCKING) */
5087 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5089 if (orig != domain) {
5091 mono_domain_unset ();
5093 mono_domain_set (orig, TRUE);
5099 mono_threads_begin_abort_protected_block (void)
5101 MonoInternalThread *thread;
5103 thread = mono_thread_internal_current ();
5104 ++thread->abort_protected_block_count;
5105 mono_memory_barrier ();
5109 mono_threads_end_abort_protected_block (void)
5111 MonoInternalThread *thread;
5113 thread = mono_thread_internal_current ();
5115 mono_memory_barrier ();
5116 --thread->abort_protected_block_count;
5120 mono_thread_try_resume_interruption (void)
5122 MonoInternalThread *thread;
5124 thread = mono_thread_internal_current ();
5125 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5128 return mono_thread_resume_interruption ();
5132 /* Returns TRUE if the current thread is ready to be interrupted. */
5134 mono_threads_is_ready_to_be_interrupted (void)
5136 MonoInternalThread *thread;
5138 thread = mono_thread_internal_current ();
5139 LOCK_THREAD (thread);
5140 if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5141 UNLOCK_THREAD (thread);
5145 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5146 UNLOCK_THREAD (thread);
5150 UNLOCK_THREAD (thread);
5156 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5158 g_string_append_printf (text, ", thread handle : %p", internal->handle);
5160 if (internal->thread_info) {
5161 g_string_append (text, ", state : ");
5162 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5165 if (internal->owned_mutexes) {
5168 g_string_append (text, ", owns : [");
5169 for (i = 0; i < internal->owned_mutexes->len; i++)
5170 g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5171 g_string_append (text, "]");
5176 mono_thread_internal_is_current (MonoInternalThread *internal)
5178 g_assert (internal);
5179 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));