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 if (mono_gc_is_moving ()) {
1090 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
1091 thread->thread_pinning_ref = NULL;
1095 SET_CURRENT_OBJECT (NULL);
1096 mono_domain_unset ();
1098 /* Don't need to close the handle to this thread, even though we took a
1099 * reference in mono_thread_attach (), because the GC will do it
1100 * when the Thread object is finalised.
1105 mono_thread_detach (MonoThread *thread)
1108 mono_thread_detach_internal (thread->internal_thread);
1112 * mono_thread_detach_if_exiting:
1114 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1115 * This should be used at the end of embedding code which calls into managed code, and which
1116 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1119 mono_thread_detach_if_exiting (void)
1121 if (mono_thread_info_is_exiting ()) {
1122 MonoInternalThread *thread;
1124 thread = mono_thread_internal_current ();
1126 mono_thread_detach_internal (thread);
1127 mono_thread_info_detach ();
1135 mono_thread_internal_current_is_attached (void)
1137 MonoInternalThread *internal;
1139 internal = GET_CURRENT_OBJECT ();
1147 mono_thread_exit (void)
1149 MonoInternalThread *thread = mono_thread_internal_current ();
1151 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1153 mono_thread_detach_internal (thread);
1155 /* we could add a callback here for embedders to use. */
1156 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1157 exit (mono_environment_exitcode_get ());
1159 mono_thread_info_exit (0);
1163 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1165 MonoInternalThread *internal;
1167 internal = create_internal_thread_object ();
1169 internal->state = ThreadState_Unstarted;
1171 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1175 ves_icall_System_Threading_Thread_GetCurrentThread (void)
1177 return mono_thread_current ();
1181 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1185 MonoInternalThread *internal;
1188 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1190 if (!this_obj->internal_thread)
1191 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1192 internal = this_obj->internal_thread;
1194 LOCK_THREAD (internal);
1196 if ((internal->state & ThreadState_Unstarted) == 0) {
1197 UNLOCK_THREAD (internal);
1198 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1202 if ((internal->state & ThreadState_Aborted) != 0) {
1203 UNLOCK_THREAD (internal);
1207 res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1209 mono_error_cleanup (&error);
1210 UNLOCK_THREAD (internal);
1214 internal->state &= ~ThreadState_Unstarted;
1216 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1218 UNLOCK_THREAD (internal);
1219 return internal->handle;
1223 * This is called from the finalizer of the internal thread object.
1226 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj)
1228 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle));
1231 * Since threads keep a reference to their thread object while running, by
1232 * the time this function is called, the thread has already exited/detached,
1233 * i.e. mono_thread_detach_internal () has ran. The exception is during
1234 * shutdown, when mono_thread_detach_internal () can be called after this.
1236 if (this_obj->handle) {
1237 mono_threads_close_thread_handle (this_obj->handle);
1238 this_obj->handle = NULL;
1242 CloseHandle (this_obj->native_handle);
1245 if (this_obj->synch_cs) {
1246 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1247 this_obj->synch_cs = NULL;
1248 mono_coop_mutex_destroy (synch_cs);
1252 if (this_obj->name) {
1253 void *name = this_obj->name;
1254 this_obj->name = NULL;
1260 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1263 MonoInternalThread *thread = mono_thread_internal_current ();
1265 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1267 if (mono_thread_current_check_pending_interrupt ())
1271 gboolean alerted = FALSE;
1273 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1275 res = mono_thread_info_sleep (ms, &alerted);
1277 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1280 MonoException* exc = mono_thread_execute_interruption ();
1282 mono_raise_exception (exc);
1284 // FIXME: !MONO_INFINITE_WAIT
1285 if (ms != MONO_INFINITE_WAIT)
1294 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1299 ves_icall_System_Threading_Thread_GetDomainID (void)
1301 return mono_domain_get()->domain_id;
1305 ves_icall_System_Threading_Thread_Yield (void)
1307 return mono_thread_info_yield ();
1311 * mono_thread_get_name:
1313 * Return the name of the thread. NAME_LEN is set to the length of the name.
1314 * Return NULL if the thread has no name. The returned memory is owned by the
1318 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1322 LOCK_THREAD (this_obj);
1324 if (!this_obj->name) {
1328 *name_len = this_obj->name_len;
1329 res = g_new (gunichar2, this_obj->name_len);
1330 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1333 UNLOCK_THREAD (this_obj);
1339 * mono_thread_get_name_utf8:
1341 * Return the name of the thread in UTF-8.
1342 * Return NULL if the thread has no name.
1343 * The returned memory is owned by the caller.
1346 mono_thread_get_name_utf8 (MonoThread *thread)
1351 MonoInternalThread *internal = thread->internal_thread;
1352 if (internal == NULL)
1355 LOCK_THREAD (internal);
1357 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1359 UNLOCK_THREAD (internal);
1365 * mono_thread_get_managed_id:
1367 * Return the Thread.ManagedThreadId value of `thread`.
1368 * Returns -1 if `thread` is NULL.
1371 mono_thread_get_managed_id (MonoThread *thread)
1376 MonoInternalThread *internal = thread->internal_thread;
1377 if (internal == NULL)
1380 int32_t id = internal->managed_id;
1386 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1391 mono_error_init (&error);
1393 LOCK_THREAD (this_obj);
1395 if (!this_obj->name)
1398 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1400 UNLOCK_THREAD (this_obj);
1402 if (mono_error_set_pending_exception (&error))
1409 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1411 LOCK_THREAD (this_obj);
1413 mono_error_init (error);
1415 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1416 UNLOCK_THREAD (this_obj);
1418 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1421 if (this_obj->name) {
1422 g_free (this_obj->name);
1423 this_obj->name_len = 0;
1426 this_obj->name = g_new (gunichar2, mono_string_length (name));
1427 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1428 this_obj->name_len = mono_string_length (name);
1431 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1434 this_obj->name = NULL;
1437 UNLOCK_THREAD (this_obj);
1439 if (this_obj->name && this_obj->tid) {
1440 char *tname = mono_string_to_utf8_checked (name, error);
1441 return_if_nok (error);
1442 mono_profiler_thread_name (this_obj->tid, tname);
1443 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1449 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1452 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1453 mono_error_set_pending_exception (&error);
1457 * ves_icall_System_Threading_Thread_GetPriority_internal:
1458 * @param this_obj: The MonoInternalThread on which to operate.
1460 * Gets the priority of the given thread.
1461 * @return: The priority of the given thread.
1464 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1467 MonoInternalThread *internal = this_obj->internal_thread;
1469 LOCK_THREAD (internal);
1470 priority = internal->priority;
1471 UNLOCK_THREAD (internal);
1477 * ves_icall_System_Threading_Thread_SetPriority_internal:
1478 * @param this_obj: The MonoInternalThread on which to operate.
1479 * @param priority: The priority to set.
1481 * Sets the priority of the given thread.
1484 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1486 MonoInternalThread *internal = this_obj->internal_thread;
1488 LOCK_THREAD (internal);
1489 internal->priority = priority;
1490 if (internal->thread_info != NULL)
1491 mono_thread_internal_set_priority (internal, priority);
1492 UNLOCK_THREAD (internal);
1495 /* If the array is already in the requested domain, we just return it,
1496 otherwise we return a copy in that domain. */
1498 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1502 mono_error_init (error);
1506 if (mono_object_domain (arr) == domain)
1509 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1510 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1515 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1518 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1519 mono_error_set_pending_exception (&error);
1524 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1527 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1528 mono_error_set_pending_exception (&error);
1533 mono_thread_current (void)
1535 MonoDomain *domain = mono_domain_get ();
1536 MonoInternalThread *internal = mono_thread_internal_current ();
1537 MonoThread **current_thread_ptr;
1539 g_assert (internal);
1540 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1542 if (!*current_thread_ptr) {
1543 g_assert (domain != mono_get_root_domain ());
1544 *current_thread_ptr = create_thread_object (domain, internal);
1546 return *current_thread_ptr;
1549 /* Return the thread object belonging to INTERNAL in the current domain */
1551 mono_thread_current_for_thread (MonoInternalThread *internal)
1553 MonoDomain *domain = mono_domain_get ();
1554 MonoThread **current_thread_ptr;
1556 g_assert (internal);
1557 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1559 if (!*current_thread_ptr) {
1560 g_assert (domain != mono_get_root_domain ());
1561 *current_thread_ptr = create_thread_object (domain, internal);
1563 return *current_thread_ptr;
1567 mono_thread_internal_current (void)
1569 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1570 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1574 static MonoThreadInfoWaitRet
1575 mono_join_uninterrupted (MonoThreadHandle* thread_to_join, gint32 ms, MonoError *error)
1578 MonoThreadInfoWaitRet ret;
1583 mono_error_init (error);
1585 start = (ms == -1) ? 0 : mono_msec_ticks ();
1588 ret = mono_thread_info_wait_one_handle (thread_to_join, ms, TRUE);
1591 if (ret != MONO_THREAD_INFO_WAIT_RET_ALERTED)
1594 exc = mono_thread_execute_interruption ();
1596 mono_error_set_exception_instance (error, exc);
1603 /* Re-calculate ms according to the time passed */
1604 diff_ms = (gint32)(mono_msec_ticks () - start);
1605 if (diff_ms >= ms) {
1606 ret = MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1609 wait = ms - diff_ms;
1616 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1618 MonoInternalThread *thread = this_obj->internal_thread;
1619 MonoThreadHandle *handle = thread->handle;
1620 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1624 if (mono_thread_current_check_pending_interrupt ())
1627 LOCK_THREAD (thread);
1629 if ((thread->state & ThreadState_Unstarted) != 0) {
1630 UNLOCK_THREAD (thread);
1632 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1636 UNLOCK_THREAD (thread);
1639 ms=MONO_INFINITE_WAIT;
1641 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1643 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1645 ret=mono_join_uninterrupted (handle, ms, &error);
1647 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1649 mono_error_set_pending_exception (&error);
1651 if(ret==MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
1652 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1657 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1662 #define MANAGED_WAIT_FAILED 0x7fffffff
1665 map_native_wait_result_to_managed (MonoW32HandleWaitRet val, gsize numobjects)
1667 if (val >= MONO_W32HANDLE_WAIT_RET_SUCCESS_0 && val < MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + numobjects) {
1668 return WAIT_OBJECT_0 + (val - MONO_W32HANDLE_WAIT_RET_SUCCESS_0);
1669 } else if (val >= MONO_W32HANDLE_WAIT_RET_ABANDONED_0 && val < MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + numobjects) {
1670 return WAIT_ABANDONED_0 + (val - MONO_W32HANDLE_WAIT_RET_ABANDONED_0);
1671 } else if (val == MONO_W32HANDLE_WAIT_RET_ALERTED) {
1672 return WAIT_IO_COMPLETION;
1673 } else if (val == MONO_W32HANDLE_WAIT_RET_TIMEOUT) {
1674 return WAIT_TIMEOUT;
1675 } else if (val == MONO_W32HANDLE_WAIT_RET_FAILED) {
1676 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1677 return MANAGED_WAIT_FAILED;
1679 g_error ("%s: unknown val value %d", __func__, val);
1683 static MonoW32HandleWaitRet
1684 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1687 MonoW32HandleWaitRet ret;
1692 mono_error_init (error);
1694 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1698 if (numhandles != 1)
1699 ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE), numhandles);
1701 ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], ms, TRUE), 1);
1703 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
1704 ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, wait, TRUE);
1705 #endif /* HOST_WIN32 */
1708 if (ret != MONO_W32HANDLE_WAIT_RET_ALERTED)
1711 exc = mono_thread_execute_interruption ();
1713 mono_error_set_exception_instance (error, exc);
1720 /* Re-calculate ms according to the time passed */
1721 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1722 if (diff_ms >= ms) {
1723 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1726 wait = ms - diff_ms;
1732 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1737 MonoW32HandleWaitRet ret;
1739 MonoObject *waitHandle;
1740 MonoInternalThread *thread = mono_thread_internal_current ();
1742 /* Do this WaitSleepJoin check before creating objects */
1743 if (mono_thread_current_check_pending_interrupt ())
1744 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1746 /* We fail in managed if the array has more than 64 elements */
1747 numhandles = (guint32)mono_array_length(mono_handles);
1748 handles = g_new0(HANDLE, numhandles);
1750 for(i = 0; i < numhandles; i++) {
1751 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1752 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1756 ms=MONO_INFINITE_WAIT;
1759 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1761 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1763 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1767 mono_error_set_pending_exception (&error);
1769 return map_native_wait_result_to_managed (ret, numhandles);
1772 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1775 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1776 uintptr_t numhandles;
1777 MonoW32HandleWaitRet ret;
1779 MonoObject *waitHandle;
1780 MonoInternalThread *thread = mono_thread_internal_current ();
1782 /* Do this WaitSleepJoin check before creating objects */
1783 if (mono_thread_current_check_pending_interrupt ())
1784 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1786 numhandles = mono_array_length(mono_handles);
1787 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1788 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1790 for(i = 0; i < numhandles; i++) {
1791 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1792 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1796 ms=MONO_INFINITE_WAIT;
1799 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1801 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1803 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1805 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1807 mono_error_set_pending_exception (&error);
1809 return map_native_wait_result_to_managed (ret, numhandles);
1812 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1815 MonoW32HandleWaitRet ret;
1816 MonoInternalThread *thread = mono_thread_internal_current ();
1818 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1821 ms=MONO_INFINITE_WAIT;
1824 if (mono_thread_current_check_pending_interrupt ())
1825 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1827 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1829 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1831 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1833 mono_error_set_pending_exception (&error);
1834 return map_native_wait_result_to_managed (ret, 1);
1838 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1840 MonoW32HandleWaitRet ret;
1841 MonoInternalThread *thread = mono_thread_internal_current ();
1844 ms = MONO_INFINITE_WAIT;
1846 if (mono_thread_current_check_pending_interrupt ())
1847 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1849 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1853 ret = mono_w32handle_convert_wait_ret (SignalObjectAndWait (toSignal, toWait, ms, TRUE), 1);
1855 ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE);
1859 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1861 return map_native_wait_result_to_managed (ret, 1);
1864 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1866 return InterlockedIncrement (location);
1869 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1871 #if SIZEOF_VOID_P == 4
1872 if (G_UNLIKELY ((size_t)location & 0x7)) {
1874 mono_interlocked_lock ();
1877 mono_interlocked_unlock ();
1881 return InterlockedIncrement64 (location);
1884 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1886 return InterlockedDecrement(location);
1889 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1891 #if SIZEOF_VOID_P == 4
1892 if (G_UNLIKELY ((size_t)location & 0x7)) {
1894 mono_interlocked_lock ();
1897 mono_interlocked_unlock ();
1901 return InterlockedDecrement64 (location);
1904 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1906 return InterlockedExchange(location, value);
1909 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1912 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1913 mono_gc_wbarrier_generic_nostore (location);
1917 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1919 return InterlockedExchangePointer(location, value);
1922 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1924 IntFloatUnion val, ret;
1927 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1933 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1935 #if SIZEOF_VOID_P == 4
1936 if (G_UNLIKELY ((size_t)location & 0x7)) {
1938 mono_interlocked_lock ();
1941 mono_interlocked_unlock ();
1945 return InterlockedExchange64 (location, value);
1949 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1951 LongDoubleUnion val, ret;
1954 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1959 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1961 return InterlockedCompareExchange(location, value, comparand);
1964 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1966 gint32 r = InterlockedCompareExchange(location, value, comparand);
1967 *success = r == comparand;
1971 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1974 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1975 mono_gc_wbarrier_generic_nostore (location);
1979 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1981 return InterlockedCompareExchangePointer(location, value, comparand);
1984 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1986 IntFloatUnion val, ret, cmp;
1989 cmp.fval = comparand;
1990 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1996 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1998 #if SIZEOF_VOID_P == 8
1999 LongDoubleUnion val, comp, ret;
2002 comp.fval = comparand;
2003 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2009 mono_interlocked_lock ();
2011 if (old == comparand)
2013 mono_interlocked_unlock ();
2020 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2022 #if SIZEOF_VOID_P == 4
2023 if (G_UNLIKELY ((size_t)location & 0x7)) {
2025 mono_interlocked_lock ();
2027 if (old == comparand)
2029 mono_interlocked_unlock ();
2033 return InterlockedCompareExchange64 (location, value, comparand);
2037 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2040 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2041 mono_gc_wbarrier_generic_nostore (location);
2046 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2049 MONO_CHECK_NULL (location, NULL);
2050 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2051 mono_gc_wbarrier_generic_nostore (location);
2056 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2058 return InterlockedAdd (location, value);
2062 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2064 #if SIZEOF_VOID_P == 4
2065 if (G_UNLIKELY ((size_t)location & 0x7)) {
2067 mono_interlocked_lock ();
2070 mono_interlocked_unlock ();
2074 return InterlockedAdd64 (location, value);
2078 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2080 #if SIZEOF_VOID_P == 4
2081 if (G_UNLIKELY ((size_t)location & 0x7)) {
2083 mono_interlocked_lock ();
2085 mono_interlocked_unlock ();
2089 return InterlockedRead64 (location);
2093 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2095 mono_memory_barrier ();
2099 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2101 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2103 if (state & ThreadState_Background) {
2104 /* If the thread changes the background mode, the main thread has to
2105 * be notified, since it has to rebuild the list of threads to
2108 mono_os_event_set (&background_change_event);
2113 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2115 mono_thread_set_state (this_obj, (MonoThreadState)state);
2117 if (state & ThreadState_Background) {
2118 /* If the thread changes the background mode, the main thread has to
2119 * be notified, since it has to rebuild the list of threads to
2122 mono_os_event_set (&background_change_event);
2127 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2131 LOCK_THREAD (this_obj);
2133 state = this_obj->state;
2135 UNLOCK_THREAD (this_obj);
2140 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2142 MonoInternalThread *current;
2144 MonoInternalThread *thread = this_obj->internal_thread;
2146 LOCK_THREAD (thread);
2148 current = mono_thread_internal_current ();
2150 thread->thread_interrupt_requested = TRUE;
2151 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2153 UNLOCK_THREAD (thread);
2156 async_abort_internal (thread, FALSE);
2161 * mono_thread_current_check_pending_interrupt:
2163 * Checks if there's a interruption request and set the pending exception if so.
2165 * @returns true if a pending exception was set
2168 mono_thread_current_check_pending_interrupt (void)
2170 MonoInternalThread *thread = mono_thread_internal_current ();
2171 gboolean throw_ = FALSE;
2173 LOCK_THREAD (thread);
2175 if (thread->thread_interrupt_requested) {
2177 thread->thread_interrupt_requested = FALSE;
2180 UNLOCK_THREAD (thread);
2183 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2188 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2190 LOCK_THREAD (thread);
2192 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2193 (thread->state & ThreadState_StopRequested) != 0 ||
2194 (thread->state & ThreadState_Stopped) != 0)
2196 UNLOCK_THREAD (thread);
2200 if ((thread->state & ThreadState_Unstarted) != 0) {
2201 thread->state |= ThreadState_Aborted;
2202 UNLOCK_THREAD (thread);
2206 thread->state |= ThreadState_AbortRequested;
2207 if (thread->abort_state_handle)
2208 mono_gchandle_free (thread->abort_state_handle);
2210 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2211 g_assert (thread->abort_state_handle);
2213 thread->abort_state_handle = 0;
2215 thread->abort_exc = NULL;
2217 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));
2219 /* During shutdown, we can't wait for other threads */
2221 /* Make sure the thread is awake */
2222 mono_thread_resume (thread);
2224 UNLOCK_THREAD (thread);
2229 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2231 if (!request_thread_abort (thread, state))
2234 if (thread == mono_thread_internal_current ()) {
2236 self_abort_internal (&error);
2237 mono_error_set_pending_exception (&error);
2239 async_abort_internal (thread, TRUE);
2244 * mono_thread_internal_abort:
2246 * Request thread @thread to be aborted.
2248 * @thread MUST NOT be the current thread.
2251 mono_thread_internal_abort (MonoInternalThread *thread)
2253 g_assert (thread != mono_thread_internal_current ());
2255 if (!request_thread_abort (thread, NULL))
2257 async_abort_internal (thread, TRUE);
2261 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2263 MonoInternalThread *thread = mono_thread_internal_current ();
2264 gboolean was_aborting;
2266 LOCK_THREAD (thread);
2267 was_aborting = thread->state & ThreadState_AbortRequested;
2268 thread->state &= ~ThreadState_AbortRequested;
2269 UNLOCK_THREAD (thread);
2271 if (!was_aborting) {
2272 const char *msg = "Unable to reset abort because no abort was requested";
2273 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2277 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2278 thread->abort_exc = NULL;
2279 if (thread->abort_state_handle) {
2280 mono_gchandle_free (thread->abort_state_handle);
2281 /* This is actually not necessary - the handle
2282 only counts if the exception is set */
2283 thread->abort_state_handle = 0;
2288 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2290 LOCK_THREAD (thread);
2292 thread->state &= ~ThreadState_AbortRequested;
2294 if (thread->abort_exc) {
2295 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2296 thread->abort_exc = NULL;
2297 if (thread->abort_state_handle) {
2298 mono_gchandle_free (thread->abort_state_handle);
2299 /* This is actually not necessary - the handle
2300 only counts if the exception is set */
2301 thread->abort_state_handle = 0;
2305 UNLOCK_THREAD (thread);
2309 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2312 MonoInternalThread *thread = this_obj->internal_thread;
2313 MonoObject *state, *deserialized = NULL;
2316 if (!thread->abort_state_handle)
2319 state = mono_gchandle_get_target (thread->abort_state_handle);
2322 domain = mono_domain_get ();
2323 if (mono_object_domain (state) == domain)
2326 deserialized = mono_object_xdomain_representation (state, domain, &error);
2328 if (!deserialized) {
2329 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2330 if (!is_ok (&error)) {
2331 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2332 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2334 mono_set_pending_exception (invalid_op_exc);
2338 return deserialized;
2342 mono_thread_suspend (MonoInternalThread *thread)
2344 LOCK_THREAD (thread);
2346 if ((thread->state & ThreadState_Unstarted) != 0 ||
2347 (thread->state & ThreadState_Aborted) != 0 ||
2348 (thread->state & ThreadState_Stopped) != 0)
2350 UNLOCK_THREAD (thread);
2354 if ((thread->state & ThreadState_Suspended) != 0 ||
2355 (thread->state & ThreadState_SuspendRequested) != 0 ||
2356 (thread->state & ThreadState_StopRequested) != 0)
2358 UNLOCK_THREAD (thread);
2362 thread->state |= ThreadState_SuspendRequested;
2363 mono_os_event_reset (thread->suspended);
2365 if (thread == mono_thread_internal_current ()) {
2366 /* calls UNLOCK_THREAD (thread) */
2367 self_suspend_internal ();
2369 /* calls UNLOCK_THREAD (thread) */
2370 async_suspend_internal (thread, FALSE);
2377 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2379 if (!mono_thread_suspend (this_obj->internal_thread)) {
2380 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2385 /* LOCKING: LOCK_THREAD(thread) must be held */
2387 mono_thread_resume (MonoInternalThread *thread)
2389 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2390 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread));
2391 thread->state &= ~ThreadState_SuspendRequested;
2392 mono_os_event_set (thread->suspended);
2396 if ((thread->state & ThreadState_Suspended) == 0 ||
2397 (thread->state & ThreadState_Unstarted) != 0 ||
2398 (thread->state & ThreadState_Aborted) != 0 ||
2399 (thread->state & ThreadState_Stopped) != 0)
2401 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread));
2405 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread));
2407 mono_os_event_set (thread->suspended);
2409 if (!thread->self_suspended) {
2410 UNLOCK_THREAD (thread);
2412 /* Awake the thread */
2413 if (!mono_thread_info_resume (thread_get_tid (thread)))
2416 LOCK_THREAD (thread);
2419 thread->state &= ~ThreadState_Suspended;
2425 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2427 if (!thread->internal_thread) {
2428 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2430 LOCK_THREAD (thread->internal_thread);
2431 if (!mono_thread_resume (thread->internal_thread))
2432 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2433 UNLOCK_THREAD (thread->internal_thread);
2438 mono_threads_is_critical_method (MonoMethod *method)
2440 switch (method->wrapper_type) {
2441 case MONO_WRAPPER_RUNTIME_INVOKE:
2442 case MONO_WRAPPER_XDOMAIN_INVOKE:
2443 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2450 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2455 if (mono_threads_is_critical_method (m)) {
2456 *((gboolean*)data) = TRUE;
2463 is_running_protected_wrapper (void)
2465 gboolean found = FALSE;
2466 mono_stack_walk (find_wrapper, &found);
2471 request_thread_stop (MonoInternalThread *thread)
2473 LOCK_THREAD (thread);
2475 if ((thread->state & ThreadState_StopRequested) != 0 ||
2476 (thread->state & ThreadState_Stopped) != 0)
2478 UNLOCK_THREAD (thread);
2482 /* Make sure the thread is awake */
2483 mono_thread_resume (thread);
2485 thread->state |= ThreadState_StopRequested;
2486 thread->state &= ~ThreadState_AbortRequested;
2488 UNLOCK_THREAD (thread);
2493 * mono_thread_internal_stop:
2495 * Request thread @thread to stop.
2497 * @thread MUST NOT be the current thread.
2500 mono_thread_internal_stop (MonoInternalThread *thread)
2502 g_assert (thread != mono_thread_internal_current ());
2504 if (!request_thread_stop (thread))
2507 async_abort_internal (thread, TRUE);
2510 void mono_thread_stop (MonoThread *thread)
2512 MonoInternalThread *internal = thread->internal_thread;
2514 if (!request_thread_stop (internal))
2517 if (internal == mono_thread_internal_current ()) {
2519 self_abort_internal (&error);
2521 This function is part of the embeding API and has no way to return the exception
2522 to be thrown. So what we do is keep the old behavior and raise the exception.
2524 mono_error_raise_exception (&error); /* OK to throw, see note */
2526 async_abort_internal (internal, TRUE);
2531 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2533 gint8 tmp = *(volatile gint8 *)ptr;
2534 mono_memory_barrier ();
2539 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2541 gint16 tmp = *(volatile gint16 *)ptr;
2542 mono_memory_barrier ();
2547 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2549 gint32 tmp = *(volatile gint32 *)ptr;
2550 mono_memory_barrier ();
2555 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2557 gint64 tmp = *(volatile gint64 *)ptr;
2558 mono_memory_barrier ();
2563 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2565 volatile void *tmp = *(volatile void **)ptr;
2566 mono_memory_barrier ();
2567 return (void *) tmp;
2571 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2573 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2574 mono_memory_barrier ();
2575 return (MonoObject *) tmp;
2579 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2581 double tmp = *(volatile double *)ptr;
2582 mono_memory_barrier ();
2587 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2589 float tmp = *(volatile float *)ptr;
2590 mono_memory_barrier ();
2595 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2597 return InterlockedRead8 ((volatile gint8 *)ptr);
2601 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2603 return InterlockedRead16 ((volatile gint16 *)ptr);
2607 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2609 return InterlockedRead ((volatile gint32 *)ptr);
2613 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2615 #if SIZEOF_VOID_P == 4
2616 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2618 mono_interlocked_lock ();
2619 val = *(gint64*)ptr;
2620 mono_interlocked_unlock ();
2624 return InterlockedRead64 ((volatile gint64 *)ptr);
2628 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2630 return InterlockedReadPointer ((volatile gpointer *)ptr);
2634 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2638 #if SIZEOF_VOID_P == 4
2639 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2641 mono_interlocked_lock ();
2642 val = *(double*)ptr;
2643 mono_interlocked_unlock ();
2648 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2654 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2658 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2664 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2666 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2670 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2672 mono_memory_barrier ();
2673 *(volatile gint8 *)ptr = value;
2677 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2679 mono_memory_barrier ();
2680 *(volatile gint16 *)ptr = value;
2684 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2686 mono_memory_barrier ();
2687 *(volatile gint32 *)ptr = value;
2691 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2693 mono_memory_barrier ();
2694 *(volatile gint64 *)ptr = value;
2698 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2700 mono_memory_barrier ();
2701 *(volatile void **)ptr = value;
2705 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2707 mono_memory_barrier ();
2708 mono_gc_wbarrier_generic_store (ptr, value);
2712 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2714 mono_memory_barrier ();
2715 *(volatile double *)ptr = value;
2719 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2721 mono_memory_barrier ();
2722 *(volatile float *)ptr = value;
2726 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2728 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2732 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2734 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2738 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2740 InterlockedWrite ((volatile gint32 *)ptr, value);
2744 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2746 #if SIZEOF_VOID_P == 4
2747 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2748 mono_interlocked_lock ();
2749 *(gint64*)ptr = value;
2750 mono_interlocked_unlock ();
2755 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2759 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2761 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2765 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2769 #if SIZEOF_VOID_P == 4
2770 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2771 mono_interlocked_lock ();
2772 *(double*)ptr = value;
2773 mono_interlocked_unlock ();
2780 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2784 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2790 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2794 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2796 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2800 free_context (void *user_data)
2802 ContextStaticData *data = user_data;
2804 mono_threads_lock ();
2807 * There is no guarantee that, by the point this reference queue callback
2808 * has been invoked, the GC handle associated with the object will fail to
2809 * resolve as one might expect. So if we don't free and remove the GC
2810 * handle here, free_context_static_data_helper () could end up resolving
2811 * a GC handle to an actually-dead context which would contain a pointer
2812 * to an already-freed static data segment, resulting in a crash when
2815 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2817 mono_threads_unlock ();
2819 mono_gchandle_free (data->gc_handle);
2820 mono_free_static_data (data->static_data);
2825 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2827 mono_threads_lock ();
2829 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2832 contexts = g_hash_table_new (NULL, NULL);
2835 context_queue = mono_gc_reference_queue_new (free_context);
2837 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2838 g_hash_table_insert (contexts, gch, gch);
2841 * We use this intermediate structure to contain a duplicate pointer to
2842 * the static data because we can't rely on being able to resolve the GC
2843 * handle in the reference queue callback.
2845 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2846 data->gc_handle = GPOINTER_TO_UINT (gch);
2849 context_adjust_static_data (ctx);
2850 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2852 mono_threads_unlock ();
2854 mono_profiler_context_loaded (ctx);
2858 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2861 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2862 * cleanup in exceptional circumstances, we don't actually do any
2863 * cleanup work here. We instead do this via a reference queue.
2866 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2868 mono_profiler_context_unloaded (ctx);
2871 void mono_thread_init (MonoThreadStartCB start_cb,
2872 MonoThreadAttachCB attach_cb)
2874 mono_coop_mutex_init_recursive (&threads_mutex);
2876 mono_os_mutex_init_recursive(&interlocked_mutex);
2877 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2879 mono_os_event_init (&background_change_event, FALSE);
2881 mono_init_static_data_info (&thread_static_info);
2882 mono_init_static_data_info (&context_static_info);
2884 mono_thread_start_cb = start_cb;
2885 mono_thread_attach_cb = attach_cb;
2888 void mono_thread_cleanup (void)
2890 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
2891 /* The main thread must abandon any held mutexes (particularly
2892 * important for named mutexes as they are shared across
2893 * processes, see bug 74680.) This will happen when the
2894 * thread exits, but if it's not running in a subthread it
2895 * won't exit in time.
2897 mono_w32mutex_abandon ();
2901 /* This stuff needs more testing, it seems one of these
2902 * critical sections can be locked when mono_thread_cleanup is
2905 mono_coop_mutex_destroy (&threads_mutex);
2906 mono_os_mutex_destroy (&interlocked_mutex);
2907 mono_os_mutex_destroy (&delayed_free_table_mutex);
2908 mono_os_mutex_destroy (&small_id_mutex);
2909 mono_os_event_destroy (&background_change_event);
2914 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2916 mono_thread_cleanup_fn = func;
2920 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2922 thread->internal_thread->manage_callback = func;
2926 static void print_tids (gpointer key, gpointer value, gpointer user)
2928 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2929 * sizeof(uint) and a cast to uint would overflow
2931 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2932 * print this as a pointer.
2934 g_message ("Waiting for: %p", key);
2939 MonoThreadHandle *handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2940 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2945 wait_for_tids (struct wait_data *wait, guint32 timeout, gboolean check_state_change)
2948 MonoThreadInfoWaitRet ret;
2950 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2952 /* Add the thread state change event, so it wakes
2953 * up if a thread changes to background mode. */
2956 if (check_state_change)
2957 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, &background_change_event, FALSE, timeout, TRUE);
2959 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, NULL, TRUE, timeout, TRUE);
2962 if (ret == MONO_THREAD_INFO_WAIT_RET_FAILED) {
2963 /* See the comment in build_wait_tids() */
2964 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2968 for( i = 0; i < wait->num; i++)
2969 mono_threads_close_thread_handle (wait->handles [i]);
2971 if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT)
2974 if (ret < wait->num) {
2975 MonoInternalThread *internal;
2977 internal = wait->threads [ret];
2979 mono_threads_lock ();
2980 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
2981 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
2982 mono_threads_unlock ();
2986 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2988 struct wait_data *wait=(struct wait_data *)user;
2990 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS - 1) {
2991 MonoInternalThread *thread=(MonoInternalThread *)value;
2993 /* Ignore background threads, we abort them later */
2994 /* Do not lock here since it is not needed and the caller holds threads_lock */
2995 if (thread->state & ThreadState_Background) {
2996 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2997 return; /* just leave, ignore */
3000 if (mono_gc_is_finalizer_internal_thread (thread)) {
3001 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3005 if (thread == mono_thread_internal_current ()) {
3006 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3010 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3011 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3015 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3016 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3020 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3021 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3022 wait->handles[wait->num]=mono_threads_open_thread_handle (thread->handle);
3023 wait->threads[wait->num]=thread;
3026 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3028 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3033 /* Just ignore the rest, we can't do anything with
3040 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3042 struct wait_data *wait=(struct wait_data *)user;
3043 MonoNativeThreadId self = mono_native_thread_id_get ();
3044 MonoInternalThread *thread = (MonoInternalThread *)value;
3046 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3049 /* The finalizer thread is not a background thread */
3050 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3051 && (thread->state & ThreadState_Background) != 0
3052 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3054 wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
3055 wait->threads[wait->num] = thread;
3058 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3059 mono_thread_internal_abort (thread);
3063 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3064 && !mono_gc_is_finalizer_internal_thread (thread);
3068 * mono_threads_set_shutting_down:
3070 * Is called by a thread that wants to shut down Mono. If the runtime is already
3071 * shutting down, the calling thread is suspended/stopped, and this function never
3075 mono_threads_set_shutting_down (void)
3077 MonoInternalThread *current_thread = mono_thread_internal_current ();
3079 mono_threads_lock ();
3081 if (shutting_down) {
3082 mono_threads_unlock ();
3084 /* Make sure we're properly suspended/stopped */
3086 LOCK_THREAD (current_thread);
3088 if ((current_thread->state & ThreadState_SuspendRequested) ||
3089 (current_thread->state & ThreadState_AbortRequested) ||
3090 (current_thread->state & ThreadState_StopRequested)) {
3091 UNLOCK_THREAD (current_thread);
3092 mono_thread_execute_interruption ();
3094 current_thread->state |= ThreadState_Stopped;
3095 UNLOCK_THREAD (current_thread);
3098 /*since we're killing the thread, detach it.*/
3099 mono_thread_detach_internal (current_thread);
3101 /* Wake up other threads potentially waiting for us */
3102 mono_thread_info_exit (0);
3104 shutting_down = TRUE;
3106 /* Not really a background state change, but this will
3107 * interrupt the main thread if it is waiting for all
3108 * the other threads.
3110 mono_os_event_set (&background_change_event);
3112 mono_threads_unlock ();
3116 void mono_thread_manage (void)
3118 struct wait_data wait_data;
3119 struct wait_data *wait = &wait_data;
3121 memset (wait, 0, sizeof (struct wait_data));
3122 /* join each thread that's still running */
3123 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3125 mono_threads_lock ();
3127 THREAD_DEBUG (g_message("%s: No threads", __func__));
3128 mono_threads_unlock ();
3131 mono_threads_unlock ();
3134 mono_threads_lock ();
3135 if (shutting_down) {
3136 /* somebody else is shutting down */
3137 mono_threads_unlock ();
3140 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3141 mono_g_hash_table_foreach (threads, print_tids, NULL));
3143 mono_os_event_reset (&background_change_event);
3145 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3146 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3147 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3148 mono_threads_unlock ();
3150 /* Something to wait for */
3151 wait_for_tids (wait, MONO_INFINITE_WAIT, TRUE);
3152 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3153 } while(wait->num>0);
3155 /* Mono is shutting down, so just wait for the end */
3156 if (!mono_runtime_try_shutdown ()) {
3157 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3158 mono_thread_suspend (mono_thread_internal_current ());
3159 mono_thread_execute_interruption ();
3163 * Remove everything but the finalizer thread and self.
3164 * Also abort all the background threads
3167 mono_threads_lock ();
3170 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3171 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3172 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3174 mono_threads_unlock ();
3176 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3177 if (wait->num > 0) {
3178 /* Something to wait for */
3179 wait_for_tids (wait, MONO_INFINITE_WAIT, FALSE);
3181 } while (wait->num > 0);
3184 * give the subthreads a chance to really quit (this is mainly needed
3185 * to get correct user and system times from getrusage/wait/time(1)).
3186 * This could be removed if we avoid pthread_detach() and use pthread_join().
3188 mono_thread_info_yield ();
3192 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3194 MonoInternalThread *thread = (MonoInternalThread*)value;
3195 struct wait_data *wait = (struct wait_data*)user_data;
3198 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3200 * This needs no locking.
3202 if ((thread->state & ThreadState_Suspended) != 0 ||
3203 (thread->state & ThreadState_Stopped) != 0)
3206 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3207 wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle);
3208 wait->threads [wait->num] = thread;
3214 * mono_thread_suspend_all_other_threads:
3216 * Suspend all managed threads except the finalizer thread and this thread. It is
3217 * not possible to resume them later.
3219 void mono_thread_suspend_all_other_threads (void)
3221 struct wait_data wait_data;
3222 struct wait_data *wait = &wait_data;
3224 MonoNativeThreadId self = mono_native_thread_id_get ();
3225 guint32 eventidx = 0;
3226 gboolean starting, finished;
3228 memset (wait, 0, sizeof (struct wait_data));
3230 * The other threads could be in an arbitrary state at this point, i.e.
3231 * they could be starting up, shutting down etc. This means that there could be
3232 * threads which are not even in the threads hash table yet.
3236 * First we set a barrier which will be checked by all threads before they
3237 * are added to the threads hash table, and they will exit if the flag is set.
3238 * This ensures that no threads could be added to the hash later.
3239 * We will use shutting_down as the barrier for now.
3241 g_assert (shutting_down);
3244 * We make multiple calls to WaitForMultipleObjects since:
3245 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3246 * - some threads could exit without becoming suspended
3251 * Make a copy of the hashtable since we can't do anything with
3252 * threads while threads_mutex is held.
3255 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3256 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3257 mono_threads_lock ();
3258 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3259 mono_threads_unlock ();
3262 /* Get the suspended events that we'll be waiting for */
3263 for (i = 0; i < wait->num; ++i) {
3264 MonoInternalThread *thread = wait->threads [i];
3266 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3267 || mono_gc_is_finalizer_internal_thread (thread)
3268 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3270 mono_threads_close_thread_handle (wait->handles [i]);
3271 wait->threads [i] = NULL;
3275 LOCK_THREAD (thread);
3277 if ((thread->state & ThreadState_Suspended) != 0 ||
3278 (thread->state & ThreadState_StopRequested) != 0 ||
3279 (thread->state & ThreadState_Stopped) != 0) {
3280 UNLOCK_THREAD (thread);
3281 mono_threads_close_thread_handle (wait->handles [i]);
3282 wait->threads [i] = NULL;
3288 /* Convert abort requests into suspend requests */
3289 if ((thread->state & ThreadState_AbortRequested) != 0)
3290 thread->state &= ~ThreadState_AbortRequested;
3292 thread->state |= ThreadState_SuspendRequested;
3293 mono_os_event_reset (thread->suspended);
3295 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3296 async_suspend_internal (thread, TRUE);
3298 mono_threads_close_thread_handle (wait->handles [i]);
3299 wait->threads [i] = NULL;
3301 if (eventidx <= 0) {
3303 * If there are threads which are starting up, we wait until they
3304 * are suspended when they try to register in the threads hash.
3305 * This is guaranteed to finish, since the threads which can create new
3306 * threads get suspended after a while.
3307 * FIXME: The finalizer thread can still create new threads.
3309 mono_threads_lock ();
3310 if (threads_starting_up)
3311 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3314 mono_threads_unlock ();
3316 mono_thread_info_sleep (100, NULL);
3324 MonoInternalThread *thread;
3325 MonoStackFrameInfo *frames;
3326 int nframes, max_frames;
3327 int nthreads, max_threads;
3328 MonoInternalThread **threads;
3329 } ThreadDumpUserData;
3331 static gboolean thread_dump_requested;
3333 /* This needs to be async safe */
3335 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3337 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3339 if (ud->nframes < ud->max_frames) {
3340 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3347 /* This needs to be async safe */
3348 static SuspendThreadResult
3349 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3351 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3352 MonoInternalThread *thread = user_data->thread;
3355 /* This no longer works with remote unwinding */
3356 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3357 mono_thread_internal_describe (thread, text);
3358 g_string_append (text, "\n");
3361 if (thread == mono_thread_internal_current ())
3362 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3364 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3366 return MonoResumeThread;
3370 int nthreads, max_threads;
3371 MonoInternalThread **threads;
3372 } CollectThreadsUserData;
3375 collect_thread (gpointer key, gpointer value, gpointer user)
3377 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3378 MonoInternalThread *thread = (MonoInternalThread *)value;
3380 if (ud->nthreads < ud->max_threads)
3381 ud->threads [ud->nthreads ++] = thread;
3385 * Collect running threads into the THREADS array.
3386 * THREADS should be an array allocated on the stack.
3389 collect_threads (MonoInternalThread **thread_array, int max_threads)
3391 CollectThreadsUserData ud;
3393 memset (&ud, 0, sizeof (ud));
3394 /* This array contains refs, but its on the stack, so its ok */
3395 ud.threads = thread_array;
3396 ud.max_threads = max_threads;
3398 mono_threads_lock ();
3399 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3400 mono_threads_unlock ();
3406 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3408 GString* text = g_string_new (0);
3410 GError *error = NULL;
3413 ud->thread = thread;
3416 /* Collect frames for the thread */
3417 if (thread == mono_thread_internal_current ()) {
3418 get_thread_dump (mono_thread_info_current (), ud);
3420 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3424 * Do all the non async-safe work outside of get_thread_dump.
3427 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3429 g_string_append_printf (text, "\n\"%s\"", name);
3432 else if (thread->threadpool_thread) {
3433 g_string_append (text, "\n\"<threadpool thread>\"");
3435 g_string_append (text, "\n\"<unnamed thread>\"");
3438 for (i = 0; i < ud->nframes; ++i) {
3439 MonoStackFrameInfo *frame = &ud->frames [i];
3440 MonoMethod *method = NULL;
3442 if (frame->type == FRAME_TYPE_MANAGED)
3443 method = mono_jit_info_get_method (frame->ji);
3446 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3447 g_string_append_printf (text, " %s\n", location);
3450 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3454 fprintf (stdout, "%s", text->str);
3456 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3457 OutputDebugStringA(text->str);
3460 g_string_free (text, TRUE);
3465 mono_threads_perform_thread_dump (void)
3467 ThreadDumpUserData ud;
3468 MonoInternalThread *thread_array [128];
3469 int tindex, nthreads;
3471 if (!thread_dump_requested)
3474 printf ("Full thread dump:\n");
3476 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3477 nthreads = collect_threads (thread_array, 128);
3479 memset (&ud, 0, sizeof (ud));
3480 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3481 ud.max_frames = 256;
3483 for (tindex = 0; tindex < nthreads; ++tindex)
3484 dump_thread (thread_array [tindex], &ud);
3488 thread_dump_requested = FALSE;
3491 /* Obtain the thread dump of all threads */
3493 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3496 ThreadDumpUserData ud;
3497 MonoInternalThread *thread_array [128];
3498 MonoDomain *domain = mono_domain_get ();
3499 MonoDebugSourceLocation *location;
3500 int tindex, nthreads;
3502 mono_error_init (error);
3504 *out_threads = NULL;
3505 *out_stack_frames = NULL;
3507 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3508 nthreads = collect_threads (thread_array, 128);
3510 memset (&ud, 0, sizeof (ud));
3511 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3512 ud.max_frames = 256;
3514 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3517 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3521 for (tindex = 0; tindex < nthreads; ++tindex) {
3522 MonoInternalThread *thread = thread_array [tindex];
3523 MonoArray *thread_frames;
3529 /* Collect frames for the thread */
3530 if (thread == mono_thread_internal_current ()) {
3531 get_thread_dump (mono_thread_info_current (), &ud);
3533 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3536 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3538 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3541 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3543 for (i = 0; i < ud.nframes; ++i) {
3544 MonoStackFrameInfo *frame = &ud.frames [i];
3545 MonoMethod *method = NULL;
3546 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3550 sf->native_offset = frame->native_offset;
3552 if (frame->type == FRAME_TYPE_MANAGED)
3553 method = mono_jit_info_get_method (frame->ji);
3556 sf->method_address = (gsize) frame->ji->code_start;
3558 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3561 MONO_OBJECT_SETREF (sf, method, rm);
3563 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3565 sf->il_offset = location->il_offset;
3567 if (location && location->source_file) {
3568 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3569 sf->line = location->row;
3570 sf->column = location->column;
3572 mono_debug_free_source_location (location);
3577 mono_array_setref (thread_frames, i, sf);
3583 return is_ok (error);
3587 * mono_threads_request_thread_dump:
3589 * Ask all threads except the current to print their stacktrace to stdout.
3592 mono_threads_request_thread_dump (void)
3594 /*The new thread dump code runs out of the finalizer thread. */
3595 thread_dump_requested = TRUE;
3596 mono_gc_finalize_notify ();
3601 gint allocated; /* +1 so that refs [allocated] == NULL */
3605 typedef struct ref_stack RefStack;
3608 ref_stack_new (gint initial_size)
3612 initial_size = MAX (initial_size, 16) + 1;
3613 rs = g_new0 (RefStack, 1);
3614 rs->refs = g_new0 (gpointer, initial_size);
3615 rs->allocated = initial_size;
3620 ref_stack_destroy (gpointer ptr)
3622 RefStack *rs = (RefStack *)ptr;
3631 ref_stack_push (RefStack *rs, gpointer ptr)
3633 g_assert (rs != NULL);
3635 if (rs->bottom >= rs->allocated) {
3636 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3637 rs->allocated <<= 1;
3638 rs->refs [rs->allocated] = NULL;
3640 rs->refs [rs->bottom++] = ptr;
3644 ref_stack_pop (RefStack *rs)
3646 if (rs == NULL || rs->bottom == 0)
3650 rs->refs [rs->bottom] = NULL;
3654 ref_stack_find (RefStack *rs, gpointer ptr)
3661 for (refs = rs->refs; refs && *refs; refs++) {
3669 * mono_thread_push_appdomain_ref:
3671 * Register that the current thread may have references to objects in domain
3672 * @domain on its stack. Each call to this function should be paired with a
3673 * call to pop_appdomain_ref.
3676 mono_thread_push_appdomain_ref (MonoDomain *domain)
3678 MonoInternalThread *thread = mono_thread_internal_current ();
3681 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3682 SPIN_LOCK (thread->lock_thread_id);
3683 if (thread->appdomain_refs == NULL)
3684 thread->appdomain_refs = ref_stack_new (16);
3685 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3686 SPIN_UNLOCK (thread->lock_thread_id);
3691 mono_thread_pop_appdomain_ref (void)
3693 MonoInternalThread *thread = mono_thread_internal_current ();
3696 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3697 SPIN_LOCK (thread->lock_thread_id);
3698 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3699 SPIN_UNLOCK (thread->lock_thread_id);
3704 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3707 SPIN_LOCK (thread->lock_thread_id);
3708 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3709 SPIN_UNLOCK (thread->lock_thread_id);
3714 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3716 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3719 typedef struct abort_appdomain_data {
3720 struct wait_data wait;
3722 } abort_appdomain_data;
3725 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3727 MonoInternalThread *thread = (MonoInternalThread*)value;
3728 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3729 MonoDomain *domain = data->domain;
3731 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3732 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3734 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3735 data->wait.handles [data->wait.num] = mono_threads_open_thread_handle (thread->handle);
3736 data->wait.threads [data->wait.num] = thread;
3739 /* Just ignore the rest, we can't do anything with
3747 * mono_threads_abort_appdomain_threads:
3749 * Abort threads which has references to the given appdomain.
3752 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3754 #ifdef __native_client__
3758 abort_appdomain_data user_data;
3760 int orig_timeout = timeout;
3763 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3765 start_time = mono_msec_ticks ();
3767 mono_threads_lock ();
3769 user_data.domain = domain;
3770 user_data.wait.num = 0;
3771 /* This shouldn't take any locks */
3772 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3773 mono_threads_unlock ();
3775 if (user_data.wait.num > 0) {
3776 /* Abort the threads outside the threads lock */
3777 for (i = 0; i < user_data.wait.num; ++i)
3778 mono_thread_internal_abort (user_data.wait.threads [i]);
3781 * We should wait for the threads either to abort, or to leave the
3782 * domain. We can't do the latter, so we wait with a timeout.
3784 wait_for_tids (&user_data.wait, 100, FALSE);
3787 /* Update remaining time */
3788 timeout -= mono_msec_ticks () - start_time;
3789 start_time = mono_msec_ticks ();
3791 if (orig_timeout != -1 && timeout < 0)
3794 while (user_data.wait.num > 0);
3796 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3802 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3804 MonoInternalThread *thread = (MonoInternalThread*)value;
3805 MonoDomain *domain = (MonoDomain*)user_data;
3808 /* No locking needed here */
3809 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3811 if (thread->cached_culture_info) {
3812 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3813 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3814 if (obj && obj->vtable->domain == domain)
3815 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3821 * mono_threads_clear_cached_culture:
3823 * Clear the cached_current_culture from all threads if it is in the
3827 mono_threads_clear_cached_culture (MonoDomain *domain)
3829 mono_threads_lock ();
3830 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3831 mono_threads_unlock ();
3835 * mono_thread_get_undeniable_exception:
3837 * Return an exception which needs to be raised when leaving a catch clause.
3838 * This is used for undeniable exception propagation.
3841 mono_thread_get_undeniable_exception (void)
3843 MonoInternalThread *thread = mono_thread_internal_current ();
3845 if (!(thread && thread->abort_exc && !is_running_protected_wrapper ()))
3848 // We don't want to have our exception effect calls made by
3849 // the catching block
3851 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
3855 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3856 * exception if the thread no longer references a dying appdomain.
3858 thread->abort_exc->trace_ips = NULL;
3859 thread->abort_exc->stack_trace = NULL;
3860 return thread->abort_exc;
3863 #if MONO_SMALL_CONFIG
3864 #define NUM_STATIC_DATA_IDX 4
3865 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3869 #define NUM_STATIC_DATA_IDX 8
3870 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3871 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3875 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3876 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3879 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3881 gpointer *static_data = (gpointer *)addr;
3883 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3884 void **ptr = (void **)static_data [i];
3889 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3890 void **p = ptr + idx;
3893 mark_func ((MonoObject**)p, gc_data);
3899 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3901 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3905 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3907 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3911 * mono_alloc_static_data
3913 * Allocate memory blocks for storing threads or context static data
3916 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3918 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3921 gpointer* static_data = *static_data_ptr;
3923 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3924 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3926 if (mono_gc_user_markers_supported ()) {
3927 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3928 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3930 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3931 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3934 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3935 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3936 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3937 *static_data_ptr = static_data;
3938 static_data [0] = static_data;
3941 for (i = 1; i <= idx; ++i) {
3942 if (static_data [i])
3945 if (mono_gc_user_markers_supported ())
3946 static_data [i] = g_malloc0 (static_data_size [i]);
3948 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3949 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3950 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3955 mono_free_static_data (gpointer* static_data)
3958 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3959 gpointer p = static_data [i];
3963 * At this point, the static data pointer array is still registered with the
3964 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3965 * data. Freeing the individual arrays without first nulling their slots
3966 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3967 * such an already freed array. See bug #13813.
3969 static_data [i] = NULL;
3970 mono_memory_write_barrier ();
3971 if (mono_gc_user_markers_supported ())
3974 mono_gc_free_fixed (p);
3976 mono_gc_free_fixed (static_data);
3980 * mono_init_static_data_info
3982 * Initializes static data counters
3984 static void mono_init_static_data_info (StaticDataInfo *static_data)
3986 static_data->idx = 0;
3987 static_data->offset = 0;
3988 static_data->freelist = NULL;
3992 * mono_alloc_static_data_slot
3994 * Generates an offset for static data. static_data contains the counters
3995 * used to generate it.
3998 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4000 if (!static_data->idx && !static_data->offset) {
4002 * we use the first chunk of the first allocation also as
4003 * an array for the rest of the data
4005 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4007 static_data->offset += align - 1;
4008 static_data->offset &= ~(align - 1);
4009 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4010 static_data->idx ++;
4011 g_assert (size <= static_data_size [static_data->idx]);
4012 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4013 static_data->offset = 0;
4015 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4016 static_data->offset += size;
4021 * LOCKING: requires that threads_mutex is held
4024 context_adjust_static_data (MonoAppContext *ctx)
4026 if (context_static_info.offset || context_static_info.idx > 0) {
4027 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4028 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4029 ctx->data->static_data = ctx->static_data;
4034 * LOCKING: requires that threads_mutex is held
4037 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4039 MonoInternalThread *thread = (MonoInternalThread *)value;
4040 guint32 offset = GPOINTER_TO_UINT (user);
4042 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4046 * LOCKING: requires that threads_mutex is held
4049 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4051 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4056 guint32 offset = GPOINTER_TO_UINT (user);
4057 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4058 ctx->data->static_data = ctx->static_data;
4061 static StaticDataFreeList*
4062 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4064 StaticDataFreeList* prev = NULL;
4065 StaticDataFreeList* tmp = static_data->freelist;
4067 if (tmp->size == size) {
4069 prev->next = tmp->next;
4071 static_data->freelist = tmp->next;
4080 #if SIZEOF_VOID_P == 4
4087 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4089 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4091 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4092 MonoBitSet *rb = sets [idx];
4093 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4094 offset /= sizeof (uintptr_t);
4095 /* offset is now the bitmap offset */
4096 for (int i = 0; i < numbits; ++i) {
4097 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4098 mono_bitset_set_fast (rb, offset + i);
4103 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4105 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4106 MonoBitSet *rb = sets [idx];
4107 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4108 offset /= sizeof (uintptr_t);
4109 /* offset is now the bitmap offset */
4110 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4111 mono_bitset_clear_fast (rb, offset + i);
4115 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4117 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4119 StaticDataInfo *info;
4122 if (static_type == SPECIAL_STATIC_THREAD) {
4123 info = &thread_static_info;
4124 sets = thread_reference_bitmaps;
4126 info = &context_static_info;
4127 sets = context_reference_bitmaps;
4130 mono_threads_lock ();
4132 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4136 offset = item->offset;
4139 offset = mono_alloc_static_data_slot (info, size, align);
4142 update_reference_bitmap (sets, offset, bitmap, numbits);
4144 if (static_type == SPECIAL_STATIC_THREAD) {
4145 /* This can be called during startup */
4146 if (threads != NULL)
4147 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4149 if (contexts != NULL)
4150 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4152 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4155 mono_threads_unlock ();
4161 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4163 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4165 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4166 return get_thread_static_data (thread, offset);
4168 return get_context_static_data (thread->current_appcontext, offset);
4173 mono_get_special_static_data (guint32 offset)
4175 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4184 * LOCKING: requires that threads_mutex is held
4187 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4189 MonoInternalThread *thread = (MonoInternalThread *)value;
4190 OffsetSize *data = (OffsetSize *)user;
4191 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4192 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4195 if (!thread->static_data || !thread->static_data [idx])
4197 ptr = ((char*) thread->static_data [idx]) + off;
4198 mono_gc_bzero_atomic (ptr, data->size);
4202 * LOCKING: requires that threads_mutex is held
4205 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4207 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4212 OffsetSize *data = (OffsetSize *)user;
4213 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4214 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4217 if (!ctx->static_data || !ctx->static_data [idx])
4220 ptr = ((char*) ctx->static_data [idx]) + off;
4221 mono_gc_bzero_atomic (ptr, data->size);
4225 do_free_special_slot (guint32 offset, guint32 size)
4227 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4229 StaticDataInfo *info;
4231 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4232 info = &thread_static_info;
4233 sets = thread_reference_bitmaps;
4235 info = &context_static_info;
4236 sets = context_reference_bitmaps;
4239 guint32 data_offset = offset;
4240 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4241 OffsetSize data = { data_offset, size };
4243 clear_reference_bitmap (sets, data.offset, data.size);
4245 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4246 if (threads != NULL)
4247 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4249 if (contexts != NULL)
4250 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4253 if (!mono_runtime_is_shutting_down ()) {
4254 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4256 item->offset = offset;
4259 item->next = info->freelist;
4260 info->freelist = item;
4265 do_free_special (gpointer key, gpointer value, gpointer data)
4267 MonoClassField *field = (MonoClassField *)key;
4268 guint32 offset = GPOINTER_TO_UINT (value);
4271 size = mono_type_size (field->type, &align);
4272 do_free_special_slot (offset, size);
4276 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4278 mono_threads_lock ();
4280 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4282 mono_threads_unlock ();
4286 static void CALLBACK dummy_apc (ULONG_PTR param)
4292 * mono_thread_execute_interruption
4294 * Performs the operation that the requested thread state requires (abort,
4297 static MonoException*
4298 mono_thread_execute_interruption (void)
4300 MonoInternalThread *thread = mono_thread_internal_current ();
4301 MonoThread *sys_thread = mono_thread_current ();
4303 LOCK_THREAD (thread);
4305 /* MonoThread::interruption_requested can only be changed with atomics */
4306 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4307 /* this will consume pending APC calls */
4309 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4311 InterlockedDecrement (&thread_interruption_requested);
4313 /* Clear the interrupted flag of the thread so it can wait again */
4314 mono_thread_info_clear_self_interrupt ();
4317 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4318 if (sys_thread->pending_exception) {
4321 exc = sys_thread->pending_exception;
4322 sys_thread->pending_exception = NULL;
4324 UNLOCK_THREAD (thread);
4326 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4327 UNLOCK_THREAD (thread);
4328 g_assert (sys_thread->pending_exception == NULL);
4329 if (thread->abort_exc == NULL) {
4331 * This might be racy, but it has to be called outside the lock
4332 * since it calls managed code.
4334 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4336 return thread->abort_exc;
4338 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4339 /* calls UNLOCK_THREAD (thread) */
4340 self_suspend_internal ();
4343 else if ((thread->state & ThreadState_StopRequested) != 0) {
4344 /* FIXME: do this through the JIT? */
4346 UNLOCK_THREAD (thread);
4348 mono_thread_exit ();
4350 } else if (thread->thread_interrupt_requested) {
4352 thread->thread_interrupt_requested = FALSE;
4353 UNLOCK_THREAD (thread);
4355 return(mono_get_exception_thread_interrupted ());
4358 UNLOCK_THREAD (thread);
4364 * mono_thread_request_interruption
4366 * A signal handler can call this method to request the interruption of a
4367 * thread. The result of the interruption will depend on the current state of
4368 * the thread. If the result is an exception that needs to be throw, it is
4369 * provided as return value.
4372 mono_thread_request_interruption (gboolean running_managed)
4374 MonoInternalThread *thread = mono_thread_internal_current ();
4376 /* The thread may already be stopping */
4381 if (thread->interrupt_on_stop &&
4382 thread->state & ThreadState_StopRequested &&
4383 thread->state & ThreadState_Background)
4386 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4388 InterlockedIncrement (&thread_interruption_requested);
4390 if (!running_managed || is_running_protected_wrapper ()) {
4391 /* Can't stop while in unmanaged code. Increase the global interruption
4392 request count. When exiting the unmanaged method the count will be
4393 checked and the thread will be interrupted. */
4395 /* this will awake the thread if it is in WaitForSingleObject
4397 /* Our implementation of this function ignores the func argument */
4399 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
4401 mono_thread_info_self_interrupt ();
4406 return mono_thread_execute_interruption ();
4410 /*This function should be called by a thread after it has exited all of
4411 * its handle blocks at interruption time.*/
4413 mono_thread_resume_interruption (void)
4415 MonoInternalThread *thread = mono_thread_internal_current ();
4416 gboolean still_aborting;
4418 /* The thread may already be stopping */
4422 LOCK_THREAD (thread);
4423 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4424 UNLOCK_THREAD (thread);
4426 /*This can happen if the protected block called Thread::ResetAbort*/
4427 if (!still_aborting)
4430 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4432 InterlockedIncrement (&thread_interruption_requested);
4434 mono_thread_info_self_interrupt ();
4436 return mono_thread_execute_interruption ();
4439 gboolean mono_thread_interruption_requested ()
4441 if (thread_interruption_requested) {
4442 MonoInternalThread *thread = mono_thread_internal_current ();
4443 /* The thread may already be stopping */
4445 return (thread->interruption_requested);
4450 static MonoException*
4451 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4453 MonoInternalThread *thread = mono_thread_internal_current ();
4455 /* The thread may already be stopping */
4458 if (!thread->interruption_requested)
4460 if (!bypass_abort_protection && is_running_protected_wrapper ())
4463 return mono_thread_execute_interruption ();
4467 * Performs the interruption of the current thread, if one has been requested,
4468 * and the thread is not running a protected wrapper.
4469 * Return the exception which needs to be thrown, if any.
4472 mono_thread_interruption_checkpoint (void)
4474 return mono_thread_interruption_checkpoint_request (FALSE);
4478 * Performs the interruption of the current thread, if one has been requested.
4479 * Return the exception which needs to be thrown, if any.
4482 mono_thread_force_interruption_checkpoint_noraise (void)
4484 return mono_thread_interruption_checkpoint_request (TRUE);
4488 * mono_set_pending_exception:
4490 * Set the pending exception of the current thread to EXC.
4491 * The exception will be thrown when execution returns to managed code.
4494 mono_set_pending_exception (MonoException *exc)
4496 MonoThread *thread = mono_thread_current ();
4498 /* The thread may already be stopping */
4502 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4504 mono_thread_request_interruption (FALSE);
4508 * mono_thread_interruption_request_flag:
4510 * Returns the address of a flag that will be non-zero if an interruption has
4511 * been requested for a thread. The thread to interrupt may not be the current
4512 * thread, so an additional call to mono_thread_interruption_requested() or
4513 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4516 gint32* mono_thread_interruption_request_flag ()
4518 return &thread_interruption_requested;
4522 mono_thread_init_apartment_state (void)
4525 MonoInternalThread* thread = mono_thread_internal_current ();
4527 /* Positive return value indicates success, either
4528 * S_OK if this is first CoInitialize call, or
4529 * S_FALSE if CoInitialize already called, but with same
4530 * threading model. A negative value indicates failure,
4531 * probably due to trying to change the threading model.
4533 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4534 ? COINIT_APARTMENTTHREADED
4535 : COINIT_MULTITHREADED) < 0) {
4536 thread->apartment_state = ThreadApartmentState_Unknown;
4542 mono_thread_cleanup_apartment_state (void)
4545 MonoInternalThread* thread = mono_thread_internal_current ();
4547 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4554 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4556 LOCK_THREAD (thread);
4557 thread->state |= state;
4558 UNLOCK_THREAD (thread);
4562 * mono_thread_test_and_set_state:
4564 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4566 * Returns TRUE is @set was OR'd in.
4569 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4571 LOCK_THREAD (thread);
4573 if ((thread->state & test) != 0) {
4574 UNLOCK_THREAD (thread);
4578 thread->state |= set;
4579 UNLOCK_THREAD (thread);
4585 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4587 LOCK_THREAD (thread);
4588 thread->state &= ~state;
4589 UNLOCK_THREAD (thread);
4593 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4595 gboolean ret = FALSE;
4597 LOCK_THREAD (thread);
4599 if ((thread->state & test) != 0) {
4603 UNLOCK_THREAD (thread);
4609 self_interrupt_thread (void *_unused)
4612 MonoThreadInfo *info;
4614 exc = mono_thread_execute_interruption ();
4616 if (mono_threads_is_coop_enabled ()) {
4617 /* We can return from an async call in coop, as
4618 * it's simply called when exiting the safepoint */
4622 g_error ("%s: we can't resume from an async call", __func__);
4625 info = mono_thread_info_current ();
4627 /* We must use _with_context since we didn't trampoline into the runtime */
4628 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. */
4632 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4636 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4640 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4642 MonoJitInfo **dest = (MonoJitInfo **)data;
4648 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4650 MonoJitInfo *ji = NULL;
4655 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4656 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4657 * where we hold runtime locks.
4659 if (!mono_threads_is_coop_enabled ())
4660 mono_thread_info_set_is_async_context (TRUE);
4661 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4662 if (!mono_threads_is_coop_enabled ())
4663 mono_thread_info_set_is_async_context (FALSE);
4668 MonoInternalThread *thread;
4669 gboolean install_async_abort;
4670 MonoThreadInfoInterruptToken *interrupt_token;
4673 static SuspendThreadResult
4674 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4676 AbortThreadData *data = (AbortThreadData *)ud;
4677 MonoInternalThread *thread = data->thread;
4678 MonoJitInfo *ji = NULL;
4679 gboolean protected_wrapper;
4680 gboolean running_managed;
4682 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4683 return MonoResumeThread;
4686 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4687 The protected block code will give them a chance when appropriate.
4689 if (thread->abort_protected_block_count)
4690 return MonoResumeThread;
4692 /*someone is already interrupting it*/
4693 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4694 return MonoResumeThread;
4696 InterlockedIncrement (&thread_interruption_requested);
4698 ji = mono_thread_info_get_last_managed (info);
4699 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4700 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4702 if (!protected_wrapper && running_managed) {
4703 /*We are in managed code*/
4704 /*Set the thread to call */
4705 if (data->install_async_abort)
4706 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4707 return MonoResumeThread;
4710 * This will cause waits to be broken.
4711 * It will also prevent the thread from entering a wait, so if the thread returns
4712 * from the wait before it receives the abort signal, it will just spin in the wait
4713 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4716 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4718 return MonoResumeThread;
4723 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4725 AbortThreadData data;
4727 g_assert (thread != mono_thread_internal_current ());
4729 data.thread = thread;
4730 data.install_async_abort = install_async_abort;
4731 data.interrupt_token = NULL;
4733 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4734 if (data.interrupt_token)
4735 mono_thread_info_finish_interrupt (data.interrupt_token);
4736 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4740 self_abort_internal (MonoError *error)
4744 mono_error_init (error);
4746 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4747 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4750 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.
4752 exc = mono_thread_request_interruption (TRUE);
4754 mono_error_set_exception_instance (error, exc);
4756 mono_thread_info_self_interrupt ();
4760 MonoInternalThread *thread;
4762 MonoThreadInfoInterruptToken *interrupt_token;
4763 } SuspendThreadData;
4765 static SuspendThreadResult
4766 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4768 SuspendThreadData *data = (SuspendThreadData *)ud;
4769 MonoInternalThread *thread = data->thread;
4770 MonoJitInfo *ji = NULL;
4771 gboolean protected_wrapper;
4772 gboolean running_managed;
4774 ji = mono_thread_info_get_last_managed (info);
4775 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4776 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4778 if (running_managed && !protected_wrapper) {
4779 if (mono_threads_is_coop_enabled ()) {
4780 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4781 return MonoResumeThread;
4783 thread->state &= ~ThreadState_SuspendRequested;
4784 thread->state |= ThreadState_Suspended;
4785 return KeepSuspended;
4788 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4789 InterlockedIncrement (&thread_interruption_requested);
4790 if (data->interrupt)
4791 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4793 return MonoResumeThread;
4797 /* LOCKING: called with @thread synch_cs held, and releases it */
4799 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4801 SuspendThreadData data;
4803 g_assert (thread != mono_thread_internal_current ());
4805 // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4807 thread->self_suspended = FALSE;
4809 data.thread = thread;
4810 data.interrupt = interrupt;
4811 data.interrupt_token = NULL;
4813 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4814 if (data.interrupt_token)
4815 mono_thread_info_finish_interrupt (data.interrupt_token);
4817 UNLOCK_THREAD (thread);
4820 /* LOCKING: called with @thread synch_cs held, and releases it */
4822 self_suspend_internal (void)
4824 MonoInternalThread *thread;
4826 MonoOSEventWaitRet res;
4828 thread = mono_thread_internal_current ();
4830 // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4832 thread->self_suspended = TRUE;
4834 thread->state &= ~ThreadState_SuspendRequested;
4835 thread->state |= ThreadState_Suspended;
4837 UNLOCK_THREAD (thread);
4839 event = thread->suspended;
4842 res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT);
4843 g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
4848 * mono_thread_is_foreign:
4849 * @thread: the thread to query
4851 * This function allows one to determine if a thread was created by the mono runtime and has
4852 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4854 * Returns: TRUE if @thread was not created by the runtime.
4857 mono_thread_is_foreign (MonoThread *thread)
4859 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4860 return info->runtime_thread == FALSE;
4864 * mono_add_joinable_thread:
4866 * Add TID to the list of joinable threads.
4867 * LOCKING: Acquires the threads lock.
4870 mono_threads_add_joinable_thread (gpointer tid)
4874 * We cannot detach from threads because it causes problems like
4875 * 2fd16f60/r114307. So we collect them and join them when
4876 * we have time (in he finalizer thread).
4878 joinable_threads_lock ();
4879 if (!joinable_threads)
4880 joinable_threads = g_hash_table_new (NULL, NULL);
4881 g_hash_table_insert (joinable_threads, tid, tid);
4882 joinable_thread_count ++;
4883 joinable_threads_unlock ();
4885 mono_gc_finalize_notify ();
4890 * mono_threads_join_threads:
4892 * Join all joinable threads. This is called from the finalizer thread.
4893 * LOCKING: Acquires the threads lock.
4896 mono_threads_join_threads (void)
4899 GHashTableIter iter;
4906 if (!joinable_thread_count)
4910 joinable_threads_lock ();
4912 if (g_hash_table_size (joinable_threads)) {
4913 g_hash_table_iter_init (&iter, joinable_threads);
4914 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4915 thread = (pthread_t)tid;
4916 g_hash_table_remove (joinable_threads, key);
4917 joinable_thread_count --;
4920 joinable_threads_unlock ();
4922 if (thread != pthread_self ()) {
4924 /* This shouldn't block */
4925 mono_native_thread_join (thread);
4938 * Wait for thread TID to exit.
4939 * LOCKING: Acquires the threads lock.
4942 mono_thread_join (gpointer tid)
4946 gboolean found = FALSE;
4948 joinable_threads_lock ();
4949 if (!joinable_threads)
4950 joinable_threads = g_hash_table_new (NULL, NULL);
4951 if (g_hash_table_lookup (joinable_threads, tid)) {
4952 g_hash_table_remove (joinable_threads, tid);
4953 joinable_thread_count --;
4956 joinable_threads_unlock ();
4959 thread = (pthread_t)tid;
4961 mono_native_thread_join (thread);
4967 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4969 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4970 mono_thread_interruption_checkpoint ();
4974 mono_thread_internal_unhandled_exception (MonoObject* exc)
4976 MonoClass *klass = exc->vtable->klass;
4977 if (is_threadabort_exception (klass)) {
4978 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4979 } else if (!is_appdomainunloaded_exception (klass)
4980 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4981 mono_unhandled_exception (exc);
4982 if (mono_environment_exitcode_get () == 1) {
4983 mono_environment_exitcode_set (255);
4984 mono_invoke_unhandled_exception_hook (exc);
4985 g_assert_not_reached ();
4991 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
4994 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
4995 mono_error_set_pending_exception (&error);
4999 * mono_threads_attach_coop: called by native->managed wrappers
5003 * - @return: the original domain which needs to be restored, or NULL.
5006 * - @dummy: contains the original domain
5007 * - @return: a cookie containing current MonoThreadInfo*.
5010 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5013 gboolean fresh_thread = FALSE;
5016 /* Happens when called from AOTed code which is only used in the root domain. */
5017 domain = mono_get_root_domain ();
5022 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5023 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5024 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5025 * we're only responsible for making the cookie. */
5026 if (mono_threads_is_coop_enabled ()) {
5027 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5028 fresh_thread = !info || !mono_thread_info_is_live (info);
5031 if (!mono_thread_internal_current ()) {
5032 mono_thread_attach_full (domain, FALSE);
5035 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5038 orig = mono_domain_get ();
5040 mono_domain_set (domain, TRUE);
5042 if (!mono_threads_is_coop_enabled ())
5043 return orig != domain ? orig : NULL;
5047 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5048 * return the right cookie. */
5049 return mono_threads_enter_gc_unsafe_region_cookie ();
5052 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5053 return mono_threads_enter_gc_unsafe_region (dummy);
5058 * mono_threads_detach_coop: called by native->managed wrappers
5061 * - @cookie: the original domain which needs to be restored, or NULL.
5065 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5066 * - @dummy: contains the original domain
5069 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5071 MonoDomain *domain, *orig;
5073 if (!mono_threads_is_coop_enabled ()) {
5074 orig = (MonoDomain*) cookie;
5076 mono_domain_set (orig, TRUE);
5078 orig = (MonoDomain*) *dummy;
5080 domain = mono_domain_get ();
5083 /* it won't do anything if cookie is NULL
5084 * thread state RUNNING -> (RUNNING|BLOCKING) */
5085 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5087 if (orig != domain) {
5089 mono_domain_unset ();
5091 mono_domain_set (orig, TRUE);
5097 mono_threads_begin_abort_protected_block (void)
5099 MonoInternalThread *thread;
5101 thread = mono_thread_internal_current ();
5102 ++thread->abort_protected_block_count;
5103 mono_memory_barrier ();
5107 mono_threads_end_abort_protected_block (void)
5109 MonoInternalThread *thread;
5111 thread = mono_thread_internal_current ();
5113 mono_memory_barrier ();
5114 --thread->abort_protected_block_count;
5118 mono_thread_try_resume_interruption (void)
5120 MonoInternalThread *thread;
5122 thread = mono_thread_internal_current ();
5123 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5126 return mono_thread_resume_interruption ();
5130 /* Returns TRUE if the current thread is ready to be interrupted. */
5132 mono_threads_is_ready_to_be_interrupted (void)
5134 MonoInternalThread *thread;
5136 thread = mono_thread_internal_current ();
5137 LOCK_THREAD (thread);
5138 if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5139 UNLOCK_THREAD (thread);
5143 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5144 UNLOCK_THREAD (thread);
5148 UNLOCK_THREAD (thread);
5154 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5156 g_string_append_printf (text, ", thread handle : %p", internal->handle);
5158 if (internal->thread_info) {
5159 g_string_append (text, ", state : ");
5160 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5163 if (internal->owned_mutexes) {
5166 g_string_append (text, ", owns : [");
5167 for (i = 0; i < internal->owned_mutexes->len; i++)
5168 g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5169 g_string_append (text, "]");
5174 mono_thread_internal_is_current (MonoInternalThread *internal)
5176 g_assert (internal);
5177 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));