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 ();
2853 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
2854 g_assert (MONO_STRUCT_OFFSET (MonoInternalThread, last) == mono_field_get_offset (mono_class_get_field_from_name (mono_defaults.internal_thread_class, "last")));
2857 void mono_thread_cleanup (void)
2859 #if !defined(RUN_IN_SUBTHREAD)
2860 /* The main thread must abandon any held mutexes (particularly
2861 * important for named mutexes as they are shared across
2862 * processes, see bug 74680.) This will happen when the
2863 * thread exits, but if it's not running in a subthread it
2864 * won't exit in time.
2866 mono_thread_info_set_exited (mono_thread_info_current ());
2870 /* This stuff needs more testing, it seems one of these
2871 * critical sections can be locked when mono_thread_cleanup is
2874 mono_coop_mutex_destroy (&threads_mutex);
2875 mono_os_mutex_destroy (&interlocked_mutex);
2876 mono_os_mutex_destroy (&delayed_free_table_mutex);
2877 mono_os_mutex_destroy (&small_id_mutex);
2878 CloseHandle (background_change_event);
2881 mono_native_tls_free (current_object_key);
2885 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2887 mono_thread_cleanup_fn = func;
2891 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2893 thread->internal_thread->manage_callback = func;
2897 static void print_tids (gpointer key, gpointer value, gpointer user)
2899 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2900 * sizeof(uint) and a cast to uint would overflow
2902 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2903 * print this as a pointer.
2905 g_message ("Waiting for: %p", key);
2910 HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2911 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2916 wait_for_tids (struct wait_data *wait, guint32 timeout)
2920 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2923 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2926 if(ret==WAIT_FAILED) {
2927 /* See the comment in build_wait_tids() */
2928 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2932 for(i=0; i<wait->num; i++)
2933 mono_threads_close_thread_handle (wait->handles [i]);
2935 if (ret == WAIT_TIMEOUT)
2938 for(i=0; i<wait->num; i++) {
2939 gsize tid = wait->threads[i]->tid;
2942 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2943 * it can still run io-layer etc. code. So wait for it to really exit.
2944 * FIXME: This won't join threads which are not in the joinable_hash yet.
2946 mono_thread_join ((gpointer)tid);
2948 mono_threads_lock ();
2949 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2950 /* This thread must have been killed, because
2951 * it hasn't cleaned itself up. (It's just
2952 * possible that the thread exited before the
2953 * parent thread had a chance to store the
2954 * handle, and now there is another pointer to
2955 * the already-exited thread stored. In this
2956 * case, we'll just get two
2957 * mono_profiler_thread_end() calls for the
2961 mono_threads_unlock ();
2962 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2963 thread_cleanup (wait->threads[i]);
2965 mono_threads_unlock ();
2970 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2972 guint32 i, ret, count;
2974 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2976 /* Add the thread state change event, so it wakes up if a thread changes
2977 * to background mode.
2980 if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
2981 wait->handles [count] = background_change_event;
2986 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2989 if(ret==WAIT_FAILED) {
2990 /* See the comment in build_wait_tids() */
2991 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2995 for(i=0; i<wait->num; i++)
2996 mono_threads_close_thread_handle (wait->handles [i]);
2998 if (ret == WAIT_TIMEOUT)
3001 if (ret < wait->num) {
3002 gsize tid = wait->threads[ret]->tid;
3003 mono_threads_lock ();
3004 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3005 /* See comment in wait_for_tids about thread cleanup */
3006 mono_threads_unlock ();
3007 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3008 thread_cleanup (wait->threads [ret]);
3010 mono_threads_unlock ();
3014 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3016 struct wait_data *wait=(struct wait_data *)user;
3018 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3020 MonoInternalThread *thread=(MonoInternalThread *)value;
3022 /* Ignore background threads, we abort them later */
3023 /* Do not lock here since it is not needed and the caller holds threads_lock */
3024 if (thread->state & ThreadState_Background) {
3025 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3026 return; /* just leave, ignore */
3029 if (mono_gc_is_finalizer_internal_thread (thread)) {
3030 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3034 if (thread == mono_thread_internal_current ()) {
3035 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3039 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3040 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3044 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3045 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3049 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3050 if (handle == NULL) {
3051 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3055 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3056 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3057 wait->handles[wait->num]=handle;
3058 wait->threads[wait->num]=thread;
3061 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3063 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3068 /* Just ignore the rest, we can't do anything with
3075 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3077 struct wait_data *wait=(struct wait_data *)user;
3078 MonoNativeThreadId self = mono_native_thread_id_get ();
3079 MonoInternalThread *thread = (MonoInternalThread *)value;
3082 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3085 /* The finalizer thread is not a background thread */
3086 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3087 && (thread->state & ThreadState_Background) != 0
3088 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3090 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3094 wait->handles[wait->num] = handle;
3095 wait->threads[wait->num] = thread;
3098 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3099 mono_thread_internal_abort (thread);
3103 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3104 && !mono_gc_is_finalizer_internal_thread (thread);
3108 * mono_threads_set_shutting_down:
3110 * Is called by a thread that wants to shut down Mono. If the runtime is already
3111 * shutting down, the calling thread is suspended/stopped, and this function never
3115 mono_threads_set_shutting_down (void)
3117 MonoInternalThread *current_thread = mono_thread_internal_current ();
3119 mono_threads_lock ();
3121 if (shutting_down) {
3122 mono_threads_unlock ();
3124 /* Make sure we're properly suspended/stopped */
3126 LOCK_THREAD (current_thread);
3128 if ((current_thread->state & ThreadState_SuspendRequested) ||
3129 (current_thread->state & ThreadState_AbortRequested) ||
3130 (current_thread->state & ThreadState_StopRequested)) {
3131 UNLOCK_THREAD (current_thread);
3132 mono_thread_execute_interruption ();
3134 current_thread->state |= ThreadState_Stopped;
3135 UNLOCK_THREAD (current_thread);
3138 /*since we're killing the thread, unset the current domain.*/
3139 mono_domain_unset ();
3141 /* Wake up other threads potentially waiting for us */
3142 mono_thread_info_exit ();
3144 shutting_down = TRUE;
3146 /* Not really a background state change, but this will
3147 * interrupt the main thread if it is waiting for all
3148 * the other threads.
3150 mono_w32event_set (background_change_event);
3152 mono_threads_unlock ();
3156 void mono_thread_manage (void)
3158 struct wait_data wait_data;
3159 struct wait_data *wait = &wait_data;
3161 memset (wait, 0, sizeof (struct wait_data));
3162 /* join each thread that's still running */
3163 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3165 mono_threads_lock ();
3167 THREAD_DEBUG (g_message("%s: No threads", __func__));
3168 mono_threads_unlock ();
3171 mono_threads_unlock ();
3174 mono_threads_lock ();
3175 if (shutting_down) {
3176 /* somebody else is shutting down */
3177 mono_threads_unlock ();
3180 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3181 mono_g_hash_table_foreach (threads, print_tids, NULL));
3183 mono_w32event_reset (background_change_event);
3185 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3186 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3187 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3188 mono_threads_unlock ();
3190 /* Something to wait for */
3191 wait_for_tids_or_state_change (wait, INFINITE);
3193 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3194 } while(wait->num>0);
3196 /* Mono is shutting down, so just wait for the end */
3197 if (!mono_runtime_try_shutdown ()) {
3198 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3199 mono_thread_suspend (mono_thread_internal_current ());
3200 mono_thread_execute_interruption ();
3204 * Remove everything but the finalizer thread and self.
3205 * Also abort all the background threads
3208 mono_threads_lock ();
3211 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3212 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3213 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3215 mono_threads_unlock ();
3217 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3219 /* Something to wait for */
3220 wait_for_tids (wait, INFINITE);
3222 } while (wait->num > 0);
3225 * give the subthreads a chance to really quit (this is mainly needed
3226 * to get correct user and system times from getrusage/wait/time(1)).
3227 * This could be removed if we avoid pthread_detach() and use pthread_join().
3229 mono_thread_info_yield ();
3233 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3235 MonoInternalThread *thread = (MonoInternalThread*)value;
3236 struct wait_data *wait = (struct wait_data*)user_data;
3240 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3242 * This needs no locking.
3244 if ((thread->state & ThreadState_Suspended) != 0 ||
3245 (thread->state & ThreadState_Stopped) != 0)
3248 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3249 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3253 wait->handles [wait->num] = handle;
3254 wait->threads [wait->num] = thread;
3260 * mono_thread_suspend_all_other_threads:
3262 * Suspend all managed threads except the finalizer thread and this thread. It is
3263 * not possible to resume them later.
3265 void mono_thread_suspend_all_other_threads (void)
3267 struct wait_data wait_data;
3268 struct wait_data *wait = &wait_data;
3270 MonoNativeThreadId self = mono_native_thread_id_get ();
3271 guint32 eventidx = 0;
3272 gboolean starting, finished;
3274 memset (wait, 0, sizeof (struct wait_data));
3276 * The other threads could be in an arbitrary state at this point, i.e.
3277 * they could be starting up, shutting down etc. This means that there could be
3278 * threads which are not even in the threads hash table yet.
3282 * First we set a barrier which will be checked by all threads before they
3283 * are added to the threads hash table, and they will exit if the flag is set.
3284 * This ensures that no threads could be added to the hash later.
3285 * We will use shutting_down as the barrier for now.
3287 g_assert (shutting_down);
3290 * We make multiple calls to WaitForMultipleObjects since:
3291 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3292 * - some threads could exit without becoming suspended
3297 * Make a copy of the hashtable since we can't do anything with
3298 * threads while threads_mutex is held.
3301 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3302 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3303 mono_threads_lock ();
3304 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3305 mono_threads_unlock ();
3308 /* Get the suspended events that we'll be waiting for */
3309 for (i = 0; i < wait->num; ++i) {
3310 MonoInternalThread *thread = wait->threads [i];
3312 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3313 || mono_gc_is_finalizer_internal_thread (thread)
3314 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3316 //mono_threads_close_thread_handle (wait->handles [i]);
3317 wait->threads [i] = NULL; /* ignore this thread in next loop */
3321 LOCK_THREAD (thread);
3323 if ((thread->state & ThreadState_Suspended) != 0 ||
3324 (thread->state & ThreadState_StopRequested) != 0 ||
3325 (thread->state & ThreadState_Stopped) != 0) {
3326 UNLOCK_THREAD (thread);
3327 mono_threads_close_thread_handle (wait->handles [i]);
3328 wait->threads [i] = NULL; /* ignore this thread in next loop */
3334 /* Convert abort requests into suspend requests */
3335 if ((thread->state & ThreadState_AbortRequested) != 0)
3336 thread->state &= ~ThreadState_AbortRequested;
3338 thread->state |= ThreadState_SuspendRequested;
3340 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3341 async_suspend_internal (thread, TRUE);
3343 if (eventidx <= 0) {
3345 * If there are threads which are starting up, we wait until they
3346 * are suspended when they try to register in the threads hash.
3347 * This is guaranteed to finish, since the threads which can create new
3348 * threads get suspended after a while.
3349 * FIXME: The finalizer thread can still create new threads.
3351 mono_threads_lock ();
3352 if (threads_starting_up)
3353 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3356 mono_threads_unlock ();
3358 mono_thread_info_sleep (100, NULL);
3366 MonoInternalThread *thread;
3367 MonoStackFrameInfo *frames;
3368 int nframes, max_frames;
3369 int nthreads, max_threads;
3370 MonoInternalThread **threads;
3371 } ThreadDumpUserData;
3373 static gboolean thread_dump_requested;
3375 /* This needs to be async safe */
3377 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3379 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3381 if (ud->nframes < ud->max_frames) {
3382 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3389 /* This needs to be async safe */
3390 static SuspendThreadResult
3391 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3393 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3394 MonoInternalThread *thread = user_data->thread;
3397 /* This no longer works with remote unwinding */
3398 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3399 mono_thread_info_describe (info, text);
3400 g_string_append (text, "\n");
3403 if (thread == mono_thread_internal_current ())
3404 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3406 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3408 return MonoResumeThread;
3412 int nthreads, max_threads;
3413 MonoInternalThread **threads;
3414 } CollectThreadsUserData;
3417 collect_thread (gpointer key, gpointer value, gpointer user)
3419 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3420 MonoInternalThread *thread = (MonoInternalThread *)value;
3422 if (ud->nthreads < ud->max_threads)
3423 ud->threads [ud->nthreads ++] = thread;
3427 * Collect running threads into the THREADS array.
3428 * THREADS should be an array allocated on the stack.
3431 collect_threads (MonoInternalThread **thread_array, int max_threads)
3433 CollectThreadsUserData ud;
3435 memset (&ud, 0, sizeof (ud));
3436 /* This array contains refs, but its on the stack, so its ok */
3437 ud.threads = thread_array;
3438 ud.max_threads = max_threads;
3440 mono_threads_lock ();
3441 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3442 mono_threads_unlock ();
3448 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3450 GString* text = g_string_new (0);
3452 GError *error = NULL;
3455 ud->thread = thread;
3458 /* Collect frames for the thread */
3459 if (thread == mono_thread_internal_current ()) {
3460 get_thread_dump (mono_thread_info_current (), ud);
3462 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3466 * Do all the non async-safe work outside of get_thread_dump.
3469 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3471 g_string_append_printf (text, "\n\"%s\"", name);
3474 else if (thread->threadpool_thread) {
3475 g_string_append (text, "\n\"<threadpool thread>\"");
3477 g_string_append (text, "\n\"<unnamed thread>\"");
3480 for (i = 0; i < ud->nframes; ++i) {
3481 MonoStackFrameInfo *frame = &ud->frames [i];
3482 MonoMethod *method = NULL;
3484 if (frame->type == FRAME_TYPE_MANAGED)
3485 method = mono_jit_info_get_method (frame->ji);
3488 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3489 g_string_append_printf (text, " %s\n", location);
3492 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3496 fprintf (stdout, "%s", text->str);
3498 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3499 OutputDebugStringA(text->str);
3502 g_string_free (text, TRUE);
3507 mono_threads_perform_thread_dump (void)
3509 ThreadDumpUserData ud;
3510 MonoInternalThread *thread_array [128];
3511 int tindex, nthreads;
3513 if (!thread_dump_requested)
3516 printf ("Full thread dump:\n");
3518 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3519 nthreads = collect_threads (thread_array, 128);
3521 memset (&ud, 0, sizeof (ud));
3522 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3523 ud.max_frames = 256;
3525 for (tindex = 0; tindex < nthreads; ++tindex)
3526 dump_thread (thread_array [tindex], &ud);
3530 thread_dump_requested = FALSE;
3533 /* Obtain the thread dump of all threads */
3535 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3538 ThreadDumpUserData ud;
3539 MonoInternalThread *thread_array [128];
3540 MonoDomain *domain = mono_domain_get ();
3541 MonoDebugSourceLocation *location;
3542 int tindex, nthreads;
3544 mono_error_init (error);
3546 *out_threads = NULL;
3547 *out_stack_frames = NULL;
3549 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3550 nthreads = collect_threads (thread_array, 128);
3552 memset (&ud, 0, sizeof (ud));
3553 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3554 ud.max_frames = 256;
3556 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3559 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3563 for (tindex = 0; tindex < nthreads; ++tindex) {
3564 MonoInternalThread *thread = thread_array [tindex];
3565 MonoArray *thread_frames;
3571 /* Collect frames for the thread */
3572 if (thread == mono_thread_internal_current ()) {
3573 get_thread_dump (mono_thread_info_current (), &ud);
3575 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3578 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3580 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3583 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3585 for (i = 0; i < ud.nframes; ++i) {
3586 MonoStackFrameInfo *frame = &ud.frames [i];
3587 MonoMethod *method = NULL;
3588 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3592 sf->native_offset = frame->native_offset;
3594 if (frame->type == FRAME_TYPE_MANAGED)
3595 method = mono_jit_info_get_method (frame->ji);
3598 sf->method_address = (gsize) frame->ji->code_start;
3600 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3603 MONO_OBJECT_SETREF (sf, method, rm);
3605 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3607 sf->il_offset = location->il_offset;
3609 if (location && location->source_file) {
3610 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3611 sf->line = location->row;
3612 sf->column = location->column;
3614 mono_debug_free_source_location (location);
3619 mono_array_setref (thread_frames, i, sf);
3625 return is_ok (error);
3629 * mono_threads_request_thread_dump:
3631 * Ask all threads except the current to print their stacktrace to stdout.
3634 mono_threads_request_thread_dump (void)
3636 /*The new thread dump code runs out of the finalizer thread. */
3637 thread_dump_requested = TRUE;
3638 mono_gc_finalize_notify ();
3643 gint allocated; /* +1 so that refs [allocated] == NULL */
3647 typedef struct ref_stack RefStack;
3650 ref_stack_new (gint initial_size)
3654 initial_size = MAX (initial_size, 16) + 1;
3655 rs = g_new0 (RefStack, 1);
3656 rs->refs = g_new0 (gpointer, initial_size);
3657 rs->allocated = initial_size;
3662 ref_stack_destroy (gpointer ptr)
3664 RefStack *rs = (RefStack *)ptr;
3673 ref_stack_push (RefStack *rs, gpointer ptr)
3675 g_assert (rs != NULL);
3677 if (rs->bottom >= rs->allocated) {
3678 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3679 rs->allocated <<= 1;
3680 rs->refs [rs->allocated] = NULL;
3682 rs->refs [rs->bottom++] = ptr;
3686 ref_stack_pop (RefStack *rs)
3688 if (rs == NULL || rs->bottom == 0)
3692 rs->refs [rs->bottom] = NULL;
3696 ref_stack_find (RefStack *rs, gpointer ptr)
3703 for (refs = rs->refs; refs && *refs; refs++) {
3711 * mono_thread_push_appdomain_ref:
3713 * Register that the current thread may have references to objects in domain
3714 * @domain on its stack. Each call to this function should be paired with a
3715 * call to pop_appdomain_ref.
3718 mono_thread_push_appdomain_ref (MonoDomain *domain)
3720 MonoInternalThread *thread = mono_thread_internal_current ();
3723 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3724 SPIN_LOCK (thread->lock_thread_id);
3725 if (thread->appdomain_refs == NULL)
3726 thread->appdomain_refs = ref_stack_new (16);
3727 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3728 SPIN_UNLOCK (thread->lock_thread_id);
3733 mono_thread_pop_appdomain_ref (void)
3735 MonoInternalThread *thread = mono_thread_internal_current ();
3738 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3739 SPIN_LOCK (thread->lock_thread_id);
3740 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3741 SPIN_UNLOCK (thread->lock_thread_id);
3746 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3749 SPIN_LOCK (thread->lock_thread_id);
3750 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3751 SPIN_UNLOCK (thread->lock_thread_id);
3756 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3758 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3761 typedef struct abort_appdomain_data {
3762 struct wait_data wait;
3764 } abort_appdomain_data;
3767 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3769 MonoInternalThread *thread = (MonoInternalThread*)value;
3770 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3771 MonoDomain *domain = data->domain;
3773 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3774 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3776 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3777 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3780 data->wait.handles [data->wait.num] = handle;
3781 data->wait.threads [data->wait.num] = thread;
3784 /* Just ignore the rest, we can't do anything with
3792 * mono_threads_abort_appdomain_threads:
3794 * Abort threads which has references to the given appdomain.
3797 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3799 #ifdef __native_client__
3803 abort_appdomain_data user_data;
3805 int orig_timeout = timeout;
3808 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3810 start_time = mono_msec_ticks ();
3812 mono_threads_lock ();
3814 user_data.domain = domain;
3815 user_data.wait.num = 0;
3816 /* This shouldn't take any locks */
3817 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3818 mono_threads_unlock ();
3820 if (user_data.wait.num > 0) {
3821 /* Abort the threads outside the threads lock */
3822 for (i = 0; i < user_data.wait.num; ++i)
3823 mono_thread_internal_abort (user_data.wait.threads [i]);
3826 * We should wait for the threads either to abort, or to leave the
3827 * domain. We can't do the latter, so we wait with a timeout.
3829 wait_for_tids (&user_data.wait, 100);
3832 /* Update remaining time */
3833 timeout -= mono_msec_ticks () - start_time;
3834 start_time = mono_msec_ticks ();
3836 if (orig_timeout != -1 && timeout < 0)
3839 while (user_data.wait.num > 0);
3841 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3847 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3849 MonoInternalThread *thread = (MonoInternalThread*)value;
3850 MonoDomain *domain = (MonoDomain*)user_data;
3853 /* No locking needed here */
3854 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3856 if (thread->cached_culture_info) {
3857 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3858 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3859 if (obj && obj->vtable->domain == domain)
3860 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3866 * mono_threads_clear_cached_culture:
3868 * Clear the cached_current_culture from all threads if it is in the
3872 mono_threads_clear_cached_culture (MonoDomain *domain)
3874 mono_threads_lock ();
3875 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3876 mono_threads_unlock ();
3880 * mono_thread_get_undeniable_exception:
3882 * Return an exception which needs to be raised when leaving a catch clause.
3883 * This is used for undeniable exception propagation.
3886 mono_thread_get_undeniable_exception (void)
3888 MonoInternalThread *thread = mono_thread_internal_current ();
3890 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3892 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3893 * exception if the thread no longer references a dying appdomain.
3895 thread->abort_exc->trace_ips = NULL;
3896 thread->abort_exc->stack_trace = NULL;
3897 return thread->abort_exc;
3903 #if MONO_SMALL_CONFIG
3904 #define NUM_STATIC_DATA_IDX 4
3905 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3909 #define NUM_STATIC_DATA_IDX 8
3910 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3911 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3915 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3916 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3919 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3921 gpointer *static_data = (gpointer *)addr;
3923 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3924 void **ptr = (void **)static_data [i];
3929 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3930 void **p = ptr + idx;
3933 mark_func ((MonoObject**)p, gc_data);
3939 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3941 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3945 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3947 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3951 * mono_alloc_static_data
3953 * Allocate memory blocks for storing threads or context static data
3956 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3958 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3961 gpointer* static_data = *static_data_ptr;
3963 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3964 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3966 if (mono_gc_user_markers_supported ()) {
3967 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3968 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3970 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3971 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3974 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3975 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3976 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3977 *static_data_ptr = static_data;
3978 static_data [0] = static_data;
3981 for (i = 1; i <= idx; ++i) {
3982 if (static_data [i])
3985 if (mono_gc_user_markers_supported ())
3986 static_data [i] = g_malloc0 (static_data_size [i]);
3988 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3989 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3990 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3995 mono_free_static_data (gpointer* static_data)
3998 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3999 gpointer p = static_data [i];
4003 * At this point, the static data pointer array is still registered with the
4004 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4005 * data. Freeing the individual arrays without first nulling their slots
4006 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4007 * such an already freed array. See bug #13813.
4009 static_data [i] = NULL;
4010 mono_memory_write_barrier ();
4011 if (mono_gc_user_markers_supported ())
4014 mono_gc_free_fixed (p);
4016 mono_gc_free_fixed (static_data);
4020 * mono_init_static_data_info
4022 * Initializes static data counters
4024 static void mono_init_static_data_info (StaticDataInfo *static_data)
4026 static_data->idx = 0;
4027 static_data->offset = 0;
4028 static_data->freelist = NULL;
4032 * mono_alloc_static_data_slot
4034 * Generates an offset for static data. static_data contains the counters
4035 * used to generate it.
4038 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4040 if (!static_data->idx && !static_data->offset) {
4042 * we use the first chunk of the first allocation also as
4043 * an array for the rest of the data
4045 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4047 static_data->offset += align - 1;
4048 static_data->offset &= ~(align - 1);
4049 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4050 static_data->idx ++;
4051 g_assert (size <= static_data_size [static_data->idx]);
4052 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4053 static_data->offset = 0;
4055 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4056 static_data->offset += size;
4061 * LOCKING: requires that threads_mutex is held
4064 context_adjust_static_data (MonoAppContext *ctx)
4066 if (context_static_info.offset || context_static_info.idx > 0) {
4067 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4068 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4069 ctx->data->static_data = ctx->static_data;
4074 * LOCKING: requires that threads_mutex is held
4077 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4079 MonoInternalThread *thread = (MonoInternalThread *)value;
4080 guint32 offset = GPOINTER_TO_UINT (user);
4082 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4086 * LOCKING: requires that threads_mutex is held
4089 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4091 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4096 guint32 offset = GPOINTER_TO_UINT (user);
4097 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4098 ctx->data->static_data = ctx->static_data;
4101 static StaticDataFreeList*
4102 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4104 StaticDataFreeList* prev = NULL;
4105 StaticDataFreeList* tmp = static_data->freelist;
4107 if (tmp->size == size) {
4109 prev->next = tmp->next;
4111 static_data->freelist = tmp->next;
4120 #if SIZEOF_VOID_P == 4
4127 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4129 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4131 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4132 MonoBitSet *rb = sets [idx];
4133 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4134 offset /= sizeof (uintptr_t);
4135 /* offset is now the bitmap offset */
4136 for (int i = 0; i < numbits; ++i) {
4137 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4138 mono_bitset_set_fast (rb, offset + i);
4143 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4145 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4146 MonoBitSet *rb = sets [idx];
4147 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4148 offset /= sizeof (uintptr_t);
4149 /* offset is now the bitmap offset */
4150 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4151 mono_bitset_clear_fast (rb, offset + i);
4155 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4157 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4159 StaticDataInfo *info;
4162 if (static_type == SPECIAL_STATIC_THREAD) {
4163 info = &thread_static_info;
4164 sets = thread_reference_bitmaps;
4166 info = &context_static_info;
4167 sets = context_reference_bitmaps;
4170 mono_threads_lock ();
4172 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4176 offset = item->offset;
4179 offset = mono_alloc_static_data_slot (info, size, align);
4182 update_reference_bitmap (sets, offset, bitmap, numbits);
4184 if (static_type == SPECIAL_STATIC_THREAD) {
4185 /* This can be called during startup */
4186 if (threads != NULL)
4187 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4189 if (contexts != NULL)
4190 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4192 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4195 mono_threads_unlock ();
4201 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4203 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4205 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4206 return get_thread_static_data (thread, offset);
4208 return get_context_static_data (thread->current_appcontext, offset);
4213 mono_get_special_static_data (guint32 offset)
4215 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4224 * LOCKING: requires that threads_mutex is held
4227 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4229 MonoInternalThread *thread = (MonoInternalThread *)value;
4230 OffsetSize *data = (OffsetSize *)user;
4231 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4232 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4235 if (!thread->static_data || !thread->static_data [idx])
4237 ptr = ((char*) thread->static_data [idx]) + off;
4238 mono_gc_bzero_atomic (ptr, data->size);
4242 * LOCKING: requires that threads_mutex is held
4245 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4247 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4252 OffsetSize *data = (OffsetSize *)user;
4253 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4254 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4257 if (!ctx->static_data || !ctx->static_data [idx])
4260 ptr = ((char*) ctx->static_data [idx]) + off;
4261 mono_gc_bzero_atomic (ptr, data->size);
4265 do_free_special_slot (guint32 offset, guint32 size)
4267 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4269 StaticDataInfo *info;
4271 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4272 info = &thread_static_info;
4273 sets = thread_reference_bitmaps;
4275 info = &context_static_info;
4276 sets = context_reference_bitmaps;
4279 guint32 data_offset = offset;
4280 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4281 OffsetSize data = { data_offset, size };
4283 clear_reference_bitmap (sets, data.offset, data.size);
4285 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4286 if (threads != NULL)
4287 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4289 if (contexts != NULL)
4290 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4293 if (!mono_runtime_is_shutting_down ()) {
4294 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4296 item->offset = offset;
4299 item->next = info->freelist;
4300 info->freelist = item;
4305 do_free_special (gpointer key, gpointer value, gpointer data)
4307 MonoClassField *field = (MonoClassField *)key;
4308 guint32 offset = GPOINTER_TO_UINT (value);
4311 size = mono_type_size (field->type, &align);
4312 do_free_special_slot (offset, size);
4316 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4318 mono_threads_lock ();
4320 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4322 mono_threads_unlock ();
4326 static void CALLBACK dummy_apc (ULONG_PTR param)
4332 * mono_thread_execute_interruption
4334 * Performs the operation that the requested thread state requires (abort,
4337 static MonoException*
4338 mono_thread_execute_interruption (void)
4340 MonoInternalThread *thread = mono_thread_internal_current ();
4341 MonoThread *sys_thread = mono_thread_current ();
4343 LOCK_THREAD (thread);
4345 /* MonoThread::interruption_requested can only be changed with atomics */
4346 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4347 /* this will consume pending APC calls */
4349 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4351 InterlockedDecrement (&thread_interruption_requested);
4353 /* Clear the interrupted flag of the thread so it can wait again */
4354 mono_thread_info_clear_self_interrupt ();
4357 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4358 if (sys_thread->pending_exception) {
4361 exc = sys_thread->pending_exception;
4362 sys_thread->pending_exception = NULL;
4364 UNLOCK_THREAD (thread);
4366 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4367 UNLOCK_THREAD (thread);
4368 g_assert (sys_thread->pending_exception == NULL);
4369 if (thread->abort_exc == NULL) {
4371 * This might be racy, but it has to be called outside the lock
4372 * since it calls managed code.
4374 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4376 return thread->abort_exc;
4378 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4379 /* calls UNLOCK_THREAD (thread) */
4380 self_suspend_internal ();
4383 else if ((thread->state & ThreadState_StopRequested) != 0) {
4384 /* FIXME: do this through the JIT? */
4386 UNLOCK_THREAD (thread);
4388 mono_thread_exit ();
4390 } else if (thread->thread_interrupt_requested) {
4392 thread->thread_interrupt_requested = FALSE;
4393 UNLOCK_THREAD (thread);
4395 return(mono_get_exception_thread_interrupted ());
4398 UNLOCK_THREAD (thread);
4404 * mono_thread_request_interruption
4406 * A signal handler can call this method to request the interruption of a
4407 * thread. The result of the interruption will depend on the current state of
4408 * the thread. If the result is an exception that needs to be throw, it is
4409 * provided as return value.
4412 mono_thread_request_interruption (gboolean running_managed)
4414 MonoInternalThread *thread = mono_thread_internal_current ();
4416 /* The thread may already be stopping */
4421 if (thread->interrupt_on_stop &&
4422 thread->state & ThreadState_StopRequested &&
4423 thread->state & ThreadState_Background)
4426 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4428 InterlockedIncrement (&thread_interruption_requested);
4430 if (!running_managed || is_running_protected_wrapper ()) {
4431 /* Can't stop while in unmanaged code. Increase the global interruption
4432 request count. When exiting the unmanaged method the count will be
4433 checked and the thread will be interrupted. */
4435 /* this will awake the thread if it is in WaitForSingleObject
4437 /* Our implementation of this function ignores the func argument */
4439 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4441 mono_thread_info_self_interrupt ();
4446 return mono_thread_execute_interruption ();
4450 /*This function should be called by a thread after it has exited all of
4451 * its handle blocks at interruption time.*/
4453 mono_thread_resume_interruption (void)
4455 MonoInternalThread *thread = mono_thread_internal_current ();
4456 gboolean still_aborting;
4458 /* The thread may already be stopping */
4462 LOCK_THREAD (thread);
4463 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4464 UNLOCK_THREAD (thread);
4466 /*This can happen if the protected block called Thread::ResetAbort*/
4467 if (!still_aborting)
4470 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4472 InterlockedIncrement (&thread_interruption_requested);
4474 mono_thread_info_self_interrupt ();
4476 return mono_thread_execute_interruption ();
4479 gboolean mono_thread_interruption_requested ()
4481 if (thread_interruption_requested) {
4482 MonoInternalThread *thread = mono_thread_internal_current ();
4483 /* The thread may already be stopping */
4485 return (thread->interruption_requested);
4490 static MonoException*
4491 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4493 MonoInternalThread *thread = mono_thread_internal_current ();
4495 /* The thread may already be stopping */
4499 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4500 MonoException* exc = mono_thread_execute_interruption ();
4508 * Performs the interruption of the current thread, if one has been requested,
4509 * and the thread is not running a protected wrapper.
4510 * Return the exception which needs to be thrown, if any.
4513 mono_thread_interruption_checkpoint (void)
4515 return mono_thread_interruption_checkpoint_request (FALSE);
4519 * Performs the interruption of the current thread, if one has been requested.
4520 * Return the exception which needs to be thrown, if any.
4523 mono_thread_force_interruption_checkpoint_noraise (void)
4525 return mono_thread_interruption_checkpoint_request (TRUE);
4529 * mono_set_pending_exception:
4531 * Set the pending exception of the current thread to EXC.
4532 * The exception will be thrown when execution returns to managed code.
4535 mono_set_pending_exception (MonoException *exc)
4537 MonoThread *thread = mono_thread_current ();
4539 /* The thread may already be stopping */
4543 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4545 mono_thread_request_interruption (FALSE);
4549 * mono_thread_interruption_request_flag:
4551 * Returns the address of a flag that will be non-zero if an interruption has
4552 * been requested for a thread. The thread to interrupt may not be the current
4553 * thread, so an additional call to mono_thread_interruption_requested() or
4554 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4557 gint32* mono_thread_interruption_request_flag ()
4559 return &thread_interruption_requested;
4563 mono_thread_init_apartment_state (void)
4566 MonoInternalThread* thread = mono_thread_internal_current ();
4568 /* Positive return value indicates success, either
4569 * S_OK if this is first CoInitialize call, or
4570 * S_FALSE if CoInitialize already called, but with same
4571 * threading model. A negative value indicates failure,
4572 * probably due to trying to change the threading model.
4574 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4575 ? COINIT_APARTMENTTHREADED
4576 : COINIT_MULTITHREADED) < 0) {
4577 thread->apartment_state = ThreadApartmentState_Unknown;
4583 mono_thread_cleanup_apartment_state (void)
4586 MonoInternalThread* thread = mono_thread_internal_current ();
4588 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4595 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4597 LOCK_THREAD (thread);
4598 thread->state |= state;
4599 UNLOCK_THREAD (thread);
4603 * mono_thread_test_and_set_state:
4605 * Test if current state of @thread include @test. If it does not, OR @set into the state.
4607 * Returns TRUE is @set was OR'd in.
4610 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4612 LOCK_THREAD (thread);
4614 if ((thread->state & test) != 0) {
4615 UNLOCK_THREAD (thread);
4619 thread->state |= set;
4620 UNLOCK_THREAD (thread);
4626 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4628 LOCK_THREAD (thread);
4629 thread->state &= ~state;
4630 UNLOCK_THREAD (thread);
4634 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4636 gboolean ret = FALSE;
4638 LOCK_THREAD (thread);
4640 if ((thread->state & test) != 0) {
4644 UNLOCK_THREAD (thread);
4649 static gboolean has_tls_get = FALSE;
4652 mono_runtime_set_has_tls_get (gboolean val)
4658 mono_runtime_has_tls_get (void)
4664 self_interrupt_thread (void *_unused)
4666 MonoThreadInfo *info = mono_thread_info_current ();
4667 MonoException *exc = mono_thread_execute_interruption ();
4668 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4669 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. */
4670 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4674 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4678 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4682 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4684 MonoJitInfo **dest = (MonoJitInfo **)data;
4690 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4692 MonoJitInfo *ji = NULL;
4697 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4698 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4699 * where we hold runtime locks.
4701 if (!mono_threads_is_coop_enabled ())
4702 mono_thread_info_set_is_async_context (TRUE);
4703 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4704 if (!mono_threads_is_coop_enabled ())
4705 mono_thread_info_set_is_async_context (FALSE);
4710 MonoInternalThread *thread;
4711 gboolean install_async_abort;
4712 MonoThreadInfoInterruptToken *interrupt_token;
4715 static SuspendThreadResult
4716 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4718 AbortThreadData *data = (AbortThreadData *)ud;
4719 MonoInternalThread *thread = data->thread;
4720 MonoJitInfo *ji = NULL;
4721 gboolean protected_wrapper;
4722 gboolean running_managed;
4724 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4725 return MonoResumeThread;
4728 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4729 The protected block code will give them a chance when appropriate.
4731 if (thread->abort_protected_block_count)
4732 return MonoResumeThread;
4734 /*someone is already interrupting it*/
4735 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4736 return MonoResumeThread;
4738 InterlockedIncrement (&thread_interruption_requested);
4740 ji = mono_thread_info_get_last_managed (info);
4741 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4742 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4744 if (!protected_wrapper && running_managed) {
4745 /*We are in managed code*/
4746 /*Set the thread to call */
4747 if (data->install_async_abort)
4748 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4749 return MonoResumeThread;
4752 * This will cause waits to be broken.
4753 * It will also prevent the thread from entering a wait, so if the thread returns
4754 * from the wait before it receives the abort signal, it will just spin in the wait
4755 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4758 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4760 return MonoResumeThread;
4765 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4767 AbortThreadData data;
4769 g_assert (thread != mono_thread_internal_current ());
4771 data.thread = thread;
4772 data.install_async_abort = install_async_abort;
4773 data.interrupt_token = NULL;
4775 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4776 if (data.interrupt_token)
4777 mono_thread_info_finish_interrupt (data.interrupt_token);
4778 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4782 self_abort_internal (MonoError *error)
4786 mono_error_init (error);
4788 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4789 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4792 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.
4794 exc = mono_thread_request_interruption (TRUE);
4796 mono_error_set_exception_instance (error, exc);
4798 mono_thread_info_self_interrupt ();
4802 MonoInternalThread *thread;
4804 MonoThreadInfoInterruptToken *interrupt_token;
4805 } SuspendThreadData;
4807 static SuspendThreadResult
4808 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4810 SuspendThreadData *data = (SuspendThreadData *)ud;
4811 MonoInternalThread *thread = data->thread;
4812 MonoJitInfo *ji = NULL;
4813 gboolean protected_wrapper;
4814 gboolean running_managed;
4816 ji = mono_thread_info_get_last_managed (info);
4817 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4818 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4820 if (running_managed && !protected_wrapper) {
4821 thread->state &= ~ThreadState_SuspendRequested;
4822 thread->state |= ThreadState_Suspended;
4823 return KeepSuspended;
4825 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4826 InterlockedIncrement (&thread_interruption_requested);
4827 if (data->interrupt)
4828 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4830 return MonoResumeThread;
4834 /* LOCKING: called with @thread synch_cs held, and releases it */
4836 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4838 SuspendThreadData data;
4840 g_assert (thread != mono_thread_internal_current ());
4842 data.thread = thread;
4843 data.interrupt = interrupt;
4844 data.interrupt_token = NULL;
4846 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4847 if (data.interrupt_token)
4848 mono_thread_info_finish_interrupt (data.interrupt_token);
4850 UNLOCK_THREAD (thread);
4853 /* LOCKING: called with @thread synch_cs held, and releases it */
4855 self_suspend_internal (void)
4857 MonoInternalThread *thread;
4859 thread = mono_thread_internal_current ();
4861 mono_thread_info_begin_self_suspend ();
4862 thread->state &= ~ThreadState_SuspendRequested;
4863 thread->state |= ThreadState_Suspended;
4865 UNLOCK_THREAD (thread);
4867 mono_thread_info_end_self_suspend ();
4871 * mono_thread_is_foreign:
4872 * @thread: the thread to query
4874 * This function allows one to determine if a thread was created by the mono runtime and has
4875 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4877 * Returns: TRUE if @thread was not created by the runtime.
4880 mono_thread_is_foreign (MonoThread *thread)
4882 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4883 return info->runtime_thread == FALSE;
4887 * mono_add_joinable_thread:
4889 * Add TID to the list of joinable threads.
4890 * LOCKING: Acquires the threads lock.
4893 mono_threads_add_joinable_thread (gpointer tid)
4897 * We cannot detach from threads because it causes problems like
4898 * 2fd16f60/r114307. So we collect them and join them when
4899 * we have time (in he finalizer thread).
4901 joinable_threads_lock ();
4902 if (!joinable_threads)
4903 joinable_threads = g_hash_table_new (NULL, NULL);
4904 g_hash_table_insert (joinable_threads, tid, tid);
4905 joinable_thread_count ++;
4906 joinable_threads_unlock ();
4908 mono_gc_finalize_notify ();
4913 * mono_threads_join_threads:
4915 * Join all joinable threads. This is called from the finalizer thread.
4916 * LOCKING: Acquires the threads lock.
4919 mono_threads_join_threads (void)
4922 GHashTableIter iter;
4929 if (!joinable_thread_count)
4933 joinable_threads_lock ();
4935 if (g_hash_table_size (joinable_threads)) {
4936 g_hash_table_iter_init (&iter, joinable_threads);
4937 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4938 thread = (pthread_t)tid;
4939 g_hash_table_remove (joinable_threads, key);
4940 joinable_thread_count --;
4943 joinable_threads_unlock ();
4945 if (thread != pthread_self ()) {
4947 /* This shouldn't block */
4948 pthread_join (thread, NULL);
4961 * Wait for thread TID to exit.
4962 * LOCKING: Acquires the threads lock.
4965 mono_thread_join (gpointer tid)
4969 gboolean found = FALSE;
4971 joinable_threads_lock ();
4972 if (!joinable_threads)
4973 joinable_threads = g_hash_table_new (NULL, NULL);
4974 if (g_hash_table_lookup (joinable_threads, tid)) {
4975 g_hash_table_remove (joinable_threads, tid);
4976 joinable_thread_count --;
4979 joinable_threads_unlock ();
4982 thread = (pthread_t)tid;
4984 pthread_join (thread, NULL);
4990 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4992 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4993 mono_thread_interruption_checkpoint ();
4997 mono_thread_internal_unhandled_exception (MonoObject* exc)
4999 MonoClass *klass = exc->vtable->klass;
5000 if (is_threadabort_exception (klass)) {
5001 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5002 } else if (!is_appdomainunloaded_exception (klass)
5003 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5004 mono_unhandled_exception (exc);
5005 if (mono_environment_exitcode_get () == 1) {
5006 mono_environment_exitcode_set (255);
5007 mono_invoke_unhandled_exception_hook (exc);
5008 g_assert_not_reached ();
5014 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5017 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5018 mono_error_set_pending_exception (&error);
5022 * mono_threads_attach_coop: called by native->managed wrappers
5026 * - @return: the original domain which needs to be restored, or NULL.
5029 * - @dummy: contains the original domain
5030 * - @return: a cookie containing current MonoThreadInfo*.
5033 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5036 gboolean fresh_thread = FALSE;
5039 /* Happens when called from AOTed code which is only used in the root domain. */
5040 domain = mono_get_root_domain ();
5045 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5046 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5047 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5048 * we're only responsible for making the cookie. */
5049 if (mono_threads_is_coop_enabled ()) {
5050 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5051 fresh_thread = !info || !mono_thread_info_is_live (info);
5054 if (!mono_thread_internal_current ()) {
5055 mono_thread_attach_full (domain, FALSE);
5058 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5061 orig = mono_domain_get ();
5063 mono_domain_set (domain, TRUE);
5065 if (!mono_threads_is_coop_enabled ())
5066 return orig != domain ? orig : NULL;
5070 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5071 * return the right cookie. */
5072 return mono_threads_enter_gc_unsafe_region_cookie ();
5075 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5076 return mono_threads_enter_gc_unsafe_region (dummy);
5081 * mono_threads_detach_coop: called by native->managed wrappers
5084 * - @cookie: the original domain which needs to be restored, or NULL.
5088 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5089 * - @dummy: contains the original domain
5092 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5094 MonoDomain *domain, *orig;
5096 if (!mono_threads_is_coop_enabled ()) {
5097 orig = (MonoDomain*) cookie;
5099 mono_domain_set (orig, TRUE);
5101 orig = (MonoDomain*) *dummy;
5103 domain = mono_domain_get ();
5106 /* it won't do anything if cookie is NULL
5107 * thread state RUNNING -> (RUNNING|BLOCKING) */
5108 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5110 if (orig != domain) {
5112 mono_domain_unset ();
5114 mono_domain_set (orig, TRUE);
5120 mono_threads_begin_abort_protected_block (void)
5122 MonoInternalThread *thread;
5124 thread = mono_thread_internal_current ();
5125 ++thread->abort_protected_block_count;
5126 mono_memory_barrier ();
5130 mono_threads_end_abort_protected_block (void)
5132 MonoInternalThread *thread;
5134 thread = mono_thread_internal_current ();
5136 mono_memory_barrier ();
5137 --thread->abort_protected_block_count;
5141 mono_thread_try_resume_interruption (void)
5143 MonoInternalThread *thread;
5145 thread = mono_thread_internal_current ();
5146 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5149 return mono_thread_resume_interruption ();
5152 /* Returns TRUE if the current thread is ready to be interrupted. */
5154 mono_threads_is_ready_to_be_interrupted (void)
5156 MonoInternalThread *thread;
5158 thread = mono_thread_internal_current ();
5159 LOCK_THREAD (thread);
5160 if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5161 UNLOCK_THREAD (thread);
5165 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5166 UNLOCK_THREAD (thread);
5170 UNLOCK_THREAD (thread);