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>
49 #include <mono/metadata/gc-internals.h>
50 #include <mono/metadata/reflection-internals.h>
56 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
57 #define USE_TKILL_ON_ANDROID 1
60 #ifdef PLATFORM_ANDROID
63 #ifdef USE_TKILL_ON_ANDROID
64 extern int tkill (pid_t tid, int signal);
68 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
69 #define THREAD_DEBUG(a)
70 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
71 #define THREAD_WAIT_DEBUG(a)
72 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
73 #define LIBGC_DEBUG(a)
75 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
76 #define SPIN_LOCK(i) do { \
77 if (SPIN_TRYLOCK (i)) \
81 #define SPIN_UNLOCK(i) i = 0
83 #define LOCK_THREAD(thread) lock_thread((thread))
84 #define UNLOCK_THREAD(thread) unlock_thread((thread))
96 typedef struct _StaticDataFreeList StaticDataFreeList;
97 struct _StaticDataFreeList {
98 StaticDataFreeList *next;
106 StaticDataFreeList *freelist;
109 /* Number of cached culture objects in the MonoThread->cached_culture_info array
110 * (per-type): we use the first NUM entries for CultureInfo and the last for
111 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
113 #define NUM_CACHED_CULTURES 4
114 #define CULTURES_START_IDX 0
115 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
117 /* Controls access to the 'threads' hash table */
118 static void mono_threads_lock (void);
119 static void mono_threads_unlock (void);
120 static MonoCoopMutex threads_mutex;
122 /* Controls access to the 'joinable_threads' hash table */
123 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
124 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
125 static mono_mutex_t joinable_threads_mutex;
127 /* Holds current status of static data heap */
128 static StaticDataInfo thread_static_info;
129 static StaticDataInfo context_static_info;
131 /* The hash of existing threads (key is thread ID, value is
132 * MonoInternalThread*) that need joining before exit
134 static MonoGHashTable *threads=NULL;
136 /* List of app context GC handles.
137 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
139 static GHashTable *contexts = NULL;
141 /* Cleanup queue for contexts. */
142 static MonoReferenceQueue *context_queue;
145 * Threads which are starting up and they are not in the 'threads' hash yet.
146 * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
147 * Protected by mono_threads_lock ().
149 static MonoGHashTable *threads_starting_up = NULL;
151 /* The TLS key that holds the MonoObject assigned to each thread */
152 static MonoNativeTlsKey current_object_key;
155 /* Protected by the threads lock */
156 static GHashTable *joinable_threads;
157 static int joinable_thread_count;
159 #ifdef MONO_HAVE_FAST_TLS
160 /* we need to use both the Tls* functions and __thread because
161 * the gc needs to see all the threads
163 MONO_FAST_TLS_DECLARE(tls_current_object);
164 #define SET_CURRENT_OBJECT(x) do { \
165 MONO_FAST_TLS_SET (tls_current_object, x); \
166 mono_native_tls_set_value (current_object_key, x); \
168 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
170 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
171 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
174 /* function called at thread start */
175 static MonoThreadStartCB mono_thread_start_cb = NULL;
177 /* function called at thread attach */
178 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
180 /* function called at thread cleanup */
181 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
183 /* The default stack size for each thread */
184 static guint32 default_stacksize = 0;
185 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
187 static void context_adjust_static_data (MonoAppContext *ctx);
188 static void mono_free_static_data (gpointer* static_data);
189 static void mono_init_static_data_info (StaticDataInfo *static_data);
190 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
191 static gboolean mono_thread_resume (MonoInternalThread* thread);
192 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
193 static void self_abort_internal (MonoError *error);
194 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
195 static void self_suspend_internal (void);
197 static MonoException* mono_thread_execute_interruption (void);
198 static void ref_stack_destroy (gpointer rs);
200 /* Spin lock for InterlockedXXX 64 bit functions */
201 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
202 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
203 static mono_mutex_t interlocked_mutex;
205 /* global count of thread interruptions requested */
206 static gint32 thread_interruption_requested = 0;
208 /* Event signaled when a thread changes its background mode */
209 static HANDLE background_change_event;
211 static gboolean shutting_down = FALSE;
213 static gint32 managed_thread_id_counter = 0;
215 /* Class lazy loading functions */
216 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
219 mono_threads_lock (void)
221 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
225 mono_threads_unlock (void)
227 mono_locks_coop_release (&threads_mutex, ThreadsLock);
232 get_next_managed_thread_id (void)
234 return InterlockedIncrement (&managed_thread_id_counter);
238 mono_thread_get_tls_key (void)
240 return current_object_key;
244 mono_thread_get_tls_offset (void)
249 if (current_object_key)
250 offset = current_object_key;
252 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
257 static inline MonoNativeThreadId
258 thread_get_tid (MonoInternalThread *thread)
260 /* We store the tid as a guint64 to keep the object layout constant between platforms */
261 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
264 static void ensure_synch_cs_set (MonoInternalThread *thread)
266 MonoCoopMutex *synch_cs;
268 if (thread->synch_cs != NULL) {
272 synch_cs = g_new0 (MonoCoopMutex, 1);
273 mono_coop_mutex_init_recursive (synch_cs);
275 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
276 synch_cs, NULL) != NULL) {
277 /* Another thread must have installed this CS */
278 mono_coop_mutex_destroy (synch_cs);
284 lock_thread (MonoInternalThread *thread)
286 if (!thread->synch_cs)
287 ensure_synch_cs_set (thread);
289 g_assert (thread->synch_cs);
291 mono_coop_mutex_lock (thread->synch_cs);
295 unlock_thread (MonoInternalThread *thread)
297 mono_coop_mutex_unlock (thread->synch_cs);
300 static inline gboolean
301 is_appdomainunloaded_exception (MonoClass *klass)
303 return klass == mono_class_get_appdomain_unloaded_exception_class ();
306 static inline gboolean
307 is_threadabort_exception (MonoClass *klass)
309 return klass == mono_defaults.threadabortexception_class;
313 * NOTE: this function can be called also for threads different from the current one:
314 * make sure no code called from it will ever assume it is run on the thread that is
315 * getting cleaned up.
317 static void thread_cleanup (MonoInternalThread *thread)
321 g_assert (thread != NULL);
323 if (thread->abort_state_handle) {
324 mono_gchandle_free (thread->abort_state_handle);
325 thread->abort_state_handle = 0;
327 thread->abort_exc = NULL;
328 thread->current_appcontext = NULL;
331 * This is necessary because otherwise we might have
332 * cross-domain references which will not get cleaned up when
333 * the target domain is unloaded.
335 if (thread->cached_culture_info) {
337 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
338 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
342 * thread->synch_cs can be NULL if this was called after
343 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
344 * This can happen only during shutdown.
345 * The shutting_down flag is not always set, so we can't assert on it.
347 if (thread->synch_cs)
348 LOCK_THREAD (thread);
350 thread->state |= ThreadState_Stopped;
351 thread->state &= ~ThreadState_Background;
353 if (thread->synch_cs)
354 UNLOCK_THREAD (thread);
357 An interruption request has leaked to cleanup. Adjust the global counter.
359 This can happen is the abort source thread finds the abortee (this) thread
360 in unmanaged code. If this thread never trips back to managed code or check
361 the local flag it will be left set and positively unbalance the global counter.
363 Leaving the counter unbalanced will cause a performance degradation since all threads
364 will now keep checking their local flags all the time.
366 if (InterlockedExchange (&thread->interruption_requested, 0))
367 InterlockedDecrement (&thread_interruption_requested);
369 mono_threads_lock ();
373 } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
374 /* We have to check whether the thread object for the
375 * tid is still the same in the table because the
376 * thread might have been destroyed and the tid reused
377 * in the meantime, in which case the tid would be in
378 * the table, but with another thread object.
382 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
386 mono_threads_unlock ();
388 /* Don't close the handle here, wait for the object finalizer
389 * to do it. Otherwise, the following race condition applies:
391 * 1) Thread exits (and thread_cleanup() closes the handle)
393 * 2) Some other handle is reassigned the same slot
395 * 3) Another thread tries to join the first thread, and
396 * blocks waiting for the reassigned handle to be signalled
397 * (which might never happen). This is possible, because the
398 * thread calling Join() still has a reference to the first
402 /* if the thread is not in the hash it has been removed already */
404 if (thread == mono_thread_internal_current ()) {
405 mono_domain_unset ();
406 mono_memory_barrier ();
408 if (mono_thread_cleanup_fn)
409 mono_thread_cleanup_fn (thread_get_tid (thread));
412 mono_release_type_locks (thread);
414 /* Can happen when we attach the profiler helper thread in order to heapshot. */
415 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
416 mono_profiler_thread_end (thread->tid);
418 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
420 if (thread == mono_thread_internal_current ()) {
422 * This will signal async signal handlers that the thread has exited.
423 * The profiler callback needs this to be set, so it cannot be done earlier.
425 mono_domain_unset ();
426 mono_memory_barrier ();
429 if (thread == mono_thread_internal_current ())
430 mono_thread_pop_appdomain_ref ();
432 thread->cached_culture_info = NULL;
434 mono_free_static_data (thread->static_data);
435 thread->static_data = NULL;
436 ref_stack_destroy (thread->appdomain_refs);
437 thread->appdomain_refs = NULL;
439 if (mono_thread_cleanup_fn)
440 mono_thread_cleanup_fn (thread_get_tid (thread));
442 if (mono_gc_is_moving ()) {
443 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
444 thread->thread_pinning_ref = NULL;
450 * A special static data offset (guint32) consists of 3 parts:
452 * [0] 6-bit index into the array of chunks.
453 * [6] 25-bit offset into the array.
454 * [31] Bit indicating thread or context static.
459 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
470 } SpecialStaticOffset;
472 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
473 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
475 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
476 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
477 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
478 (((SpecialStaticOffset *) &(x))->fields.f)
481 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
483 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
485 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
486 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
488 return ((char *) thread->static_data [idx]) + off;
492 get_context_static_data (MonoAppContext *ctx, guint32 offset)
494 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
496 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
497 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
499 return ((char *) ctx->static_data [idx]) + off;
503 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
505 static MonoClassField *current_thread_field = NULL;
509 if (!current_thread_field) {
510 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
511 g_assert (current_thread_field);
514 mono_class_vtable (domain, mono_defaults.thread_class);
515 mono_domain_lock (domain);
516 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
517 mono_domain_unlock (domain);
520 return (MonoThread **)get_thread_static_data (thread, offset);
524 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
526 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
528 g_assert (current->obj.vtable->domain == domain);
530 g_assert (!*current_thread_ptr);
531 *current_thread_ptr = current;
535 create_thread_object (MonoDomain *domain)
538 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
539 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, &error);
540 /* only possible failure mode is OOM, from which we don't expect to recover. */
541 mono_error_assert_ok (&error);
546 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
550 thread = create_thread_object (domain);
551 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
553 MONO_OBJECT_SETREF (thread, internal_thread, internal);
558 static MonoInternalThread*
559 create_internal_thread (void)
562 MonoInternalThread *thread;
565 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
566 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
567 /* only possible failure mode is OOM, from which we don't exect to recover */
568 mono_error_assert_ok (&error);
570 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
571 mono_coop_mutex_init_recursive (thread->synch_cs);
573 thread->apartment_state = ThreadApartmentState_Unknown;
574 thread->managed_id = get_next_managed_thread_id ();
575 if (mono_gc_is_moving ()) {
576 thread->thread_pinning_ref = thread;
577 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
584 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
587 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
589 MonoThreadInfo *info;
590 MonoInternalThread *internal;
591 MonoDomain *domain, *root_domain;
595 info = mono_thread_info_current ();
597 internal = thread->internal_thread;
598 internal->handle = mono_thread_info_duplicate_handle (info);
599 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
600 internal->thread_info = info;
601 internal->small_id = info->small_id;
602 internal->stack_ptr = stack_ptr;
604 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
606 SET_CURRENT_OBJECT (internal);
608 domain = mono_object_domain (thread);
610 mono_thread_push_appdomain_ref (domain);
611 if (!mono_domain_set (domain, force_domain)) {
612 mono_thread_pop_appdomain_ref ();
616 mono_threads_lock ();
618 if (threads_starting_up)
619 mono_g_hash_table_remove (threads_starting_up, thread);
621 if (shutting_down && !force_attach) {
622 mono_threads_unlock ();
627 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
628 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
631 /* We don't need to duplicate thread->handle, because it is
632 * only closed when the thread object is finalized by the GC. */
633 mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
635 /* We have to do this here because mono_thread_start_cb
636 * requires that root_domain_thread is set up. */
637 if (thread_static_info.offset || thread_static_info.idx > 0) {
638 /* get the current allocated size */
639 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
640 mono_alloc_static_data (&internal->static_data, offset, TRUE);
643 mono_threads_unlock ();
645 root_domain = mono_get_root_domain ();
647 g_assert (!internal->root_domain_thread);
648 if (domain != root_domain)
649 MONO_OBJECT_SETREF (internal, root_domain_thread, new_thread_with_internal (root_domain, internal));
651 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
653 if (domain != root_domain)
654 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
656 set_current_thread_for_domain (domain, internal, thread);
658 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
666 MonoObject *start_delegate;
667 MonoObject *start_delegate_arg;
668 MonoThreadStart start_func;
669 gpointer start_func_arg;
671 MonoCoopSem registered;
674 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
677 MonoThreadStart start_func;
678 void *start_func_arg;
681 * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
685 MonoInternalThread *internal;
686 MonoObject *start_delegate;
687 MonoObject *start_delegate_arg;
690 thread = start_info->thread;
691 internal = thread->internal_thread;
692 domain = mono_object_domain (start_info->thread);
694 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
696 if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
697 start_info->failed = TRUE;
699 mono_coop_sem_post (&start_info->registered);
701 if (InterlockedDecrement (&start_info->ref) == 0) {
702 mono_coop_sem_destroy (&start_info->registered);
711 start_delegate = start_info->start_delegate;
712 start_delegate_arg = start_info->start_delegate_arg;
713 start_func = start_info->start_func;
714 start_func_arg = start_info->start_func_arg;
716 /* This MUST be called before any managed code can be
717 * executed, as it calls the callback function that (for the
718 * jit) sets the lmf marker.
721 if (mono_thread_start_cb)
722 mono_thread_start_cb (tid, stack_ptr, start_func);
724 /* On 2.0 profile (and higher), set explicitly since state might have been
726 if (internal->apartment_state == ThreadApartmentState_Unknown)
727 internal->apartment_state = ThreadApartmentState_MTA;
729 mono_thread_init_apartment_state ();
731 /* Let the thread that called Start() know we're ready */
732 mono_coop_sem_post (&start_info->registered);
734 if (InterlockedDecrement (&start_info->ref) == 0) {
735 mono_coop_sem_destroy (&start_info->registered);
739 /* start_info is not valid anymore */
743 * Call this after calling start_notify, since the profiler callback might want
744 * to lock the thread, and the lock is held by thread_start () which waits for
747 mono_profiler_thread_start (tid);
749 /* if the name was set before starting, we didn't invoke the profiler callback */
750 if (internal->name) {
751 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
752 mono_profiler_thread_name (internal->tid, tname);
753 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
757 /* start_func is set only for unmanaged start functions */
759 start_func (start_func_arg);
763 g_assert (start_delegate != NULL);
765 /* we may want to handle the exception here. See comment below on unhandled exceptions */
766 args [0] = (gpointer) start_delegate_arg;
767 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
769 if (!mono_error_ok (&error)) {
770 MonoException *ex = mono_error_convert_to_exception (&error);
772 g_assert (ex != NULL);
773 MonoClass *klass = mono_object_get_class (&ex->object);
774 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
775 !is_threadabort_exception (klass)) {
776 mono_unhandled_exception (&ex->object);
777 mono_invoke_unhandled_exception_hook (&ex->object);
778 g_assert_not_reached ();
781 mono_error_cleanup (&error);
785 /* If the thread calls ExitThread at all, this remaining code
786 * will not be executed, but the main thread will eventually
787 * call thread_cleanup() on this thread's behalf.
790 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
792 /* Do any cleanup needed for apartment state. This
793 * cannot be done in thread_cleanup since thread_cleanup could be
794 * called for a thread other than the current thread.
795 * mono_thread_cleanup_apartment_state cleans up apartment
796 * for the current thead */
797 mono_thread_cleanup_apartment_state ();
799 thread_cleanup (internal);
803 /* Remove the reference to the thread object in the TLS data,
804 * so the thread object can be finalized. This won't be
805 * reached if the thread threw an uncaught exception, so those
806 * thread handles will stay referenced :-( (This is due to
807 * missing support for scanning thread-specific data in the
808 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
811 SET_CURRENT_OBJECT (NULL);
816 static gsize WINAPI start_wrapper(void *data)
818 volatile gsize dummy;
820 /* Avoid scanning the frames above this frame during a GC */
821 mono_gc_set_stack_end ((void*)&dummy);
823 return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
829 * Common thread creation code.
830 * LOCKING: Acquires the threads lock.
833 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
834 gboolean threadpool_thread, guint32 stack_size, MonoError *error)
836 StartInfo *start_info = NULL;
837 HANDLE thread_handle;
838 MonoNativeThreadId tid;
843 g_assert (!start_func && !start_func_arg);
845 g_assert (!start_delegate);
848 * Join joinable threads to prevent running out of threads since the finalizer
849 * thread might be blocked/backlogged.
851 mono_threads_join_threads ();
853 mono_error_init (error);
855 mono_threads_lock ();
857 mono_threads_unlock ();
860 if (threads_starting_up == NULL) {
861 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
862 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
864 mono_g_hash_table_insert (threads_starting_up, thread, thread);
865 mono_threads_unlock ();
867 internal->threadpool_thread = threadpool_thread;
868 if (threadpool_thread)
869 mono_thread_set_state (internal, ThreadState_Background);
871 start_info = g_new0 (StartInfo, 1);
873 start_info->thread = thread;
874 start_info->start_delegate = start_delegate;
875 start_info->start_delegate_arg = thread->start_obj;
876 start_info->start_func = start_func;
877 start_info->start_func_arg = start_func_arg;
878 start_info->failed = FALSE;
879 mono_coop_sem_init (&start_info->registered, 0);
882 stack_size = default_stacksize_for_thread (internal);
884 tp.priority = thread->priority;
885 tp.stack_size = stack_size;
886 tp.creation_flags = 0;
888 thread_handle = mono_threads_create_thread (start_wrapper, start_info, &tp, &tid);
890 if (thread_handle == NULL) {
891 /* The thread couldn't be created, so set an exception */
892 mono_threads_lock ();
893 mono_g_hash_table_remove (threads_starting_up, thread);
894 mono_threads_unlock ();
895 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
896 /* ref is not going to be decremented in start_wrapper_internal */
897 InterlockedDecrement (&start_info->ref);
902 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
905 * Wait for the thread to set up its TLS data etc, so
906 * theres no potential race condition if someone tries
907 * to look up the data believing the thread has
911 mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
913 mono_threads_close_thread_handle (thread_handle);
915 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));
917 ret = !start_info->failed;
920 if (InterlockedDecrement (&start_info->ref) == 0) {
921 mono_coop_sem_destroy (&start_info->registered);
928 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
930 if (mono_thread_start_cb) {
931 mono_thread_start_cb (tid, stack_start, func);
935 void mono_threads_set_default_stacksize (guint32 stacksize)
937 default_stacksize = stacksize;
940 guint32 mono_threads_get_default_stacksize (void)
942 return default_stacksize;
946 * mono_thread_create_internal:
948 * ARG should not be a GC reference.
951 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
954 MonoInternalThread *internal;
957 mono_error_init (error);
959 thread = create_thread_object (domain);
960 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
962 internal = create_internal_thread ();
964 MONO_OBJECT_SETREF (thread, internal_thread, internal);
966 res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
967 return_val_if_nok (error, NULL);
969 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
970 #ifndef MONO_CROSS_COMPILE
971 if (mono_check_corlib_version () == NULL)
972 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
979 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
982 if (!mono_thread_create_checked (domain, func, arg, &error))
983 mono_error_cleanup (&error);
987 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
989 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
993 mono_thread_attach (MonoDomain *domain)
995 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1001 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1003 MonoInternalThread *internal;
1005 MonoNativeThreadId tid;
1008 if ((internal = mono_thread_internal_current ())) {
1009 if (domain != mono_domain_get ())
1010 mono_domain_set (domain, TRUE);
1011 /* Already attached */
1012 return mono_thread_current ();
1015 if (!mono_gc_register_thread (&domain)) {
1016 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 ());
1019 tid=mono_native_thread_id_get ();
1021 internal = create_internal_thread ();
1023 thread = new_thread_with_internal (domain, internal);
1025 if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
1026 /* Mono is shutting down, so just wait for the end */
1028 mono_thread_info_sleep (10000, NULL);
1031 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1033 if (mono_thread_attach_cb) {
1037 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1040 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1042 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1045 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1046 if (!mono_thread_info_current ()->tools_thread)
1047 // FIXME: Need a separate callback
1048 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1054 mono_thread_detach_internal (MonoInternalThread *thread)
1056 g_return_if_fail (thread != NULL);
1058 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1060 thread_cleanup (thread);
1062 SET_CURRENT_OBJECT (NULL);
1063 mono_domain_unset ();
1065 /* Don't need to close the handle to this thread, even though we took a
1066 * reference in mono_thread_attach (), because the GC will do it
1067 * when the Thread object is finalised.
1072 mono_thread_detach (MonoThread *thread)
1075 mono_thread_detach_internal (thread->internal_thread);
1079 * mono_thread_detach_if_exiting:
1081 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1082 * This should be used at the end of embedding code which calls into managed code, and which
1083 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1086 mono_thread_detach_if_exiting (void)
1088 if (mono_thread_info_is_exiting ()) {
1089 MonoInternalThread *thread;
1091 thread = mono_thread_internal_current ();
1093 mono_thread_detach_internal (thread);
1094 mono_thread_info_detach ();
1102 mono_thread_exit (void)
1104 MonoInternalThread *thread = mono_thread_internal_current ();
1106 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1108 thread_cleanup (thread);
1109 SET_CURRENT_OBJECT (NULL);
1110 mono_domain_unset ();
1112 /* we could add a callback here for embedders to use. */
1113 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1114 exit (mono_environment_exitcode_get ());
1115 mono_thread_info_exit ();
1119 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1121 MonoInternalThread *internal;
1123 internal = create_internal_thread ();
1125 internal->state = ThreadState_Unstarted;
1127 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1131 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1135 MonoInternalThread *internal;
1138 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1140 if (!this_obj->internal_thread)
1141 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1142 internal = this_obj->internal_thread;
1144 LOCK_THREAD (internal);
1146 if ((internal->state & ThreadState_Unstarted) == 0) {
1147 UNLOCK_THREAD (internal);
1148 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1152 if ((internal->state & ThreadState_Aborted) != 0) {
1153 UNLOCK_THREAD (internal);
1157 res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1159 mono_error_cleanup (&error);
1160 UNLOCK_THREAD (internal);
1164 internal->state &= ~ThreadState_Unstarted;
1166 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1168 UNLOCK_THREAD (internal);
1169 return internal->handle;
1173 * This is called from the finalizer of the internal thread object.
1176 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1178 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1181 * Since threads keep a reference to their thread object while running, by the time this function is called,
1182 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1183 * when thread_cleanup () can be called after this.
1186 mono_threads_close_thread_handle (thread);
1188 if (this_obj->synch_cs) {
1189 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1190 this_obj->synch_cs = NULL;
1191 mono_coop_mutex_destroy (synch_cs);
1195 if (this_obj->name) {
1196 void *name = this_obj->name;
1197 this_obj->name = NULL;
1203 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1206 MonoInternalThread *thread = mono_thread_internal_current ();
1208 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1210 if (mono_thread_current_check_pending_interrupt ())
1214 gboolean alerted = FALSE;
1216 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1218 res = mono_thread_info_sleep (ms, &alerted);
1220 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1223 MonoException* exc = mono_thread_execute_interruption ();
1225 mono_raise_exception (exc);
1237 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1242 ves_icall_System_Threading_Thread_GetDomainID (void)
1244 return mono_domain_get()->domain_id;
1248 ves_icall_System_Threading_Thread_Yield (void)
1250 return mono_thread_info_yield ();
1254 * mono_thread_get_name:
1256 * Return the name of the thread. NAME_LEN is set to the length of the name.
1257 * Return NULL if the thread has no name. The returned memory is owned by the
1261 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1265 LOCK_THREAD (this_obj);
1267 if (!this_obj->name) {
1271 *name_len = this_obj->name_len;
1272 res = g_new (gunichar2, this_obj->name_len);
1273 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1276 UNLOCK_THREAD (this_obj);
1282 * mono_thread_get_name_utf8:
1284 * Return the name of the thread in UTF-8.
1285 * Return NULL if the thread has no name.
1286 * The returned memory is owned by the caller.
1289 mono_thread_get_name_utf8 (MonoThread *thread)
1294 MonoInternalThread *internal = thread->internal_thread;
1295 if (internal == NULL)
1298 LOCK_THREAD (internal);
1300 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1302 UNLOCK_THREAD (internal);
1308 * mono_thread_get_managed_id:
1310 * Return the Thread.ManagedThreadId value of `thread`.
1311 * Returns -1 if `thread` is NULL.
1314 mono_thread_get_managed_id (MonoThread *thread)
1319 MonoInternalThread *internal = thread->internal_thread;
1320 if (internal == NULL)
1323 int32_t id = internal->managed_id;
1329 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1334 mono_error_init (&error);
1336 LOCK_THREAD (this_obj);
1338 if (!this_obj->name)
1341 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1343 UNLOCK_THREAD (this_obj);
1345 if (mono_error_set_pending_exception (&error))
1352 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1354 LOCK_THREAD (this_obj);
1356 mono_error_init (error);
1358 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1359 UNLOCK_THREAD (this_obj);
1361 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1364 if (this_obj->name) {
1365 g_free (this_obj->name);
1366 this_obj->name_len = 0;
1369 this_obj->name = g_new (gunichar2, mono_string_length (name));
1370 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1371 this_obj->name_len = mono_string_length (name);
1374 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1377 this_obj->name = NULL;
1380 UNLOCK_THREAD (this_obj);
1382 if (this_obj->name && this_obj->tid) {
1383 char *tname = mono_string_to_utf8_checked (name, error);
1384 return_if_nok (error);
1385 mono_profiler_thread_name (this_obj->tid, tname);
1386 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1392 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1395 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1396 mono_error_set_pending_exception (&error);
1400 * ves_icall_System_Threading_Thread_GetPriority_internal:
1401 * @param this_obj: The MonoInternalThread on which to operate.
1403 * Gets the priority of the given thread.
1404 * @return: The priority of the given thread.
1407 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1410 MonoInternalThread *internal = this_obj->internal_thread;
1412 LOCK_THREAD (internal);
1413 if (internal->handle != NULL)
1414 priority = mono_thread_info_get_priority ((MonoThreadInfo*) internal->thread_info);
1416 priority = this_obj->priority;
1417 UNLOCK_THREAD (internal);
1422 * ves_icall_System_Threading_Thread_SetPriority_internal:
1423 * @param this_obj: The MonoInternalThread on which to operate.
1424 * @param priority: The priority to set.
1426 * Sets the priority of the given thread.
1429 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1431 MonoInternalThread *internal = this_obj->internal_thread;
1433 LOCK_THREAD (internal);
1434 this_obj->priority = priority;
1435 if (internal->handle != NULL)
1436 mono_thread_info_set_priority ((MonoThreadInfo*) internal->thread_info, this_obj->priority);
1437 UNLOCK_THREAD (internal);
1440 /* If the array is already in the requested domain, we just return it,
1441 otherwise we return a copy in that domain. */
1443 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1447 mono_error_init (error);
1451 if (mono_object_domain (arr) == domain)
1454 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1455 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1460 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1463 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1464 mono_error_set_pending_exception (&error);
1469 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1472 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1473 mono_error_set_pending_exception (&error);
1478 mono_thread_current (void)
1480 MonoDomain *domain = mono_domain_get ();
1481 MonoInternalThread *internal = mono_thread_internal_current ();
1482 MonoThread **current_thread_ptr;
1484 g_assert (internal);
1485 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1487 if (!*current_thread_ptr) {
1488 g_assert (domain != mono_get_root_domain ());
1489 *current_thread_ptr = new_thread_with_internal (domain, internal);
1491 return *current_thread_ptr;
1494 /* Return the thread object belonging to INTERNAL in the current domain */
1496 mono_thread_current_for_thread (MonoInternalThread *internal)
1498 MonoDomain *domain = mono_domain_get ();
1499 MonoThread **current_thread_ptr;
1501 g_assert (internal);
1502 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1504 if (!*current_thread_ptr) {
1505 g_assert (domain != mono_get_root_domain ());
1506 *current_thread_ptr = new_thread_with_internal (domain, internal);
1508 return *current_thread_ptr;
1512 mono_thread_internal_current (void)
1514 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1515 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1520 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1522 MonoInternalThread *thread = this_obj->internal_thread;
1523 HANDLE handle = thread->handle;
1524 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1527 if (mono_thread_current_check_pending_interrupt ())
1530 LOCK_THREAD (thread);
1532 if ((thread->state & ThreadState_Unstarted) != 0) {
1533 UNLOCK_THREAD (thread);
1535 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1539 UNLOCK_THREAD (thread);
1544 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1546 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1549 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1552 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1554 if(ret==WAIT_OBJECT_0) {
1555 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1560 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1565 #define MANAGED_WAIT_FAILED 0x7fffffff
1568 map_native_wait_result_to_managed (gint32 val)
1570 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1571 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1575 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1583 mono_error_init (error);
1585 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1588 if (numhandles != 1)
1589 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1591 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1594 if (ret != WAIT_IO_COMPLETION)
1597 exc = mono_thread_execute_interruption ();
1599 mono_error_set_exception_instance (error, exc);
1606 /* Re-calculate ms according to the time passed */
1607 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1608 if (diff_ms >= ms) {
1612 wait = ms - diff_ms;
1618 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1625 MonoObject *waitHandle;
1626 MonoInternalThread *thread = mono_thread_internal_current ();
1628 /* Do this WaitSleepJoin check before creating objects */
1629 if (mono_thread_current_check_pending_interrupt ())
1630 return map_native_wait_result_to_managed (WAIT_FAILED);
1632 /* We fail in managed if the array has more than 64 elements */
1633 numhandles = (guint32)mono_array_length(mono_handles);
1634 handles = g_new0(HANDLE, numhandles);
1636 for(i = 0; i < numhandles; i++) {
1637 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1638 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1645 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1647 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1649 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1653 mono_error_set_pending_exception (&error);
1655 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1656 return map_native_wait_result_to_managed (ret);
1659 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1662 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1663 uintptr_t numhandles;
1666 MonoObject *waitHandle;
1667 MonoInternalThread *thread = mono_thread_internal_current ();
1669 /* Do this WaitSleepJoin check before creating objects */
1670 if (mono_thread_current_check_pending_interrupt ())
1671 return map_native_wait_result_to_managed (WAIT_FAILED);
1673 numhandles = mono_array_length(mono_handles);
1674 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1675 return map_native_wait_result_to_managed (WAIT_FAILED);
1677 for(i = 0; i < numhandles; i++) {
1678 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1679 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1686 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1688 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1690 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1692 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1694 mono_error_set_pending_exception (&error);
1696 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1698 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1699 return map_native_wait_result_to_managed (ret - WAIT_OBJECT_0);
1701 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1702 return map_native_wait_result_to_managed (ret - WAIT_ABANDONED_0);
1705 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1706 return map_native_wait_result_to_managed (ret);
1710 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1714 MonoInternalThread *thread = mono_thread_internal_current ();
1716 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1722 if (mono_thread_current_check_pending_interrupt ())
1723 return map_native_wait_result_to_managed (WAIT_FAILED);
1725 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1727 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1729 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1731 mono_error_set_pending_exception (&error);
1732 return map_native_wait_result_to_managed (ret);
1736 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1739 MonoInternalThread *thread = mono_thread_internal_current ();
1744 if (mono_thread_current_check_pending_interrupt ())
1745 return map_native_wait_result_to_managed (WAIT_FAILED);
1747 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1750 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1753 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1755 return map_native_wait_result_to_managed (ret);
1758 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1765 mutex = CreateMutex (NULL, owned, NULL);
1767 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1769 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1777 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1778 return(ReleaseMutex (handle));
1781 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1787 *error = ERROR_SUCCESS;
1789 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1791 *error = GetLastError ();
1798 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, gint32 *error)
1803 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1805 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1806 mono_string_chars (name));
1809 *error = GetLastError ();
1814 MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, gint32 *prevcount)
1816 return ReleaseSemaphore (handle, releaseCount, prevcount);
1819 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1823 sem = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1825 *error = GetLastError ();
1830 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, gint32 *error)
1835 event = CreateEvent (NULL, manual, initial, NULL);
1837 event = CreateEvent (NULL, manual, initial,
1838 mono_string_chars (name));
1841 *error = GetLastError ();
1846 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1847 return (SetEvent(handle));
1850 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1851 return (ResetEvent(handle));
1855 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1856 CloseHandle (handle);
1859 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1865 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1867 *error = GetLastError ();
1869 *error = ERROR_SUCCESS;
1875 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1877 return InterlockedIncrement (location);
1880 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1882 #if SIZEOF_VOID_P == 4
1883 if (G_UNLIKELY ((size_t)location & 0x7)) {
1885 mono_interlocked_lock ();
1888 mono_interlocked_unlock ();
1892 return InterlockedIncrement64 (location);
1895 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1897 return InterlockedDecrement(location);
1900 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1902 #if SIZEOF_VOID_P == 4
1903 if (G_UNLIKELY ((size_t)location & 0x7)) {
1905 mono_interlocked_lock ();
1908 mono_interlocked_unlock ();
1912 return InterlockedDecrement64 (location);
1915 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1917 return InterlockedExchange(location, value);
1920 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1923 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1924 mono_gc_wbarrier_generic_nostore (location);
1928 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1930 return InterlockedExchangePointer(location, value);
1933 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1935 IntFloatUnion val, ret;
1938 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1944 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1946 #if SIZEOF_VOID_P == 4
1947 if (G_UNLIKELY ((size_t)location & 0x7)) {
1949 mono_interlocked_lock ();
1952 mono_interlocked_unlock ();
1956 return InterlockedExchange64 (location, value);
1960 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1962 LongDoubleUnion val, ret;
1965 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1970 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1972 return InterlockedCompareExchange(location, value, comparand);
1975 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1977 gint32 r = InterlockedCompareExchange(location, value, comparand);
1978 *success = r == comparand;
1982 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1985 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1986 mono_gc_wbarrier_generic_nostore (location);
1990 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1992 return InterlockedCompareExchangePointer(location, value, comparand);
1995 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1997 IntFloatUnion val, ret, cmp;
2000 cmp.fval = comparand;
2001 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2007 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2009 #if SIZEOF_VOID_P == 8
2010 LongDoubleUnion val, comp, ret;
2013 comp.fval = comparand;
2014 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2020 mono_interlocked_lock ();
2022 if (old == comparand)
2024 mono_interlocked_unlock ();
2031 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2033 #if SIZEOF_VOID_P == 4
2034 if (G_UNLIKELY ((size_t)location & 0x7)) {
2036 mono_interlocked_lock ();
2038 if (old == comparand)
2040 mono_interlocked_unlock ();
2044 return InterlockedCompareExchange64 (location, value, comparand);
2048 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2051 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2052 mono_gc_wbarrier_generic_nostore (location);
2057 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2060 MONO_CHECK_NULL (location, NULL);
2061 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2062 mono_gc_wbarrier_generic_nostore (location);
2067 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2069 return InterlockedAdd (location, value);
2073 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2075 #if SIZEOF_VOID_P == 4
2076 if (G_UNLIKELY ((size_t)location & 0x7)) {
2078 mono_interlocked_lock ();
2081 mono_interlocked_unlock ();
2085 return InterlockedAdd64 (location, value);
2089 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2091 #if SIZEOF_VOID_P == 4
2092 if (G_UNLIKELY ((size_t)location & 0x7)) {
2094 mono_interlocked_lock ();
2096 mono_interlocked_unlock ();
2100 return InterlockedRead64 (location);
2104 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2106 mono_memory_barrier ();
2110 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2112 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2114 if (state & ThreadState_Background) {
2115 /* If the thread changes the background mode, the main thread has to
2116 * be notified, since it has to rebuild the list of threads to
2119 SetEvent (background_change_event);
2124 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2126 mono_thread_set_state (this_obj, (MonoThreadState)state);
2128 if (state & ThreadState_Background) {
2129 /* If the thread changes the background mode, the main thread has to
2130 * be notified, since it has to rebuild the list of threads to
2133 SetEvent (background_change_event);
2138 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2142 LOCK_THREAD (this_obj);
2144 state = this_obj->state;
2146 UNLOCK_THREAD (this_obj);
2151 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2153 MonoInternalThread *current;
2155 MonoInternalThread *thread = this_obj->internal_thread;
2157 LOCK_THREAD (thread);
2159 current = mono_thread_internal_current ();
2161 thread->thread_interrupt_requested = TRUE;
2162 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2164 UNLOCK_THREAD (thread);
2167 async_abort_internal (thread, FALSE);
2172 * mono_thread_current_check_pending_interrupt:
2174 * Checks if there's a interruption request and set the pending exception if so.
2176 * @returns true if a pending exception was set
2179 mono_thread_current_check_pending_interrupt (void)
2181 MonoInternalThread *thread = mono_thread_internal_current ();
2182 gboolean throw_ = FALSE;
2184 LOCK_THREAD (thread);
2186 if (thread->thread_interrupt_requested) {
2188 thread->thread_interrupt_requested = FALSE;
2191 UNLOCK_THREAD (thread);
2194 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2199 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2201 LOCK_THREAD (thread);
2203 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2204 (thread->state & ThreadState_StopRequested) != 0 ||
2205 (thread->state & ThreadState_Stopped) != 0)
2207 UNLOCK_THREAD (thread);
2211 if ((thread->state & ThreadState_Unstarted) != 0) {
2212 thread->state |= ThreadState_Aborted;
2213 UNLOCK_THREAD (thread);
2217 thread->state |= ThreadState_AbortRequested;
2218 if (thread->abort_state_handle)
2219 mono_gchandle_free (thread->abort_state_handle);
2221 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2222 g_assert (thread->abort_state_handle);
2224 thread->abort_state_handle = 0;
2226 thread->abort_exc = NULL;
2228 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));
2230 /* During shutdown, we can't wait for other threads */
2232 /* Make sure the thread is awake */
2233 mono_thread_resume (thread);
2235 UNLOCK_THREAD (thread);
2240 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2242 if (!request_thread_abort (thread, state))
2245 if (thread == mono_thread_internal_current ()) {
2247 self_abort_internal (&error);
2248 mono_error_set_pending_exception (&error);
2250 async_abort_internal (thread, TRUE);
2255 * mono_thread_internal_abort:
2257 * Request thread @thread to be aborted.
2259 * @thread MUST NOT be the current thread.
2262 mono_thread_internal_abort (MonoInternalThread *thread)
2264 g_assert (thread != mono_thread_internal_current ());
2266 if (!request_thread_abort (thread, NULL))
2268 async_abort_internal (thread, TRUE);
2272 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2274 MonoInternalThread *thread = mono_thread_internal_current ();
2275 gboolean was_aborting;
2277 LOCK_THREAD (thread);
2278 was_aborting = thread->state & ThreadState_AbortRequested;
2279 thread->state &= ~ThreadState_AbortRequested;
2280 UNLOCK_THREAD (thread);
2282 if (!was_aborting) {
2283 const char *msg = "Unable to reset abort because no abort was requested";
2284 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2287 thread->abort_exc = NULL;
2288 if (thread->abort_state_handle) {
2289 mono_gchandle_free (thread->abort_state_handle);
2290 /* This is actually not necessary - the handle
2291 only counts if the exception is set */
2292 thread->abort_state_handle = 0;
2297 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2299 LOCK_THREAD (thread);
2301 thread->state &= ~ThreadState_AbortRequested;
2303 if (thread->abort_exc) {
2304 thread->abort_exc = NULL;
2305 if (thread->abort_state_handle) {
2306 mono_gchandle_free (thread->abort_state_handle);
2307 /* This is actually not necessary - the handle
2308 only counts if the exception is set */
2309 thread->abort_state_handle = 0;
2313 UNLOCK_THREAD (thread);
2317 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2320 MonoInternalThread *thread = this_obj->internal_thread;
2321 MonoObject *state, *deserialized = NULL;
2324 if (!thread->abort_state_handle)
2327 state = mono_gchandle_get_target (thread->abort_state_handle);
2330 domain = mono_domain_get ();
2331 if (mono_object_domain (state) == domain)
2334 deserialized = mono_object_xdomain_representation (state, domain, &error);
2336 if (!deserialized) {
2337 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2338 if (!is_ok (&error)) {
2339 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2340 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2342 mono_set_pending_exception (invalid_op_exc);
2346 return deserialized;
2350 mono_thread_suspend (MonoInternalThread *thread)
2352 LOCK_THREAD (thread);
2354 if ((thread->state & ThreadState_Unstarted) != 0 ||
2355 (thread->state & ThreadState_Aborted) != 0 ||
2356 (thread->state & ThreadState_Stopped) != 0)
2358 UNLOCK_THREAD (thread);
2362 if ((thread->state & ThreadState_Suspended) != 0 ||
2363 (thread->state & ThreadState_SuspendRequested) != 0 ||
2364 (thread->state & ThreadState_StopRequested) != 0)
2366 UNLOCK_THREAD (thread);
2370 thread->state |= ThreadState_SuspendRequested;
2372 if (thread == mono_thread_internal_current ()) {
2373 /* calls UNLOCK_THREAD (thread) */
2374 self_suspend_internal ();
2376 /* calls UNLOCK_THREAD (thread) */
2377 async_suspend_internal (thread, FALSE);
2384 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2386 if (!mono_thread_suspend (this_obj->internal_thread)) {
2387 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2392 /* LOCKING: LOCK_THREAD(thread) must be held */
2394 mono_thread_resume (MonoInternalThread *thread)
2396 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2397 thread->state &= ~ThreadState_SuspendRequested;
2401 if ((thread->state & ThreadState_Suspended) == 0 ||
2402 (thread->state & ThreadState_Unstarted) != 0 ||
2403 (thread->state & ThreadState_Aborted) != 0 ||
2404 (thread->state & ThreadState_Stopped) != 0)
2409 UNLOCK_THREAD (thread);
2411 /* Awake the thread */
2412 if (!mono_thread_info_resume (thread_get_tid (thread)))
2415 LOCK_THREAD (thread);
2417 thread->state &= ~ThreadState_Suspended;
2423 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2425 if (!thread->internal_thread) {
2426 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2428 LOCK_THREAD (thread->internal_thread);
2429 if (!mono_thread_resume (thread->internal_thread))
2430 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2431 UNLOCK_THREAD (thread->internal_thread);
2436 mono_threads_is_critical_method (MonoMethod *method)
2438 switch (method->wrapper_type) {
2439 case MONO_WRAPPER_RUNTIME_INVOKE:
2440 case MONO_WRAPPER_XDOMAIN_INVOKE:
2441 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2448 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2453 if (mono_threads_is_critical_method (m)) {
2454 *((gboolean*)data) = TRUE;
2461 is_running_protected_wrapper (void)
2463 gboolean found = FALSE;
2464 mono_stack_walk (find_wrapper, &found);
2469 request_thread_stop (MonoInternalThread *thread)
2471 LOCK_THREAD (thread);
2473 if ((thread->state & ThreadState_StopRequested) != 0 ||
2474 (thread->state & ThreadState_Stopped) != 0)
2476 UNLOCK_THREAD (thread);
2480 /* Make sure the thread is awake */
2481 mono_thread_resume (thread);
2483 thread->state |= ThreadState_StopRequested;
2484 thread->state &= ~ThreadState_AbortRequested;
2486 UNLOCK_THREAD (thread);
2491 * mono_thread_internal_stop:
2493 * Request thread @thread to stop.
2495 * @thread MUST NOT be the current thread.
2498 mono_thread_internal_stop (MonoInternalThread *thread)
2500 g_assert (thread != mono_thread_internal_current ());
2502 if (!request_thread_stop (thread))
2505 async_abort_internal (thread, TRUE);
2508 void mono_thread_stop (MonoThread *thread)
2510 MonoInternalThread *internal = thread->internal_thread;
2512 if (!request_thread_stop (internal))
2515 if (internal == mono_thread_internal_current ()) {
2517 self_abort_internal (&error);
2519 This function is part of the embeding API and has no way to return the exception
2520 to be thrown. So what we do is keep the old behavior and raise the exception.
2522 mono_error_raise_exception (&error); /* OK to throw, see note */
2524 async_abort_internal (internal, TRUE);
2529 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2531 gint8 tmp = *(volatile gint8 *)ptr;
2532 mono_memory_barrier ();
2537 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2539 gint16 tmp = *(volatile gint16 *)ptr;
2540 mono_memory_barrier ();
2545 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2547 gint32 tmp = *(volatile gint32 *)ptr;
2548 mono_memory_barrier ();
2553 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2555 gint64 tmp = *(volatile gint64 *)ptr;
2556 mono_memory_barrier ();
2561 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2563 volatile void *tmp = *(volatile void **)ptr;
2564 mono_memory_barrier ();
2565 return (void *) tmp;
2569 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2571 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2572 mono_memory_barrier ();
2573 return (MonoObject *) tmp;
2577 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2579 double tmp = *(volatile double *)ptr;
2580 mono_memory_barrier ();
2585 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2587 float tmp = *(volatile float *)ptr;
2588 mono_memory_barrier ();
2593 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2595 return InterlockedRead8 ((volatile gint8 *)ptr);
2599 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2601 return InterlockedRead16 ((volatile gint16 *)ptr);
2605 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2607 return InterlockedRead ((volatile gint32 *)ptr);
2611 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2613 #if SIZEOF_VOID_P == 4
2614 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2616 mono_interlocked_lock ();
2617 val = *(gint64*)ptr;
2618 mono_interlocked_unlock ();
2622 return InterlockedRead64 ((volatile gint64 *)ptr);
2626 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2628 return InterlockedReadPointer ((volatile gpointer *)ptr);
2632 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2636 #if SIZEOF_VOID_P == 4
2637 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2639 mono_interlocked_lock ();
2640 val = *(double*)ptr;
2641 mono_interlocked_unlock ();
2646 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2652 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2656 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2662 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2664 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2668 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2670 mono_memory_barrier ();
2671 *(volatile gint8 *)ptr = value;
2675 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2677 mono_memory_barrier ();
2678 *(volatile gint16 *)ptr = value;
2682 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2684 mono_memory_barrier ();
2685 *(volatile gint32 *)ptr = value;
2689 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2691 mono_memory_barrier ();
2692 *(volatile gint64 *)ptr = value;
2696 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2698 mono_memory_barrier ();
2699 *(volatile void **)ptr = value;
2703 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2705 mono_memory_barrier ();
2706 mono_gc_wbarrier_generic_store (ptr, value);
2710 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2712 mono_memory_barrier ();
2713 *(volatile double *)ptr = value;
2717 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2719 mono_memory_barrier ();
2720 *(volatile float *)ptr = value;
2724 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2726 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2730 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2732 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2736 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2738 InterlockedWrite ((volatile gint32 *)ptr, value);
2742 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2744 #if SIZEOF_VOID_P == 4
2745 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2746 mono_interlocked_lock ();
2747 *(gint64*)ptr = value;
2748 mono_interlocked_unlock ();
2753 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2757 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2759 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2763 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2767 #if SIZEOF_VOID_P == 4
2768 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2769 mono_interlocked_lock ();
2770 *(double*)ptr = value;
2771 mono_interlocked_unlock ();
2778 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2782 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2788 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2792 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2794 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2798 free_context (void *user_data)
2800 ContextStaticData *data = user_data;
2802 mono_threads_lock ();
2805 * There is no guarantee that, by the point this reference queue callback
2806 * has been invoked, the GC handle associated with the object will fail to
2807 * resolve as one might expect. So if we don't free and remove the GC
2808 * handle here, free_context_static_data_helper () could end up resolving
2809 * a GC handle to an actually-dead context which would contain a pointer
2810 * to an already-freed static data segment, resulting in a crash when
2813 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2815 mono_threads_unlock ();
2817 mono_gchandle_free (data->gc_handle);
2818 mono_free_static_data (data->static_data);
2823 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2825 mono_threads_lock ();
2827 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2830 contexts = g_hash_table_new (NULL, NULL);
2833 context_queue = mono_gc_reference_queue_new (free_context);
2835 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2836 g_hash_table_insert (contexts, gch, gch);
2839 * We use this intermediate structure to contain a duplicate pointer to
2840 * the static data because we can't rely on being able to resolve the GC
2841 * handle in the reference queue callback.
2843 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2844 data->gc_handle = GPOINTER_TO_UINT (gch);
2847 context_adjust_static_data (ctx);
2848 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2850 mono_threads_unlock ();
2852 mono_profiler_context_loaded (ctx);
2856 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2859 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2860 * cleanup in exceptional circumstances, we don't actually do any
2861 * cleanup work here. We instead do this via a reference queue.
2864 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2866 mono_profiler_context_unloaded (ctx);
2870 mono_thread_init_tls (void)
2872 MONO_FAST_TLS_INIT (tls_current_object);
2873 mono_native_tls_alloc (¤t_object_key, NULL);
2876 void mono_thread_init (MonoThreadStartCB start_cb,
2877 MonoThreadAttachCB attach_cb)
2879 mono_coop_mutex_init_recursive (&threads_mutex);
2881 mono_os_mutex_init_recursive(&interlocked_mutex);
2882 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2884 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2885 g_assert(background_change_event != NULL);
2887 mono_init_static_data_info (&thread_static_info);
2888 mono_init_static_data_info (&context_static_info);
2890 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2892 mono_thread_start_cb = start_cb;
2893 mono_thread_attach_cb = attach_cb;
2895 /* Get a pseudo handle to the current process. This is just a
2896 * kludge so that wapi can build a process handle if needed.
2897 * As a pseudo handle is returned, we don't need to clean
2900 GetCurrentProcess ();
2903 void mono_thread_cleanup (void)
2905 #if !defined(RUN_IN_SUBTHREAD)
2906 /* The main thread must abandon any held mutexes (particularly
2907 * important for named mutexes as they are shared across
2908 * processes, see bug 74680.) This will happen when the
2909 * thread exits, but if it's not running in a subthread it
2910 * won't exit in time.
2912 mono_thread_info_set_exited (mono_thread_info_current ());
2916 /* This stuff needs more testing, it seems one of these
2917 * critical sections can be locked when mono_thread_cleanup is
2920 mono_coop_mutex_destroy (&threads_mutex);
2921 mono_os_mutex_destroy (&interlocked_mutex);
2922 mono_os_mutex_destroy (&delayed_free_table_mutex);
2923 mono_os_mutex_destroy (&small_id_mutex);
2924 CloseHandle (background_change_event);
2927 mono_native_tls_free (current_object_key);
2931 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2933 mono_thread_cleanup_fn = func;
2937 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2939 thread->internal_thread->manage_callback = func;
2943 static void print_tids (gpointer key, gpointer value, gpointer user)
2945 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2946 * sizeof(uint) and a cast to uint would overflow
2948 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2949 * print this as a pointer.
2951 g_message ("Waiting for: %p", key);
2956 HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2957 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2962 wait_for_tids (struct wait_data *wait, guint32 timeout)
2966 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2969 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2972 if(ret==WAIT_FAILED) {
2973 /* See the comment in build_wait_tids() */
2974 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2978 for(i=0; i<wait->num; i++)
2979 mono_threads_close_thread_handle (wait->handles [i]);
2981 if (ret == WAIT_TIMEOUT)
2984 for(i=0; i<wait->num; i++) {
2985 gsize tid = wait->threads[i]->tid;
2988 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2989 * it can still run io-layer etc. code. So wait for it to really exit.
2990 * FIXME: This won't join threads which are not in the joinable_hash yet.
2992 mono_thread_join ((gpointer)tid);
2994 mono_threads_lock ();
2995 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2996 /* This thread must have been killed, because
2997 * it hasn't cleaned itself up. (It's just
2998 * possible that the thread exited before the
2999 * parent thread had a chance to store the
3000 * handle, and now there is another pointer to
3001 * the already-exited thread stored. In this
3002 * case, we'll just get two
3003 * mono_profiler_thread_end() calls for the
3007 mono_threads_unlock ();
3008 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
3009 thread_cleanup (wait->threads[i]);
3011 mono_threads_unlock ();
3016 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
3018 guint32 i, ret, count;
3020 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3022 /* Add the thread state change event, so it wakes up if a thread changes
3023 * to background mode.
3026 if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3027 wait->handles [count] = background_change_event;
3032 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
3035 if(ret==WAIT_FAILED) {
3036 /* See the comment in build_wait_tids() */
3037 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3041 for(i=0; i<wait->num; i++)
3042 mono_threads_close_thread_handle (wait->handles [i]);
3044 if (ret == WAIT_TIMEOUT)
3047 if (ret < wait->num) {
3048 gsize tid = wait->threads[ret]->tid;
3049 mono_threads_lock ();
3050 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3051 /* See comment in wait_for_tids about thread cleanup */
3052 mono_threads_unlock ();
3053 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3054 thread_cleanup (wait->threads [ret]);
3056 mono_threads_unlock ();
3060 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3062 struct wait_data *wait=(struct wait_data *)user;
3064 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3066 MonoInternalThread *thread=(MonoInternalThread *)value;
3068 /* Ignore background threads, we abort them later */
3069 /* Do not lock here since it is not needed and the caller holds threads_lock */
3070 if (thread->state & ThreadState_Background) {
3071 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3072 return; /* just leave, ignore */
3075 if (mono_gc_is_finalizer_internal_thread (thread)) {
3076 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3080 if (thread == mono_thread_internal_current ()) {
3081 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3085 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3086 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3090 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3091 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3095 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3096 if (handle == NULL) {
3097 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3101 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3102 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3103 wait->handles[wait->num]=handle;
3104 wait->threads[wait->num]=thread;
3107 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3109 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3114 /* Just ignore the rest, we can't do anything with
3121 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3123 struct wait_data *wait=(struct wait_data *)user;
3124 MonoNativeThreadId self = mono_native_thread_id_get ();
3125 MonoInternalThread *thread = (MonoInternalThread *)value;
3128 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3131 /* The finalizer thread is not a background thread */
3132 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3133 && (thread->state & ThreadState_Background) != 0
3134 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3136 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3140 wait->handles[wait->num] = handle;
3141 wait->threads[wait->num] = thread;
3144 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3145 mono_thread_internal_abort (thread);
3149 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3150 && !mono_gc_is_finalizer_internal_thread (thread);
3154 * mono_threads_set_shutting_down:
3156 * Is called by a thread that wants to shut down Mono. If the runtime is already
3157 * shutting down, the calling thread is suspended/stopped, and this function never
3161 mono_threads_set_shutting_down (void)
3163 MonoInternalThread *current_thread = mono_thread_internal_current ();
3165 mono_threads_lock ();
3167 if (shutting_down) {
3168 mono_threads_unlock ();
3170 /* Make sure we're properly suspended/stopped */
3172 LOCK_THREAD (current_thread);
3174 if ((current_thread->state & ThreadState_SuspendRequested) ||
3175 (current_thread->state & ThreadState_AbortRequested) ||
3176 (current_thread->state & ThreadState_StopRequested)) {
3177 UNLOCK_THREAD (current_thread);
3178 mono_thread_execute_interruption ();
3180 current_thread->state |= ThreadState_Stopped;
3181 UNLOCK_THREAD (current_thread);
3184 /*since we're killing the thread, unset the current domain.*/
3185 mono_domain_unset ();
3187 /* Wake up other threads potentially waiting for us */
3188 mono_thread_info_exit ();
3190 shutting_down = TRUE;
3192 /* Not really a background state change, but this will
3193 * interrupt the main thread if it is waiting for all
3194 * the other threads.
3196 SetEvent (background_change_event);
3198 mono_threads_unlock ();
3202 void mono_thread_manage (void)
3204 struct wait_data wait_data;
3205 struct wait_data *wait = &wait_data;
3207 memset (wait, 0, sizeof (struct wait_data));
3208 /* join each thread that's still running */
3209 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3211 mono_threads_lock ();
3213 THREAD_DEBUG (g_message("%s: No threads", __func__));
3214 mono_threads_unlock ();
3217 mono_threads_unlock ();
3220 mono_threads_lock ();
3221 if (shutting_down) {
3222 /* somebody else is shutting down */
3223 mono_threads_unlock ();
3226 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3227 mono_g_hash_table_foreach (threads, print_tids, NULL));
3229 ResetEvent (background_change_event);
3231 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3232 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3233 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3234 mono_threads_unlock ();
3236 /* Something to wait for */
3237 wait_for_tids_or_state_change (wait, INFINITE);
3239 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3240 } while(wait->num>0);
3242 /* Mono is shutting down, so just wait for the end */
3243 if (!mono_runtime_try_shutdown ()) {
3244 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3245 mono_thread_suspend (mono_thread_internal_current ());
3246 mono_thread_execute_interruption ();
3250 * Remove everything but the finalizer thread and self.
3251 * Also abort all the background threads
3254 mono_threads_lock ();
3257 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3258 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3259 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3261 mono_threads_unlock ();
3263 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3265 /* Something to wait for */
3266 wait_for_tids (wait, INFINITE);
3268 } while (wait->num > 0);
3271 * give the subthreads a chance to really quit (this is mainly needed
3272 * to get correct user and system times from getrusage/wait/time(1)).
3273 * This could be removed if we avoid pthread_detach() and use pthread_join().
3275 mono_thread_info_yield ();
3279 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3281 MonoInternalThread *thread = (MonoInternalThread*)value;
3282 struct wait_data *wait = (struct wait_data*)user_data;
3286 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3288 * This needs no locking.
3290 if ((thread->state & ThreadState_Suspended) != 0 ||
3291 (thread->state & ThreadState_Stopped) != 0)
3294 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3295 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3299 wait->handles [wait->num] = handle;
3300 wait->threads [wait->num] = thread;
3306 * mono_thread_suspend_all_other_threads:
3308 * Suspend all managed threads except the finalizer thread and this thread. It is
3309 * not possible to resume them later.
3311 void mono_thread_suspend_all_other_threads (void)
3313 struct wait_data wait_data;
3314 struct wait_data *wait = &wait_data;
3316 MonoNativeThreadId self = mono_native_thread_id_get ();
3317 guint32 eventidx = 0;
3318 gboolean starting, finished;
3320 memset (wait, 0, sizeof (struct wait_data));
3322 * The other threads could be in an arbitrary state at this point, i.e.
3323 * they could be starting up, shutting down etc. This means that there could be
3324 * threads which are not even in the threads hash table yet.
3328 * First we set a barrier which will be checked by all threads before they
3329 * are added to the threads hash table, and they will exit if the flag is set.
3330 * This ensures that no threads could be added to the hash later.
3331 * We will use shutting_down as the barrier for now.
3333 g_assert (shutting_down);
3336 * We make multiple calls to WaitForMultipleObjects since:
3337 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3338 * - some threads could exit without becoming suspended
3343 * Make a copy of the hashtable since we can't do anything with
3344 * threads while threads_mutex is held.
3347 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3348 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3349 mono_threads_lock ();
3350 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3351 mono_threads_unlock ();
3354 /* Get the suspended events that we'll be waiting for */
3355 for (i = 0; i < wait->num; ++i) {
3356 MonoInternalThread *thread = wait->threads [i];
3358 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3359 || mono_gc_is_finalizer_internal_thread (thread)
3360 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3362 //mono_threads_close_thread_handle (wait->handles [i]);
3363 wait->threads [i] = NULL; /* ignore this thread in next loop */
3367 LOCK_THREAD (thread);
3369 if ((thread->state & ThreadState_Suspended) != 0 ||
3370 (thread->state & ThreadState_StopRequested) != 0 ||
3371 (thread->state & ThreadState_Stopped) != 0) {
3372 UNLOCK_THREAD (thread);
3373 mono_threads_close_thread_handle (wait->handles [i]);
3374 wait->threads [i] = NULL; /* ignore this thread in next loop */
3380 /* Convert abort requests into suspend requests */
3381 if ((thread->state & ThreadState_AbortRequested) != 0)
3382 thread->state &= ~ThreadState_AbortRequested;
3384 thread->state |= ThreadState_SuspendRequested;
3386 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3387 async_suspend_internal (thread, TRUE);
3389 if (eventidx <= 0) {
3391 * If there are threads which are starting up, we wait until they
3392 * are suspended when they try to register in the threads hash.
3393 * This is guaranteed to finish, since the threads which can create new
3394 * threads get suspended after a while.
3395 * FIXME: The finalizer thread can still create new threads.
3397 mono_threads_lock ();
3398 if (threads_starting_up)
3399 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3402 mono_threads_unlock ();
3404 mono_thread_info_sleep (100, NULL);
3412 MonoInternalThread *thread;
3413 MonoStackFrameInfo *frames;
3414 int nframes, max_frames;
3415 int nthreads, max_threads;
3416 MonoInternalThread **threads;
3417 } ThreadDumpUserData;
3419 static gboolean thread_dump_requested;
3421 /* This needs to be async safe */
3423 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3425 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3427 if (ud->nframes < ud->max_frames) {
3428 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3435 /* This needs to be async safe */
3436 static SuspendThreadResult
3437 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3439 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3440 MonoInternalThread *thread = user_data->thread;
3443 /* This no longer works with remote unwinding */
3444 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3445 mono_thread_info_describe (info, text);
3446 g_string_append (text, "\n");
3449 if (thread == mono_thread_internal_current ())
3450 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3452 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3454 return MonoResumeThread;
3458 int nthreads, max_threads;
3459 MonoInternalThread **threads;
3460 } CollectThreadsUserData;
3463 collect_thread (gpointer key, gpointer value, gpointer user)
3465 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3466 MonoInternalThread *thread = (MonoInternalThread *)value;
3468 if (ud->nthreads < ud->max_threads)
3469 ud->threads [ud->nthreads ++] = thread;
3473 * Collect running threads into the THREADS array.
3474 * THREADS should be an array allocated on the stack.
3477 collect_threads (MonoInternalThread **thread_array, int max_threads)
3479 CollectThreadsUserData ud;
3481 memset (&ud, 0, sizeof (ud));
3482 /* This array contains refs, but its on the stack, so its ok */
3483 ud.threads = thread_array;
3484 ud.max_threads = max_threads;
3486 mono_threads_lock ();
3487 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3488 mono_threads_unlock ();
3494 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3496 GString* text = g_string_new (0);
3498 GError *error = NULL;
3501 ud->thread = thread;
3504 /* Collect frames for the thread */
3505 if (thread == mono_thread_internal_current ()) {
3506 get_thread_dump (mono_thread_info_current (), ud);
3508 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3512 * Do all the non async-safe work outside of get_thread_dump.
3515 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3517 g_string_append_printf (text, "\n\"%s\"", name);
3520 else if (thread->threadpool_thread) {
3521 g_string_append (text, "\n\"<threadpool thread>\"");
3523 g_string_append (text, "\n\"<unnamed thread>\"");
3526 for (i = 0; i < ud->nframes; ++i) {
3527 MonoStackFrameInfo *frame = &ud->frames [i];
3528 MonoMethod *method = NULL;
3530 if (frame->type == FRAME_TYPE_MANAGED)
3531 method = mono_jit_info_get_method (frame->ji);
3534 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3535 g_string_append_printf (text, " %s\n", location);
3538 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3542 fprintf (stdout, "%s", text->str);
3544 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3545 OutputDebugStringA(text->str);
3548 g_string_free (text, TRUE);
3553 mono_threads_perform_thread_dump (void)
3555 ThreadDumpUserData ud;
3556 MonoInternalThread *thread_array [128];
3557 int tindex, nthreads;
3559 if (!thread_dump_requested)
3562 printf ("Full thread dump:\n");
3564 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3565 nthreads = collect_threads (thread_array, 128);
3567 memset (&ud, 0, sizeof (ud));
3568 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3569 ud.max_frames = 256;
3571 for (tindex = 0; tindex < nthreads; ++tindex)
3572 dump_thread (thread_array [tindex], &ud);
3576 thread_dump_requested = FALSE;
3579 /* Obtain the thread dump of all threads */
3581 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3584 ThreadDumpUserData ud;
3585 MonoInternalThread *thread_array [128];
3586 MonoDomain *domain = mono_domain_get ();
3587 MonoDebugSourceLocation *location;
3588 int tindex, nthreads;
3590 mono_error_init (error);
3592 *out_threads = NULL;
3593 *out_stack_frames = NULL;
3595 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3596 nthreads = collect_threads (thread_array, 128);
3598 memset (&ud, 0, sizeof (ud));
3599 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3600 ud.max_frames = 256;
3602 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3605 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3609 for (tindex = 0; tindex < nthreads; ++tindex) {
3610 MonoInternalThread *thread = thread_array [tindex];
3611 MonoArray *thread_frames;
3617 /* Collect frames for the thread */
3618 if (thread == mono_thread_internal_current ()) {
3619 get_thread_dump (mono_thread_info_current (), &ud);
3621 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3624 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3626 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3629 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3631 for (i = 0; i < ud.nframes; ++i) {
3632 MonoStackFrameInfo *frame = &ud.frames [i];
3633 MonoMethod *method = NULL;
3634 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3638 sf->native_offset = frame->native_offset;
3640 if (frame->type == FRAME_TYPE_MANAGED)
3641 method = mono_jit_info_get_method (frame->ji);
3644 sf->method_address = (gsize) frame->ji->code_start;
3646 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3649 MONO_OBJECT_SETREF (sf, method, rm);
3651 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3653 sf->il_offset = location->il_offset;
3655 if (location && location->source_file) {
3656 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3657 sf->line = location->row;
3658 sf->column = location->column;
3660 mono_debug_free_source_location (location);
3665 mono_array_setref (thread_frames, i, sf);
3671 return is_ok (error);
3675 * mono_threads_request_thread_dump:
3677 * Ask all threads except the current to print their stacktrace to stdout.
3680 mono_threads_request_thread_dump (void)
3682 /*The new thread dump code runs out of the finalizer thread. */
3683 thread_dump_requested = TRUE;
3684 mono_gc_finalize_notify ();
3689 gint allocated; /* +1 so that refs [allocated] == NULL */
3693 typedef struct ref_stack RefStack;
3696 ref_stack_new (gint initial_size)
3700 initial_size = MAX (initial_size, 16) + 1;
3701 rs = g_new0 (RefStack, 1);
3702 rs->refs = g_new0 (gpointer, initial_size);
3703 rs->allocated = initial_size;
3708 ref_stack_destroy (gpointer ptr)
3710 RefStack *rs = (RefStack *)ptr;
3719 ref_stack_push (RefStack *rs, gpointer ptr)
3721 g_assert (rs != NULL);
3723 if (rs->bottom >= rs->allocated) {
3724 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3725 rs->allocated <<= 1;
3726 rs->refs [rs->allocated] = NULL;
3728 rs->refs [rs->bottom++] = ptr;
3732 ref_stack_pop (RefStack *rs)
3734 if (rs == NULL || rs->bottom == 0)
3738 rs->refs [rs->bottom] = NULL;
3742 ref_stack_find (RefStack *rs, gpointer ptr)
3749 for (refs = rs->refs; refs && *refs; refs++) {
3757 * mono_thread_push_appdomain_ref:
3759 * Register that the current thread may have references to objects in domain
3760 * @domain on its stack. Each call to this function should be paired with a
3761 * call to pop_appdomain_ref.
3764 mono_thread_push_appdomain_ref (MonoDomain *domain)
3766 MonoInternalThread *thread = mono_thread_internal_current ();
3769 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3770 SPIN_LOCK (thread->lock_thread_id);
3771 if (thread->appdomain_refs == NULL)
3772 thread->appdomain_refs = ref_stack_new (16);
3773 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3774 SPIN_UNLOCK (thread->lock_thread_id);
3779 mono_thread_pop_appdomain_ref (void)
3781 MonoInternalThread *thread = mono_thread_internal_current ();
3784 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3785 SPIN_LOCK (thread->lock_thread_id);
3786 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3787 SPIN_UNLOCK (thread->lock_thread_id);
3792 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3795 SPIN_LOCK (thread->lock_thread_id);
3796 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3797 SPIN_UNLOCK (thread->lock_thread_id);
3802 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3804 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3807 typedef struct abort_appdomain_data {
3808 struct wait_data wait;
3810 } abort_appdomain_data;
3813 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3815 MonoInternalThread *thread = (MonoInternalThread*)value;
3816 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3817 MonoDomain *domain = data->domain;
3819 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3820 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3822 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3823 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3826 data->wait.handles [data->wait.num] = handle;
3827 data->wait.threads [data->wait.num] = thread;
3830 /* Just ignore the rest, we can't do anything with
3838 * mono_threads_abort_appdomain_threads:
3840 * Abort threads which has references to the given appdomain.
3843 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3845 #ifdef __native_client__
3849 abort_appdomain_data user_data;
3851 int orig_timeout = timeout;
3854 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3856 start_time = mono_msec_ticks ();
3858 mono_threads_lock ();
3860 user_data.domain = domain;
3861 user_data.wait.num = 0;
3862 /* This shouldn't take any locks */
3863 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3864 mono_threads_unlock ();
3866 if (user_data.wait.num > 0) {
3867 /* Abort the threads outside the threads lock */
3868 for (i = 0; i < user_data.wait.num; ++i)
3869 mono_thread_internal_abort (user_data.wait.threads [i]);
3872 * We should wait for the threads either to abort, or to leave the
3873 * domain. We can't do the latter, so we wait with a timeout.
3875 wait_for_tids (&user_data.wait, 100);
3878 /* Update remaining time */
3879 timeout -= mono_msec_ticks () - start_time;
3880 start_time = mono_msec_ticks ();
3882 if (orig_timeout != -1 && timeout < 0)
3885 while (user_data.wait.num > 0);
3887 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3893 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3895 MonoInternalThread *thread = (MonoInternalThread*)value;
3896 MonoDomain *domain = (MonoDomain*)user_data;
3899 /* No locking needed here */
3900 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3902 if (thread->cached_culture_info) {
3903 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3904 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3905 if (obj && obj->vtable->domain == domain)
3906 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3912 * mono_threads_clear_cached_culture:
3914 * Clear the cached_current_culture from all threads if it is in the
3918 mono_threads_clear_cached_culture (MonoDomain *domain)
3920 mono_threads_lock ();
3921 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3922 mono_threads_unlock ();
3926 * mono_thread_get_undeniable_exception:
3928 * Return an exception which needs to be raised when leaving a catch clause.
3929 * This is used for undeniable exception propagation.
3932 mono_thread_get_undeniable_exception (void)
3934 MonoInternalThread *thread = mono_thread_internal_current ();
3936 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3938 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3939 * exception if the thread no longer references a dying appdomain.
3941 thread->abort_exc->trace_ips = NULL;
3942 thread->abort_exc->stack_trace = NULL;
3943 return thread->abort_exc;
3949 #if MONO_SMALL_CONFIG
3950 #define NUM_STATIC_DATA_IDX 4
3951 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3955 #define NUM_STATIC_DATA_IDX 8
3956 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3957 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3961 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3962 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3965 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3967 gpointer *static_data = (gpointer *)addr;
3969 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3970 void **ptr = (void **)static_data [i];
3975 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3976 void **p = ptr + idx;
3979 mark_func ((MonoObject**)p, gc_data);
3985 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3987 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3991 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3993 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3997 * mono_alloc_static_data
3999 * Allocate memory blocks for storing threads or context static data
4002 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4004 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4007 gpointer* static_data = *static_data_ptr;
4009 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4010 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4012 if (mono_gc_user_markers_supported ()) {
4013 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4014 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4016 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4017 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4020 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4021 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4022 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4023 *static_data_ptr = static_data;
4024 static_data [0] = static_data;
4027 for (i = 1; i <= idx; ++i) {
4028 if (static_data [i])
4031 if (mono_gc_user_markers_supported ())
4032 static_data [i] = g_malloc0 (static_data_size [i]);
4034 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4035 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4036 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4041 mono_free_static_data (gpointer* static_data)
4044 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4045 gpointer p = static_data [i];
4049 * At this point, the static data pointer array is still registered with the
4050 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4051 * data. Freeing the individual arrays without first nulling their slots
4052 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4053 * such an already freed array. See bug #13813.
4055 static_data [i] = NULL;
4056 mono_memory_write_barrier ();
4057 if (mono_gc_user_markers_supported ())
4060 mono_gc_free_fixed (p);
4062 mono_gc_free_fixed (static_data);
4066 * mono_init_static_data_info
4068 * Initializes static data counters
4070 static void mono_init_static_data_info (StaticDataInfo *static_data)
4072 static_data->idx = 0;
4073 static_data->offset = 0;
4074 static_data->freelist = NULL;
4078 * mono_alloc_static_data_slot
4080 * Generates an offset for static data. static_data contains the counters
4081 * used to generate it.
4084 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4086 if (!static_data->idx && !static_data->offset) {
4088 * we use the first chunk of the first allocation also as
4089 * an array for the rest of the data
4091 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4093 static_data->offset += align - 1;
4094 static_data->offset &= ~(align - 1);
4095 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4096 static_data->idx ++;
4097 g_assert (size <= static_data_size [static_data->idx]);
4098 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4099 static_data->offset = 0;
4101 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4102 static_data->offset += size;
4107 * LOCKING: requires that threads_mutex is held
4110 context_adjust_static_data (MonoAppContext *ctx)
4112 if (context_static_info.offset || context_static_info.idx > 0) {
4113 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4114 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4115 ctx->data->static_data = ctx->static_data;
4120 * LOCKING: requires that threads_mutex is held
4123 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4125 MonoInternalThread *thread = (MonoInternalThread *)value;
4126 guint32 offset = GPOINTER_TO_UINT (user);
4128 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4132 * LOCKING: requires that threads_mutex is held
4135 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4137 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4142 guint32 offset = GPOINTER_TO_UINT (user);
4143 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4144 ctx->data->static_data = ctx->static_data;
4147 static StaticDataFreeList*
4148 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4150 StaticDataFreeList* prev = NULL;
4151 StaticDataFreeList* tmp = static_data->freelist;
4153 if (tmp->size == size) {
4155 prev->next = tmp->next;
4157 static_data->freelist = tmp->next;
4166 #if SIZEOF_VOID_P == 4
4173 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4175 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4177 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4178 MonoBitSet *rb = sets [idx];
4179 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4180 offset /= sizeof (uintptr_t);
4181 /* offset is now the bitmap offset */
4182 for (int i = 0; i < numbits; ++i) {
4183 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4184 mono_bitset_set_fast (rb, offset + i);
4189 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4191 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4192 MonoBitSet *rb = sets [idx];
4193 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4194 offset /= sizeof (uintptr_t);
4195 /* offset is now the bitmap offset */
4196 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4197 mono_bitset_clear_fast (rb, offset + i);
4201 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4203 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4205 StaticDataInfo *info;
4208 if (static_type == SPECIAL_STATIC_THREAD) {
4209 info = &thread_static_info;
4210 sets = thread_reference_bitmaps;
4212 info = &context_static_info;
4213 sets = context_reference_bitmaps;
4216 mono_threads_lock ();
4218 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4222 offset = item->offset;
4225 offset = mono_alloc_static_data_slot (info, size, align);
4228 update_reference_bitmap (sets, offset, bitmap, numbits);
4230 if (static_type == SPECIAL_STATIC_THREAD) {
4231 /* This can be called during startup */
4232 if (threads != NULL)
4233 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4235 if (contexts != NULL)
4236 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4238 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4241 mono_threads_unlock ();
4247 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4249 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4251 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4252 return get_thread_static_data (thread, offset);
4254 return get_context_static_data (thread->current_appcontext, offset);
4259 mono_get_special_static_data (guint32 offset)
4261 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4270 * LOCKING: requires that threads_mutex is held
4273 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4275 MonoInternalThread *thread = (MonoInternalThread *)value;
4276 OffsetSize *data = (OffsetSize *)user;
4277 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4278 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4281 if (!thread->static_data || !thread->static_data [idx])
4283 ptr = ((char*) thread->static_data [idx]) + off;
4284 mono_gc_bzero_atomic (ptr, data->size);
4288 * LOCKING: requires that threads_mutex is held
4291 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4293 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4298 OffsetSize *data = (OffsetSize *)user;
4299 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4300 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4303 if (!ctx->static_data || !ctx->static_data [idx])
4306 ptr = ((char*) ctx->static_data [idx]) + off;
4307 mono_gc_bzero_atomic (ptr, data->size);
4311 do_free_special_slot (guint32 offset, guint32 size)
4313 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4315 StaticDataInfo *info;
4317 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4318 info = &thread_static_info;
4319 sets = thread_reference_bitmaps;
4321 info = &context_static_info;
4322 sets = context_reference_bitmaps;
4325 guint32 data_offset = offset;
4326 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4327 OffsetSize data = { data_offset, size };
4329 clear_reference_bitmap (sets, data.offset, data.size);
4331 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4332 if (threads != NULL)
4333 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4335 if (contexts != NULL)
4336 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4339 if (!mono_runtime_is_shutting_down ()) {
4340 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4342 item->offset = offset;
4345 item->next = info->freelist;
4346 info->freelist = item;
4351 do_free_special (gpointer key, gpointer value, gpointer data)
4353 MonoClassField *field = (MonoClassField *)key;
4354 guint32 offset = GPOINTER_TO_UINT (value);
4357 size = mono_type_size (field->type, &align);
4358 do_free_special_slot (offset, size);
4362 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4364 mono_threads_lock ();
4366 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4368 mono_threads_unlock ();
4372 static void CALLBACK dummy_apc (ULONG_PTR param)
4378 * mono_thread_execute_interruption
4380 * Performs the operation that the requested thread state requires (abort,
4383 static MonoException*
4384 mono_thread_execute_interruption (void)
4386 MonoInternalThread *thread = mono_thread_internal_current ();
4387 MonoThread *sys_thread = mono_thread_current ();
4389 LOCK_THREAD (thread);
4391 /* MonoThread::interruption_requested can only be changed with atomics */
4392 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4393 /* this will consume pending APC calls */
4395 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4397 InterlockedDecrement (&thread_interruption_requested);
4399 /* Clear the interrupted flag of the thread so it can wait again */
4400 mono_thread_info_clear_self_interrupt ();
4403 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4404 if (sys_thread->pending_exception) {
4407 exc = sys_thread->pending_exception;
4408 sys_thread->pending_exception = NULL;
4410 UNLOCK_THREAD (thread);
4412 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4413 UNLOCK_THREAD (thread);
4414 g_assert (sys_thread->pending_exception == NULL);
4415 if (thread->abort_exc == NULL) {
4417 * This might be racy, but it has to be called outside the lock
4418 * since it calls managed code.
4420 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4422 return thread->abort_exc;
4424 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4425 /* calls UNLOCK_THREAD (thread) */
4426 self_suspend_internal ();
4429 else if ((thread->state & ThreadState_StopRequested) != 0) {
4430 /* FIXME: do this through the JIT? */
4432 UNLOCK_THREAD (thread);
4434 mono_thread_exit ();
4436 } else if (thread->thread_interrupt_requested) {
4438 thread->thread_interrupt_requested = FALSE;
4439 UNLOCK_THREAD (thread);
4441 return(mono_get_exception_thread_interrupted ());
4444 UNLOCK_THREAD (thread);
4450 * mono_thread_request_interruption
4452 * A signal handler can call this method to request the interruption of a
4453 * thread. The result of the interruption will depend on the current state of
4454 * the thread. If the result is an exception that needs to be throw, it is
4455 * provided as return value.
4458 mono_thread_request_interruption (gboolean running_managed)
4460 MonoInternalThread *thread = mono_thread_internal_current ();
4462 /* The thread may already be stopping */
4467 if (thread->interrupt_on_stop &&
4468 thread->state & ThreadState_StopRequested &&
4469 thread->state & ThreadState_Background)
4472 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4474 InterlockedIncrement (&thread_interruption_requested);
4476 if (!running_managed || is_running_protected_wrapper ()) {
4477 /* Can't stop while in unmanaged code. Increase the global interruption
4478 request count. When exiting the unmanaged method the count will be
4479 checked and the thread will be interrupted. */
4481 /* this will awake the thread if it is in WaitForSingleObject
4483 /* Our implementation of this function ignores the func argument */
4485 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4487 mono_thread_info_self_interrupt ();
4492 return mono_thread_execute_interruption ();
4496 /*This function should be called by a thread after it has exited all of
4497 * its handle blocks at interruption time.*/
4499 mono_thread_resume_interruption (void)
4501 MonoInternalThread *thread = mono_thread_internal_current ();
4502 gboolean still_aborting;
4504 /* The thread may already be stopping */
4508 LOCK_THREAD (thread);
4509 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4510 UNLOCK_THREAD (thread);
4512 /*This can happen if the protected block called Thread::ResetAbort*/
4513 if (!still_aborting)
4516 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4518 InterlockedIncrement (&thread_interruption_requested);
4520 mono_thread_info_self_interrupt ();
4522 return mono_thread_execute_interruption ();
4525 gboolean mono_thread_interruption_requested ()
4527 if (thread_interruption_requested) {
4528 MonoInternalThread *thread = mono_thread_internal_current ();
4529 /* The thread may already be stopping */
4531 return (thread->interruption_requested);
4536 static MonoException*
4537 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4539 MonoInternalThread *thread = mono_thread_internal_current ();
4541 /* The thread may already be stopping */
4545 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4546 MonoException* exc = mono_thread_execute_interruption ();
4554 * Performs the interruption of the current thread, if one has been requested,
4555 * and the thread is not running a protected wrapper.
4556 * Return the exception which needs to be thrown, if any.
4559 mono_thread_interruption_checkpoint (void)
4561 return mono_thread_interruption_checkpoint_request (FALSE);
4565 * Performs the interruption of the current thread, if one has been requested.
4566 * Return the exception which needs to be thrown, if any.
4569 mono_thread_force_interruption_checkpoint_noraise (void)
4571 return mono_thread_interruption_checkpoint_request (TRUE);
4575 * mono_set_pending_exception:
4577 * Set the pending exception of the current thread to EXC.
4578 * The exception will be thrown when execution returns to managed code.
4581 mono_set_pending_exception (MonoException *exc)
4583 MonoThread *thread = mono_thread_current ();
4585 /* The thread may already be stopping */
4589 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4591 mono_thread_request_interruption (FALSE);
4595 * mono_thread_interruption_request_flag:
4597 * Returns the address of a flag that will be non-zero if an interruption has
4598 * been requested for a thread. The thread to interrupt may not be the current
4599 * thread, so an additional call to mono_thread_interruption_requested() or
4600 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4603 gint32* mono_thread_interruption_request_flag ()
4605 return &thread_interruption_requested;
4609 mono_thread_init_apartment_state (void)
4612 MonoInternalThread* thread = mono_thread_internal_current ();
4614 /* Positive return value indicates success, either
4615 * S_OK if this is first CoInitialize call, or
4616 * S_FALSE if CoInitialize already called, but with same
4617 * threading model. A negative value indicates failure,
4618 * probably due to trying to change the threading model.
4620 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4621 ? COINIT_APARTMENTTHREADED
4622 : COINIT_MULTITHREADED) < 0) {
4623 thread->apartment_state = ThreadApartmentState_Unknown;
4629 mono_thread_cleanup_apartment_state (void)
4632 MonoInternalThread* thread = mono_thread_internal_current ();
4634 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4641 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4643 LOCK_THREAD (thread);
4644 thread->state |= state;
4645 UNLOCK_THREAD (thread);
4649 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4651 LOCK_THREAD (thread);
4652 thread->state &= ~state;
4653 UNLOCK_THREAD (thread);
4657 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4659 gboolean ret = FALSE;
4661 LOCK_THREAD (thread);
4663 if ((thread->state & test) != 0) {
4667 UNLOCK_THREAD (thread);
4672 static gboolean has_tls_get = FALSE;
4675 mono_runtime_set_has_tls_get (gboolean val)
4681 mono_runtime_has_tls_get (void)
4687 self_interrupt_thread (void *_unused)
4689 MonoThreadInfo *info = mono_thread_info_current ();
4690 MonoException *exc = mono_thread_execute_interruption ();
4691 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4692 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. */
4693 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4697 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4701 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4705 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4707 MonoJitInfo **dest = (MonoJitInfo **)data;
4713 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4715 MonoJitInfo *ji = NULL;
4720 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4721 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4722 * where we hold runtime locks.
4724 if (!mono_threads_is_coop_enabled ())
4725 mono_thread_info_set_is_async_context (TRUE);
4726 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4727 if (!mono_threads_is_coop_enabled ())
4728 mono_thread_info_set_is_async_context (FALSE);
4733 MonoInternalThread *thread;
4734 gboolean install_async_abort;
4735 MonoThreadInfoInterruptToken *interrupt_token;
4738 static SuspendThreadResult
4739 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4741 AbortThreadData *data = (AbortThreadData *)ud;
4742 MonoInternalThread *thread = data->thread;
4743 MonoJitInfo *ji = NULL;
4744 gboolean protected_wrapper;
4745 gboolean running_managed;
4747 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4748 return MonoResumeThread;
4751 The target thread is running at least one protected block, which must not be interrupted, so we give up.
4752 The protected block code will give them a chance when appropriate.
4754 if (thread->abort_protected_block_count)
4755 return MonoResumeThread;
4757 /*someone is already interrupting it*/
4758 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4759 return MonoResumeThread;
4761 InterlockedIncrement (&thread_interruption_requested);
4763 ji = mono_thread_info_get_last_managed (info);
4764 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4765 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4767 if (!protected_wrapper && running_managed) {
4768 /*We are in managed code*/
4769 /*Set the thread to call */
4770 if (data->install_async_abort)
4771 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4772 return MonoResumeThread;
4775 * This will cause waits to be broken.
4776 * It will also prevent the thread from entering a wait, so if the thread returns
4777 * from the wait before it receives the abort signal, it will just spin in the wait
4778 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4781 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4783 return MonoResumeThread;
4788 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4790 AbortThreadData data;
4792 g_assert (thread != mono_thread_internal_current ());
4794 data.thread = thread;
4795 data.install_async_abort = install_async_abort;
4796 data.interrupt_token = NULL;
4798 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4799 if (data.interrupt_token)
4800 mono_thread_info_finish_interrupt (data.interrupt_token);
4801 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4805 self_abort_internal (MonoError *error)
4809 mono_error_init (error);
4811 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4812 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4815 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.
4817 exc = mono_thread_request_interruption (TRUE);
4819 mono_error_set_exception_instance (error, exc);
4821 mono_thread_info_self_interrupt ();
4825 MonoInternalThread *thread;
4827 MonoThreadInfoInterruptToken *interrupt_token;
4828 } SuspendThreadData;
4830 static SuspendThreadResult
4831 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4833 SuspendThreadData *data = (SuspendThreadData *)ud;
4834 MonoInternalThread *thread = data->thread;
4835 MonoJitInfo *ji = NULL;
4836 gboolean protected_wrapper;
4837 gboolean running_managed;
4839 ji = mono_thread_info_get_last_managed (info);
4840 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4841 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4843 if (running_managed && !protected_wrapper) {
4844 thread->state &= ~ThreadState_SuspendRequested;
4845 thread->state |= ThreadState_Suspended;
4846 return KeepSuspended;
4848 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4849 InterlockedIncrement (&thread_interruption_requested);
4850 if (data->interrupt)
4851 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4853 return MonoResumeThread;
4857 /* LOCKING: called with @thread synch_cs held, and releases it */
4859 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4861 SuspendThreadData data;
4863 g_assert (thread != mono_thread_internal_current ());
4865 data.thread = thread;
4866 data.interrupt = interrupt;
4867 data.interrupt_token = NULL;
4869 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4870 if (data.interrupt_token)
4871 mono_thread_info_finish_interrupt (data.interrupt_token);
4873 UNLOCK_THREAD (thread);
4876 /* LOCKING: called with @thread synch_cs held, and releases it */
4878 self_suspend_internal (void)
4880 MonoInternalThread *thread;
4882 thread = mono_thread_internal_current ();
4884 mono_thread_info_begin_self_suspend ();
4885 thread->state &= ~ThreadState_SuspendRequested;
4886 thread->state |= ThreadState_Suspended;
4888 UNLOCK_THREAD (thread);
4890 mono_thread_info_end_self_suspend ();
4894 * mono_thread_is_foreign:
4895 * @thread: the thread to query
4897 * This function allows one to determine if a thread was created by the mono runtime and has
4898 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4900 * Returns: TRUE if @thread was not created by the runtime.
4903 mono_thread_is_foreign (MonoThread *thread)
4905 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4906 return info->runtime_thread == FALSE;
4910 * mono_add_joinable_thread:
4912 * Add TID to the list of joinable threads.
4913 * LOCKING: Acquires the threads lock.
4916 mono_threads_add_joinable_thread (gpointer tid)
4920 * We cannot detach from threads because it causes problems like
4921 * 2fd16f60/r114307. So we collect them and join them when
4922 * we have time (in he finalizer thread).
4924 joinable_threads_lock ();
4925 if (!joinable_threads)
4926 joinable_threads = g_hash_table_new (NULL, NULL);
4927 g_hash_table_insert (joinable_threads, tid, tid);
4928 joinable_thread_count ++;
4929 joinable_threads_unlock ();
4931 mono_gc_finalize_notify ();
4936 * mono_threads_join_threads:
4938 * Join all joinable threads. This is called from the finalizer thread.
4939 * LOCKING: Acquires the threads lock.
4942 mono_threads_join_threads (void)
4945 GHashTableIter iter;
4952 if (!joinable_thread_count)
4956 joinable_threads_lock ();
4958 if (g_hash_table_size (joinable_threads)) {
4959 g_hash_table_iter_init (&iter, joinable_threads);
4960 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4961 thread = (pthread_t)tid;
4962 g_hash_table_remove (joinable_threads, key);
4963 joinable_thread_count --;
4966 joinable_threads_unlock ();
4968 if (thread != pthread_self ()) {
4970 /* This shouldn't block */
4971 pthread_join (thread, NULL);
4984 * Wait for thread TID to exit.
4985 * LOCKING: Acquires the threads lock.
4988 mono_thread_join (gpointer tid)
4992 gboolean found = FALSE;
4994 joinable_threads_lock ();
4995 if (!joinable_threads)
4996 joinable_threads = g_hash_table_new (NULL, NULL);
4997 if (g_hash_table_lookup (joinable_threads, tid)) {
4998 g_hash_table_remove (joinable_threads, tid);
4999 joinable_thread_count --;
5002 joinable_threads_unlock ();
5005 thread = (pthread_t)tid;
5007 pthread_join (thread, NULL);
5013 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
5015 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
5016 mono_thread_interruption_checkpoint ();
5020 mono_thread_internal_unhandled_exception (MonoObject* exc)
5022 MonoClass *klass = exc->vtable->klass;
5023 if (is_threadabort_exception (klass)) {
5024 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5025 } else if (!is_appdomainunloaded_exception (klass)
5026 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5027 mono_unhandled_exception (exc);
5028 if (mono_environment_exitcode_get () == 1) {
5029 mono_environment_exitcode_set (255);
5030 mono_invoke_unhandled_exception_hook (exc);
5031 g_assert_not_reached ();
5037 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5040 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5041 mono_error_set_pending_exception (&error);
5045 * mono_threads_attach_coop: called by native->managed wrappers
5049 * - @return: the original domain which needs to be restored, or NULL.
5052 * - @dummy: contains the original domain
5053 * - @return: a cookie containing current MonoThreadInfo*.
5056 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5059 gboolean fresh_thread = FALSE;
5062 /* Happens when called from AOTed code which is only used in the root domain. */
5063 domain = mono_get_root_domain ();
5068 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5069 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5070 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5071 * we're only responsible for making the cookie. */
5072 if (mono_threads_is_coop_enabled ()) {
5073 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5074 fresh_thread = !info || !mono_thread_info_is_live (info);
5077 if (!mono_thread_internal_current ()) {
5078 mono_thread_attach_full (domain, FALSE);
5081 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5084 orig = mono_domain_get ();
5086 mono_domain_set (domain, TRUE);
5088 if (!mono_threads_is_coop_enabled ())
5089 return orig != domain ? orig : NULL;
5093 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5094 * return the right cookie. */
5095 return mono_threads_enter_gc_unsafe_region_cookie ();
5098 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5099 return mono_threads_enter_gc_unsafe_region (dummy);
5104 * mono_threads_detach_coop: called by native->managed wrappers
5107 * - @cookie: the original domain which needs to be restored, or NULL.
5111 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5112 * - @dummy: contains the original domain
5115 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5117 MonoDomain *domain, *orig;
5119 if (!mono_threads_is_coop_enabled ()) {
5120 orig = (MonoDomain*) cookie;
5122 mono_domain_set (orig, TRUE);
5124 orig = (MonoDomain*) *dummy;
5126 domain = mono_domain_get ();
5129 /* it won't do anything if cookie is NULL
5130 * thread state RUNNING -> (RUNNING|BLOCKING) */
5131 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5133 if (orig != domain) {
5135 mono_domain_unset ();
5137 mono_domain_set (orig, TRUE);
5143 mono_threads_begin_abort_protected_block (void)
5145 MonoInternalThread *thread;
5147 thread = mono_thread_internal_current ();
5148 ++thread->abort_protected_block_count;
5149 mono_memory_barrier ();
5153 mono_threads_end_abort_protected_block (void)
5155 MonoInternalThread *thread;
5157 thread = mono_thread_internal_current ();
5159 mono_memory_barrier ();
5160 --thread->abort_protected_block_count;
5164 mono_thread_try_resume_interruption (void)
5166 MonoInternalThread *thread;
5168 thread = mono_thread_internal_current ();
5169 if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5172 return mono_thread_resume_interruption ();