2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/threads.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internals.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/mono-threads-coop.h>
41 #include <mono/utils/hazard-pointer.h>
42 #include <mono/utils/mono-tls.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/mono-threads-coop.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/w32handle.h>
48 #include <mono/metadata/w32event.h>
50 #include <mono/metadata/gc-internals.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/abi-details.h>
58 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
59 #define USE_TKILL_ON_ANDROID 1
62 #ifdef PLATFORM_ANDROID
65 #ifdef USE_TKILL_ON_ANDROID
66 extern int tkill (pid_t tid, int signal);
70 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
71 #define THREAD_DEBUG(a)
72 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
73 #define THREAD_WAIT_DEBUG(a)
74 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
75 #define LIBGC_DEBUG(a)
77 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
78 #define SPIN_LOCK(i) do { \
79 if (SPIN_TRYLOCK (i)) \
83 #define SPIN_UNLOCK(i) i = 0
85 #define LOCK_THREAD(thread) lock_thread((thread))
86 #define UNLOCK_THREAD(thread) unlock_thread((thread))
98 typedef struct _StaticDataFreeList StaticDataFreeList;
99 struct _StaticDataFreeList {
100 StaticDataFreeList *next;
108 StaticDataFreeList *freelist;
111 /* Number of cached culture objects in the MonoThread->cached_culture_info array
112 * (per-type): we use the first NUM entries for CultureInfo and the last for
113 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
115 #define NUM_CACHED_CULTURES 4
116 #define CULTURES_START_IDX 0
117 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
119 /* Controls access to the 'threads' hash table */
120 static void mono_threads_lock (void);
121 static void mono_threads_unlock (void);
122 static MonoCoopMutex threads_mutex;
124 /* Controls access to the 'joinable_threads' hash table */
125 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
126 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
127 static mono_mutex_t joinable_threads_mutex;
129 /* Holds current status of static data heap */
130 static StaticDataInfo thread_static_info;
131 static StaticDataInfo context_static_info;
133 /* The hash of existing threads (key is thread ID, value is
134 * MonoInternalThread*) that need joining before exit
136 static MonoGHashTable *threads=NULL;
138 /* List of app context GC handles.
139 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
141 static GHashTable *contexts = NULL;
143 /* Cleanup queue for contexts. */
144 static MonoReferenceQueue *context_queue;
147 * Threads which are starting up and they are not in the 'threads' hash yet.
148 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
149 * Protected by mono_threads_lock ().
151 static MonoGHashTable *threads_starting_up = NULL;
153 /* The TLS key that holds the MonoObject assigned to each thread */
154 static MonoNativeTlsKey current_object_key;
157 /* Protected by the threads lock */
158 static GHashTable *joinable_threads;
159 static int joinable_thread_count;
161 #ifdef MONO_HAVE_FAST_TLS
162 /* we need to use both the Tls* functions and __thread because
163 * the gc needs to see all the threads
165 MONO_FAST_TLS_DECLARE(tls_current_object);
166 #define SET_CURRENT_OBJECT(x) do { \
167 MONO_FAST_TLS_SET (tls_current_object, x); \
168 mono_native_tls_set_value (current_object_key, x); \
170 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
172 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
173 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
176 /* function called at thread start */
177 static MonoThreadStartCB mono_thread_start_cb = NULL;
179 /* function called at thread attach */
180 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
182 /* function called at thread cleanup */
183 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
185 /* The default stack size for each thread */
186 static guint32 default_stacksize = 0;
187 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
189 static void context_adjust_static_data (MonoAppContext *ctx);
190 static void mono_free_static_data (gpointer* static_data);
191 static void mono_init_static_data_info (StaticDataInfo *static_data);
192 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
193 static gboolean mono_thread_resume (MonoInternalThread* thread);
194 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
195 static void self_abort_internal (MonoError *error);
196 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
197 static void self_suspend_internal (void);
199 static MonoException* mono_thread_execute_interruption (void);
200 static void ref_stack_destroy (gpointer rs);
202 /* Spin lock for InterlockedXXX 64 bit functions */
203 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
204 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
205 static mono_mutex_t interlocked_mutex;
207 /* global count of thread interruptions requested */
208 static gint32 thread_interruption_requested = 0;
210 /* Event signaled when a thread changes its background mode */
211 static HANDLE background_change_event;
213 static gboolean shutting_down = FALSE;
215 static gint32 managed_thread_id_counter = 0;
217 /* Class lazy loading functions */
218 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
221 mono_threads_lock (void)
223 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
227 mono_threads_unlock (void)
229 mono_locks_coop_release (&threads_mutex, ThreadsLock);
234 get_next_managed_thread_id (void)
236 return InterlockedIncrement (&managed_thread_id_counter);
240 mono_thread_get_tls_key (void)
242 return current_object_key;
246 mono_thread_get_tls_offset (void)
251 if (current_object_key)
252 offset = current_object_key;
254 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
259 static inline MonoNativeThreadId
260 thread_get_tid (MonoInternalThread *thread)
262 /* We store the tid as a guint64 to keep the object layout constant between platforms */
263 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
266 static void ensure_synch_cs_set (MonoInternalThread *thread)
268 MonoCoopMutex *synch_cs;
270 if (thread->synch_cs != NULL) {
274 synch_cs = g_new0 (MonoCoopMutex, 1);
275 mono_coop_mutex_init_recursive (synch_cs);
277 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
278 synch_cs, NULL) != NULL) {
279 /* Another thread must have installed this CS */
280 mono_coop_mutex_destroy (synch_cs);
286 lock_thread (MonoInternalThread *thread)
288 if (!thread->synch_cs)
289 ensure_synch_cs_set (thread);
291 g_assert (thread->synch_cs);
293 mono_coop_mutex_lock (thread->synch_cs);
297 unlock_thread (MonoInternalThread *thread)
299 mono_coop_mutex_unlock (thread->synch_cs);
302 static inline gboolean
303 is_appdomainunloaded_exception (MonoClass *klass)
305 return klass == mono_class_get_appdomain_unloaded_exception_class ();
308 static inline gboolean
309 is_threadabort_exception (MonoClass *klass)
311 return klass == mono_defaults.threadabortexception_class;
315 * NOTE: this function can be called also for threads different from the current one:
316 * make sure no code called from it will ever assume it is run on the thread that is
317 * getting cleaned up.
319 static void thread_cleanup (MonoInternalThread *thread)
323 g_assert (thread != NULL);
325 if (thread->abort_state_handle) {
326 mono_gchandle_free (thread->abort_state_handle);
327 thread->abort_state_handle = 0;
329 thread->abort_exc = NULL;
330 thread->current_appcontext = NULL;
333 * This is necessary because otherwise we might have
334 * cross-domain references which will not get cleaned up when
335 * the target domain is unloaded.
337 if (thread->cached_culture_info) {
339 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
340 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
344 * thread->synch_cs can be NULL if this was called after
345 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
346 * This can happen only during shutdown.
347 * The shutting_down flag is not always set, so we can't assert on it.
349 if (thread->synch_cs)
350 LOCK_THREAD (thread);
352 thread->state |= ThreadState_Stopped;
353 thread->state &= ~ThreadState_Background;
355 if (thread->synch_cs)
356 UNLOCK_THREAD (thread);
359 An interruption request has leaked to cleanup. Adjust the global counter.
361 This can happen is the abort source thread finds the abortee (this) thread
362 in unmanaged code. If this thread never trips back to managed code or check
363 the local flag it will be left set and positively unbalance the global counter.
365 Leaving the counter unbalanced will cause a performance degradation since all threads
366 will now keep checking their local flags all the time.
368 if (InterlockedExchange (&thread->interruption_requested, 0))
369 InterlockedDecrement (&thread_interruption_requested);
371 mono_threads_lock ();
375 } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
376 /* We have to check whether the thread object for the
377 * tid is still the same in the table because the
378 * thread might have been destroyed and the tid reused
379 * in the meantime, in which case the tid would be in
380 * the table, but with another thread object.
384 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
388 mono_threads_unlock ();
390 /* Don't close the handle here, wait for the object finalizer
391 * to do it. Otherwise, the following race condition applies:
393 * 1) Thread exits (and thread_cleanup() closes the handle)
395 * 2) Some other handle is reassigned the same slot
397 * 3) Another thread tries to join the first thread, and
398 * blocks waiting for the reassigned handle to be signalled
399 * (which might never happen). This is possible, because the
400 * thread calling Join() still has a reference to the first
404 /* if the thread is not in the hash it has been removed already */
406 if (thread == mono_thread_internal_current ()) {
407 mono_domain_unset ();
408 mono_memory_barrier ();
410 if (mono_thread_cleanup_fn)
411 mono_thread_cleanup_fn (thread_get_tid (thread));
414 mono_release_type_locks (thread);
416 /* Can happen when we attach the profiler helper thread in order to heapshot. */
417 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
418 mono_profiler_thread_end (thread->tid);
420 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
422 if (thread == mono_thread_internal_current ()) {
424 * This will signal async signal handlers that the thread has exited.
425 * The profiler callback needs this to be set, so it cannot be done earlier.
427 mono_domain_unset ();
428 mono_memory_barrier ();
431 if (thread == mono_thread_internal_current ())
432 mono_thread_pop_appdomain_ref ();
434 thread->cached_culture_info = NULL;
436 mono_free_static_data (thread->static_data);
437 thread->static_data = NULL;
438 ref_stack_destroy (thread->appdomain_refs);
439 thread->appdomain_refs = NULL;
441 if (mono_thread_cleanup_fn)
442 mono_thread_cleanup_fn (thread_get_tid (thread));
444 if (mono_gc_is_moving ()) {
445 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
446 thread->thread_pinning_ref = NULL;
452 * A special static data offset (guint32) consists of 3 parts:
454 * [0] 6-bit index into the array of chunks.
455 * [6] 25-bit offset into the array.
456 * [31] Bit indicating thread or context static.
461 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
472 } SpecialStaticOffset;
474 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
475 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
477 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
478 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
479 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
480 (((SpecialStaticOffset *) &(x))->fields.f)
483 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
485 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
487 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
488 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
490 return ((char *) thread->static_data [idx]) + off;
494 get_context_static_data (MonoAppContext *ctx, guint32 offset)
496 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
498 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
499 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
501 return ((char *) ctx->static_data [idx]) + off;
505 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
507 static MonoClassField *current_thread_field = NULL;
511 if (!current_thread_field) {
512 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
513 g_assert (current_thread_field);
516 mono_class_vtable (domain, mono_defaults.thread_class);
517 mono_domain_lock (domain);
518 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
519 mono_domain_unlock (domain);
522 return (MonoThread **)get_thread_static_data (thread, offset);
526 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
528 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
530 g_assert (current->obj.vtable->domain == domain);
532 g_assert (!*current_thread_ptr);
533 *current_thread_ptr = current;
537 create_thread_object (MonoDomain *domain)
540 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
541 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, &error);
542 /* only possible failure mode is OOM, from which we don't expect to recover. */
543 mono_error_assert_ok (&error);
548 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
552 thread = create_thread_object (domain);
554 MONO_OBJECT_SETREF (thread, internal_thread, internal);
559 static MonoInternalThread*
560 create_internal_thread (void)
563 MonoInternalThread *thread;
566 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
567 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
568 /* only possible failure mode is OOM, from which we don't exect to recover */
569 mono_error_assert_ok (&error);
571 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
572 mono_coop_mutex_init_recursive (thread->synch_cs);
574 thread->apartment_state = ThreadApartmentState_Unknown;
575 thread->managed_id = get_next_managed_thread_id ();
576 if (mono_gc_is_moving ()) {
577 thread->thread_pinning_ref = thread;
578 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
581 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
587 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
590 g_assert (internal->handle);
592 g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
593 g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
594 g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
599 res = SetThreadPriority (internal->handle, priority - 2);
601 g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
602 #else /* HOST_WIN32 */
605 struct sched_param param;
608 tid = thread_get_tid (internal);
610 res = pthread_getschedparam (tid, &policy, ¶m);
612 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
614 #ifdef _POSIX_PRIORITY_SCHEDULING
617 /* Necessary to get valid priority range */
619 min = sched_get_priority_min (policy);
620 max = sched_get_priority_max (policy);
622 if (max > 0 && min >= 0 && max > min) {
623 double srange, drange, sposition, dposition;
624 srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
626 sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
627 dposition = (sposition / srange) * drange;
628 param.sched_priority = (int)(dposition + min);
635 param.sched_priority = 50;
641 param.sched_priority = 0;
644 g_error ("%s: unknown policy %d", __func__, policy);
648 res = pthread_setschedparam (tid, policy, ¶m);
651 g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
654 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
656 #endif /* HOST_WIN32 */
660 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
663 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
665 MonoThreadInfo *info;
666 MonoInternalThread *internal;
667 MonoDomain *domain, *root_domain;
671 info = mono_thread_info_current ();
673 internal = thread->internal_thread;
674 internal->handle = mono_thread_info_duplicate_handle (info);
675 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
676 internal->thread_info = info;
677 internal->small_id = info->small_id;
678 internal->stack_ptr = stack_ptr;
680 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
682 SET_CURRENT_OBJECT (internal);
684 domain = mono_object_domain (thread);
686 mono_thread_push_appdomain_ref (domain);
687 if (!mono_domain_set (domain, force_domain)) {
688 mono_thread_pop_appdomain_ref ();
692 mono_threads_lock ();
694 if (threads_starting_up)
695 mono_g_hash_table_remove (threads_starting_up, thread);
697 if (shutting_down && !force_attach) {
698 mono_threads_unlock ();
703 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
704 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
707 /* We don't need to duplicate thread->handle, because it is
708 * only closed when the thread object is finalized by the GC. */
709 mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
711 /* We have to do this here because mono_thread_start_cb
712 * requires that root_domain_thread is set up. */
713 if (thread_static_info.offset || thread_static_info.idx > 0) {
714 /* get the current allocated size */
715 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
716 mono_alloc_static_data (&internal->static_data, offset, TRUE);
719 mono_threads_unlock ();
721 root_domain = mono_get_root_domain ();
723 g_assert (!internal->root_domain_thread);
724 if (domain != root_domain)
725 MONO_OBJECT_SETREF (internal, root_domain_thread, new_thread_with_internal (root_domain, internal));
727 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
729 if (domain != root_domain)
730 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
732 set_current_thread_for_domain (domain, internal, thread);
734 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
742 MonoObject *start_delegate;
743 MonoObject *start_delegate_arg;
744 MonoThreadStart start_func;
745 gpointer start_func_arg;
747 MonoCoopSem registered;
750 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
753 MonoThreadStart start_func;
754 void *start_func_arg;
757 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
761 MonoInternalThread *internal;
762 MonoObject *start_delegate;
763 MonoObject *start_delegate_arg;
766 thread = start_info->thread;
767 internal = thread->internal_thread;
768 domain = mono_object_domain (start_info->thread);
770 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
772 if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
773 start_info->failed = TRUE;
775 mono_coop_sem_post (&start_info->registered);
777 if (InterlockedDecrement (&start_info->ref) == 0) {
778 mono_coop_sem_destroy (&start_info->registered);
785 mono_thread_internal_set_priority (internal, internal->priority);
789 start_delegate = start_info->start_delegate;
790 start_delegate_arg = start_info->start_delegate_arg;
791 start_func = start_info->start_func;
792 start_func_arg = start_info->start_func_arg;
794 /* This MUST be called before any managed code can be
795 * executed, as it calls the callback function that (for the
796 * jit) sets the lmf marker.
799 if (mono_thread_start_cb)
800 mono_thread_start_cb (tid, stack_ptr, start_func);
802 /* On 2.0 profile (and higher), set explicitly since state might have been
804 if (internal->apartment_state == ThreadApartmentState_Unknown)
805 internal->apartment_state = ThreadApartmentState_MTA;
807 mono_thread_init_apartment_state ();
809 /* Let the thread that called Start() know we're ready */
810 mono_coop_sem_post (&start_info->registered);
812 if (InterlockedDecrement (&start_info->ref) == 0) {
813 mono_coop_sem_destroy (&start_info->registered);
817 /* start_info is not valid anymore */
821 * Call this after calling start_notify, since the profiler callback might want
822 * to lock the thread, and the lock is held by thread_start () which waits for
825 mono_profiler_thread_start (tid);
827 /* if the name was set before starting, we didn't invoke the profiler callback */
828 if (internal->name) {
829 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
830 mono_profiler_thread_name (internal->tid, tname);
831 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
835 /* start_func is set only for unmanaged start functions */
837 start_func (start_func_arg);
841 g_assert (start_delegate != NULL);
843 /* we may want to handle the exception here. See comment below on unhandled exceptions */
844 args [0] = (gpointer) start_delegate_arg;
845 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
847 if (!mono_error_ok (&error)) {
848 MonoException *ex = mono_error_convert_to_exception (&error);
850 g_assert (ex != NULL);
851 MonoClass *klass = mono_object_get_class (&ex->object);
852 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
853 !is_threadabort_exception (klass)) {
854 mono_unhandled_exception (&ex->object);
855 mono_invoke_unhandled_exception_hook (&ex->object);
856 g_assert_not_reached ();
859 mono_error_cleanup (&error);
863 /* If the thread calls ExitThread at all, this remaining code
864 * will not be executed, but the main thread will eventually
865 * call thread_cleanup() on this thread's behalf.
868 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
870 /* Do any cleanup needed for apartment state. This
871 * cannot be done in thread_cleanup since thread_cleanup could be
872 * called for a thread other than the current thread.
873 * mono_thread_cleanup_apartment_state cleans up apartment
874 * for the current thead */
875 mono_thread_cleanup_apartment_state ();
877 thread_cleanup (internal);
881 /* Remove the reference to the thread object in the TLS data,
882 * so the thread object can be finalized. This won't be
883 * reached if the thread threw an uncaught exception, so those
884 * thread handles will stay referenced :-( (This is due to
885 * missing support for scanning thread-specific data in the
886 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
889 SET_CURRENT_OBJECT (NULL);
894 static gsize WINAPI start_wrapper(void *data)
896 volatile gsize dummy;
898 /* Avoid scanning the frames above this frame during a GC */
899 mono_gc_set_stack_end ((void*)&dummy);
901 return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
907 * Common thread creation code.
908 * LOCKING: Acquires the threads lock.
911 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
912 gboolean threadpool_thread, guint32 stack_size, MonoError *error)
914 StartInfo *start_info = NULL;
915 HANDLE thread_handle;
916 MonoNativeThreadId tid;
920 g_assert (!start_func && !start_func_arg);
922 g_assert (!start_delegate);
925 * Join joinable threads to prevent running out of threads since the finalizer
926 * thread might be blocked/backlogged.
928 mono_threads_join_threads ();
930 mono_error_init (error);
932 mono_threads_lock ();
934 mono_threads_unlock ();
937 if (threads_starting_up == NULL) {
938 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
939 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
941 mono_g_hash_table_insert (threads_starting_up, thread, thread);
942 mono_threads_unlock ();
944 internal->threadpool_thread = threadpool_thread;
945 if (threadpool_thread)
946 mono_thread_set_state (internal, ThreadState_Background);
948 start_info = g_new0 (StartInfo, 1);
950 start_info->thread = thread;
951 start_info->start_delegate = start_delegate;
952 start_info->start_delegate_arg = thread->start_obj;
953 start_info->start_func = start_func;
954 start_info->start_func_arg = start_func_arg;
955 start_info->failed = FALSE;
956 mono_coop_sem_init (&start_info->registered, 0);
959 stack_size = default_stacksize_for_thread (internal);
961 thread_handle = mono_threads_create_thread (start_wrapper, start_info, stack_size, &tid);
963 if (thread_handle == NULL) {
964 /* The thread couldn't be created, so set an exception */
965 mono_threads_lock ();
966 mono_g_hash_table_remove (threads_starting_up, thread);
967 mono_threads_unlock ();
968 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
969 /* ref is not going to be decremented in start_wrapper_internal */
970 InterlockedDecrement (&start_info->ref);
975 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
978 * Wait for the thread to set up its TLS data etc, so
979 * theres no potential race condition if someone tries
980 * to look up the data believing the thread has
984 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
986 mono_threads_close_thread_handle (thread_handle);
988 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));
990 ret = !start_info->failed;
993 if (InterlockedDecrement (&start_info->ref) == 0) {
994 mono_coop_sem_destroy (&start_info->registered);
1001 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
1003 if (mono_thread_start_cb) {
1004 mono_thread_start_cb (tid, stack_start, func);
1008 void mono_threads_set_default_stacksize (guint32 stacksize)
1010 default_stacksize = stacksize;
1013 guint32 mono_threads_get_default_stacksize (void)
1015 return default_stacksize;
1019 * mono_thread_create_internal:
1021 * ARG should not be a GC reference.
1024 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
1027 MonoInternalThread *internal;
1030 mono_error_init (error);
1032 thread = create_thread_object (domain);
1034 internal = create_internal_thread ();
1036 MONO_OBJECT_SETREF (thread, internal_thread, internal);
1038 LOCK_THREAD (internal);
1040 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
1041 return_val_if_nok (error, NULL);
1043 UNLOCK_THREAD (internal);
1049 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1052 if (!mono_thread_create_checked (domain, func, arg, &error))
1053 mono_error_cleanup (&error);
1057 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1059 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
1063 mono_thread_attach (MonoDomain *domain)
1065 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1071 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1073 MonoInternalThread *internal;
1075 MonoNativeThreadId tid;
1078 if ((internal = mono_thread_internal_current ())) {
1079 if (domain != mono_domain_get ())
1080 mono_domain_set (domain, TRUE);
1081 /* Already attached */
1082 return mono_thread_current ();
1085 if (!mono_gc_register_thread (&domain)) {
1086 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 ());
1089 tid=mono_native_thread_id_get ();
1091 internal = create_internal_thread ();
1093 thread = new_thread_with_internal (domain, internal);
1095 if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
1096 /* Mono is shutting down, so just wait for the end */
1098 mono_thread_info_sleep (10000, NULL);
1101 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1103 if (mono_thread_attach_cb) {
1107 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1110 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1112 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1115 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1116 if (!mono_thread_info_current ()->tools_thread)
1117 // FIXME: Need a separate callback
1118 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1124 mono_thread_detach_internal (MonoInternalThread *thread)
1126 g_return_if_fail (thread != NULL);
1128 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1130 thread_cleanup (thread);
1132 SET_CURRENT_OBJECT (NULL);
1133 mono_domain_unset ();
1135 /* Don't need to close the handle to this thread, even though we took a
1136 * reference in mono_thread_attach (), because the GC will do it
1137 * when the Thread object is finalised.
1142 mono_thread_detach (MonoThread *thread)
1145 mono_thread_detach_internal (thread->internal_thread);
1149 * mono_thread_detach_if_exiting:
1151 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1152 * This should be used at the end of embedding code which calls into managed code, and which
1153 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1156 mono_thread_detach_if_exiting (void)
1158 if (mono_thread_info_is_exiting ()) {
1159 MonoInternalThread *thread;
1161 thread = mono_thread_internal_current ();
1163 mono_thread_detach_internal (thread);
1164 mono_thread_info_detach ();
1172 mono_thread_exit (void)
1174 MonoInternalThread *thread = mono_thread_internal_current ();
1176 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1178 thread_cleanup (thread);
1179 SET_CURRENT_OBJECT (NULL);
1180 mono_domain_unset ();
1182 /* we could add a callback here for embedders to use. */
1183 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1184 exit (mono_environment_exitcode_get ());
1185 mono_thread_info_exit ();
1189 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1191 MonoInternalThread *internal;
1193 internal = create_internal_thread ();
1195 internal->state = ThreadState_Unstarted;
1197 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1201 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1205 MonoInternalThread *internal;
1208 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1210 if (!this_obj->internal_thread)
1211 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1212 internal = this_obj->internal_thread;
1214 LOCK_THREAD (internal);
1216 if ((internal->state & ThreadState_Unstarted) == 0) {
1217 UNLOCK_THREAD (internal);
1218 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1222 if ((internal->state & ThreadState_Aborted) != 0) {
1223 UNLOCK_THREAD (internal);
1227 res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1229 mono_error_cleanup (&error);
1230 UNLOCK_THREAD (internal);
1234 internal->state &= ~ThreadState_Unstarted;
1236 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1238 UNLOCK_THREAD (internal);
1239 return internal->handle;
1243 * This is called from the finalizer of the internal thread object.
1246 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1248 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1251 * Since threads keep a reference to their thread object while running, by the time this function is called,
1252 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1253 * when thread_cleanup () can be called after this.
1256 mono_threads_close_thread_handle (thread);
1258 if (this_obj->synch_cs) {
1259 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1260 this_obj->synch_cs = NULL;
1261 mono_coop_mutex_destroy (synch_cs);
1265 if (this_obj->name) {
1266 void *name = this_obj->name;
1267 this_obj->name = NULL;
1273 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1276 MonoInternalThread *thread = mono_thread_internal_current ();
1278 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1280 if (mono_thread_current_check_pending_interrupt ())
1284 gboolean alerted = FALSE;
1286 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1288 res = mono_thread_info_sleep (ms, &alerted);
1290 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1293 MonoException* exc = mono_thread_execute_interruption ();
1295 mono_raise_exception (exc);
1307 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1312 ves_icall_System_Threading_Thread_GetDomainID (void)
1314 return mono_domain_get()->domain_id;
1318 ves_icall_System_Threading_Thread_Yield (void)
1320 return mono_thread_info_yield ();
1324 * mono_thread_get_name:
1326 * Return the name of the thread. NAME_LEN is set to the length of the name.
1327 * Return NULL if the thread has no name. The returned memory is owned by the
1331 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1335 LOCK_THREAD (this_obj);
1337 if (!this_obj->name) {
1341 *name_len = this_obj->name_len;
1342 res = g_new (gunichar2, this_obj->name_len);
1343 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1346 UNLOCK_THREAD (this_obj);
1352 * mono_thread_get_name_utf8:
1354 * Return the name of the thread in UTF-8.
1355 * Return NULL if the thread has no name.
1356 * The returned memory is owned by the caller.
1359 mono_thread_get_name_utf8 (MonoThread *thread)
1364 MonoInternalThread *internal = thread->internal_thread;
1365 if (internal == NULL)
1368 LOCK_THREAD (internal);
1370 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1372 UNLOCK_THREAD (internal);
1378 * mono_thread_get_managed_id:
1380 * Return the Thread.ManagedThreadId value of `thread`.
1381 * Returns -1 if `thread` is NULL.
1384 mono_thread_get_managed_id (MonoThread *thread)
1389 MonoInternalThread *internal = thread->internal_thread;
1390 if (internal == NULL)
1393 int32_t id = internal->managed_id;
1399 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1404 mono_error_init (&error);
1406 LOCK_THREAD (this_obj);
1408 if (!this_obj->name)
1411 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1413 UNLOCK_THREAD (this_obj);
1415 if (mono_error_set_pending_exception (&error))
1422 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1424 LOCK_THREAD (this_obj);
1426 mono_error_init (error);
1428 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1429 UNLOCK_THREAD (this_obj);
1431 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1434 if (this_obj->name) {
1435 g_free (this_obj->name);
1436 this_obj->name_len = 0;
1439 this_obj->name = g_new (gunichar2, mono_string_length (name));
1440 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1441 this_obj->name_len = mono_string_length (name);
1444 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1447 this_obj->name = NULL;
1450 UNLOCK_THREAD (this_obj);
1452 if (this_obj->name && this_obj->tid) {
1453 char *tname = mono_string_to_utf8_checked (name, error);
1454 return_if_nok (error);
1455 mono_profiler_thread_name (this_obj->tid, tname);
1456 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1462 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1465 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1466 mono_error_set_pending_exception (&error);
1470 * ves_icall_System_Threading_Thread_GetPriority_internal:
1471 * @param this_obj: The MonoInternalThread on which to operate.
1473 * Gets the priority of the given thread.
1474 * @return: The priority of the given thread.
1477 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1480 MonoInternalThread *internal = this_obj->internal_thread;
1482 LOCK_THREAD (internal);
1483 priority = internal->priority;
1484 UNLOCK_THREAD (internal);
1490 * ves_icall_System_Threading_Thread_SetPriority_internal:
1491 * @param this_obj: The MonoInternalThread on which to operate.
1492 * @param priority: The priority to set.
1494 * Sets the priority of the given thread.
1497 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1499 MonoInternalThread *internal = this_obj->internal_thread;
1501 LOCK_THREAD (internal);
1502 internal->priority = priority;
1503 if (internal->handle != NULL)
1504 mono_thread_internal_set_priority (internal, priority);
1505 UNLOCK_THREAD (internal);
1508 /* If the array is already in the requested domain, we just return it,
1509 otherwise we return a copy in that domain. */
1511 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1515 mono_error_init (error);
1519 if (mono_object_domain (arr) == domain)
1522 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1523 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1528 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1531 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1532 mono_error_set_pending_exception (&error);
1537 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1540 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1541 mono_error_set_pending_exception (&error);
1546 mono_thread_current (void)
1548 MonoDomain *domain = mono_domain_get ();
1549 MonoInternalThread *internal = mono_thread_internal_current ();
1550 MonoThread **current_thread_ptr;
1552 g_assert (internal);
1553 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1555 if (!*current_thread_ptr) {
1556 g_assert (domain != mono_get_root_domain ());
1557 *current_thread_ptr = new_thread_with_internal (domain, internal);
1559 return *current_thread_ptr;
1562 /* Return the thread object belonging to INTERNAL in the current domain */
1564 mono_thread_current_for_thread (MonoInternalThread *internal)
1566 MonoDomain *domain = mono_domain_get ();
1567 MonoThread **current_thread_ptr;
1569 g_assert (internal);
1570 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1572 if (!*current_thread_ptr) {
1573 g_assert (domain != mono_get_root_domain ());
1574 *current_thread_ptr = new_thread_with_internal (domain, internal);
1576 return *current_thread_ptr;
1580 mono_thread_internal_current (void)
1582 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1583 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1588 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1590 MonoInternalThread *thread = this_obj->internal_thread;
1591 HANDLE handle = thread->handle;
1592 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1595 if (mono_thread_current_check_pending_interrupt ())
1598 LOCK_THREAD (thread);
1600 if ((thread->state & ThreadState_Unstarted) != 0) {
1601 UNLOCK_THREAD (thread);
1603 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1607 UNLOCK_THREAD (thread);
1612 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1614 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1617 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1620 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1622 if(ret==WAIT_OBJECT_0) {
1623 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1628 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1633 #define MANAGED_WAIT_FAILED 0x7fffffff
1636 map_native_wait_result_to_managed (gint32 val)
1638 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1639 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1643 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1651 mono_error_init (error);
1653 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1656 if (numhandles != 1)
1657 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1659 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1662 if (ret != WAIT_IO_COMPLETION)
1665 exc = mono_thread_execute_interruption ();
1667 mono_error_set_exception_instance (error, exc);
1674 /* Re-calculate ms according to the time passed */
1675 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1676 if (diff_ms >= ms) {
1680 wait = ms - diff_ms;
1686 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1693 MonoObject *waitHandle;
1694 MonoInternalThread *thread = mono_thread_internal_current ();
1696 /* Do this WaitSleepJoin check before creating objects */
1697 if (mono_thread_current_check_pending_interrupt ())
1698 return map_native_wait_result_to_managed (WAIT_FAILED);
1700 /* We fail in managed if the array has more than 64 elements */
1701 numhandles = (guint32)mono_array_length(mono_handles);
1702 handles = g_new0(HANDLE, numhandles);
1704 for(i = 0; i < numhandles; i++) {
1705 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1706 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1713 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1715 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1717 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1721 mono_error_set_pending_exception (&error);
1723 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1724 return map_native_wait_result_to_managed (ret);
1727 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1730 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1731 uintptr_t numhandles;
1734 MonoObject *waitHandle;
1735 MonoInternalThread *thread = mono_thread_internal_current ();
1737 /* Do this WaitSleepJoin check before creating objects */
1738 if (mono_thread_current_check_pending_interrupt ())
1739 return map_native_wait_result_to_managed (WAIT_FAILED);
1741 numhandles = mono_array_length(mono_handles);
1742 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1743 return map_native_wait_result_to_managed (WAIT_FAILED);
1745 for(i = 0; i < numhandles; i++) {
1746 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1747 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1754 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1756 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1758 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1760 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1762 mono_error_set_pending_exception (&error);
1764 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1766 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1767 return map_native_wait_result_to_managed (ret - WAIT_OBJECT_0);
1769 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1770 return map_native_wait_result_to_managed (ret - WAIT_ABANDONED_0);
1773 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1774 return map_native_wait_result_to_managed (ret);
1778 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1782 MonoInternalThread *thread = mono_thread_internal_current ();
1784 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1790 if (mono_thread_current_check_pending_interrupt ())
1791 return map_native_wait_result_to_managed (WAIT_FAILED);
1793 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1795 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1797 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1799 mono_error_set_pending_exception (&error);
1800 return map_native_wait_result_to_managed (ret);
1804 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1807 MonoInternalThread *thread = mono_thread_internal_current ();
1812 if (mono_thread_current_check_pending_interrupt ())
1813 return map_native_wait_result_to_managed (WAIT_FAILED);
1815 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1818 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1821 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1823 return map_native_wait_result_to_managed (ret);
1826 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1828 return InterlockedIncrement (location);
1831 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1833 #if SIZEOF_VOID_P == 4
1834 if (G_UNLIKELY ((size_t)location & 0x7)) {
1836 mono_interlocked_lock ();
1839 mono_interlocked_unlock ();
1843 return InterlockedIncrement64 (location);
1846 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1848 return InterlockedDecrement(location);
1851 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1853 #if SIZEOF_VOID_P == 4
1854 if (G_UNLIKELY ((size_t)location & 0x7)) {
1856 mono_interlocked_lock ();
1859 mono_interlocked_unlock ();
1863 return InterlockedDecrement64 (location);
1866 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1868 return InterlockedExchange(location, value);
1871 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1874 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1875 mono_gc_wbarrier_generic_nostore (location);
1879 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1881 return InterlockedExchangePointer(location, value);
1884 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1886 IntFloatUnion val, ret;
1889 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1895 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1897 #if SIZEOF_VOID_P == 4
1898 if (G_UNLIKELY ((size_t)location & 0x7)) {
1900 mono_interlocked_lock ();
1903 mono_interlocked_unlock ();
1907 return InterlockedExchange64 (location, value);
1911 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1913 LongDoubleUnion val, ret;
1916 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1921 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1923 return InterlockedCompareExchange(location, value, comparand);
1926 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1928 gint32 r = InterlockedCompareExchange(location, value, comparand);
1929 *success = r == comparand;
1933 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1936 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1937 mono_gc_wbarrier_generic_nostore (location);
1941 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1943 return InterlockedCompareExchangePointer(location, value, comparand);
1946 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1948 IntFloatUnion val, ret, cmp;
1951 cmp.fval = comparand;
1952 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1958 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1960 #if SIZEOF_VOID_P == 8
1961 LongDoubleUnion val, comp, ret;
1964 comp.fval = comparand;
1965 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1971 mono_interlocked_lock ();
1973 if (old == comparand)
1975 mono_interlocked_unlock ();
1982 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1984 #if SIZEOF_VOID_P == 4
1985 if (G_UNLIKELY ((size_t)location & 0x7)) {
1987 mono_interlocked_lock ();
1989 if (old == comparand)
1991 mono_interlocked_unlock ();
1995 return InterlockedCompareExchange64 (location, value, comparand);
1999 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2002 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2003 mono_gc_wbarrier_generic_nostore (location);
2008 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2011 MONO_CHECK_NULL (location, NULL);
2012 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2013 mono_gc_wbarrier_generic_nostore (location);
2018 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2020 return InterlockedAdd (location, value);
2024 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2026 #if SIZEOF_VOID_P == 4
2027 if (G_UNLIKELY ((size_t)location & 0x7)) {
2029 mono_interlocked_lock ();
2032 mono_interlocked_unlock ();
2036 return InterlockedAdd64 (location, value);
2040 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2042 #if SIZEOF_VOID_P == 4
2043 if (G_UNLIKELY ((size_t)location & 0x7)) {
2045 mono_interlocked_lock ();
2047 mono_interlocked_unlock ();
2051 return InterlockedRead64 (location);
2055 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2057 mono_memory_barrier ();
2061 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2063 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2065 if (state & ThreadState_Background) {
2066 /* If the thread changes the background mode, the main thread has to
2067 * be notified, since it has to rebuild the list of threads to
2070 mono_w32event_set (background_change_event);
2075 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2077 mono_thread_set_state (this_obj, (MonoThreadState)state);
2079 if (state & ThreadState_Background) {
2080 /* If the thread changes the background mode, the main thread has to
2081 * be notified, since it has to rebuild the list of threads to
2084 mono_w32event_set (background_change_event);
2089 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2093 LOCK_THREAD (this_obj);
2095 state = this_obj->state;
2097 UNLOCK_THREAD (this_obj);
2102 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2104 MonoInternalThread *current;
2106 MonoInternalThread *thread = this_obj->internal_thread;
2108 LOCK_THREAD (thread);
2110 current = mono_thread_internal_current ();
2112 thread->thread_interrupt_requested = TRUE;
2113 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2115 UNLOCK_THREAD (thread);
2118 async_abort_internal (thread, FALSE);
2123 * mono_thread_current_check_pending_interrupt:
2125 * Checks if there's a interruption request and set the pending exception if so.
2127 * @returns true if a pending exception was set
2130 mono_thread_current_check_pending_interrupt (void)
2132 MonoInternalThread *thread = mono_thread_internal_current ();
2133 gboolean throw_ = FALSE;
2135 LOCK_THREAD (thread);
2137 if (thread->thread_interrupt_requested) {
2139 thread->thread_interrupt_requested = FALSE;
2142 UNLOCK_THREAD (thread);
2145 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2150 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2152 LOCK_THREAD (thread);
2154 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2155 (thread->state & ThreadState_StopRequested) != 0 ||
2156 (thread->state & ThreadState_Stopped) != 0)
2158 UNLOCK_THREAD (thread);
2162 if ((thread->state & ThreadState_Unstarted) != 0) {
2163 thread->state |= ThreadState_Aborted;
2164 UNLOCK_THREAD (thread);
2168 thread->state |= ThreadState_AbortRequested;
2169 if (thread->abort_state_handle)
2170 mono_gchandle_free (thread->abort_state_handle);
2172 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2173 g_assert (thread->abort_state_handle);
2175 thread->abort_state_handle = 0;
2177 thread->abort_exc = NULL;
2179 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));
2181 /* During shutdown, we can't wait for other threads */
2183 /* Make sure the thread is awake */
2184 mono_thread_resume (thread);
2186 UNLOCK_THREAD (thread);
2191 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2193 if (!request_thread_abort (thread, state))
2196 if (thread == mono_thread_internal_current ()) {
2198 self_abort_internal (&error);
2199 mono_error_set_pending_exception (&error);
2201 async_abort_internal (thread, TRUE);
2206 * mono_thread_internal_abort:
2208 * Request thread @thread to be aborted.
2210 * @thread MUST NOT be the current thread.
2213 mono_thread_internal_abort (MonoInternalThread *thread)
2215 g_assert (thread != mono_thread_internal_current ());
2217 if (!request_thread_abort (thread, NULL))
2219 async_abort_internal (thread, TRUE);
2223 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2225 MonoInternalThread *thread = mono_thread_internal_current ();
2226 gboolean was_aborting;
2228 LOCK_THREAD (thread);
2229 was_aborting = thread->state & ThreadState_AbortRequested;
2230 thread->state &= ~ThreadState_AbortRequested;
2231 UNLOCK_THREAD (thread);
2233 if (!was_aborting) {
2234 const char *msg = "Unable to reset abort because no abort was requested";
2235 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2238 thread->abort_exc = NULL;
2239 if (thread->abort_state_handle) {
2240 mono_gchandle_free (thread->abort_state_handle);
2241 /* This is actually not necessary - the handle
2242 only counts if the exception is set */
2243 thread->abort_state_handle = 0;
2248 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2250 LOCK_THREAD (thread);
2252 thread->state &= ~ThreadState_AbortRequested;
2254 if (thread->abort_exc) {
2255 thread->abort_exc = NULL;
2256 if (thread->abort_state_handle) {
2257 mono_gchandle_free (thread->abort_state_handle);
2258 /* This is actually not necessary - the handle
2259 only counts if the exception is set */
2260 thread->abort_state_handle = 0;
2264 UNLOCK_THREAD (thread);
2268 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2271 MonoInternalThread *thread = this_obj->internal_thread;
2272 MonoObject *state, *deserialized = NULL;
2275 if (!thread->abort_state_handle)
2278 state = mono_gchandle_get_target (thread->abort_state_handle);
2281 domain = mono_domain_get ();
2282 if (mono_object_domain (state) == domain)
2285 deserialized = mono_object_xdomain_representation (state, domain, &error);
2287 if (!deserialized) {
2288 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2289 if (!is_ok (&error)) {
2290 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2291 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2293 mono_set_pending_exception (invalid_op_exc);
2297 return deserialized;
2301 mono_thread_suspend (MonoInternalThread *thread)
2303 LOCK_THREAD (thread);
2305 if ((thread->state & ThreadState_Unstarted) != 0 ||
2306 (thread->state & ThreadState_Aborted) != 0 ||
2307 (thread->state & ThreadState_Stopped) != 0)
2309 UNLOCK_THREAD (thread);
2313 if ((thread->state & ThreadState_Suspended) != 0 ||
2314 (thread->state & ThreadState_SuspendRequested) != 0 ||
2315 (thread->state & ThreadState_StopRequested) != 0)
2317 UNLOCK_THREAD (thread);
2321 thread->state |= ThreadState_SuspendRequested;
2323 if (thread == mono_thread_internal_current ()) {
2324 /* calls UNLOCK_THREAD (thread) */
2325 self_suspend_internal ();
2327 /* calls UNLOCK_THREAD (thread) */
2328 async_suspend_internal (thread, FALSE);
2335 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2337 if (!mono_thread_suspend (this_obj->internal_thread)) {
2338 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2343 /* LOCKING: LOCK_THREAD(thread) must be held */
2345 mono_thread_resume (MonoInternalThread *thread)
2347 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2348 thread->state &= ~ThreadState_SuspendRequested;
2352 if ((thread->state & ThreadState_Suspended) == 0 ||
2353 (thread->state & ThreadState_Unstarted) != 0 ||
2354 (thread->state & ThreadState_Aborted) != 0 ||
2355 (thread->state & ThreadState_Stopped) != 0)
2360 UNLOCK_THREAD (thread);
2362 /* Awake the thread */
2363 if (!mono_thread_info_resume (thread_get_tid (thread)))
2366 LOCK_THREAD (thread);
2368 thread->state &= ~ThreadState_Suspended;
2374 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2376 if (!thread->internal_thread) {
2377 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2379 LOCK_THREAD (thread->internal_thread);
2380 if (!mono_thread_resume (thread->internal_thread))
2381 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2382 UNLOCK_THREAD (thread->internal_thread);
2387 mono_threads_is_critical_method (MonoMethod *method)
2389 switch (method->wrapper_type) {
2390 case MONO_WRAPPER_RUNTIME_INVOKE:
2391 case MONO_WRAPPER_XDOMAIN_INVOKE:
2392 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2399 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2404 if (mono_threads_is_critical_method (m)) {
2405 *((gboolean*)data) = TRUE;
2412 is_running_protected_wrapper (void)
2414 gboolean found = FALSE;
2415 mono_stack_walk (find_wrapper, &found);
2420 request_thread_stop (MonoInternalThread *thread)
2422 LOCK_THREAD (thread);
2424 if ((thread->state & ThreadState_StopRequested) != 0 ||
2425 (thread->state & ThreadState_Stopped) != 0)
2427 UNLOCK_THREAD (thread);
2431 /* Make sure the thread is awake */
2432 mono_thread_resume (thread);
2434 thread->state |= ThreadState_StopRequested;
2435 thread->state &= ~ThreadState_AbortRequested;
2437 UNLOCK_THREAD (thread);
2442 * mono_thread_internal_stop:
2444 * Request thread @thread to stop.
2446 * @thread MUST NOT be the current thread.
2449 mono_thread_internal_stop (MonoInternalThread *thread)
2451 g_assert (thread != mono_thread_internal_current ());
2453 if (!request_thread_stop (thread))
2456 async_abort_internal (thread, TRUE);
2459 void mono_thread_stop (MonoThread *thread)
2461 MonoInternalThread *internal = thread->internal_thread;
2463 if (!request_thread_stop (internal))
2466 if (internal == mono_thread_internal_current ()) {
2468 self_abort_internal (&error);
2470 This function is part of the embeding API and has no way to return the exception
2471 to be thrown. So what we do is keep the old behavior and raise the exception.
2473 mono_error_raise_exception (&error); /* OK to throw, see note */
2475 async_abort_internal (internal, TRUE);
2480 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2482 gint8 tmp = *(volatile gint8 *)ptr;
2483 mono_memory_barrier ();
2488 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2490 gint16 tmp = *(volatile gint16 *)ptr;
2491 mono_memory_barrier ();
2496 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2498 gint32 tmp = *(volatile gint32 *)ptr;
2499 mono_memory_barrier ();
2504 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2506 gint64 tmp = *(volatile gint64 *)ptr;
2507 mono_memory_barrier ();
2512 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2514 volatile void *tmp = *(volatile void **)ptr;
2515 mono_memory_barrier ();
2516 return (void *) tmp;
2520 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2522 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2523 mono_memory_barrier ();
2524 return (MonoObject *) tmp;
2528 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2530 double tmp = *(volatile double *)ptr;
2531 mono_memory_barrier ();
2536 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2538 float tmp = *(volatile float *)ptr;
2539 mono_memory_barrier ();
2544 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2546 return InterlockedRead8 ((volatile gint8 *)ptr);
2550 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2552 return InterlockedRead16 ((volatile gint16 *)ptr);
2556 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2558 return InterlockedRead ((volatile gint32 *)ptr);
2562 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2564 #if SIZEOF_VOID_P == 4
2565 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2567 mono_interlocked_lock ();
2568 val = *(gint64*)ptr;
2569 mono_interlocked_unlock ();
2573 return InterlockedRead64 ((volatile gint64 *)ptr);
2577 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2579 return InterlockedReadPointer ((volatile gpointer *)ptr);
2583 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2587 #if SIZEOF_VOID_P == 4
2588 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2590 mono_interlocked_lock ();
2591 val = *(double*)ptr;
2592 mono_interlocked_unlock ();
2597 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2603 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2607 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2613 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2615 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2619 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2621 mono_memory_barrier ();
2622 *(volatile gint8 *)ptr = value;
2626 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2628 mono_memory_barrier ();
2629 *(volatile gint16 *)ptr = value;
2633 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2635 mono_memory_barrier ();
2636 *(volatile gint32 *)ptr = value;
2640 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2642 mono_memory_barrier ();
2643 *(volatile gint64 *)ptr = value;
2647 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2649 mono_memory_barrier ();
2650 *(volatile void **)ptr = value;
2654 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2656 mono_memory_barrier ();
2657 mono_gc_wbarrier_generic_store (ptr, value);
2661 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2663 mono_memory_barrier ();
2664 *(volatile double *)ptr = value;
2668 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2670 mono_memory_barrier ();
2671 *(volatile float *)ptr = value;
2675 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2677 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2681 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2683 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2687 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2689 InterlockedWrite ((volatile gint32 *)ptr, value);
2693 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2695 #if SIZEOF_VOID_P == 4
2696 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2697 mono_interlocked_lock ();
2698 *(gint64*)ptr = value;
2699 mono_interlocked_unlock ();
2704 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2708 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2710 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2714 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2718 #if SIZEOF_VOID_P == 4
2719 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2720 mono_interlocked_lock ();
2721 *(double*)ptr = value;
2722 mono_interlocked_unlock ();
2729 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2733 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2739 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2743 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2745 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2749 free_context (void *user_data)
2751 ContextStaticData *data = user_data;
2753 mono_threads_lock ();
2756 * There is no guarantee that, by the point this reference queue callback
2757 * has been invoked, the GC handle associated with the object will fail to
2758 * resolve as one might expect. So if we don't free and remove the GC
2759 * handle here, free_context_static_data_helper () could end up resolving
2760 * a GC handle to an actually-dead context which would contain a pointer
2761 * to an already-freed static data segment, resulting in a crash when
2764 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2766 mono_threads_unlock ();
2768 mono_gchandle_free (data->gc_handle);
2769 mono_free_static_data (data->static_data);
2774 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2776 mono_threads_lock ();
2778 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2781 contexts = g_hash_table_new (NULL, NULL);
2784 context_queue = mono_gc_reference_queue_new (free_context);
2786 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2787 g_hash_table_insert (contexts, gch, gch);
2790 * We use this intermediate structure to contain a duplicate pointer to
2791 * the static data because we can't rely on being able to resolve the GC
2792 * handle in the reference queue callback.
2794 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2795 data->gc_handle = GPOINTER_TO_UINT (gch);
2798 context_adjust_static_data (ctx);
2799 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2801 mono_threads_unlock ();
2803 mono_profiler_context_loaded (ctx);
2807 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2810 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2811 * cleanup in exceptional circumstances, we don't actually do any
2812 * cleanup work here. We instead do this via a reference queue.
2815 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2817 mono_profiler_context_unloaded (ctx);
2821 mono_thread_init_tls (void)
2823 MONO_FAST_TLS_INIT (tls_current_object);
2824 mono_native_tls_alloc (¤t_object_key, NULL);
2827 void mono_thread_init (MonoThreadStartCB start_cb,
2828 MonoThreadAttachCB attach_cb)
2830 mono_coop_mutex_init_recursive (&threads_mutex);
2832 mono_os_mutex_init_recursive(&interlocked_mutex);
2833 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2835 background_change_event = mono_w32event_create (TRUE, FALSE);
2836 g_assert(background_change_event != NULL);
2838 mono_init_static_data_info (&thread_static_info);
2839 mono_init_static_data_info (&context_static_info);
2841 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2843 mono_thread_start_cb = start_cb;
2844 mono_thread_attach_cb = attach_cb;
2846 /* Get a pseudo handle to the current process. This is just a
2847 * kludge so that wapi can build a process handle if needed.
2848 * As a pseudo handle is returned, we don't need to clean
2851 GetCurrentProcess ();
2854 void mono_thread_cleanup (void)
2856 #if !defined(RUN_IN_SUBTHREAD)
2857 /* The main thread must abandon any held mutexes (particularly
2858 * important for named mutexes as they are shared across
2859 * processes, see bug 74680.) This will happen when the
2860 * thread exits, but if it's not running in a subthread it
2861 * won't exit in time.
2863 mono_thread_info_set_exited (mono_thread_info_current ());
2867 /* This stuff needs more testing, it seems one of these
2868 * critical sections can be locked when mono_thread_cleanup is
2871 mono_coop_mutex_destroy (&threads_mutex);
2872 mono_os_mutex_destroy (&interlocked_mutex);
2873 mono_os_mutex_destroy (&delayed_free_table_mutex);
2874 mono_os_mutex_destroy (&small_id_mutex);
2875 CloseHandle (background_change_event);
2878 mono_native_tls_free (current_object_key);
2882 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2884 mono_thread_cleanup_fn = func;
2888 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2890 thread->internal_thread->manage_callback = func;
2894 static void print_tids (gpointer key, gpointer value, gpointer user)
2896 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2897 * sizeof(uint) and a cast to uint would overflow
2899 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2900 * print this as a pointer.
2902 g_message ("Waiting for: %p", key);
2907 HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2908 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2913 wait_for_tids (struct wait_data *wait, guint32 timeout)
2917 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2920 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2923 if(ret==WAIT_FAILED) {
2924 /* See the comment in build_wait_tids() */
2925 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2929 for(i=0; i<wait->num; i++)
2930 mono_threads_close_thread_handle (wait->handles [i]);
2932 if (ret == WAIT_TIMEOUT)
2935 for(i=0; i<wait->num; i++) {
2936 gsize tid = wait->threads[i]->tid;
2939 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2940 * it can still run io-layer etc. code. So wait for it to really exit.
2941 * FIXME: This won't join threads which are not in the joinable_hash yet.
2943 mono_thread_join ((gpointer)tid);
2945 mono_threads_lock ();
2946 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2947 /* This thread must have been killed, because
2948 * it hasn't cleaned itself up. (It's just
2949 * possible that the thread exited before the
2950 * parent thread had a chance to store the
2951 * handle, and now there is another pointer to
2952 * the already-exited thread stored. In this
2953 * case, we'll just get two
2954 * mono_profiler_thread_end() calls for the
2958 mono_threads_unlock ();
2959 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2960 thread_cleanup (wait->threads[i]);
2962 mono_threads_unlock ();
2967 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2969 guint32 i, ret, count;
2971 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2973 /* Add the thread state change event, so it wakes up if a thread changes
2974 * to background mode.
2977 if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
2978 wait->handles [count] = background_change_event;
2983 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2986 if(ret==WAIT_FAILED) {
2987 /* See the comment in build_wait_tids() */
2988 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2992 for(i=0; i<wait->num; i++)
2993 mono_threads_close_thread_handle (wait->handles [i]);
2995 if (ret == WAIT_TIMEOUT)
2998 if (ret < wait->num) {
2999 gsize tid = wait->threads[ret]->tid;
3000 mono_threads_lock ();
3001 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3002 /* See comment in wait_for_tids about thread cleanup */
3003 mono_threads_unlock ();
3004 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3005 thread_cleanup (wait->threads [ret]);
3007 mono_threads_unlock ();
3011 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3013 struct wait_data *wait=(struct wait_data *)user;
3015 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3017 MonoInternalThread *thread=(MonoInternalThread *)value;
3019 /* Ignore background threads, we abort them later */
3020 /* Do not lock here since it is not needed and the caller holds threads_lock */
3021 if (thread->state & ThreadState_Background) {
3022 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3023 return; /* just leave, ignore */
3026 if (mono_gc_is_finalizer_internal_thread (thread)) {
3027 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3031 if (thread == mono_thread_internal_current ()) {
3032 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3036 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3037 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3041 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3042 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3046 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3047 if (handle == NULL) {
3048 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3052 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3053 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3054 wait->handles[wait->num]=handle;
3055 wait->threads[wait->num]=thread;
3058 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3060 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3065 /* Just ignore the rest, we can't do anything with
3072 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3074 struct wait_data *wait=(struct wait_data *)user;
3075 MonoNativeThreadId self = mono_native_thread_id_get ();
3076 MonoInternalThread *thread = (MonoInternalThread *)value;
3079 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3082 /* The finalizer thread is not a background thread */
3083 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3084 && (thread->state & ThreadState_Background) != 0
3085 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3087 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3091 wait->handles[wait->num] = handle;
3092 wait->threads[wait->num] = thread;
3095 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3096 mono_thread_internal_abort (thread);
3100 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3101 && !mono_gc_is_finalizer_internal_thread (thread);
3105 * mono_threads_set_shutting_down:
3107 * Is called by a thread that wants to shut down Mono. If the runtime is already
3108 * shutting down, the calling thread is suspended/stopped, and this function never
3112 mono_threads_set_shutting_down (void)
3114 MonoInternalThread *current_thread = mono_thread_internal_current ();
3116 mono_threads_lock ();
3118 if (shutting_down) {
3119 mono_threads_unlock ();
3121 /* Make sure we're properly suspended/stopped */
3123 LOCK_THREAD (current_thread);
3125 if ((current_thread->state & ThreadState_SuspendRequested) ||
3126 (current_thread->state & ThreadState_AbortRequested) ||
3127 (current_thread->state & ThreadState_StopRequested)) {
3128 UNLOCK_THREAD (current_thread);
3129 mono_thread_execute_interruption ();
3131 current_thread->state |= ThreadState_Stopped;
3132 UNLOCK_THREAD (current_thread);
3135 /*since we're killing the thread, unset the current domain.*/
3136 mono_domain_unset ();
3138 /* Wake up other threads potentially waiting for us */
3139 mono_thread_info_exit ();
3141 shutting_down = TRUE;
3143 /* Not really a background state change, but this will
3144 * interrupt the main thread if it is waiting for all
3145 * the other threads.
3147 mono_w32event_set (background_change_event);
3149 mono_threads_unlock ();
3153 void mono_thread_manage (void)
3155 struct wait_data wait_data;
3156 struct wait_data *wait = &wait_data;
3158 memset (wait, 0, sizeof (struct wait_data));
3159 /* join each thread that's still running */
3160 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3162 mono_threads_lock ();
3164 THREAD_DEBUG (g_message("%s: No threads", __func__));
3165 mono_threads_unlock ();
3168 mono_threads_unlock ();
3171 mono_threads_lock ();
3172 if (shutting_down) {
3173 /* somebody else is shutting down */
3174 mono_threads_unlock ();
3177 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3178 mono_g_hash_table_foreach (threads, print_tids, NULL));
3180 mono_w32event_reset (background_change_event);
3182 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3183 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3184 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3185 mono_threads_unlock ();
3187 /* Something to wait for */
3188 wait_for_tids_or_state_change (wait, INFINITE);
3190 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3191 } while(wait->num>0);
3193 /* Mono is shutting down, so just wait for the end */
3194 if (!mono_runtime_try_shutdown ()) {
3195 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3196 mono_thread_suspend (mono_thread_internal_current ());
3197 mono_thread_execute_interruption ();
3201 * Remove everything but the finalizer thread and self.
3202 * Also abort all the background threads
3205 mono_threads_lock ();
3208 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3209 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3210 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3212 mono_threads_unlock ();
3214 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3216 /* Something to wait for */
3217 wait_for_tids (wait, INFINITE);
3219 } while (wait->num > 0);
3222 * give the subthreads a chance to really quit (this is mainly needed
3223 * to get correct user and system times from getrusage/wait/time(1)).
3224 * This could be removed if we avoid pthread_detach() and use pthread_join().
3226 mono_thread_info_yield ();
3230 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3232 MonoInternalThread *thread = (MonoInternalThread*)value;
3233 struct wait_data *wait = (struct wait_data*)user_data;
3237 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3239 * This needs no locking.
3241 if ((thread->state & ThreadState_Suspended) != 0 ||
3242 (thread->state & ThreadState_Stopped) != 0)
3245 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3246 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3250 wait->handles [wait->num] = handle;
3251 wait->threads [wait->num] = thread;
3257 * mono_thread_suspend_all_other_threads:
3259 * Suspend all managed threads except the finalizer thread and this thread. It is
3260 * not possible to resume them later.
3262 void mono_thread_suspend_all_other_threads (void)
3264 struct wait_data wait_data;
3265 struct wait_data *wait = &wait_data;
3267 MonoNativeThreadId self = mono_native_thread_id_get ();
3268 guint32 eventidx = 0;
3269 gboolean starting, finished;
3271 memset (wait, 0, sizeof (struct wait_data));
3273 * The other threads could be in an arbitrary state at this point, i.e.
3274 * they could be starting up, shutting down etc. This means that there could be
3275 * threads which are not even in the threads hash table yet.
3279 * First we set a barrier which will be checked by all threads before they
3280 * are added to the threads hash table, and they will exit if the flag is set.
3281 * This ensures that no threads could be added to the hash later.
3282 * We will use shutting_down as the barrier for now.
3284 g_assert (shutting_down);
3287 * We make multiple calls to WaitForMultipleObjects since:
3288 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3289 * - some threads could exit without becoming suspended
3294 * Make a copy of the hashtable since we can't do anything with
3295 * threads while threads_mutex is held.
3298 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3299 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3300 mono_threads_lock ();
3301 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3302 mono_threads_unlock ();
3305 /* Get the suspended events that we'll be waiting for */
3306 for (i = 0; i < wait->num; ++i) {
3307 MonoInternalThread *thread = wait->threads [i];
3309 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3310 || mono_gc_is_finalizer_internal_thread (thread)
3311 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3313 //mono_threads_close_thread_handle (wait->handles [i]);
3314 wait->threads [i] = NULL; /* ignore this thread in next loop */
3318 LOCK_THREAD (thread);
3320 if ((thread->state & ThreadState_Suspended) != 0 ||
3321 (thread->state & ThreadState_StopRequested) != 0 ||
3322 (thread->state & ThreadState_Stopped) != 0) {
3323 UNLOCK_THREAD (thread);
3324 mono_threads_close_thread_handle (wait->handles [i]);
3325 wait->threads [i] = NULL; /* ignore this thread in next loop */
3331 /* Convert abort requests into suspend requests */
3332 if ((thread->state & ThreadState_AbortRequested) != 0)
3333 thread->state &= ~ThreadState_AbortRequested;
3335 thread->state |= ThreadState_SuspendRequested;
3337 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3338 async_suspend_internal (thread, TRUE);
3340 if (eventidx <= 0) {
3342 * If there are threads which are starting up, we wait until they
3343 * are suspended when they try to register in the threads hash.
3344 * This is guaranteed to finish, since the threads which can create new
3345 * threads get suspended after a while.
3346 * FIXME: The finalizer thread can still create new threads.
3348 mono_threads_lock ();
3349 if (threads_starting_up)
3350 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3353 mono_threads_unlock ();
3355 mono_thread_info_sleep (100, NULL);
3363 MonoInternalThread *thread;
3364 MonoStackFrameInfo *frames;
3365 int nframes, max_frames;
3366 int nthreads, max_threads;
3367 MonoInternalThread **threads;
3368 } ThreadDumpUserData;
3370 static gboolean thread_dump_requested;
3372 /* This needs to be async safe */
3374 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3376 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3378 if (ud->nframes < ud->max_frames) {
3379 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3386 /* This needs to be async safe */
3387 static SuspendThreadResult
3388 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3390 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3391 MonoInternalThread *thread = user_data->thread;
3394 /* This no longer works with remote unwinding */
3395 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3396 mono_thread_info_describe (info, text);
3397 g_string_append (text, "\n");
3400 if (thread == mono_thread_internal_current ())
3401 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3403 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3405 return MonoResumeThread;
3409 int nthreads, max_threads;
3410 MonoInternalThread **threads;
3411 } CollectThreadsUserData;
3414 collect_thread (gpointer key, gpointer value, gpointer user)
3416 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3417 MonoInternalThread *thread = (MonoInternalThread *)value;
3419 if (ud->nthreads < ud->max_threads)
3420 ud->threads [ud->nthreads ++] = thread;
3424 * Collect running threads into the THREADS array.
3425 * THREADS should be an array allocated on the stack.
3428 collect_threads (MonoInternalThread **thread_array, int max_threads)
3430 CollectThreadsUserData ud;
3432 memset (&ud, 0, sizeof (ud));
3433 /* This array contains refs, but its on the stack, so its ok */
3434 ud.threads = thread_array;
3435 ud.max_threads = max_threads;
3437 mono_threads_lock ();
3438 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3439 mono_threads_unlock ();
3445 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3447 GString* text = g_string_new (0);
3449 GError *error = NULL;
3452 ud->thread = thread;
3455 /* Collect frames for the thread */
3456 if (thread == mono_thread_internal_current ()) {
3457 get_thread_dump (mono_thread_info_current (), ud);
3459 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3463 * Do all the non async-safe work outside of get_thread_dump.
3466 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3468 g_string_append_printf (text, "\n\"%s\"", name);
3471 else if (thread->threadpool_thread) {
3472 g_string_append (text, "\n\"<threadpool thread>\"");
3474 g_string_append (text, "\n\"<unnamed thread>\"");
3477 for (i = 0; i < ud->nframes; ++i) {
3478 MonoStackFrameInfo *frame = &ud->frames [i];
3479 MonoMethod *method = NULL;
3481 if (frame->type == FRAME_TYPE_MANAGED)
3482 method = mono_jit_info_get_method (frame->ji);
3485 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3486 g_string_append_printf (text, " %s\n", location);
3489 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3493 fprintf (stdout, "%s", text->str);
3495 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3496 OutputDebugStringA(text->str);
3499 g_string_free (text, TRUE);
3504 mono_threads_perform_thread_dump (void)
3506 ThreadDumpUserData ud;
3507 MonoInternalThread *thread_array [128];
3508 int tindex, nthreads;
3510 if (!thread_dump_requested)
3513 printf ("Full thread dump:\n");
3515 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3516 nthreads = collect_threads (thread_array, 128);
3518 memset (&ud, 0, sizeof (ud));
3519 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3520 ud.max_frames = 256;
3522 for (tindex = 0; tindex < nthreads; ++tindex)
3523 dump_thread (thread_array [tindex], &ud);
3527 thread_dump_requested = FALSE;
3530 /* Obtain the thread dump of all threads */
3532 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3535 ThreadDumpUserData ud;
3536 MonoInternalThread *thread_array [128];
3537 MonoDomain *domain = mono_domain_get ();
3538 MonoDebugSourceLocation *location;
3539 int tindex, nthreads;
3541 mono_error_init (error);
3543 *out_threads = NULL;
3544 *out_stack_frames = NULL;
3546 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3547 nthreads = collect_threads (thread_array, 128);
3549 memset (&ud, 0, sizeof (ud));
3550 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3551 ud.max_frames = 256;
3553 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3556 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3560 for (tindex = 0; tindex < nthreads; ++tindex) {
3561 MonoInternalThread *thread = thread_array [tindex];
3562 MonoArray *thread_frames;
3568 /* Collect frames for the thread */
3569 if (thread == mono_thread_internal_current ()) {
3570 get_thread_dump (mono_thread_info_current (), &ud);
3572 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3575 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3577 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3580 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3582 for (i = 0; i < ud.nframes; ++i) {
3583 MonoStackFrameInfo *frame = &ud.frames [i];
3584 MonoMethod *method = NULL;
3585 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3589 sf->native_offset = frame->native_offset;
3591 if (frame->type == FRAME_TYPE_MANAGED)
3592 method = mono_jit_info_get_method (frame->ji);
3595 sf->method_address = (gsize) frame->ji->code_start;
3597 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3600 MONO_OBJECT_SETREF (sf, method, rm);
3602 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3604 sf->il_offset = location->il_offset;
3606 if (location && location->source_file) {
3607 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3608 sf->line = location->row;
3609 sf->column = location->column;
3611 mono_debug_free_source_location (location);
3616 mono_array_setref (thread_frames, i, sf);
3622 return is_ok (error);
3626 * mono_threads_request_thread_dump:
3628 * Ask all threads except the current to print their stacktrace to stdout.
3631 mono_threads_request_thread_dump (void)
3633 /*The new thread dump code runs out of the finalizer thread. */
3634 thread_dump_requested = TRUE;
3635 mono_gc_finalize_notify ();
3640 gint allocated; /* +1 so that refs [allocated] == NULL */
3644 typedef struct ref_stack RefStack;
3647 ref_stack_new (gint initial_size)
3651 initial_size = MAX (initial_size, 16) + 1;
3652 rs = g_new0 (RefStack, 1);
3653 rs->refs = g_new0 (gpointer, initial_size);
3654 rs->allocated = initial_size;
3659 ref_stack_destroy (gpointer ptr)
3661 RefStack *rs = (RefStack *)ptr;
3670 ref_stack_push (RefStack *rs, gpointer ptr)
3672 g_assert (rs != NULL);
3674 if (rs->bottom >= rs->allocated) {
3675 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3676 rs->allocated <<= 1;
3677 rs->refs [rs->allocated] = NULL;
3679 rs->refs [rs->bottom++] = ptr;
3683 ref_stack_pop (RefStack *rs)
3685 if (rs == NULL || rs->bottom == 0)
3689 rs->refs [rs->bottom] = NULL;
3693 ref_stack_find (RefStack *rs, gpointer ptr)
3700 for (refs = rs->refs; refs && *refs; refs++) {
3708 * mono_thread_push_appdomain_ref:
3710 * Register that the current thread may have references to objects in domain
3711 * @domain on its stack. Each call to this function should be paired with a
3712 * call to pop_appdomain_ref.
3715 mono_thread_push_appdomain_ref (MonoDomain *domain)
3717 MonoInternalThread *thread = mono_thread_internal_current ();
3720 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3721 SPIN_LOCK (thread->lock_thread_id);
3722 if (thread->appdomain_refs == NULL)
3723 thread->appdomain_refs = ref_stack_new (16);
3724 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3725 SPIN_UNLOCK (thread->lock_thread_id);
3730 mono_thread_pop_appdomain_ref (void)
3732 MonoInternalThread *thread = mono_thread_internal_current ();
3735 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3736 SPIN_LOCK (thread->lock_thread_id);
3737 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3738 SPIN_UNLOCK (thread->lock_thread_id);
3743 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3746 SPIN_LOCK (thread->lock_thread_id);
3747 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3748 SPIN_UNLOCK (thread->lock_thread_id);
3753 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3755 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3758 typedef struct abort_appdomain_data {
3759 struct wait_data wait;
3761 } abort_appdomain_data;
3764 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3766 MonoInternalThread *thread = (MonoInternalThread*)value;
3767 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3768 MonoDomain *domain = data->domain;
3770 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3771 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3773 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3774 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3777 data->wait.handles [data->wait.num] = handle;
3778 data->wait.threads [data->wait.num] = thread;
3781 /* Just ignore the rest, we can't do anything with
3789 * mono_threads_abort_appdomain_threads:
3791 * Abort threads which has references to the given appdomain.
3794 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3796 #ifdef __native_client__
3800 abort_appdomain_data user_data;
3802 int orig_timeout = timeout;
3805 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3807 start_time = mono_msec_ticks ();
3809 mono_threads_lock ();
3811 user_data.domain = domain;
3812 user_data.wait.num = 0;
3813 /* This shouldn't take any locks */
3814 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3815 mono_threads_unlock ();
3817 if (user_data.wait.num > 0) {
3818 /* Abort the threads outside the threads lock */
3819 for (i = 0; i < user_data.wait.num; ++i)
3820 mono_thread_internal_abort (user_data.wait.threads [i]);
3823 * We should wait for the threads either to abort, or to leave the
3824 * domain. We can't do the latter, so we wait with a timeout.
3826 wait_for_tids (&user_data.wait, 100);
3829 /* Update remaining time */
3830 timeout -= mono_msec_ticks () - start_time;
3831 start_time = mono_msec_ticks ();
3833 if (orig_timeout != -1 && timeout < 0)
3836 while (user_data.wait.num > 0);
3838 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3844 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3846 MonoInternalThread *thread = (MonoInternalThread*)value;
3847 MonoDomain *domain = (MonoDomain*)user_data;
3850 /* No locking needed here */
3851 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3853 if (thread->cached_culture_info) {
3854 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3855 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3856 if (obj && obj->vtable->domain == domain)
3857 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3863 * mono_threads_clear_cached_culture:
3865 * Clear the cached_current_culture from all threads if it is in the
3869 mono_threads_clear_cached_culture (MonoDomain *domain)
3871 mono_threads_lock ();
3872 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3873 mono_threads_unlock ();
3877 * mono_thread_get_undeniable_exception:
3879 * Return an exception which needs to be raised when leaving a catch clause.
3880 * This is used for undeniable exception propagation.
3883 mono_thread_get_undeniable_exception (void)
3885 MonoInternalThread *thread = mono_thread_internal_current ();
3887 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3889 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3890 * exception if the thread no longer references a dying appdomain.
3892 thread->abort_exc->trace_ips = NULL;
3893 thread->abort_exc->stack_trace = NULL;
3894 return thread->abort_exc;
3900 #if MONO_SMALL_CONFIG
3901 #define NUM_STATIC_DATA_IDX 4
3902 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3906 #define NUM_STATIC_DATA_IDX 8
3907 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3908 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3912 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3913 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3916 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3918 gpointer *static_data = (gpointer *)addr;
3920 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3921 void **ptr = (void **)static_data [i];
3926 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3927 void **p = ptr + idx;
3930 mark_func ((MonoObject**)p, gc_data);
3936 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3938 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3942 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3944 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3948 * mono_alloc_static_data
3950 * Allocate memory blocks for storing threads or context static data
3953 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3955 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3958 gpointer* static_data = *static_data_ptr;
3960 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3961 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3963 if (mono_gc_user_markers_supported ()) {
3964 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3965 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3967 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3968 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3971 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3972 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3973 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3974 *static_data_ptr = static_data;
3975 static_data [0] = static_data;
3978 for (i = 1; i <= idx; ++i) {
3979 if (static_data [i])
3982 if (mono_gc_user_markers_supported ())
3983 static_data [i] = g_malloc0 (static_data_size [i]);
3985 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3986 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3987 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3992 mono_free_static_data (gpointer* static_data)
3995 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3996 gpointer p = static_data [i];
4000 * At this point, the static data pointer array is still registered with the
4001 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4002 * data. Freeing the individual arrays without first nulling their slots
4003 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4004 * such an already freed array. See bug #13813.
4006 static_data [i] = NULL;
4007 mono_memory_write_barrier ();
4008 if (mono_gc_user_markers_supported ())
4011 mono_gc_free_fixed (p);
4013 mono_gc_free_fixed (static_data);
4017 * mono_init_static_data_info
4019 * Initializes static data counters
4021 static void mono_init_static_data_info (StaticDataInfo *static_data)
4023 static_data->idx = 0;
4024 static_data->offset = 0;
4025 static_data->freelist = NULL;
4029 * mono_alloc_static_data_slot
4031 * Generates an offset for static data. static_data contains the counters
4032 * used to generate it.
4035 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4037 if (!static_data->idx && !static_data->offset) {
4039 * we use the first chunk of the first allocation also as
4040 * an array for the rest of the data
4042 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4044 static_data->offset += align - 1;
4045 static_data->offset &= ~(align - 1);
4046 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4047 static_data->idx ++;
4048 g_assert (size <= static_data_size [static_data->idx]);
4049 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4050 static_data->offset = 0;
4052 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4053 static_data->offset += size;
4058 * LOCKING: requires that threads_mutex is held
4061 context_adjust_static_data (MonoAppContext *ctx)
4063 if (context_static_info.offset || context_static_info.idx > 0) {
4064 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4065 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4066 ctx->data->static_data = ctx->static_data;
4071 * LOCKING: requires that threads_mutex is held
4074 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4076 MonoInternalThread *thread = (MonoInternalThread *)value;
4077 guint32 offset = GPOINTER_TO_UINT (user);
4079 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4083 * LOCKING: requires that threads_mutex is held
4086 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4088 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4093 guint32 offset = GPOINTER_TO_UINT (user);
4094 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4095 ctx->data->static_data = ctx->static_data;
4098 static StaticDataFreeList*
4099 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4101 StaticDataFreeList* prev = NULL;
4102 StaticDataFreeList* tmp = static_data->freelist;
4104 if (tmp->size == size) {
4106 prev->next = tmp->next;
4108 static_data->freelist = tmp->next;
4117 #if SIZEOF_VOID_P == 4
4124 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4126 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4128 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4129 MonoBitSet *rb = sets [idx];
4130 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4131 offset /= sizeof (uintptr_t);
4132 /* offset is now the bitmap offset */
4133 for (int i = 0; i < numbits; ++i) {
4134 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4135 mono_bitset_set_fast (rb, offset + i);
4140 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4142 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4143 MonoBitSet *rb = sets [idx];
4144 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4145 offset /= sizeof (uintptr_t);
4146 /* offset is now the bitmap offset */
4147 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4148 mono_bitset_clear_fast (rb, offset + i);
4152 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4154 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4156 StaticDataInfo *info;
4159 if (static_type == SPECIAL_STATIC_THREAD) {
4160 info = &thread_static_info;
4161 sets = thread_reference_bitmaps;
4163 info = &context_static_info;
4164 sets = context_reference_bitmaps;
4167 mono_threads_lock ();
4169 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4173 offset = item->offset;
4176 offset = mono_alloc_static_data_slot (info, size, align);
4179 update_reference_bitmap (sets, offset, bitmap, numbits);
4181 if (static_type == SPECIAL_STATIC_THREAD) {
4182 /* This can be called during startup */
4183 if (threads != NULL)
4184 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4186 if (contexts != NULL)
4187 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4189 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4192 mono_threads_unlock ();
4198 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4200 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4202 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4203 return get_thread_static_data (thread, offset);
4205 return get_context_static_data (thread->current_appcontext, offset);
4210 mono_get_special_static_data (guint32 offset)
4212 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4221 * LOCKING: requires that threads_mutex is held
4224 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4226 MonoInternalThread *thread = (MonoInternalThread *)value;
4227 OffsetSize *data = (OffsetSize *)user;
4228 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4229 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4232 if (!thread->static_data || !thread->static_data [idx])
4234 ptr = ((char*) thread->static_data [idx]) + off;
4235 mono_gc_bzero_atomic (ptr, data->size);
4239 * LOCKING: requires that threads_mutex is held
4242 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4244 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4249 OffsetSize *data = (OffsetSize *)user;
4250 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4251 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4254 if (!ctx->static_data || !ctx->static_data [idx])
4257 ptr = ((char*) ctx->static_data [idx]) + off;
4258 mono_gc_bzero_atomic (ptr, data->size);
4262 do_free_special_slot (guint32 offset, guint32 size)
4264 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4266 StaticDataInfo *info;
4268 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4269 info = &thread_static_info;
4270 sets = thread_reference_bitmaps;
4272 info = &context_static_info;
4273 sets = context_reference_bitmaps;
4276 guint32 data_offset = offset;
4277 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4278 OffsetSize data = { data_offset, size };
4280 clear_reference_bitmap (sets, data.offset, data.size);
4282 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4283 if (threads != NULL)
4284 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4286 if (contexts != NULL)
4287 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4290 if (!mono_runtime_is_shutting_down ()) {
4291 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4293 item->offset = offset;
4296 item->next = info->freelist;
4297 info->freelist = item;
4302 do_free_special (gpointer key, gpointer value, gpointer data)
4304 MonoClassField *field = (MonoClassField *)key;
4305 guint32 offset = GPOINTER_TO_UINT (value);
4308 size = mono_type_size (field->type, &align);
4309 do_free_special_slot (offset, size);
4313 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4315 mono_threads_lock ();
4317 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4319 mono_threads_unlock ();
4323 static void CALLBACK dummy_apc (ULONG_PTR param)
4329 * mono_thread_execute_interruption
4331 * Performs the operation that the requested thread state requires (abort,
4334 static MonoException*
4335 mono_thread_execute_interruption (void)
4337 MonoInternalThread *thread = mono_thread_internal_current ();
4338 MonoThread *sys_thread = mono_thread_current ();
4340 LOCK_THREAD (thread);
4342 /* MonoThread::interruption_requested can only be changed with atomics */
4343 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4344 /* this will consume pending APC calls */
4346 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4348 InterlockedDecrement (&thread_interruption_requested);
4350 /* Clear the interrupted flag of the thread so it can wait again */
4351 mono_thread_info_clear_self_interrupt ();
4354 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4355 if (sys_thread->pending_exception) {
4358 exc = sys_thread->pending_exception;
4359 sys_thread->pending_exception = NULL;
4361 UNLOCK_THREAD (thread);
4363 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4364 UNLOCK_THREAD (thread);
4365 g_assert (sys_thread->pending_exception == NULL);
4366 if (thread->abort_exc == NULL) {
4368 * This might be racy, but it has to be called outside the lock
4369 * since it calls managed code.
4371 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4373 return thread->abort_exc;
4375 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4376 /* calls UNLOCK_THREAD (thread) */
4377 self_suspend_internal ();
4380 else if ((thread->state & ThreadState_StopRequested) != 0) {
4381 /* FIXME: do this through the JIT? */
4383 UNLOCK_THREAD (thread);
4385 mono_thread_exit ();
4387 } else if (thread->thread_interrupt_requested) {
4389 thread->thread_interrupt_requested = FALSE;
4390 UNLOCK_THREAD (thread);
4392 return(mono_get_exception_thread_interrupted ());
4395 UNLOCK_THREAD (thread);
4401 * mono_thread_request_interruption
4403 * A signal handler can call this method to request the interruption of a
4404 * thread. The result of the interruption will depend on the current state of
4405 * the thread. If the result is an exception that needs to be throw, it is
4406 * provided as return value.
4409 mono_thread_request_interruption (gboolean running_managed)
4411 MonoInternalThread *thread = mono_thread_internal_current ();
4413 /* The thread may already be stopping */
4418 if (thread->interrupt_on_stop &&
4419 thread->state & ThreadState_StopRequested &&
4420 thread->state & ThreadState_Background)
4423 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4425 InterlockedIncrement (&thread_interruption_requested);
4427 if (!running_managed || is_running_protected_wrapper ()) {
4428 /* Can't stop while in unmanaged code. Increase the global interruption
4429 request count. When exiting the unmanaged method the count will be
4430 checked and the thread will be interrupted. */
4432 /* this will awake the thread if it is in WaitForSingleObject
4434 /* Our implementation of this function ignores the func argument */
4436 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4438 mono_thread_info_self_interrupt ();
4443 return mono_thread_execute_interruption ();
4447 /*This function should be called by a thread after it has exited all of
4448 * its handle blocks at interruption time.*/
4450 mono_thread_resume_interruption (void)
4452 MonoInternalThread *thread = mono_thread_internal_current ();
4453 gboolean still_aborting;
4455 /* The thread may already be stopping */
4459 LOCK_THREAD (thread);
4460 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4461 UNLOCK_THREAD (thread);
4463 /*This can happen if the protected block called Thread::ResetAbort*/
4464 if (!still_aborting)
4467 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4469 InterlockedIncrement (&thread_interruption_requested);
4471 mono_thread_info_self_interrupt ();
4473 return mono_thread_execute_interruption ();
4476 gboolean mono_thread_interruption_requested ()
4478 if (thread_interruption_requested) {
4479 MonoInternalThread *thread = mono_thread_internal_current ();
4480 /* The thread may already be stopping */
4482 return (thread->interruption_requested);
4487 static MonoException*
4488 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4490 MonoInternalThread *thread = mono_thread_internal_current ();
4492 /* The thread may already be stopping */
4496 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4497 MonoException* exc = mono_thread_execute_interruption ();
4505 * Performs the interruption of the current thread, if one has been requested,
4506 * and the thread is not running a protected wrapper.
4507 * Return the exception which needs to be thrown, if any.
4510 mono_thread_interruption_checkpoint (void)
4512 return mono_thread_interruption_checkpoint_request (FALSE);
4516 * Performs the interruption of the current thread, if one has been requested.
4517 * Return the exception which needs to be thrown, if any.
4520 mono_thread_force_interruption_checkpoint_noraise (void)
4522 return mono_thread_interruption_checkpoint_request (TRUE);
4526 * mono_set_pending_exception:
4528 * Set the pending exception of the current thread to EXC.
4529 * The exception will be thrown when execution returns to managed code.
4532 mono_set_pending_exception (MonoException *exc)
4534 MonoThread *thread = mono_thread_current ();
4536 /* The thread may already be stopping */
4540 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4542 mono_thread_request_interruption (FALSE);
4546 * mono_thread_interruption_request_flag:
4548 * Returns the address of a flag that will be non-zero if an interruption has
4549 * been requested for a thread. The thread to interrupt may not be the current
4550 * thread, so an additional call to mono_thread_interruption_requested() or
4551 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4554 gint32* mono_thread_interruption_request_flag ()
4556 return &thread_interruption_requested;
4560 mono_thread_init_apartment_state (void)
4563 MonoInternalThread* thread = mono_thread_internal_current ();
4565 /* Positive return value indicates success, either
4566 * S_OK if this is first CoInitialize call, or
4567 * S_FALSE if CoInitialize already called, but with same
4568 * threading model. A negative value indicates failure,
4569 * probably due to trying to change the threading model.
4571 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4572 ? COINIT_APARTMENTTHREADED
4573 : COINIT_MULTITHREADED) < 0) {
4574 thread->apartment_state = ThreadApartmentState_Unknown;
4580 mono_thread_cleanup_apartment_state (void)
4583 MonoInternalThread* thread = mono_thread_internal_current ();
4585 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4592 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4594 LOCK_THREAD (thread);
4595 thread->state |= state;
4596 UNLOCK_THREAD (thread);
4600 * mono_thread_test_and_set_state:
4602 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4604 * Returns TRUE is @set was OR'd in.
4607 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4609 LOCK_THREAD (thread);
4611 if ((thread->state & test) != 0) {
4612 UNLOCK_THREAD (thread);
4616 thread->state |= set;
4617 UNLOCK_THREAD (thread);
4623 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4625 LOCK_THREAD (thread);
4626 thread->state &= ~state;
4627 UNLOCK_THREAD (thread);
4631 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4633 gboolean ret = FALSE;
4635 LOCK_THREAD (thread);
4637 if ((thread->state & test) != 0) {
4641 UNLOCK_THREAD (thread);
4646 static gboolean has_tls_get = FALSE;
4649 mono_runtime_set_has_tls_get (gboolean val)
4655 mono_runtime_has_tls_get (void)
4661 self_interrupt_thread (void *_unused)
4663 MonoThreadInfo *info = mono_thread_info_current ();
4664 MonoException *exc = mono_thread_execute_interruption ();
4665 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4666 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. */
4667 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4671 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4675 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4679 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4681 MonoJitInfo **dest = (MonoJitInfo **)data;
4687 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4689 MonoJitInfo *ji = NULL;
4694 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4695 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4696 * where we hold runtime locks.
4698 if (!mono_threads_is_coop_enabled ())
4699 mono_thread_info_set_is_async_context (TRUE);
4700 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4701 if (!mono_threads_is_coop_enabled ())
4702 mono_thread_info_set_is_async_context (FALSE);
4707 MonoInternalThread *thread;
4708 gboolean install_async_abort;
4709 MonoThreadInfoInterruptToken *interrupt_token;
4712 static SuspendThreadResult
4713 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4715 AbortThreadData *data = (AbortThreadData *)ud;
4716 MonoInternalThread *thread = data->thread;
4717 MonoJitInfo *ji = NULL;
4718 gboolean protected_wrapper;
4719 gboolean running_managed;
4721 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4722 return MonoResumeThread;
4725 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4726 The protected block code will give them a chance when appropriate.
4728 if (thread->abort_protected_block_count)
4729 return MonoResumeThread;
4731 /*someone is already interrupting it*/
4732 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4733 return MonoResumeThread;
4735 InterlockedIncrement (&thread_interruption_requested);
4737 ji = mono_thread_info_get_last_managed (info);
4738 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4739 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4741 if (!protected_wrapper && running_managed) {
4742 /*We are in managed code*/
4743 /*Set the thread to call */
4744 if (data->install_async_abort)
4745 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4746 return MonoResumeThread;
4749 * This will cause waits to be broken.
4750 * It will also prevent the thread from entering a wait, so if the thread returns
4751 * from the wait before it receives the abort signal, it will just spin in the wait
4752 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4755 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4757 return MonoResumeThread;
4762 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4764 AbortThreadData data;
4766 g_assert (thread != mono_thread_internal_current ());
4768 data.thread = thread;
4769 data.install_async_abort = install_async_abort;
4770 data.interrupt_token = NULL;
4772 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4773 if (data.interrupt_token)
4774 mono_thread_info_finish_interrupt (data.interrupt_token);
4775 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4779 self_abort_internal (MonoError *error)
4783 mono_error_init (error);
4785 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4786 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4789 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.
4791 exc = mono_thread_request_interruption (TRUE);
4793 mono_error_set_exception_instance (error, exc);
4795 mono_thread_info_self_interrupt ();
4799 MonoInternalThread *thread;
4801 MonoThreadInfoInterruptToken *interrupt_token;
4802 } SuspendThreadData;
4804 static SuspendThreadResult
4805 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4807 SuspendThreadData *data = (SuspendThreadData *)ud;
4808 MonoInternalThread *thread = data->thread;
4809 MonoJitInfo *ji = NULL;
4810 gboolean protected_wrapper;
4811 gboolean running_managed;
4813 ji = mono_thread_info_get_last_managed (info);
4814 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4815 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4817 if (running_managed && !protected_wrapper) {
4818 thread->state &= ~ThreadState_SuspendRequested;
4819 thread->state |= ThreadState_Suspended;
4820 return KeepSuspended;
4822 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4823 InterlockedIncrement (&thread_interruption_requested);
4824 if (data->interrupt)
4825 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4827 return MonoResumeThread;
4831 /* LOCKING: called with @thread synch_cs held, and releases it */
4833 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4835 SuspendThreadData data;
4837 g_assert (thread != mono_thread_internal_current ());
4839 data.thread = thread;
4840 data.interrupt = interrupt;
4841 data.interrupt_token = NULL;
4843 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4844 if (data.interrupt_token)
4845 mono_thread_info_finish_interrupt (data.interrupt_token);
4847 UNLOCK_THREAD (thread);
4850 /* LOCKING: called with @thread synch_cs held, and releases it */
4852 self_suspend_internal (void)
4854 MonoInternalThread *thread;
4856 thread = mono_thread_internal_current ();
4858 mono_thread_info_begin_self_suspend ();
4859 thread->state &= ~ThreadState_SuspendRequested;
4860 thread->state |= ThreadState_Suspended;
4862 UNLOCK_THREAD (thread);
4864 mono_thread_info_end_self_suspend ();
4868 * mono_thread_is_foreign:
4869 * @thread: the thread to query
4871 * This function allows one to determine if a thread was created by the mono runtime and has
4872 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4874 * Returns: TRUE if @thread was not created by the runtime.
4877 mono_thread_is_foreign (MonoThread *thread)
4879 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4880 return info->runtime_thread == FALSE;
4884 * mono_add_joinable_thread:
4886 * Add TID to the list of joinable threads.
4887 * LOCKING: Acquires the threads lock.
4890 mono_threads_add_joinable_thread (gpointer tid)
4894 * We cannot detach from threads because it causes problems like
4895 * 2fd16f60/r114307. So we collect them and join them when
4896 * we have time (in he finalizer thread).
4898 joinable_threads_lock ();
4899 if (!joinable_threads)
4900 joinable_threads = g_hash_table_new (NULL, NULL);
4901 g_hash_table_insert (joinable_threads, tid, tid);
4902 joinable_thread_count ++;
4903 joinable_threads_unlock ();
4905 mono_gc_finalize_notify ();
4910 * mono_threads_join_threads:
4912 * Join all joinable threads. This is called from the finalizer thread.
4913 * LOCKING: Acquires the threads lock.
4916 mono_threads_join_threads (void)
4919 GHashTableIter iter;
4926 if (!joinable_thread_count)
4930 joinable_threads_lock ();
4932 if (g_hash_table_size (joinable_threads)) {
4933 g_hash_table_iter_init (&iter, joinable_threads);
4934 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4935 thread = (pthread_t)tid;
4936 g_hash_table_remove (joinable_threads, key);
4937 joinable_thread_count --;
4940 joinable_threads_unlock ();
4942 if (thread != pthread_self ()) {
4944 /* This shouldn't block */
4945 pthread_join (thread, NULL);
4958 * Wait for thread TID to exit.
4959 * LOCKING: Acquires the threads lock.
4962 mono_thread_join (gpointer tid)
4966 gboolean found = FALSE;
4968 joinable_threads_lock ();
4969 if (!joinable_threads)
4970 joinable_threads = g_hash_table_new (NULL, NULL);
4971 if (g_hash_table_lookup (joinable_threads, tid)) {
4972 g_hash_table_remove (joinable_threads, tid);
4973 joinable_thread_count --;
4976 joinable_threads_unlock ();
4979 thread = (pthread_t)tid;
4981 pthread_join (thread, NULL);
4987 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4989 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4990 mono_thread_interruption_checkpoint ();
4994 mono_thread_internal_unhandled_exception (MonoObject* exc)
4996 MonoClass *klass = exc->vtable->klass;
4997 if (is_threadabort_exception (klass)) {
4998 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4999 } else if (!is_appdomainunloaded_exception (klass)
5000 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5001 mono_unhandled_exception (exc);
5002 if (mono_environment_exitcode_get () == 1) {
5003 mono_environment_exitcode_set (255);
5004 mono_invoke_unhandled_exception_hook (exc);
5005 g_assert_not_reached ();
5011 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5014 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5015 mono_error_set_pending_exception (&error);
5019 * mono_threads_attach_coop: called by native->managed wrappers
5023 * - @return: the original domain which needs to be restored, or NULL.
5026 * - @dummy: contains the original domain
5027 * - @return: a cookie containing current MonoThreadInfo*.
5030 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5033 gboolean fresh_thread = FALSE;
5036 /* Happens when called from AOTed code which is only used in the root domain. */
5037 domain = mono_get_root_domain ();
5042 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5043 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5044 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5045 * we're only responsible for making the cookie. */
5046 if (mono_threads_is_coop_enabled ()) {
5047 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5048 fresh_thread = !info || !mono_thread_info_is_live (info);
5051 if (!mono_thread_internal_current ()) {
5052 mono_thread_attach_full (domain, FALSE);
5055 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5058 orig = mono_domain_get ();
5060 mono_domain_set (domain, TRUE);
5062 if (!mono_threads_is_coop_enabled ())
5063 return orig != domain ? orig : NULL;
5067 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5068 * return the right cookie. */
5069 return mono_threads_enter_gc_unsafe_region_cookie ();
5072 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5073 return mono_threads_enter_gc_unsafe_region (dummy);
5078 * mono_threads_detach_coop: called by native->managed wrappers
5081 * - @cookie: the original domain which needs to be restored, or NULL.
5085 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5086 * - @dummy: contains the original domain
5089 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5091 MonoDomain *domain, *orig;
5093 if (!mono_threads_is_coop_enabled ()) {
5094 orig = (MonoDomain*) cookie;
5096 mono_domain_set (orig, TRUE);
5098 orig = (MonoDomain*) *dummy;
5100 domain = mono_domain_get ();
5103 /* it won't do anything if cookie is NULL
5104 * thread state RUNNING -> (RUNNING|BLOCKING) */
5105 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5107 if (orig != domain) {
5109 mono_domain_unset ();
5111 mono_domain_set (orig, TRUE);
5117 mono_threads_begin_abort_protected_block (void)
5119 MonoInternalThread *thread;
5121 thread = mono_thread_internal_current ();
5122 ++thread->abort_protected_block_count;
5123 mono_memory_barrier ();
5127 mono_threads_end_abort_protected_block (void)
5129 MonoInternalThread *thread;
5131 thread = mono_thread_internal_current ();
5133 mono_memory_barrier ();
5134 --thread->abort_protected_block_count;
5138 mono_thread_try_resume_interruption (void)
5140 MonoInternalThread *thread;
5142 thread = mono_thread_internal_current ();
5143 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5146 return mono_thread_resume_interruption ();
5149 /* Returns TRUE if the current thread is ready to be interrupted. */
5151 mono_threads_is_ready_to_be_interrupted (void)
5153 MonoInternalThread *thread;
5155 thread = mono_thread_internal_current ();
5156 LOCK_THREAD (thread);
5157 if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5158 UNLOCK_THREAD (thread);
5162 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5163 UNLOCK_THREAD (thread);
5167 UNLOCK_THREAD (thread);