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/metadata/object-internals.h>
32 #include <mono/metadata/mono-debug-debugger.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/mono-threads-coop.h>
40 #include <mono/utils/hazard-pointer.h>
41 #include <mono/utils/mono-tls.h>
42 #include <mono/utils/atomic.h>
43 #include <mono/utils/mono-memory-model.h>
44 #include <mono/utils/mono-threads-coop.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/os-event.h>
47 #include <mono/utils/mono-threads-debug.h>
48 #include <mono/metadata/w32handle.h>
49 #include <mono/metadata/w32event.h>
50 #include <mono/metadata/w32mutex.h>
52 #include <mono/metadata/gc-internals.h>
53 #include <mono/metadata/reflection-internals.h>
54 #include <mono/metadata/abi-details.h>
55 #include <mono/metadata/w32error.h>
56 #include <mono/utils/w32api.h>
62 #if defined(HOST_WIN32)
66 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
67 #define USE_TKILL_ON_ANDROID 1
70 #ifdef PLATFORM_ANDROID
73 #ifdef USE_TKILL_ON_ANDROID
74 extern int tkill (pid_t tid, int signal);
78 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
79 #define THREAD_DEBUG(a)
80 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
81 #define THREAD_WAIT_DEBUG(a)
82 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
83 #define LIBGC_DEBUG(a)
85 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
86 #define SPIN_LOCK(i) do { \
87 if (SPIN_TRYLOCK (i)) \
91 #define SPIN_UNLOCK(i) i = 0
93 #define LOCK_THREAD(thread) lock_thread((thread))
94 #define UNLOCK_THREAD(thread) unlock_thread((thread))
106 typedef struct _StaticDataFreeList StaticDataFreeList;
107 struct _StaticDataFreeList {
108 StaticDataFreeList *next;
116 StaticDataFreeList *freelist;
119 /* Number of cached culture objects in the MonoThread->cached_culture_info array
120 * (per-type): we use the first NUM entries for CultureInfo and the last for
121 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
123 #define NUM_CACHED_CULTURES 4
124 #define CULTURES_START_IDX 0
125 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
127 /* Controls access to the 'threads' hash table */
128 static void mono_threads_lock (void);
129 static void mono_threads_unlock (void);
130 static MonoCoopMutex threads_mutex;
132 /* Controls access to the 'joinable_threads' hash table */
133 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
134 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
135 static mono_mutex_t joinable_threads_mutex;
137 /* Holds current status of static data heap */
138 static StaticDataInfo thread_static_info;
139 static StaticDataInfo context_static_info;
141 /* The hash of existing threads (key is thread ID, value is
142 * MonoInternalThread*) that need joining before exit
144 static MonoGHashTable *threads=NULL;
146 /* List of app context GC handles.
147 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
149 static GHashTable *contexts = NULL;
151 /* Cleanup queue for contexts. */
152 static MonoReferenceQueue *context_queue;
155 * Threads which are starting up and they are not in the 'threads' hash yet.
156 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
157 * Protected by mono_threads_lock ().
159 static MonoGHashTable *threads_starting_up = NULL;
162 /* Protected by the threads lock */
163 static GHashTable *joinable_threads;
164 static int joinable_thread_count;
166 #define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
167 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
169 /* function called at thread start */
170 static MonoThreadStartCB mono_thread_start_cb = NULL;
172 /* function called at thread attach */
173 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
175 /* function called at thread cleanup */
176 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
178 /* The default stack size for each thread */
179 static guint32 default_stacksize = 0;
180 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
182 static void context_adjust_static_data (MonoAppContext *ctx);
183 static void mono_free_static_data (gpointer* static_data);
184 static void mono_init_static_data_info (StaticDataInfo *static_data);
185 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
186 static gboolean mono_thread_resume (MonoInternalThread* thread);
187 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
188 static void self_abort_internal (MonoError *error);
189 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
190 static void self_suspend_internal (void);
192 static MonoException* mono_thread_execute_interruption (void);
193 static void ref_stack_destroy (gpointer rs);
195 /* Spin lock for InterlockedXXX 64 bit functions */
196 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
197 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
198 static mono_mutex_t interlocked_mutex;
200 /* global count of thread interruptions requested */
201 static gint32 thread_interruption_requested = 0;
203 /* Event signaled when a thread changes its background mode */
204 static MonoOSEvent background_change_event;
206 static gboolean shutting_down = FALSE;
208 static gint32 managed_thread_id_counter = 0;
210 /* Class lazy loading functions */
211 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
214 mono_threads_lock (void)
216 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
220 mono_threads_unlock (void)
222 mono_locks_coop_release (&threads_mutex, ThreadsLock);
227 get_next_managed_thread_id (void)
229 return InterlockedIncrement (&managed_thread_id_counter);
232 static inline MonoNativeThreadId
233 thread_get_tid (MonoInternalThread *thread)
235 /* We store the tid as a guint64 to keep the object layout constant between platforms */
236 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
239 static void ensure_synch_cs_set (MonoInternalThread *thread)
241 MonoCoopMutex *synch_cs;
243 if (thread->synch_cs != NULL) {
247 synch_cs = g_new0 (MonoCoopMutex, 1);
248 mono_coop_mutex_init_recursive (synch_cs);
250 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
251 synch_cs, NULL) != NULL) {
252 /* Another thread must have installed this CS */
253 mono_coop_mutex_destroy (synch_cs);
259 lock_thread (MonoInternalThread *thread)
261 if (!thread->synch_cs)
262 ensure_synch_cs_set (thread);
264 g_assert (thread->synch_cs);
266 mono_coop_mutex_lock (thread->synch_cs);
270 unlock_thread (MonoInternalThread *thread)
272 mono_coop_mutex_unlock (thread->synch_cs);
275 static inline gboolean
276 is_appdomainunloaded_exception (MonoClass *klass)
278 return klass == mono_class_get_appdomain_unloaded_exception_class ();
281 static inline gboolean
282 is_threadabort_exception (MonoClass *klass)
284 return klass == mono_defaults.threadabortexception_class;
288 * A special static data offset (guint32) consists of 3 parts:
290 * [0] 6-bit index into the array of chunks.
291 * [6] 25-bit offset into the array.
292 * [31] Bit indicating thread or context static.
297 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
308 } SpecialStaticOffset;
310 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
311 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
313 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
314 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
315 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
316 (((SpecialStaticOffset *) &(x))->fields.f)
319 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
321 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
323 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
324 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
326 return ((char *) thread->static_data [idx]) + off;
330 get_context_static_data (MonoAppContext *ctx, guint32 offset)
332 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
334 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
335 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
337 return ((char *) ctx->static_data [idx]) + off;
341 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
343 static MonoClassField *current_thread_field = NULL;
347 if (!current_thread_field) {
348 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
349 g_assert (current_thread_field);
352 mono_class_vtable (domain, mono_defaults.thread_class);
353 mono_domain_lock (domain);
354 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
355 mono_domain_unlock (domain);
358 return (MonoThread **)get_thread_static_data (thread, offset);
362 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
364 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
366 g_assert (current->obj.vtable->domain == domain);
368 g_assert (!*current_thread_ptr);
369 *current_thread_ptr = current;
373 create_thread_object (MonoDomain *domain, MonoInternalThread *internal)
379 vtable = mono_class_vtable (domain, mono_defaults.thread_class);
382 thread = (MonoThread*)mono_object_new_mature (vtable, &error);
383 /* only possible failure mode is OOM, from which we don't expect to recover. */
384 mono_error_assert_ok (&error);
386 MONO_OBJECT_SETREF (thread, internal_thread, internal);
391 static MonoInternalThread*
392 create_internal_thread_object (void)
395 MonoInternalThread *thread;
398 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
399 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
400 /* only possible failure mode is OOM, from which we don't exect to recover */
401 mono_error_assert_ok (&error);
403 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
404 mono_coop_mutex_init_recursive (thread->synch_cs);
406 thread->apartment_state = ThreadApartmentState_Unknown;
407 thread->managed_id = get_next_managed_thread_id ();
408 if (mono_gc_is_moving ()) {
409 thread->thread_pinning_ref = thread;
410 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
413 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
415 thread->suspended = g_new0 (MonoOSEvent, 1);
416 mono_os_event_init (thread->suspended, TRUE);
422 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
426 g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
427 g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
428 g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
433 g_assert (internal->native_handle);
435 res = SetThreadPriority (internal->native_handle, priority - 2);
437 g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
438 #else /* HOST_WIN32 */
441 struct sched_param param;
444 tid = thread_get_tid (internal);
446 res = pthread_getschedparam (tid, &policy, ¶m);
448 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
450 #ifdef _POSIX_PRIORITY_SCHEDULING
453 /* Necessary to get valid priority range */
455 min = sched_get_priority_min (policy);
456 max = sched_get_priority_max (policy);
458 if (max > 0 && min >= 0 && max > min) {
459 double srange, drange, sposition, dposition;
460 srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
462 sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
463 dposition = (sposition / srange) * drange;
464 param.sched_priority = (int)(dposition + min);
471 param.sched_priority = 50;
477 param.sched_priority = 0;
480 g_warning ("%s: unknown policy %d", __func__, policy);
485 res = pthread_setschedparam (tid, policy, ¶m);
488 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
491 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
493 #endif /* HOST_WIN32 */
497 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
500 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
502 MonoThreadInfo *info;
503 MonoInternalThread *internal;
504 MonoDomain *domain, *root_domain;
508 info = mono_thread_info_current ();
510 internal = thread->internal_thread;
511 internal->handle = mono_threads_open_thread_handle (info->handle);
513 internal->native_handle = OpenThread (THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId ());
515 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
516 internal->thread_info = info;
517 internal->small_id = info->small_id;
518 internal->stack_ptr = stack_ptr;
520 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
522 SET_CURRENT_OBJECT (internal);
524 domain = mono_object_domain (thread);
526 mono_thread_push_appdomain_ref (domain);
527 if (!mono_domain_set (domain, force_domain)) {
528 mono_thread_pop_appdomain_ref ();
532 mono_threads_lock ();
534 if (threads_starting_up)
535 mono_g_hash_table_remove (threads_starting_up, thread);
537 if (shutting_down && !force_attach) {
538 mono_threads_unlock ();
543 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
544 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
547 /* We don't need to duplicate thread->handle, because it is
548 * only closed when the thread object is finalized by the GC. */
549 mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
551 /* We have to do this here because mono_thread_start_cb
552 * requires that root_domain_thread is set up. */
553 if (thread_static_info.offset || thread_static_info.idx > 0) {
554 /* get the current allocated size */
555 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
556 mono_alloc_static_data (&internal->static_data, offset, TRUE);
559 mono_threads_unlock ();
561 root_domain = mono_get_root_domain ();
563 g_assert (!internal->root_domain_thread);
564 if (domain != root_domain)
565 MONO_OBJECT_SETREF (internal, root_domain_thread, create_thread_object (root_domain, internal));
567 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
569 if (domain != root_domain)
570 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
572 set_current_thread_for_domain (domain, internal, thread);
574 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
582 MonoObject *start_delegate;
583 MonoObject *start_delegate_arg;
584 MonoThreadStart start_func;
585 gpointer start_func_arg;
587 MonoCoopSem registered;
590 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
593 MonoThreadStart start_func;
594 void *start_func_arg;
597 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
601 MonoInternalThread *internal;
602 MonoObject *start_delegate;
603 MonoObject *start_delegate_arg;
606 thread = start_info->thread;
607 internal = thread->internal_thread;
608 domain = mono_object_domain (start_info->thread);
610 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
612 if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
613 start_info->failed = TRUE;
615 mono_coop_sem_post (&start_info->registered);
617 if (InterlockedDecrement (&start_info->ref) == 0) {
618 mono_coop_sem_destroy (&start_info->registered);
625 mono_thread_internal_set_priority (internal, internal->priority);
629 start_delegate = start_info->start_delegate;
630 start_delegate_arg = start_info->start_delegate_arg;
631 start_func = start_info->start_func;
632 start_func_arg = start_info->start_func_arg;
634 /* This MUST be called before any managed code can be
635 * executed, as it calls the callback function that (for the
636 * jit) sets the lmf marker.
639 if (mono_thread_start_cb)
640 mono_thread_start_cb (tid, stack_ptr, start_func);
642 /* On 2.0 profile (and higher), set explicitly since state might have been
644 if (internal->apartment_state == ThreadApartmentState_Unknown)
645 internal->apartment_state = ThreadApartmentState_MTA;
647 mono_thread_init_apartment_state ();
649 /* Let the thread that called Start() know we're ready */
650 mono_coop_sem_post (&start_info->registered);
652 if (InterlockedDecrement (&start_info->ref) == 0) {
653 mono_coop_sem_destroy (&start_info->registered);
657 /* start_info is not valid anymore */
661 * Call this after calling start_notify, since the profiler callback might want
662 * to lock the thread, and the lock is held by thread_start () which waits for
665 mono_profiler_thread_start (tid);
667 /* if the name was set before starting, we didn't invoke the profiler callback */
668 if (internal->name) {
669 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
670 mono_profiler_thread_name (internal->tid, tname);
671 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
675 /* start_func is set only for unmanaged start functions */
677 start_func (start_func_arg);
681 g_assert (start_delegate != NULL);
683 /* we may want to handle the exception here. See comment below on unhandled exceptions */
684 args [0] = (gpointer) start_delegate_arg;
685 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
687 if (!mono_error_ok (&error)) {
688 MonoException *ex = mono_error_convert_to_exception (&error);
690 g_assert (ex != NULL);
691 MonoClass *klass = mono_object_get_class (&ex->object);
692 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
693 !is_threadabort_exception (klass)) {
694 mono_unhandled_exception (&ex->object);
695 mono_invoke_unhandled_exception_hook (&ex->object);
696 g_assert_not_reached ();
699 mono_error_cleanup (&error);
703 /* If the thread calls ExitThread at all, this remaining code
704 * will not be executed, but the main thread will eventually
705 * call mono_thread_detach_internal() on this thread's behalf.
708 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
710 /* Do any cleanup needed for apartment state. This
711 * cannot be done in mono_thread_detach_internal since
712 * mono_thread_detach_internal could be called for a
713 * thread other than the current thread.
714 * mono_thread_cleanup_apartment_state cleans up apartment
715 * for the current thead */
716 mono_thread_cleanup_apartment_state ();
718 mono_thread_detach_internal (internal);
725 static gsize WINAPI start_wrapper(void *data)
727 volatile gsize dummy;
729 return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
735 * Common thread creation code.
736 * LOCKING: Acquires the threads lock.
739 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
740 gboolean threadpool_thread, guint32 stack_size, MonoError *error)
742 StartInfo *start_info = NULL;
743 MonoThreadHandle *thread_handle;
744 MonoNativeThreadId tid;
746 gsize stack_set_size;
749 g_assert (!start_func && !start_func_arg);
751 g_assert (!start_delegate);
754 * Join joinable threads to prevent running out of threads since the finalizer
755 * thread might be blocked/backlogged.
757 mono_threads_join_threads ();
759 mono_error_init (error);
761 mono_threads_lock ();
763 mono_threads_unlock ();
766 if (threads_starting_up == NULL) {
767 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
768 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
770 mono_g_hash_table_insert (threads_starting_up, thread, thread);
771 mono_threads_unlock ();
773 internal->threadpool_thread = threadpool_thread;
774 if (threadpool_thread)
775 mono_thread_set_state (internal, ThreadState_Background);
777 start_info = g_new0 (StartInfo, 1);
779 start_info->thread = thread;
780 start_info->start_delegate = start_delegate;
781 start_info->start_delegate_arg = thread->start_obj;
782 start_info->start_func = start_func;
783 start_info->start_func_arg = start_func_arg;
784 start_info->failed = FALSE;
785 mono_coop_sem_init (&start_info->registered, 0);
788 stack_set_size = default_stacksize_for_thread (internal);
792 thread_handle = mono_threads_create_thread (start_wrapper, start_info, &stack_set_size, &tid);
794 if (thread_handle == NULL) {
795 /* The thread couldn't be created, so set an exception */
796 mono_threads_lock ();
797 mono_g_hash_table_remove (threads_starting_up, thread);
798 mono_threads_unlock ();
799 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
800 /* ref is not going to be decremented in start_wrapper_internal */
801 InterlockedDecrement (&start_info->ref);
806 internal->stack_size = (int) stack_set_size;
808 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
811 * Wait for the thread to set up its TLS data etc, so
812 * theres no potential race condition if someone tries
813 * to look up the data believing the thread has
817 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
819 mono_threads_close_thread_handle (thread_handle);
821 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));
823 ret = !start_info->failed;
826 if (InterlockedDecrement (&start_info->ref) == 0) {
827 mono_coop_sem_destroy (&start_info->registered);
834 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
836 if (mono_thread_start_cb) {
837 mono_thread_start_cb (tid, stack_start, func);
841 void mono_threads_set_default_stacksize (guint32 stacksize)
843 default_stacksize = stacksize;
846 guint32 mono_threads_get_default_stacksize (void)
848 return default_stacksize;
852 * mono_thread_create_internal:
854 * ARG should not be a GC reference.
857 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
860 MonoInternalThread *internal;
863 mono_error_init (error);
865 internal = create_internal_thread_object ();
867 thread = create_thread_object (domain, internal);
869 LOCK_THREAD (internal);
871 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
872 return_val_if_nok (error, NULL);
874 UNLOCK_THREAD (internal);
880 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
883 if (!mono_thread_create_checked (domain, func, arg, &error))
884 mono_error_cleanup (&error);
888 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
890 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
894 mono_thread_attach (MonoDomain *domain)
896 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
902 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
904 MonoInternalThread *internal;
906 MonoNativeThreadId tid;
909 if (mono_thread_internal_current_is_attached ()) {
910 if (domain != mono_domain_get ())
911 mono_domain_set (domain, TRUE);
912 /* Already attached */
913 return mono_thread_current ();
916 if (!mono_gc_register_thread (&domain)) {
917 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 ());
920 tid=mono_native_thread_id_get ();
922 internal = create_internal_thread_object ();
924 thread = create_thread_object (domain, internal);
926 if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
927 /* Mono is shutting down, so just wait for the end */
929 mono_thread_info_sleep (10000, NULL);
932 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
934 if (mono_thread_attach_cb) {
938 mono_thread_info_get_stack_bounds (&staddr, &stsize);
941 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
943 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
946 /* Can happen when we attach the profiler helper thread in order to heapshot. */
947 if (!mono_thread_info_current ()->tools_thread)
948 // FIXME: Need a separate callback
949 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
955 mono_thread_detach_internal (MonoInternalThread *thread)
959 g_assert (thread != NULL);
961 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
964 mono_w32mutex_abandon ();
967 if (thread->abort_state_handle) {
968 mono_gchandle_free (thread->abort_state_handle);
969 thread->abort_state_handle = 0;
972 thread->abort_exc = NULL;
973 thread->current_appcontext = NULL;
976 * This is necessary because otherwise we might have
977 * cross-domain references which will not get cleaned up when
978 * the target domain is unloaded.
980 if (thread->cached_culture_info) {
982 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
983 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
987 * thread->synch_cs can be NULL if this was called after
988 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
989 * This can happen only during shutdown.
990 * The shutting_down flag is not always set, so we can't assert on it.
992 if (thread->synch_cs)
993 LOCK_THREAD (thread);
995 thread->state |= ThreadState_Stopped;
996 thread->state &= ~ThreadState_Background;
998 if (thread->synch_cs)
999 UNLOCK_THREAD (thread);
1002 An interruption request has leaked to cleanup. Adjust the global counter.
1004 This can happen is the abort source thread finds the abortee (this) thread
1005 in unmanaged code. If this thread never trips back to managed code or check
1006 the local flag it will be left set and positively unbalance the global counter.
1008 Leaving the counter unbalanced will cause a performance degradation since all threads
1009 will now keep checking their local flags all the time.
1011 if (InterlockedExchange (&thread->interruption_requested, 0) != 0)
1012 InterlockedDecrement (&thread_interruption_requested);
1014 mono_threads_lock ();
1018 } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
1019 /* We have to check whether the thread object for the
1020 * tid is still the same in the table because the
1021 * thread might have been destroyed and the tid reused
1022 * in the meantime, in which case the tid would be in
1023 * the table, but with another thread object.
1027 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
1031 mono_threads_unlock ();
1033 /* Don't close the handle here, wait for the object finalizer
1034 * to do it. Otherwise, the following race condition applies:
1036 * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
1038 * 2) Some other handle is reassigned the same slot
1040 * 3) Another thread tries to join the first thread, and
1041 * blocks waiting for the reassigned handle to be signalled
1042 * (which might never happen). This is possible, because the
1043 * thread calling Join() still has a reference to the first
1047 /* if the thread is not in the hash it has been removed already */
1049 mono_domain_unset ();
1050 mono_memory_barrier ();
1052 if (mono_thread_cleanup_fn)
1053 mono_thread_cleanup_fn (thread_get_tid (thread));
1058 mono_release_type_locks (thread);
1060 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1061 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
1062 mono_profiler_thread_end (thread->tid);
1064 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1067 * This will signal async signal handlers that the thread has exited.
1068 * The profiler callback needs this to be set, so it cannot be done earlier.
1070 mono_domain_unset ();
1071 mono_memory_barrier ();
1073 if (thread == mono_thread_internal_current ())
1074 mono_thread_pop_appdomain_ref ();
1076 thread->cached_culture_info = NULL;
1078 mono_free_static_data (thread->static_data);
1079 thread->static_data = NULL;
1080 ref_stack_destroy (thread->appdomain_refs);
1081 thread->appdomain_refs = NULL;
1083 g_assert (thread->suspended);
1084 mono_os_event_destroy (thread->suspended);
1085 g_free (thread->suspended);
1086 thread->suspended = NULL;
1088 if (mono_thread_cleanup_fn)
1089 mono_thread_cleanup_fn (thread_get_tid (thread));
1091 mono_memory_barrier ();
1093 if (mono_gc_is_moving ()) {
1094 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
1095 thread->thread_pinning_ref = NULL;
1099 SET_CURRENT_OBJECT (NULL);
1100 mono_domain_unset ();
1102 /* Don't need to close the handle to this thread, even though we took a
1103 * reference in mono_thread_attach (), because the GC will do it
1104 * when the Thread object is finalised.
1109 mono_thread_detach (MonoThread *thread)
1112 mono_thread_detach_internal (thread->internal_thread);
1116 * mono_thread_detach_if_exiting:
1118 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1119 * This should be used at the end of embedding code which calls into managed code, and which
1120 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1123 mono_thread_detach_if_exiting (void)
1125 if (mono_thread_info_is_exiting ()) {
1126 MonoInternalThread *thread;
1128 thread = mono_thread_internal_current ();
1130 mono_thread_detach_internal (thread);
1131 mono_thread_info_detach ();
1139 mono_thread_internal_current_is_attached (void)
1141 MonoInternalThread *internal;
1143 internal = GET_CURRENT_OBJECT ();
1151 mono_thread_exit (void)
1153 MonoInternalThread *thread = mono_thread_internal_current ();
1155 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1157 mono_thread_detach_internal (thread);
1159 /* we could add a callback here for embedders to use. */
1160 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1161 exit (mono_environment_exitcode_get ());
1163 mono_thread_info_exit (0);
1167 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1169 MonoInternalThread *internal;
1171 internal = create_internal_thread_object ();
1173 internal->state = ThreadState_Unstarted;
1175 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1179 ves_icall_System_Threading_Thread_GetCurrentThread (void)
1181 return mono_thread_current ();
1185 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1189 MonoInternalThread *internal;
1192 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1194 if (!this_obj->internal_thread)
1195 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1196 internal = this_obj->internal_thread;
1198 LOCK_THREAD (internal);
1200 if ((internal->state & ThreadState_Unstarted) == 0) {
1201 UNLOCK_THREAD (internal);
1202 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1206 if ((internal->state & ThreadState_Aborted) != 0) {
1207 UNLOCK_THREAD (internal);
1211 res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1213 mono_error_cleanup (&error);
1214 UNLOCK_THREAD (internal);
1218 internal->state &= ~ThreadState_Unstarted;
1220 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1222 UNLOCK_THREAD (internal);
1223 return internal->handle;
1227 * This is called from the finalizer of the internal thread object.
1230 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj)
1232 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle));
1235 * Since threads keep a reference to their thread object while running, by
1236 * the time this function is called, the thread has already exited/detached,
1237 * i.e. mono_thread_detach_internal () has ran. The exception is during
1238 * shutdown, when mono_thread_detach_internal () can be called after this.
1240 if (this_obj->handle) {
1241 mono_threads_close_thread_handle (this_obj->handle);
1242 this_obj->handle = NULL;
1246 CloseHandle (this_obj->native_handle);
1249 if (this_obj->synch_cs) {
1250 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1251 this_obj->synch_cs = NULL;
1252 mono_coop_mutex_destroy (synch_cs);
1256 if (this_obj->name) {
1257 void *name = this_obj->name;
1258 this_obj->name = NULL;
1264 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1267 MonoInternalThread *thread = mono_thread_internal_current ();
1269 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1271 if (mono_thread_current_check_pending_interrupt ())
1275 gboolean alerted = FALSE;
1277 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1279 res = mono_thread_info_sleep (ms, &alerted);
1281 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1284 MonoException* exc = mono_thread_execute_interruption ();
1286 mono_raise_exception (exc);
1288 // FIXME: !MONO_INFINITE_WAIT
1289 if (ms != MONO_INFINITE_WAIT)
1298 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1303 ves_icall_System_Threading_Thread_GetDomainID (void)
1305 return mono_domain_get()->domain_id;
1309 ves_icall_System_Threading_Thread_Yield (void)
1311 return mono_thread_info_yield ();
1315 * mono_thread_get_name:
1317 * Return the name of the thread. NAME_LEN is set to the length of the name.
1318 * Return NULL if the thread has no name. The returned memory is owned by the
1322 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1326 LOCK_THREAD (this_obj);
1328 if (!this_obj->name) {
1332 *name_len = this_obj->name_len;
1333 res = g_new (gunichar2, this_obj->name_len);
1334 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1337 UNLOCK_THREAD (this_obj);
1343 * mono_thread_get_name_utf8:
1345 * Return the name of the thread in UTF-8.
1346 * Return NULL if the thread has no name.
1347 * The returned memory is owned by the caller.
1350 mono_thread_get_name_utf8 (MonoThread *thread)
1355 MonoInternalThread *internal = thread->internal_thread;
1356 if (internal == NULL)
1359 LOCK_THREAD (internal);
1361 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1363 UNLOCK_THREAD (internal);
1369 * mono_thread_get_managed_id:
1371 * Return the Thread.ManagedThreadId value of `thread`.
1372 * Returns -1 if `thread` is NULL.
1375 mono_thread_get_managed_id (MonoThread *thread)
1380 MonoInternalThread *internal = thread->internal_thread;
1381 if (internal == NULL)
1384 int32_t id = internal->managed_id;
1390 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1395 mono_error_init (&error);
1397 LOCK_THREAD (this_obj);
1399 if (!this_obj->name)
1402 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1404 UNLOCK_THREAD (this_obj);
1406 if (mono_error_set_pending_exception (&error))
1413 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1415 LOCK_THREAD (this_obj);
1417 mono_error_init (error);
1419 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1420 UNLOCK_THREAD (this_obj);
1422 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1425 if (this_obj->name) {
1426 g_free (this_obj->name);
1427 this_obj->name_len = 0;
1430 this_obj->name = g_new (gunichar2, mono_string_length (name));
1431 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1432 this_obj->name_len = mono_string_length (name);
1435 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1438 this_obj->name = NULL;
1441 UNLOCK_THREAD (this_obj);
1443 if (this_obj->name && this_obj->tid) {
1444 char *tname = mono_string_to_utf8_checked (name, error);
1445 return_if_nok (error);
1446 mono_profiler_thread_name (this_obj->tid, tname);
1447 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1453 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1456 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1457 mono_error_set_pending_exception (&error);
1461 * ves_icall_System_Threading_Thread_GetPriority_internal:
1462 * @param this_obj: The MonoInternalThread on which to operate.
1464 * Gets the priority of the given thread.
1465 * @return: The priority of the given thread.
1468 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1471 MonoInternalThread *internal = this_obj->internal_thread;
1473 LOCK_THREAD (internal);
1474 priority = internal->priority;
1475 UNLOCK_THREAD (internal);
1481 * ves_icall_System_Threading_Thread_SetPriority_internal:
1482 * @param this_obj: The MonoInternalThread on which to operate.
1483 * @param priority: The priority to set.
1485 * Sets the priority of the given thread.
1488 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1490 MonoInternalThread *internal = this_obj->internal_thread;
1492 LOCK_THREAD (internal);
1493 internal->priority = priority;
1494 if (internal->thread_info != NULL)
1495 mono_thread_internal_set_priority (internal, priority);
1496 UNLOCK_THREAD (internal);
1499 /* If the array is already in the requested domain, we just return it,
1500 otherwise we return a copy in that domain. */
1502 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1506 mono_error_init (error);
1510 if (mono_object_domain (arr) == domain)
1513 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1514 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1519 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1522 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1523 mono_error_set_pending_exception (&error);
1528 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1531 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1532 mono_error_set_pending_exception (&error);
1537 mono_thread_current (void)
1539 MonoDomain *domain = mono_domain_get ();
1540 MonoInternalThread *internal = mono_thread_internal_current ();
1541 MonoThread **current_thread_ptr;
1543 g_assert (internal);
1544 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1546 if (!*current_thread_ptr) {
1547 g_assert (domain != mono_get_root_domain ());
1548 *current_thread_ptr = create_thread_object (domain, internal);
1550 return *current_thread_ptr;
1553 /* Return the thread object belonging to INTERNAL in the current domain */
1555 mono_thread_current_for_thread (MonoInternalThread *internal)
1557 MonoDomain *domain = mono_domain_get ();
1558 MonoThread **current_thread_ptr;
1560 g_assert (internal);
1561 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1563 if (!*current_thread_ptr) {
1564 g_assert (domain != mono_get_root_domain ());
1565 *current_thread_ptr = create_thread_object (domain, internal);
1567 return *current_thread_ptr;
1571 mono_thread_internal_current (void)
1573 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1574 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1578 static MonoThreadInfoWaitRet
1579 mono_join_uninterrupted (MonoThreadHandle* thread_to_join, gint32 ms, MonoError *error)
1582 MonoThreadInfoWaitRet ret;
1587 mono_error_init (error);
1589 start = (ms == -1) ? 0 : mono_msec_ticks ();
1592 ret = mono_thread_info_wait_one_handle (thread_to_join, ms, TRUE);
1595 if (ret != MONO_THREAD_INFO_WAIT_RET_ALERTED)
1598 exc = mono_thread_execute_interruption ();
1600 mono_error_set_exception_instance (error, exc);
1607 /* Re-calculate ms according to the time passed */
1608 diff_ms = (gint32)(mono_msec_ticks () - start);
1609 if (diff_ms >= ms) {
1610 ret = MONO_THREAD_INFO_WAIT_RET_TIMEOUT;
1613 wait = ms - diff_ms;
1620 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1622 MonoInternalThread *thread = this_obj->internal_thread;
1623 MonoThreadHandle *handle = thread->handle;
1624 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1628 if (mono_thread_current_check_pending_interrupt ())
1631 LOCK_THREAD (thread);
1633 if ((thread->state & ThreadState_Unstarted) != 0) {
1634 UNLOCK_THREAD (thread);
1636 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1640 UNLOCK_THREAD (thread);
1643 ms=MONO_INFINITE_WAIT;
1645 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1647 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1649 ret=mono_join_uninterrupted (handle, ms, &error);
1651 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1653 mono_error_set_pending_exception (&error);
1655 if(ret==MONO_THREAD_INFO_WAIT_RET_SUCCESS_0) {
1656 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1661 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1666 #define MANAGED_WAIT_FAILED 0x7fffffff
1669 map_native_wait_result_to_managed (MonoW32HandleWaitRet val, gsize numobjects)
1671 if (val >= MONO_W32HANDLE_WAIT_RET_SUCCESS_0 && val < MONO_W32HANDLE_WAIT_RET_SUCCESS_0 + numobjects) {
1672 return WAIT_OBJECT_0 + (val - MONO_W32HANDLE_WAIT_RET_SUCCESS_0);
1673 } else if (val >= MONO_W32HANDLE_WAIT_RET_ABANDONED_0 && val < MONO_W32HANDLE_WAIT_RET_ABANDONED_0 + numobjects) {
1674 return WAIT_ABANDONED_0 + (val - MONO_W32HANDLE_WAIT_RET_ABANDONED_0);
1675 } else if (val == MONO_W32HANDLE_WAIT_RET_ALERTED) {
1676 return WAIT_IO_COMPLETION;
1677 } else if (val == MONO_W32HANDLE_WAIT_RET_TIMEOUT) {
1678 return WAIT_TIMEOUT;
1679 } else if (val == MONO_W32HANDLE_WAIT_RET_FAILED) {
1680 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1681 return MANAGED_WAIT_FAILED;
1683 g_error ("%s: unknown val value %d", __func__, val);
1687 static MonoW32HandleWaitRet
1688 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1691 MonoW32HandleWaitRet ret;
1696 mono_error_init (error);
1698 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1702 if (numhandles != 1)
1703 ret = mono_w32handle_convert_wait_ret (WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE), numhandles);
1705 ret = mono_w32handle_convert_wait_ret (WaitForSingleObjectEx (handles [0], ms, TRUE), 1);
1707 /* mono_w32handle_wait_multiple optimizes the case for numhandles == 1 */
1708 ret = mono_w32handle_wait_multiple (handles, numhandles, waitall, wait, TRUE);
1709 #endif /* HOST_WIN32 */
1712 if (ret != MONO_W32HANDLE_WAIT_RET_ALERTED)
1715 exc = mono_thread_execute_interruption ();
1717 mono_error_set_exception_instance (error, exc);
1724 /* Re-calculate ms according to the time passed */
1725 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1726 if (diff_ms >= ms) {
1727 ret = MONO_W32HANDLE_WAIT_RET_TIMEOUT;
1730 wait = ms - diff_ms;
1736 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1741 MonoW32HandleWaitRet ret;
1743 MonoObject *waitHandle;
1744 MonoInternalThread *thread = mono_thread_internal_current ();
1746 /* Do this WaitSleepJoin check before creating objects */
1747 if (mono_thread_current_check_pending_interrupt ())
1748 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1750 /* We fail in managed if the array has more than 64 elements */
1751 numhandles = (guint32)mono_array_length(mono_handles);
1752 handles = g_new0(HANDLE, numhandles);
1754 for(i = 0; i < numhandles; i++) {
1755 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1756 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1760 ms=MONO_INFINITE_WAIT;
1763 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1765 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1767 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1771 mono_error_set_pending_exception (&error);
1773 return map_native_wait_result_to_managed (ret, numhandles);
1776 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1779 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1780 uintptr_t numhandles;
1781 MonoW32HandleWaitRet ret;
1783 MonoObject *waitHandle;
1784 MonoInternalThread *thread = mono_thread_internal_current ();
1786 /* Do this WaitSleepJoin check before creating objects */
1787 if (mono_thread_current_check_pending_interrupt ())
1788 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1790 numhandles = mono_array_length(mono_handles);
1791 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1792 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1794 for(i = 0; i < numhandles; i++) {
1795 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1796 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1800 ms=MONO_INFINITE_WAIT;
1803 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1805 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1807 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1809 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1811 mono_error_set_pending_exception (&error);
1813 return map_native_wait_result_to_managed (ret, numhandles);
1816 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1819 MonoW32HandleWaitRet ret;
1820 MonoInternalThread *thread = mono_thread_internal_current ();
1822 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1825 ms=MONO_INFINITE_WAIT;
1828 if (mono_thread_current_check_pending_interrupt ())
1829 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1831 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1833 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1835 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1837 mono_error_set_pending_exception (&error);
1838 return map_native_wait_result_to_managed (ret, 1);
1842 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1844 MonoW32HandleWaitRet ret;
1845 MonoInternalThread *thread = mono_thread_internal_current ();
1848 ms = MONO_INFINITE_WAIT;
1850 if (mono_thread_current_check_pending_interrupt ())
1851 return map_native_wait_result_to_managed (MONO_W32HANDLE_WAIT_RET_FAILED, 0);
1853 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1857 ret = mono_w32handle_convert_wait_ret (SignalObjectAndWait (toSignal, toWait, ms, TRUE), 1);
1859 ret = mono_w32handle_signal_and_wait (toSignal, toWait, ms, TRUE);
1863 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1865 return map_native_wait_result_to_managed (ret, 1);
1868 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1870 return InterlockedIncrement (location);
1873 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1875 #if SIZEOF_VOID_P == 4
1876 if (G_UNLIKELY ((size_t)location & 0x7)) {
1878 mono_interlocked_lock ();
1881 mono_interlocked_unlock ();
1885 return InterlockedIncrement64 (location);
1888 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1890 return InterlockedDecrement(location);
1893 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1895 #if SIZEOF_VOID_P == 4
1896 if (G_UNLIKELY ((size_t)location & 0x7)) {
1898 mono_interlocked_lock ();
1901 mono_interlocked_unlock ();
1905 return InterlockedDecrement64 (location);
1908 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1910 return InterlockedExchange(location, value);
1913 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1916 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1917 mono_gc_wbarrier_generic_nostore (location);
1921 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1923 return InterlockedExchangePointer(location, value);
1926 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1928 IntFloatUnion val, ret;
1931 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1937 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1939 #if SIZEOF_VOID_P == 4
1940 if (G_UNLIKELY ((size_t)location & 0x7)) {
1942 mono_interlocked_lock ();
1945 mono_interlocked_unlock ();
1949 return InterlockedExchange64 (location, value);
1953 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1955 LongDoubleUnion val, ret;
1958 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1963 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1965 return InterlockedCompareExchange(location, value, comparand);
1968 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1970 gint32 r = InterlockedCompareExchange(location, value, comparand);
1971 *success = r == comparand;
1975 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1978 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1979 mono_gc_wbarrier_generic_nostore (location);
1983 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1985 return InterlockedCompareExchangePointer(location, value, comparand);
1988 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1990 IntFloatUnion val, ret, cmp;
1993 cmp.fval = comparand;
1994 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2000 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2002 #if SIZEOF_VOID_P == 8
2003 LongDoubleUnion val, comp, ret;
2006 comp.fval = comparand;
2007 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2013 mono_interlocked_lock ();
2015 if (old == comparand)
2017 mono_interlocked_unlock ();
2024 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2026 #if SIZEOF_VOID_P == 4
2027 if (G_UNLIKELY ((size_t)location & 0x7)) {
2029 mono_interlocked_lock ();
2031 if (old == comparand)
2033 mono_interlocked_unlock ();
2037 return InterlockedCompareExchange64 (location, value, comparand);
2041 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2044 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2045 mono_gc_wbarrier_generic_nostore (location);
2050 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2053 MONO_CHECK_NULL (location, NULL);
2054 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2055 mono_gc_wbarrier_generic_nostore (location);
2060 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2062 return InterlockedAdd (location, value);
2066 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2068 #if SIZEOF_VOID_P == 4
2069 if (G_UNLIKELY ((size_t)location & 0x7)) {
2071 mono_interlocked_lock ();
2074 mono_interlocked_unlock ();
2078 return InterlockedAdd64 (location, value);
2082 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2084 #if SIZEOF_VOID_P == 4
2085 if (G_UNLIKELY ((size_t)location & 0x7)) {
2087 mono_interlocked_lock ();
2089 mono_interlocked_unlock ();
2093 return InterlockedRead64 (location);
2097 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2099 mono_memory_barrier ();
2103 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2105 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2107 if (state & ThreadState_Background) {
2108 /* If the thread changes the background mode, the main thread has to
2109 * be notified, since it has to rebuild the list of threads to
2112 mono_os_event_set (&background_change_event);
2117 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2119 mono_thread_set_state (this_obj, (MonoThreadState)state);
2121 if (state & ThreadState_Background) {
2122 /* If the thread changes the background mode, the main thread has to
2123 * be notified, since it has to rebuild the list of threads to
2126 mono_os_event_set (&background_change_event);
2131 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2135 LOCK_THREAD (this_obj);
2137 state = this_obj->state;
2139 UNLOCK_THREAD (this_obj);
2144 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2146 MonoInternalThread *current;
2148 MonoInternalThread *thread = this_obj->internal_thread;
2150 LOCK_THREAD (thread);
2152 current = mono_thread_internal_current ();
2154 thread->thread_interrupt_requested = TRUE;
2155 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2157 UNLOCK_THREAD (thread);
2160 async_abort_internal (thread, FALSE);
2165 * mono_thread_current_check_pending_interrupt:
2167 * Checks if there's a interruption request and set the pending exception if so.
2169 * @returns true if a pending exception was set
2172 mono_thread_current_check_pending_interrupt (void)
2174 MonoInternalThread *thread = mono_thread_internal_current ();
2175 gboolean throw_ = FALSE;
2177 LOCK_THREAD (thread);
2179 if (thread->thread_interrupt_requested) {
2181 thread->thread_interrupt_requested = FALSE;
2184 UNLOCK_THREAD (thread);
2187 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2192 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2194 LOCK_THREAD (thread);
2196 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2197 (thread->state & ThreadState_StopRequested) != 0 ||
2198 (thread->state & ThreadState_Stopped) != 0)
2200 UNLOCK_THREAD (thread);
2204 if ((thread->state & ThreadState_Unstarted) != 0) {
2205 thread->state |= ThreadState_Aborted;
2206 UNLOCK_THREAD (thread);
2210 thread->state |= ThreadState_AbortRequested;
2211 if (thread->abort_state_handle)
2212 mono_gchandle_free (thread->abort_state_handle);
2214 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2215 g_assert (thread->abort_state_handle);
2217 thread->abort_state_handle = 0;
2219 thread->abort_exc = NULL;
2221 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));
2223 /* During shutdown, we can't wait for other threads */
2225 /* Make sure the thread is awake */
2226 mono_thread_resume (thread);
2228 UNLOCK_THREAD (thread);
2233 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2235 if (!request_thread_abort (thread, state))
2238 if (thread == mono_thread_internal_current ()) {
2240 self_abort_internal (&error);
2241 mono_error_set_pending_exception (&error);
2243 async_abort_internal (thread, TRUE);
2248 * mono_thread_internal_abort:
2250 * Request thread @thread to be aborted.
2252 * @thread MUST NOT be the current thread.
2255 mono_thread_internal_abort (MonoInternalThread *thread)
2257 g_assert (thread != mono_thread_internal_current ());
2259 if (!request_thread_abort (thread, NULL))
2261 async_abort_internal (thread, TRUE);
2265 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2267 MonoInternalThread *thread = mono_thread_internal_current ();
2268 gboolean was_aborting;
2270 LOCK_THREAD (thread);
2271 was_aborting = thread->state & ThreadState_AbortRequested;
2272 thread->state &= ~ThreadState_AbortRequested;
2273 UNLOCK_THREAD (thread);
2275 if (!was_aborting) {
2276 const char *msg = "Unable to reset abort because no abort was requested";
2277 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2281 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2282 thread->abort_exc = NULL;
2283 if (thread->abort_state_handle) {
2284 mono_gchandle_free (thread->abort_state_handle);
2285 /* This is actually not necessary - the handle
2286 only counts if the exception is set */
2287 thread->abort_state_handle = 0;
2292 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2294 LOCK_THREAD (thread);
2296 thread->state &= ~ThreadState_AbortRequested;
2298 if (thread->abort_exc) {
2299 mono_get_eh_callbacks ()->mono_clear_abort_threshold ();
2300 thread->abort_exc = NULL;
2301 if (thread->abort_state_handle) {
2302 mono_gchandle_free (thread->abort_state_handle);
2303 /* This is actually not necessary - the handle
2304 only counts if the exception is set */
2305 thread->abort_state_handle = 0;
2309 UNLOCK_THREAD (thread);
2313 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2316 MonoInternalThread *thread = this_obj->internal_thread;
2317 MonoObject *state, *deserialized = NULL;
2320 if (!thread->abort_state_handle)
2323 state = mono_gchandle_get_target (thread->abort_state_handle);
2326 domain = mono_domain_get ();
2327 if (mono_object_domain (state) == domain)
2330 deserialized = mono_object_xdomain_representation (state, domain, &error);
2332 if (!deserialized) {
2333 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2334 if (!is_ok (&error)) {
2335 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2336 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2338 mono_set_pending_exception (invalid_op_exc);
2342 return deserialized;
2346 mono_thread_suspend (MonoInternalThread *thread)
2348 LOCK_THREAD (thread);
2350 if ((thread->state & ThreadState_Unstarted) != 0 ||
2351 (thread->state & ThreadState_Aborted) != 0 ||
2352 (thread->state & ThreadState_Stopped) != 0)
2354 UNLOCK_THREAD (thread);
2358 if ((thread->state & ThreadState_Suspended) != 0 ||
2359 (thread->state & ThreadState_SuspendRequested) != 0 ||
2360 (thread->state & ThreadState_StopRequested) != 0)
2362 UNLOCK_THREAD (thread);
2366 thread->state |= ThreadState_SuspendRequested;
2367 mono_os_event_reset (thread->suspended);
2369 if (thread == mono_thread_internal_current ()) {
2370 /* calls UNLOCK_THREAD (thread) */
2371 self_suspend_internal ();
2373 /* calls UNLOCK_THREAD (thread) */
2374 async_suspend_internal (thread, FALSE);
2381 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2383 if (!mono_thread_suspend (this_obj->internal_thread)) {
2384 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2389 /* LOCKING: LOCK_THREAD(thread) must be held */
2391 mono_thread_resume (MonoInternalThread *thread)
2393 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2394 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (1) thread %p\n", thread_get_tid (thread));
2395 thread->state &= ~ThreadState_SuspendRequested;
2396 mono_os_event_set (thread->suspended);
2400 if ((thread->state & ThreadState_Suspended) == 0 ||
2401 (thread->state & ThreadState_Unstarted) != 0 ||
2402 (thread->state & ThreadState_Aborted) != 0 ||
2403 (thread->state & ThreadState_Stopped) != 0)
2405 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (2) thread %p\n", thread_get_tid (thread));
2409 // MOSTLY_ASYNC_SAFE_PRINTF ("RESUME (3) thread %p\n", thread_get_tid (thread));
2411 mono_os_event_set (thread->suspended);
2413 if (!thread->self_suspended) {
2414 UNLOCK_THREAD (thread);
2416 /* Awake the thread */
2417 if (!mono_thread_info_resume (thread_get_tid (thread)))
2420 LOCK_THREAD (thread);
2423 thread->state &= ~ThreadState_Suspended;
2429 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2431 if (!thread->internal_thread) {
2432 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2434 LOCK_THREAD (thread->internal_thread);
2435 if (!mono_thread_resume (thread->internal_thread))
2436 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2437 UNLOCK_THREAD (thread->internal_thread);
2442 mono_threads_is_critical_method (MonoMethod *method)
2444 switch (method->wrapper_type) {
2445 case MONO_WRAPPER_RUNTIME_INVOKE:
2446 case MONO_WRAPPER_XDOMAIN_INVOKE:
2447 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2454 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2459 if (mono_threads_is_critical_method (m)) {
2460 *((gboolean*)data) = TRUE;
2467 is_running_protected_wrapper (void)
2469 gboolean found = FALSE;
2470 mono_stack_walk (find_wrapper, &found);
2475 request_thread_stop (MonoInternalThread *thread)
2477 LOCK_THREAD (thread);
2479 if ((thread->state & ThreadState_StopRequested) != 0 ||
2480 (thread->state & ThreadState_Stopped) != 0)
2482 UNLOCK_THREAD (thread);
2486 /* Make sure the thread is awake */
2487 mono_thread_resume (thread);
2489 thread->state |= ThreadState_StopRequested;
2490 thread->state &= ~ThreadState_AbortRequested;
2492 UNLOCK_THREAD (thread);
2497 * mono_thread_internal_stop:
2499 * Request thread @thread to stop.
2501 * @thread MUST NOT be the current thread.
2504 mono_thread_internal_stop (MonoInternalThread *thread)
2506 g_assert (thread != mono_thread_internal_current ());
2508 if (!request_thread_stop (thread))
2511 async_abort_internal (thread, TRUE);
2514 void mono_thread_stop (MonoThread *thread)
2516 MonoInternalThread *internal = thread->internal_thread;
2518 if (!request_thread_stop (internal))
2521 if (internal == mono_thread_internal_current ()) {
2523 self_abort_internal (&error);
2525 This function is part of the embeding API and has no way to return the exception
2526 to be thrown. So what we do is keep the old behavior and raise the exception.
2528 mono_error_raise_exception (&error); /* OK to throw, see note */
2530 async_abort_internal (internal, TRUE);
2535 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2537 gint8 tmp = *(volatile gint8 *)ptr;
2538 mono_memory_barrier ();
2543 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2545 gint16 tmp = *(volatile gint16 *)ptr;
2546 mono_memory_barrier ();
2551 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2553 gint32 tmp = *(volatile gint32 *)ptr;
2554 mono_memory_barrier ();
2559 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2561 gint64 tmp = *(volatile gint64 *)ptr;
2562 mono_memory_barrier ();
2567 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2569 volatile void *tmp = *(volatile void **)ptr;
2570 mono_memory_barrier ();
2571 return (void *) tmp;
2575 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2577 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2578 mono_memory_barrier ();
2579 return (MonoObject *) tmp;
2583 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2585 double tmp = *(volatile double *)ptr;
2586 mono_memory_barrier ();
2591 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2593 float tmp = *(volatile float *)ptr;
2594 mono_memory_barrier ();
2599 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2601 return InterlockedRead8 ((volatile gint8 *)ptr);
2605 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2607 return InterlockedRead16 ((volatile gint16 *)ptr);
2611 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2613 return InterlockedRead ((volatile gint32 *)ptr);
2617 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2619 #if SIZEOF_VOID_P == 4
2620 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2622 mono_interlocked_lock ();
2623 val = *(gint64*)ptr;
2624 mono_interlocked_unlock ();
2628 return InterlockedRead64 ((volatile gint64 *)ptr);
2632 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2634 return InterlockedReadPointer ((volatile gpointer *)ptr);
2638 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2642 #if SIZEOF_VOID_P == 4
2643 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2645 mono_interlocked_lock ();
2646 val = *(double*)ptr;
2647 mono_interlocked_unlock ();
2652 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2658 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2662 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2668 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2670 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2674 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2676 mono_memory_barrier ();
2677 *(volatile gint8 *)ptr = value;
2681 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2683 mono_memory_barrier ();
2684 *(volatile gint16 *)ptr = value;
2688 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2690 mono_memory_barrier ();
2691 *(volatile gint32 *)ptr = value;
2695 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2697 mono_memory_barrier ();
2698 *(volatile gint64 *)ptr = value;
2702 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2704 mono_memory_barrier ();
2705 *(volatile void **)ptr = value;
2709 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2711 mono_memory_barrier ();
2712 mono_gc_wbarrier_generic_store (ptr, value);
2716 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2718 mono_memory_barrier ();
2719 *(volatile double *)ptr = value;
2723 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2725 mono_memory_barrier ();
2726 *(volatile float *)ptr = value;
2730 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2732 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2736 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2738 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2742 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2744 InterlockedWrite ((volatile gint32 *)ptr, value);
2748 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2750 #if SIZEOF_VOID_P == 4
2751 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2752 mono_interlocked_lock ();
2753 *(gint64*)ptr = value;
2754 mono_interlocked_unlock ();
2759 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2763 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2765 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2769 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2773 #if SIZEOF_VOID_P == 4
2774 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2775 mono_interlocked_lock ();
2776 *(double*)ptr = value;
2777 mono_interlocked_unlock ();
2784 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2788 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2794 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2798 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2800 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2804 free_context (void *user_data)
2806 ContextStaticData *data = user_data;
2808 mono_threads_lock ();
2811 * There is no guarantee that, by the point this reference queue callback
2812 * has been invoked, the GC handle associated with the object will fail to
2813 * resolve as one might expect. So if we don't free and remove the GC
2814 * handle here, free_context_static_data_helper () could end up resolving
2815 * a GC handle to an actually-dead context which would contain a pointer
2816 * to an already-freed static data segment, resulting in a crash when
2819 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2821 mono_threads_unlock ();
2823 mono_gchandle_free (data->gc_handle);
2824 mono_free_static_data (data->static_data);
2829 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2831 mono_threads_lock ();
2833 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2836 contexts = g_hash_table_new (NULL, NULL);
2839 context_queue = mono_gc_reference_queue_new (free_context);
2841 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2842 g_hash_table_insert (contexts, gch, gch);
2845 * We use this intermediate structure to contain a duplicate pointer to
2846 * the static data because we can't rely on being able to resolve the GC
2847 * handle in the reference queue callback.
2849 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2850 data->gc_handle = GPOINTER_TO_UINT (gch);
2853 context_adjust_static_data (ctx);
2854 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2856 mono_threads_unlock ();
2858 mono_profiler_context_loaded (ctx);
2862 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2865 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2866 * cleanup in exceptional circumstances, we don't actually do any
2867 * cleanup work here. We instead do this via a reference queue.
2870 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2872 mono_profiler_context_unloaded (ctx);
2875 void mono_thread_init (MonoThreadStartCB start_cb,
2876 MonoThreadAttachCB attach_cb)
2878 mono_coop_mutex_init_recursive (&threads_mutex);
2880 mono_os_mutex_init_recursive(&interlocked_mutex);
2881 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2883 mono_os_event_init (&background_change_event, FALSE);
2885 mono_init_static_data_info (&thread_static_info);
2886 mono_init_static_data_info (&context_static_info);
2888 mono_thread_start_cb = start_cb;
2889 mono_thread_attach_cb = attach_cb;
2892 void mono_thread_cleanup (void)
2894 #if !defined(RUN_IN_SUBTHREAD) && !defined(HOST_WIN32)
2895 /* The main thread must abandon any held mutexes (particularly
2896 * important for named mutexes as they are shared across
2897 * processes, see bug 74680.) This will happen when the
2898 * thread exits, but if it's not running in a subthread it
2899 * won't exit in time.
2901 mono_w32mutex_abandon ();
2905 /* This stuff needs more testing, it seems one of these
2906 * critical sections can be locked when mono_thread_cleanup is
2909 mono_coop_mutex_destroy (&threads_mutex);
2910 mono_os_mutex_destroy (&interlocked_mutex);
2911 mono_os_mutex_destroy (&delayed_free_table_mutex);
2912 mono_os_mutex_destroy (&small_id_mutex);
2913 mono_os_event_destroy (&background_change_event);
2918 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2920 mono_thread_cleanup_fn = func;
2924 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2926 thread->internal_thread->manage_callback = func;
2930 static void print_tids (gpointer key, gpointer value, gpointer user)
2932 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2933 * sizeof(uint) and a cast to uint would overflow
2935 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2936 * print this as a pointer.
2938 g_message ("Waiting for: %p", key);
2943 MonoThreadHandle *handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2944 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2949 wait_for_tids (struct wait_data *wait, guint32 timeout, gboolean check_state_change)
2952 MonoThreadInfoWaitRet ret;
2954 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2956 /* Add the thread state change event, so it wakes
2957 * up if a thread changes to background mode. */
2960 if (check_state_change)
2961 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, &background_change_event, FALSE, timeout, TRUE);
2963 ret = mono_thread_info_wait_multiple_handle (wait->handles, wait->num, NULL, TRUE, timeout, TRUE);
2966 if (ret == MONO_THREAD_INFO_WAIT_RET_FAILED) {
2967 /* See the comment in build_wait_tids() */
2968 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2972 for( i = 0; i < wait->num; i++)
2973 mono_threads_close_thread_handle (wait->handles [i]);
2975 if (ret == MONO_THREAD_INFO_WAIT_RET_TIMEOUT)
2978 if (ret < wait->num) {
2979 MonoInternalThread *internal;
2981 internal = wait->threads [ret];
2983 mono_threads_lock ();
2984 if (mono_g_hash_table_lookup (threads, (gpointer) internal->tid) == internal)
2985 g_error ("%s: failed to call mono_thread_detach_internal on thread %p, InternalThread: %p", __func__, internal->tid, internal);
2986 mono_threads_unlock ();
2990 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2992 struct wait_data *wait=(struct wait_data *)user;
2994 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS - 1) {
2995 MonoInternalThread *thread=(MonoInternalThread *)value;
2997 /* Ignore background threads, we abort them later */
2998 /* Do not lock here since it is not needed and the caller holds threads_lock */
2999 if (thread->state & ThreadState_Background) {
3000 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3001 return; /* just leave, ignore */
3004 if (mono_gc_is_finalizer_internal_thread (thread)) {
3005 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3009 if (thread == mono_thread_internal_current ()) {
3010 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3014 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3015 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3019 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3020 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3024 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3025 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3026 wait->handles[wait->num]=mono_threads_open_thread_handle (thread->handle);
3027 wait->threads[wait->num]=thread;
3030 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3032 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3037 /* Just ignore the rest, we can't do anything with
3044 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3046 struct wait_data *wait=(struct wait_data *)user;
3047 MonoNativeThreadId self = mono_native_thread_id_get ();
3048 MonoInternalThread *thread = (MonoInternalThread *)value;
3050 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3053 /* The finalizer thread is not a background thread */
3054 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3055 && (thread->state & ThreadState_Background) != 0
3056 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3058 wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
3059 wait->threads[wait->num] = thread;
3062 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3063 mono_thread_internal_abort (thread);
3067 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3068 && !mono_gc_is_finalizer_internal_thread (thread);
3072 * mono_threads_set_shutting_down:
3074 * Is called by a thread that wants to shut down Mono. If the runtime is already
3075 * shutting down, the calling thread is suspended/stopped, and this function never
3079 mono_threads_set_shutting_down (void)
3081 MonoInternalThread *current_thread = mono_thread_internal_current ();
3083 mono_threads_lock ();
3085 if (shutting_down) {
3086 mono_threads_unlock ();
3088 /* Make sure we're properly suspended/stopped */
3090 LOCK_THREAD (current_thread);
3092 if ((current_thread->state & ThreadState_SuspendRequested) ||
3093 (current_thread->state & ThreadState_AbortRequested) ||
3094 (current_thread->state & ThreadState_StopRequested)) {
3095 UNLOCK_THREAD (current_thread);
3096 mono_thread_execute_interruption ();
3098 current_thread->state |= ThreadState_Stopped;
3099 UNLOCK_THREAD (current_thread);
3102 /*since we're killing the thread, detach it.*/
3103 mono_thread_detach_internal (current_thread);
3105 /* Wake up other threads potentially waiting for us */
3106 mono_thread_info_exit (0);
3108 shutting_down = TRUE;
3110 /* Not really a background state change, but this will
3111 * interrupt the main thread if it is waiting for all
3112 * the other threads.
3114 mono_os_event_set (&background_change_event);
3116 mono_threads_unlock ();
3120 void mono_thread_manage (void)
3122 struct wait_data wait_data;
3123 struct wait_data *wait = &wait_data;
3125 memset (wait, 0, sizeof (struct wait_data));
3126 /* join each thread that's still running */
3127 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3129 mono_threads_lock ();
3131 THREAD_DEBUG (g_message("%s: No threads", __func__));
3132 mono_threads_unlock ();
3135 mono_threads_unlock ();
3138 mono_threads_lock ();
3139 if (shutting_down) {
3140 /* somebody else is shutting down */
3141 mono_threads_unlock ();
3144 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3145 mono_g_hash_table_foreach (threads, print_tids, NULL));
3147 mono_os_event_reset (&background_change_event);
3149 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3150 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3151 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3152 mono_threads_unlock ();
3154 /* Something to wait for */
3155 wait_for_tids (wait, MONO_INFINITE_WAIT, TRUE);
3156 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3157 } while(wait->num>0);
3159 /* Mono is shutting down, so just wait for the end */
3160 if (!mono_runtime_try_shutdown ()) {
3161 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3162 mono_thread_suspend (mono_thread_internal_current ());
3163 mono_thread_execute_interruption ();
3167 * Remove everything but the finalizer thread and self.
3168 * Also abort all the background threads
3171 mono_threads_lock ();
3174 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3175 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3176 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3178 mono_threads_unlock ();
3180 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3181 if (wait->num > 0) {
3182 /* Something to wait for */
3183 wait_for_tids (wait, MONO_INFINITE_WAIT, FALSE);
3185 } while (wait->num > 0);
3188 * give the subthreads a chance to really quit (this is mainly needed
3189 * to get correct user and system times from getrusage/wait/time(1)).
3190 * This could be removed if we avoid pthread_detach() and use pthread_join().
3192 mono_thread_info_yield ();
3196 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3198 MonoInternalThread *thread = (MonoInternalThread*)value;
3199 struct wait_data *wait = (struct wait_data*)user_data;
3202 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3204 * This needs no locking.
3206 if ((thread->state & ThreadState_Suspended) != 0 ||
3207 (thread->state & ThreadState_Stopped) != 0)
3210 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3211 wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle);
3212 wait->threads [wait->num] = thread;
3218 * mono_thread_suspend_all_other_threads:
3220 * Suspend all managed threads except the finalizer thread and this thread. It is
3221 * not possible to resume them later.
3223 void mono_thread_suspend_all_other_threads (void)
3225 struct wait_data wait_data;
3226 struct wait_data *wait = &wait_data;
3228 MonoNativeThreadId self = mono_native_thread_id_get ();
3229 guint32 eventidx = 0;
3230 gboolean starting, finished;
3232 memset (wait, 0, sizeof (struct wait_data));
3234 * The other threads could be in an arbitrary state at this point, i.e.
3235 * they could be starting up, shutting down etc. This means that there could be
3236 * threads which are not even in the threads hash table yet.
3240 * First we set a barrier which will be checked by all threads before they
3241 * are added to the threads hash table, and they will exit if the flag is set.
3242 * This ensures that no threads could be added to the hash later.
3243 * We will use shutting_down as the barrier for now.
3245 g_assert (shutting_down);
3248 * We make multiple calls to WaitForMultipleObjects since:
3249 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3250 * - some threads could exit without becoming suspended
3255 * Make a copy of the hashtable since we can't do anything with
3256 * threads while threads_mutex is held.
3259 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3260 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3261 mono_threads_lock ();
3262 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3263 mono_threads_unlock ();
3266 /* Get the suspended events that we'll be waiting for */
3267 for (i = 0; i < wait->num; ++i) {
3268 MonoInternalThread *thread = wait->threads [i];
3270 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3271 || mono_gc_is_finalizer_internal_thread (thread)
3272 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3274 mono_threads_close_thread_handle (wait->handles [i]);
3275 wait->threads [i] = NULL;
3279 LOCK_THREAD (thread);
3281 if ((thread->state & ThreadState_Suspended) != 0 ||
3282 (thread->state & ThreadState_StopRequested) != 0 ||
3283 (thread->state & ThreadState_Stopped) != 0) {
3284 UNLOCK_THREAD (thread);
3285 mono_threads_close_thread_handle (wait->handles [i]);
3286 wait->threads [i] = NULL;
3292 /* Convert abort requests into suspend requests */
3293 if ((thread->state & ThreadState_AbortRequested) != 0)
3294 thread->state &= ~ThreadState_AbortRequested;
3296 thread->state |= ThreadState_SuspendRequested;
3297 mono_os_event_reset (thread->suspended);
3299 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3300 async_suspend_internal (thread, TRUE);
3302 mono_threads_close_thread_handle (wait->handles [i]);
3303 wait->threads [i] = NULL;
3305 if (eventidx <= 0) {
3307 * If there are threads which are starting up, we wait until they
3308 * are suspended when they try to register in the threads hash.
3309 * This is guaranteed to finish, since the threads which can create new
3310 * threads get suspended after a while.
3311 * FIXME: The finalizer thread can still create new threads.
3313 mono_threads_lock ();
3314 if (threads_starting_up)
3315 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3318 mono_threads_unlock ();
3320 mono_thread_info_sleep (100, NULL);
3328 MonoInternalThread *thread;
3329 MonoStackFrameInfo *frames;
3330 int nframes, max_frames;
3331 int nthreads, max_threads;
3332 MonoInternalThread **threads;
3333 } ThreadDumpUserData;
3335 static gboolean thread_dump_requested;
3337 /* This needs to be async safe */
3339 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3341 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3343 if (ud->nframes < ud->max_frames) {
3344 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3351 /* This needs to be async safe */
3352 static SuspendThreadResult
3353 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3355 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3356 MonoInternalThread *thread = user_data->thread;
3359 /* This no longer works with remote unwinding */
3360 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3361 mono_thread_internal_describe (thread, text);
3362 g_string_append (text, "\n");
3365 if (thread == mono_thread_internal_current ())
3366 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3368 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3370 return MonoResumeThread;
3374 int nthreads, max_threads;
3375 MonoInternalThread **threads;
3376 } CollectThreadsUserData;
3379 collect_thread (gpointer key, gpointer value, gpointer user)
3381 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3382 MonoInternalThread *thread = (MonoInternalThread *)value;
3384 if (ud->nthreads < ud->max_threads)
3385 ud->threads [ud->nthreads ++] = thread;
3389 * Collect running threads into the THREADS array.
3390 * THREADS should be an array allocated on the stack.
3393 collect_threads (MonoInternalThread **thread_array, int max_threads)
3395 CollectThreadsUserData ud;
3397 memset (&ud, 0, sizeof (ud));
3398 /* This array contains refs, but its on the stack, so its ok */
3399 ud.threads = thread_array;
3400 ud.max_threads = max_threads;
3402 mono_threads_lock ();
3403 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3404 mono_threads_unlock ();
3410 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3412 GString* text = g_string_new (0);
3414 GError *error = NULL;
3417 ud->thread = thread;
3420 /* Collect frames for the thread */
3421 if (thread == mono_thread_internal_current ()) {
3422 get_thread_dump (mono_thread_info_current (), ud);
3424 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3428 * Do all the non async-safe work outside of get_thread_dump.
3431 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3433 g_string_append_printf (text, "\n\"%s\"", name);
3436 else if (thread->threadpool_thread) {
3437 g_string_append (text, "\n\"<threadpool thread>\"");
3439 g_string_append (text, "\n\"<unnamed thread>\"");
3442 for (i = 0; i < ud->nframes; ++i) {
3443 MonoStackFrameInfo *frame = &ud->frames [i];
3444 MonoMethod *method = NULL;
3446 if (frame->type == FRAME_TYPE_MANAGED)
3447 method = mono_jit_info_get_method (frame->ji);
3450 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3451 g_string_append_printf (text, " %s\n", location);
3454 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3458 fprintf (stdout, "%s", text->str);
3460 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3461 OutputDebugStringA(text->str);
3464 g_string_free (text, TRUE);
3469 mono_threads_perform_thread_dump (void)
3471 ThreadDumpUserData ud;
3472 MonoInternalThread *thread_array [128];
3473 int tindex, nthreads;
3475 if (!thread_dump_requested)
3478 printf ("Full thread dump:\n");
3480 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3481 nthreads = collect_threads (thread_array, 128);
3483 memset (&ud, 0, sizeof (ud));
3484 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3485 ud.max_frames = 256;
3487 for (tindex = 0; tindex < nthreads; ++tindex)
3488 dump_thread (thread_array [tindex], &ud);
3492 thread_dump_requested = FALSE;
3495 /* Obtain the thread dump of all threads */
3497 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3500 ThreadDumpUserData ud;
3501 MonoInternalThread *thread_array [128];
3502 MonoDomain *domain = mono_domain_get ();
3503 MonoDebugSourceLocation *location;
3504 int tindex, nthreads;
3506 mono_error_init (error);
3508 *out_threads = NULL;
3509 *out_stack_frames = NULL;
3511 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3512 nthreads = collect_threads (thread_array, 128);
3514 memset (&ud, 0, sizeof (ud));
3515 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3516 ud.max_frames = 256;
3518 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3521 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3525 for (tindex = 0; tindex < nthreads; ++tindex) {
3526 MonoInternalThread *thread = thread_array [tindex];
3527 MonoArray *thread_frames;
3533 /* Collect frames for the thread */
3534 if (thread == mono_thread_internal_current ()) {
3535 get_thread_dump (mono_thread_info_current (), &ud);
3537 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3540 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3542 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3545 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3547 for (i = 0; i < ud.nframes; ++i) {
3548 MonoStackFrameInfo *frame = &ud.frames [i];
3549 MonoMethod *method = NULL;
3550 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3554 sf->native_offset = frame->native_offset;
3556 if (frame->type == FRAME_TYPE_MANAGED)
3557 method = mono_jit_info_get_method (frame->ji);
3560 sf->method_address = (gsize) frame->ji->code_start;
3562 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3565 MONO_OBJECT_SETREF (sf, method, rm);
3567 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3569 sf->il_offset = location->il_offset;
3571 if (location && location->source_file) {
3572 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3573 sf->line = location->row;
3574 sf->column = location->column;
3576 mono_debug_free_source_location (location);
3581 mono_array_setref (thread_frames, i, sf);
3587 return is_ok (error);
3591 * mono_threads_request_thread_dump:
3593 * Ask all threads except the current to print their stacktrace to stdout.
3596 mono_threads_request_thread_dump (void)
3598 /*The new thread dump code runs out of the finalizer thread. */
3599 thread_dump_requested = TRUE;
3600 mono_gc_finalize_notify ();
3605 gint allocated; /* +1 so that refs [allocated] == NULL */
3609 typedef struct ref_stack RefStack;
3612 ref_stack_new (gint initial_size)
3616 initial_size = MAX (initial_size, 16) + 1;
3617 rs = g_new0 (RefStack, 1);
3618 rs->refs = g_new0 (gpointer, initial_size);
3619 rs->allocated = initial_size;
3624 ref_stack_destroy (gpointer ptr)
3626 RefStack *rs = (RefStack *)ptr;
3635 ref_stack_push (RefStack *rs, gpointer ptr)
3637 g_assert (rs != NULL);
3639 if (rs->bottom >= rs->allocated) {
3640 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3641 rs->allocated <<= 1;
3642 rs->refs [rs->allocated] = NULL;
3644 rs->refs [rs->bottom++] = ptr;
3648 ref_stack_pop (RefStack *rs)
3650 if (rs == NULL || rs->bottom == 0)
3654 rs->refs [rs->bottom] = NULL;
3658 ref_stack_find (RefStack *rs, gpointer ptr)
3665 for (refs = rs->refs; refs && *refs; refs++) {
3673 * mono_thread_push_appdomain_ref:
3675 * Register that the current thread may have references to objects in domain
3676 * @domain on its stack. Each call to this function should be paired with a
3677 * call to pop_appdomain_ref.
3680 mono_thread_push_appdomain_ref (MonoDomain *domain)
3682 MonoInternalThread *thread = mono_thread_internal_current ();
3685 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3686 SPIN_LOCK (thread->lock_thread_id);
3687 if (thread->appdomain_refs == NULL)
3688 thread->appdomain_refs = ref_stack_new (16);
3689 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3690 SPIN_UNLOCK (thread->lock_thread_id);
3695 mono_thread_pop_appdomain_ref (void)
3697 MonoInternalThread *thread = mono_thread_internal_current ();
3700 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3701 SPIN_LOCK (thread->lock_thread_id);
3702 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3703 SPIN_UNLOCK (thread->lock_thread_id);
3708 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3711 SPIN_LOCK (thread->lock_thread_id);
3712 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3713 SPIN_UNLOCK (thread->lock_thread_id);
3718 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3720 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3723 typedef struct abort_appdomain_data {
3724 struct wait_data wait;
3726 } abort_appdomain_data;
3729 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3731 MonoInternalThread *thread = (MonoInternalThread*)value;
3732 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3733 MonoDomain *domain = data->domain;
3735 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3736 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3738 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3739 data->wait.handles [data->wait.num] = mono_threads_open_thread_handle (thread->handle);
3740 data->wait.threads [data->wait.num] = thread;
3743 /* Just ignore the rest, we can't do anything with
3751 * mono_threads_abort_appdomain_threads:
3753 * Abort threads which has references to the given appdomain.
3756 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3758 #ifdef __native_client__
3762 abort_appdomain_data user_data;
3764 int orig_timeout = timeout;
3767 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3769 start_time = mono_msec_ticks ();
3771 mono_threads_lock ();
3773 user_data.domain = domain;
3774 user_data.wait.num = 0;
3775 /* This shouldn't take any locks */
3776 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3777 mono_threads_unlock ();
3779 if (user_data.wait.num > 0) {
3780 /* Abort the threads outside the threads lock */
3781 for (i = 0; i < user_data.wait.num; ++i)
3782 mono_thread_internal_abort (user_data.wait.threads [i]);
3785 * We should wait for the threads either to abort, or to leave the
3786 * domain. We can't do the latter, so we wait with a timeout.
3788 wait_for_tids (&user_data.wait, 100, FALSE);
3791 /* Update remaining time */
3792 timeout -= mono_msec_ticks () - start_time;
3793 start_time = mono_msec_ticks ();
3795 if (orig_timeout != -1 && timeout < 0)
3798 while (user_data.wait.num > 0);
3800 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3806 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3808 MonoInternalThread *thread = (MonoInternalThread*)value;
3809 MonoDomain *domain = (MonoDomain*)user_data;
3812 /* No locking needed here */
3813 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3815 if (thread->cached_culture_info) {
3816 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3817 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3818 if (obj && obj->vtable->domain == domain)
3819 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3825 * mono_threads_clear_cached_culture:
3827 * Clear the cached_current_culture from all threads if it is in the
3831 mono_threads_clear_cached_culture (MonoDomain *domain)
3833 mono_threads_lock ();
3834 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3835 mono_threads_unlock ();
3839 * mono_thread_get_undeniable_exception:
3841 * Return an exception which needs to be raised when leaving a catch clause.
3842 * This is used for undeniable exception propagation.
3845 mono_thread_get_undeniable_exception (void)
3847 MonoInternalThread *thread = mono_thread_internal_current ();
3849 if (!(thread && thread->abort_exc && !is_running_protected_wrapper ()))
3852 // We don't want to have our exception effect calls made by
3853 // the catching block
3855 if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
3859 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3860 * exception if the thread no longer references a dying appdomain.
3862 thread->abort_exc->trace_ips = NULL;
3863 thread->abort_exc->stack_trace = NULL;
3864 return thread->abort_exc;
3867 #if MONO_SMALL_CONFIG
3868 #define NUM_STATIC_DATA_IDX 4
3869 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3873 #define NUM_STATIC_DATA_IDX 8
3874 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3875 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3879 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3880 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3883 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3885 gpointer *static_data = (gpointer *)addr;
3887 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3888 void **ptr = (void **)static_data [i];
3893 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3894 void **p = ptr + idx;
3897 mark_func ((MonoObject**)p, gc_data);
3903 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3905 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3909 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3911 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3915 * mono_alloc_static_data
3917 * Allocate memory blocks for storing threads or context static data
3920 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3922 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3925 gpointer* static_data = *static_data_ptr;
3927 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3928 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3930 if (mono_gc_user_markers_supported ()) {
3931 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3932 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3934 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3935 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3938 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3939 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3940 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3941 *static_data_ptr = static_data;
3942 static_data [0] = static_data;
3945 for (i = 1; i <= idx; ++i) {
3946 if (static_data [i])
3949 if (mono_gc_user_markers_supported ())
3950 static_data [i] = g_malloc0 (static_data_size [i]);
3952 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3953 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3954 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3959 mono_free_static_data (gpointer* static_data)
3962 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3963 gpointer p = static_data [i];
3967 * At this point, the static data pointer array is still registered with the
3968 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3969 * data. Freeing the individual arrays without first nulling their slots
3970 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3971 * such an already freed array. See bug #13813.
3973 static_data [i] = NULL;
3974 mono_memory_write_barrier ();
3975 if (mono_gc_user_markers_supported ())
3978 mono_gc_free_fixed (p);
3980 mono_gc_free_fixed (static_data);
3984 * mono_init_static_data_info
3986 * Initializes static data counters
3988 static void mono_init_static_data_info (StaticDataInfo *static_data)
3990 static_data->idx = 0;
3991 static_data->offset = 0;
3992 static_data->freelist = NULL;
3996 * mono_alloc_static_data_slot
3998 * Generates an offset for static data. static_data contains the counters
3999 * used to generate it.
4002 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4004 if (!static_data->idx && !static_data->offset) {
4006 * we use the first chunk of the first allocation also as
4007 * an array for the rest of the data
4009 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4011 static_data->offset += align - 1;
4012 static_data->offset &= ~(align - 1);
4013 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4014 static_data->idx ++;
4015 g_assert (size <= static_data_size [static_data->idx]);
4016 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4017 static_data->offset = 0;
4019 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4020 static_data->offset += size;
4025 * LOCKING: requires that threads_mutex is held
4028 context_adjust_static_data (MonoAppContext *ctx)
4030 if (context_static_info.offset || context_static_info.idx > 0) {
4031 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4032 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4033 ctx->data->static_data = ctx->static_data;
4038 * LOCKING: requires that threads_mutex is held
4041 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4043 MonoInternalThread *thread = (MonoInternalThread *)value;
4044 guint32 offset = GPOINTER_TO_UINT (user);
4046 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4050 * LOCKING: requires that threads_mutex is held
4053 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4055 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4060 guint32 offset = GPOINTER_TO_UINT (user);
4061 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4062 ctx->data->static_data = ctx->static_data;
4065 static StaticDataFreeList*
4066 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4068 StaticDataFreeList* prev = NULL;
4069 StaticDataFreeList* tmp = static_data->freelist;
4071 if (tmp->size == size) {
4073 prev->next = tmp->next;
4075 static_data->freelist = tmp->next;
4084 #if SIZEOF_VOID_P == 4
4091 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4093 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4095 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4096 MonoBitSet *rb = sets [idx];
4097 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4098 offset /= sizeof (uintptr_t);
4099 /* offset is now the bitmap offset */
4100 for (int i = 0; i < numbits; ++i) {
4101 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4102 mono_bitset_set_fast (rb, offset + i);
4107 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4109 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4110 MonoBitSet *rb = sets [idx];
4111 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4112 offset /= sizeof (uintptr_t);
4113 /* offset is now the bitmap offset */
4114 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4115 mono_bitset_clear_fast (rb, offset + i);
4119 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4121 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4123 StaticDataInfo *info;
4126 if (static_type == SPECIAL_STATIC_THREAD) {
4127 info = &thread_static_info;
4128 sets = thread_reference_bitmaps;
4130 info = &context_static_info;
4131 sets = context_reference_bitmaps;
4134 mono_threads_lock ();
4136 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4140 offset = item->offset;
4143 offset = mono_alloc_static_data_slot (info, size, align);
4146 update_reference_bitmap (sets, offset, bitmap, numbits);
4148 if (static_type == SPECIAL_STATIC_THREAD) {
4149 /* This can be called during startup */
4150 if (threads != NULL)
4151 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4153 if (contexts != NULL)
4154 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4156 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4159 mono_threads_unlock ();
4165 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4167 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4169 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4170 return get_thread_static_data (thread, offset);
4172 return get_context_static_data (thread->current_appcontext, offset);
4177 mono_get_special_static_data (guint32 offset)
4179 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4188 * LOCKING: requires that threads_mutex is held
4191 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4193 MonoInternalThread *thread = (MonoInternalThread *)value;
4194 OffsetSize *data = (OffsetSize *)user;
4195 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4196 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4199 if (!thread->static_data || !thread->static_data [idx])
4201 ptr = ((char*) thread->static_data [idx]) + off;
4202 mono_gc_bzero_atomic (ptr, data->size);
4206 * LOCKING: requires that threads_mutex is held
4209 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4211 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4216 OffsetSize *data = (OffsetSize *)user;
4217 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4218 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4221 if (!ctx->static_data || !ctx->static_data [idx])
4224 ptr = ((char*) ctx->static_data [idx]) + off;
4225 mono_gc_bzero_atomic (ptr, data->size);
4229 do_free_special_slot (guint32 offset, guint32 size)
4231 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4233 StaticDataInfo *info;
4235 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4236 info = &thread_static_info;
4237 sets = thread_reference_bitmaps;
4239 info = &context_static_info;
4240 sets = context_reference_bitmaps;
4243 guint32 data_offset = offset;
4244 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4245 OffsetSize data = { data_offset, size };
4247 clear_reference_bitmap (sets, data.offset, data.size);
4249 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4250 if (threads != NULL)
4251 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4253 if (contexts != NULL)
4254 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4257 if (!mono_runtime_is_shutting_down ()) {
4258 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4260 item->offset = offset;
4263 item->next = info->freelist;
4264 info->freelist = item;
4269 do_free_special (gpointer key, gpointer value, gpointer data)
4271 MonoClassField *field = (MonoClassField *)key;
4272 guint32 offset = GPOINTER_TO_UINT (value);
4275 size = mono_type_size (field->type, &align);
4276 do_free_special_slot (offset, size);
4280 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4282 mono_threads_lock ();
4284 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4286 mono_threads_unlock ();
4290 static void CALLBACK dummy_apc (ULONG_PTR param)
4296 * mono_thread_execute_interruption
4298 * Performs the operation that the requested thread state requires (abort,
4301 static MonoException*
4302 mono_thread_execute_interruption (void)
4304 MonoInternalThread *thread = mono_thread_internal_current ();
4305 MonoThread *sys_thread = mono_thread_current ();
4307 LOCK_THREAD (thread);
4309 /* MonoThread::interruption_requested can only be changed with atomics */
4310 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4311 /* this will consume pending APC calls */
4313 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4315 InterlockedDecrement (&thread_interruption_requested);
4317 /* Clear the interrupted flag of the thread so it can wait again */
4318 mono_thread_info_clear_self_interrupt ();
4321 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4322 if (sys_thread->pending_exception) {
4325 exc = sys_thread->pending_exception;
4326 sys_thread->pending_exception = NULL;
4328 UNLOCK_THREAD (thread);
4330 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4331 UNLOCK_THREAD (thread);
4332 g_assert (sys_thread->pending_exception == NULL);
4333 if (thread->abort_exc == NULL) {
4335 * This might be racy, but it has to be called outside the lock
4336 * since it calls managed code.
4338 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4340 return thread->abort_exc;
4342 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4343 /* calls UNLOCK_THREAD (thread) */
4344 self_suspend_internal ();
4347 else if ((thread->state & ThreadState_StopRequested) != 0) {
4348 /* FIXME: do this through the JIT? */
4350 UNLOCK_THREAD (thread);
4352 mono_thread_exit ();
4354 } else if (thread->thread_interrupt_requested) {
4356 thread->thread_interrupt_requested = FALSE;
4357 UNLOCK_THREAD (thread);
4359 return(mono_get_exception_thread_interrupted ());
4362 UNLOCK_THREAD (thread);
4368 * mono_thread_request_interruption
4370 * A signal handler can call this method to request the interruption of a
4371 * thread. The result of the interruption will depend on the current state of
4372 * the thread. If the result is an exception that needs to be throw, it is
4373 * provided as return value.
4376 mono_thread_request_interruption (gboolean running_managed)
4378 MonoInternalThread *thread = mono_thread_internal_current ();
4380 /* The thread may already be stopping */
4385 if (thread->interrupt_on_stop &&
4386 thread->state & ThreadState_StopRequested &&
4387 thread->state & ThreadState_Background)
4390 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4392 InterlockedIncrement (&thread_interruption_requested);
4394 if (!running_managed || is_running_protected_wrapper ()) {
4395 /* Can't stop while in unmanaged code. Increase the global interruption
4396 request count. When exiting the unmanaged method the count will be
4397 checked and the thread will be interrupted. */
4399 /* this will awake the thread if it is in WaitForSingleObject
4401 /* Our implementation of this function ignores the func argument */
4403 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
4405 mono_thread_info_self_interrupt ();
4410 return mono_thread_execute_interruption ();
4414 /*This function should be called by a thread after it has exited all of
4415 * its handle blocks at interruption time.*/
4417 mono_thread_resume_interruption (void)
4419 MonoInternalThread *thread = mono_thread_internal_current ();
4420 gboolean still_aborting;
4422 /* The thread may already be stopping */
4426 LOCK_THREAD (thread);
4427 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4428 UNLOCK_THREAD (thread);
4430 /*This can happen if the protected block called Thread::ResetAbort*/
4431 if (!still_aborting)
4434 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4436 InterlockedIncrement (&thread_interruption_requested);
4438 mono_thread_info_self_interrupt ();
4440 return mono_thread_execute_interruption ();
4443 gboolean mono_thread_interruption_requested ()
4445 if (thread_interruption_requested) {
4446 MonoInternalThread *thread = mono_thread_internal_current ();
4447 /* The thread may already be stopping */
4449 return (thread->interruption_requested);
4454 static MonoException*
4455 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4457 MonoInternalThread *thread = mono_thread_internal_current ();
4459 /* The thread may already be stopping */
4462 if (!thread->interruption_requested)
4464 if (!bypass_abort_protection && is_running_protected_wrapper ())
4467 return mono_thread_execute_interruption ();
4471 * Performs the interruption of the current thread, if one has been requested,
4472 * and the thread is not running a protected wrapper.
4473 * Return the exception which needs to be thrown, if any.
4476 mono_thread_interruption_checkpoint (void)
4478 return mono_thread_interruption_checkpoint_request (FALSE);
4482 * Performs the interruption of the current thread, if one has been requested.
4483 * Return the exception which needs to be thrown, if any.
4486 mono_thread_force_interruption_checkpoint_noraise (void)
4488 return mono_thread_interruption_checkpoint_request (TRUE);
4492 * mono_set_pending_exception:
4494 * Set the pending exception of the current thread to EXC.
4495 * The exception will be thrown when execution returns to managed code.
4498 mono_set_pending_exception (MonoException *exc)
4500 MonoThread *thread = mono_thread_current ();
4502 /* The thread may already be stopping */
4506 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4508 mono_thread_request_interruption (FALSE);
4512 * mono_thread_interruption_request_flag:
4514 * Returns the address of a flag that will be non-zero if an interruption has
4515 * been requested for a thread. The thread to interrupt may not be the current
4516 * thread, so an additional call to mono_thread_interruption_requested() or
4517 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4520 gint32* mono_thread_interruption_request_flag ()
4522 return &thread_interruption_requested;
4526 mono_thread_init_apartment_state (void)
4529 MonoInternalThread* thread = mono_thread_internal_current ();
4531 /* Positive return value indicates success, either
4532 * S_OK if this is first CoInitialize call, or
4533 * S_FALSE if CoInitialize already called, but with same
4534 * threading model. A negative value indicates failure,
4535 * probably due to trying to change the threading model.
4537 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4538 ? COINIT_APARTMENTTHREADED
4539 : COINIT_MULTITHREADED) < 0) {
4540 thread->apartment_state = ThreadApartmentState_Unknown;
4546 mono_thread_cleanup_apartment_state (void)
4549 MonoInternalThread* thread = mono_thread_internal_current ();
4551 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4558 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4560 LOCK_THREAD (thread);
4561 thread->state |= state;
4562 UNLOCK_THREAD (thread);
4566 * mono_thread_test_and_set_state:
4568 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4570 * Returns TRUE is @set was OR'd in.
4573 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4575 LOCK_THREAD (thread);
4577 if ((thread->state & test) != 0) {
4578 UNLOCK_THREAD (thread);
4582 thread->state |= set;
4583 UNLOCK_THREAD (thread);
4589 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4591 LOCK_THREAD (thread);
4592 thread->state &= ~state;
4593 UNLOCK_THREAD (thread);
4597 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4599 gboolean ret = FALSE;
4601 LOCK_THREAD (thread);
4603 if ((thread->state & test) != 0) {
4607 UNLOCK_THREAD (thread);
4613 self_interrupt_thread (void *_unused)
4616 MonoThreadInfo *info;
4618 exc = mono_thread_execute_interruption ();
4620 if (mono_threads_is_coop_enabled ()) {
4621 /* We can return from an async call in coop, as
4622 * it's simply called when exiting the safepoint */
4626 g_error ("%s: we can't resume from an async call", __func__);
4629 info = mono_thread_info_current ();
4631 /* We must use _with_context since we didn't trampoline into the runtime */
4632 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. */
4636 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4640 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4644 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4646 MonoJitInfo **dest = (MonoJitInfo **)data;
4652 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4654 MonoJitInfo *ji = NULL;
4659 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4660 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4661 * where we hold runtime locks.
4663 if (!mono_threads_is_coop_enabled ())
4664 mono_thread_info_set_is_async_context (TRUE);
4665 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4666 if (!mono_threads_is_coop_enabled ())
4667 mono_thread_info_set_is_async_context (FALSE);
4672 MonoInternalThread *thread;
4673 gboolean install_async_abort;
4674 MonoThreadInfoInterruptToken *interrupt_token;
4677 static SuspendThreadResult
4678 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4680 AbortThreadData *data = (AbortThreadData *)ud;
4681 MonoInternalThread *thread = data->thread;
4682 MonoJitInfo *ji = NULL;
4683 gboolean protected_wrapper;
4684 gboolean running_managed;
4686 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4687 return MonoResumeThread;
4690 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4691 The protected block code will give them a chance when appropriate.
4693 if (thread->abort_protected_block_count)
4694 return MonoResumeThread;
4696 /*someone is already interrupting it*/
4697 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4698 return MonoResumeThread;
4700 InterlockedIncrement (&thread_interruption_requested);
4702 ji = mono_thread_info_get_last_managed (info);
4703 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4704 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4706 if (!protected_wrapper && running_managed) {
4707 /*We are in managed code*/
4708 /*Set the thread to call */
4709 if (data->install_async_abort)
4710 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4711 return MonoResumeThread;
4714 * This will cause waits to be broken.
4715 * It will also prevent the thread from entering a wait, so if the thread returns
4716 * from the wait before it receives the abort signal, it will just spin in the wait
4717 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4720 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4722 return MonoResumeThread;
4727 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4729 AbortThreadData data;
4731 g_assert (thread != mono_thread_internal_current ());
4733 data.thread = thread;
4734 data.install_async_abort = install_async_abort;
4735 data.interrupt_token = NULL;
4737 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4738 if (data.interrupt_token)
4739 mono_thread_info_finish_interrupt (data.interrupt_token);
4740 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4744 self_abort_internal (MonoError *error)
4748 mono_error_init (error);
4750 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4751 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4754 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.
4756 exc = mono_thread_request_interruption (TRUE);
4758 mono_error_set_exception_instance (error, exc);
4760 mono_thread_info_self_interrupt ();
4764 MonoInternalThread *thread;
4766 MonoThreadInfoInterruptToken *interrupt_token;
4767 } SuspendThreadData;
4769 static SuspendThreadResult
4770 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4772 SuspendThreadData *data = (SuspendThreadData *)ud;
4773 MonoInternalThread *thread = data->thread;
4774 MonoJitInfo *ji = NULL;
4775 gboolean protected_wrapper;
4776 gboolean running_managed;
4778 ji = mono_thread_info_get_last_managed (info);
4779 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4780 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4782 if (running_managed && !protected_wrapper) {
4783 if (mono_threads_is_coop_enabled ()) {
4784 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4785 return MonoResumeThread;
4787 thread->state &= ~ThreadState_SuspendRequested;
4788 thread->state |= ThreadState_Suspended;
4789 return KeepSuspended;
4792 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4793 InterlockedIncrement (&thread_interruption_requested);
4794 if (data->interrupt)
4795 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4797 return MonoResumeThread;
4801 /* LOCKING: called with @thread synch_cs held, and releases it */
4803 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4805 SuspendThreadData data;
4807 g_assert (thread != mono_thread_internal_current ());
4809 // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4811 thread->self_suspended = FALSE;
4813 data.thread = thread;
4814 data.interrupt = interrupt;
4815 data.interrupt_token = NULL;
4817 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4818 if (data.interrupt_token)
4819 mono_thread_info_finish_interrupt (data.interrupt_token);
4821 UNLOCK_THREAD (thread);
4824 /* LOCKING: called with @thread synch_cs held, and releases it */
4826 self_suspend_internal (void)
4828 MonoInternalThread *thread;
4830 MonoOSEventWaitRet res;
4832 thread = mono_thread_internal_current ();
4834 // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4836 thread->self_suspended = TRUE;
4838 thread->state &= ~ThreadState_SuspendRequested;
4839 thread->state |= ThreadState_Suspended;
4841 UNLOCK_THREAD (thread);
4843 event = thread->suspended;
4846 res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT);
4847 g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
4852 * mono_thread_is_foreign:
4853 * @thread: the thread to query
4855 * This function allows one to determine if a thread was created by the mono runtime and has
4856 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4858 * Returns: TRUE if @thread was not created by the runtime.
4861 mono_thread_is_foreign (MonoThread *thread)
4863 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4864 return info->runtime_thread == FALSE;
4868 * mono_add_joinable_thread:
4870 * Add TID to the list of joinable threads.
4871 * LOCKING: Acquires the threads lock.
4874 mono_threads_add_joinable_thread (gpointer tid)
4878 * We cannot detach from threads because it causes problems like
4879 * 2fd16f60/r114307. So we collect them and join them when
4880 * we have time (in he finalizer thread).
4882 joinable_threads_lock ();
4883 if (!joinable_threads)
4884 joinable_threads = g_hash_table_new (NULL, NULL);
4885 g_hash_table_insert (joinable_threads, tid, tid);
4886 joinable_thread_count ++;
4887 joinable_threads_unlock ();
4889 mono_gc_finalize_notify ();
4894 * mono_threads_join_threads:
4896 * Join all joinable threads. This is called from the finalizer thread.
4897 * LOCKING: Acquires the threads lock.
4900 mono_threads_join_threads (void)
4903 GHashTableIter iter;
4910 if (!joinable_thread_count)
4914 joinable_threads_lock ();
4916 if (g_hash_table_size (joinable_threads)) {
4917 g_hash_table_iter_init (&iter, joinable_threads);
4918 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4919 thread = (pthread_t)tid;
4920 g_hash_table_remove (joinable_threads, key);
4921 joinable_thread_count --;
4924 joinable_threads_unlock ();
4926 if (thread != pthread_self ()) {
4928 /* This shouldn't block */
4929 mono_native_thread_join (thread);
4942 * Wait for thread TID to exit.
4943 * LOCKING: Acquires the threads lock.
4946 mono_thread_join (gpointer tid)
4950 gboolean found = FALSE;
4952 joinable_threads_lock ();
4953 if (!joinable_threads)
4954 joinable_threads = g_hash_table_new (NULL, NULL);
4955 if (g_hash_table_lookup (joinable_threads, tid)) {
4956 g_hash_table_remove (joinable_threads, tid);
4957 joinable_thread_count --;
4960 joinable_threads_unlock ();
4963 thread = (pthread_t)tid;
4965 mono_native_thread_join (thread);
4971 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4973 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4974 mono_thread_interruption_checkpoint ();
4978 mono_thread_internal_unhandled_exception (MonoObject* exc)
4980 MonoClass *klass = exc->vtable->klass;
4981 if (is_threadabort_exception (klass)) {
4982 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4983 } else if (!is_appdomainunloaded_exception (klass)
4984 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4985 mono_unhandled_exception (exc);
4986 if (mono_environment_exitcode_get () == 1) {
4987 mono_environment_exitcode_set (255);
4988 mono_invoke_unhandled_exception_hook (exc);
4989 g_assert_not_reached ();
4995 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
4998 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
4999 mono_error_set_pending_exception (&error);
5003 * mono_threads_attach_coop: called by native->managed wrappers
5007 * - @return: the original domain which needs to be restored, or NULL.
5010 * - @dummy: contains the original domain
5011 * - @return: a cookie containing current MonoThreadInfo*.
5014 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5017 gboolean fresh_thread = FALSE;
5020 /* Happens when called from AOTed code which is only used in the root domain. */
5021 domain = mono_get_root_domain ();
5026 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5027 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5028 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5029 * we're only responsible for making the cookie. */
5030 if (mono_threads_is_coop_enabled ()) {
5031 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5032 fresh_thread = !info || !mono_thread_info_is_live (info);
5035 if (!mono_thread_internal_current ()) {
5036 mono_thread_attach_full (domain, FALSE);
5039 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5042 orig = mono_domain_get ();
5044 mono_domain_set (domain, TRUE);
5046 if (!mono_threads_is_coop_enabled ())
5047 return orig != domain ? orig : NULL;
5051 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5052 * return the right cookie. */
5053 return mono_threads_enter_gc_unsafe_region_cookie ();
5056 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5057 return mono_threads_enter_gc_unsafe_region (dummy);
5062 * mono_threads_detach_coop: called by native->managed wrappers
5065 * - @cookie: the original domain which needs to be restored, or NULL.
5069 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5070 * - @dummy: contains the original domain
5073 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5075 MonoDomain *domain, *orig;
5077 if (!mono_threads_is_coop_enabled ()) {
5078 orig = (MonoDomain*) cookie;
5080 mono_domain_set (orig, TRUE);
5082 orig = (MonoDomain*) *dummy;
5084 domain = mono_domain_get ();
5087 /* it won't do anything if cookie is NULL
5088 * thread state RUNNING -> (RUNNING|BLOCKING) */
5089 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5091 if (orig != domain) {
5093 mono_domain_unset ();
5095 mono_domain_set (orig, TRUE);
5101 mono_threads_begin_abort_protected_block (void)
5103 MonoInternalThread *thread;
5105 thread = mono_thread_internal_current ();
5106 ++thread->abort_protected_block_count;
5107 mono_memory_barrier ();
5111 mono_threads_end_abort_protected_block (void)
5113 MonoInternalThread *thread;
5115 thread = mono_thread_internal_current ();
5117 mono_memory_barrier ();
5118 --thread->abort_protected_block_count;
5122 mono_thread_try_resume_interruption (void)
5124 MonoInternalThread *thread;
5126 thread = mono_thread_internal_current ();
5127 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5130 return mono_thread_resume_interruption ();
5134 /* Returns TRUE if the current thread is ready to be interrupted. */
5136 mono_threads_is_ready_to_be_interrupted (void)
5138 MonoInternalThread *thread;
5140 thread = mono_thread_internal_current ();
5141 LOCK_THREAD (thread);
5142 if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5143 UNLOCK_THREAD (thread);
5147 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5148 UNLOCK_THREAD (thread);
5152 UNLOCK_THREAD (thread);
5158 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5160 g_string_append_printf (text, ", thread handle : %p", internal->handle);
5162 if (internal->thread_info) {
5163 g_string_append (text, ", state : ");
5164 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5167 if (internal->owned_mutexes) {
5170 g_string_append (text, ", owns : [");
5171 for (i = 0; i < internal->owned_mutexes->len; i++)
5172 g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5173 g_string_append (text, "]");
5178 mono_thread_internal_is_current (MonoInternalThread *internal)
5180 g_assert (internal);
5181 return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));