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))
88 guint32 (*func)(void *);
104 typedef struct _StaticDataFreeList StaticDataFreeList;
105 struct _StaticDataFreeList {
106 StaticDataFreeList *next;
114 StaticDataFreeList *freelist;
117 /* Number of cached culture objects in the MonoThread->cached_culture_info array
118 * (per-type): we use the first NUM entries for CultureInfo and the last for
119 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
121 #define NUM_CACHED_CULTURES 4
122 #define CULTURES_START_IDX 0
123 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
125 /* Controls access to the 'threads' hash table */
126 static void mono_threads_lock (void);
127 static void mono_threads_unlock (void);
128 static MonoCoopMutex threads_mutex;
130 /* Controls access to the 'joinable_threads' hash table */
131 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
132 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
133 static mono_mutex_t joinable_threads_mutex;
135 /* Holds current status of static data heap */
136 static StaticDataInfo thread_static_info;
137 static StaticDataInfo context_static_info;
139 /* The hash of existing threads (key is thread ID, value is
140 * MonoInternalThread*) that need joining before exit
142 static MonoGHashTable *threads=NULL;
144 /* List of app context GC handles.
145 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
147 static GHashTable *contexts = NULL;
149 /* Cleanup queue for contexts. */
150 static MonoReferenceQueue *context_queue;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable *threads_starting_up = NULL;
159 /* The TLS key that holds the MonoObject assigned to each thread */
160 static MonoNativeTlsKey current_object_key;
163 /* Protected by the threads lock */
164 static GHashTable *joinable_threads;
165 static int joinable_thread_count;
167 #ifdef MONO_HAVE_FAST_TLS
168 /* we need to use both the Tls* functions and __thread because
169 * the gc needs to see all the threads
171 MONO_FAST_TLS_DECLARE(tls_current_object);
172 #define SET_CURRENT_OBJECT(x) do { \
173 MONO_FAST_TLS_SET (tls_current_object, x); \
174 mono_native_tls_set_value (current_object_key, x); \
176 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
178 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
179 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
182 /* function called at thread start */
183 static MonoThreadStartCB mono_thread_start_cb = NULL;
185 /* function called at thread attach */
186 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
188 /* function called at thread cleanup */
189 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
191 /* The default stack size for each thread */
192 static guint32 default_stacksize = 0;
193 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
195 static void thread_adjust_static_data (MonoInternalThread *thread);
196 static void context_adjust_static_data (MonoAppContext *ctx);
197 static void mono_free_static_data (gpointer* static_data);
198 static void mono_init_static_data_info (StaticDataInfo *static_data);
199 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
200 static gboolean mono_thread_resume (MonoInternalThread* thread);
201 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
202 static void self_abort_internal (MonoError *error);
203 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
204 static void self_suspend_internal (void);
206 static MonoException* mono_thread_execute_interruption (void);
207 static void ref_stack_destroy (gpointer rs);
209 /* Spin lock for InterlockedXXX 64 bit functions */
210 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
211 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
212 static mono_mutex_t interlocked_mutex;
214 /* global count of thread interruptions requested */
215 static gint32 thread_interruption_requested = 0;
217 /* Event signaled when a thread changes its background mode */
218 static HANDLE background_change_event;
220 static gboolean shutting_down = FALSE;
222 static gint32 managed_thread_id_counter = 0;
224 /* Class lazy loading functions */
225 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
228 mono_threads_lock (void)
230 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
234 mono_threads_unlock (void)
236 mono_locks_coop_release (&threads_mutex, ThreadsLock);
241 get_next_managed_thread_id (void)
243 return InterlockedIncrement (&managed_thread_id_counter);
247 mono_thread_get_tls_key (void)
249 return current_object_key;
253 mono_thread_get_tls_offset (void)
258 if (current_object_key)
259 offset = current_object_key;
261 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
266 static inline MonoNativeThreadId
267 thread_get_tid (MonoInternalThread *thread)
269 /* We store the tid as a guint64 to keep the object layout constant between platforms */
270 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
273 /* handle_store() and handle_remove() manage the array of threads that
274 * still need to be waited for when the main thread exits.
276 * If handle_store() returns FALSE the thread must not be started
277 * because Mono is shutting down.
279 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
281 mono_threads_lock ();
283 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
285 if (threads_starting_up)
286 mono_g_hash_table_remove (threads_starting_up, thread);
288 if (shutting_down && !force_attach) {
289 mono_threads_unlock ();
294 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
295 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
298 /* We don't need to duplicate thread->handle, because it is
299 * only closed when the thread object is finalized by the GC.
301 g_assert (thread->internal_thread);
302 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
303 thread->internal_thread);
305 mono_threads_unlock ();
310 static gboolean handle_remove(MonoInternalThread *thread)
313 gsize tid = thread->tid;
315 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
317 mono_threads_lock ();
320 /* We have to check whether the thread object for the
321 * tid is still the same in the table because the
322 * thread might have been destroyed and the tid reused
323 * in the meantime, in which case the tid would be in
324 * the table, but with another thread object.
326 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
327 mono_g_hash_table_remove (threads, (gpointer)tid);
336 mono_threads_unlock ();
338 /* Don't close the handle here, wait for the object finalizer
339 * to do it. Otherwise, the following race condition applies:
341 * 1) Thread exits (and handle_remove() closes the handle)
343 * 2) Some other handle is reassigned the same slot
345 * 3) Another thread tries to join the first thread, and
346 * blocks waiting for the reassigned handle to be signalled
347 * (which might never happen). This is possible, because the
348 * thread calling Join() still has a reference to the first
354 static void ensure_synch_cs_set (MonoInternalThread *thread)
356 MonoCoopMutex *synch_cs;
358 if (thread->synch_cs != NULL) {
362 synch_cs = g_new0 (MonoCoopMutex, 1);
363 mono_coop_mutex_init_recursive (synch_cs);
365 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
366 synch_cs, NULL) != NULL) {
367 /* Another thread must have installed this CS */
368 mono_coop_mutex_destroy (synch_cs);
374 lock_thread (MonoInternalThread *thread)
376 if (!thread->synch_cs)
377 ensure_synch_cs_set (thread);
379 g_assert (thread->synch_cs);
381 mono_coop_mutex_lock (thread->synch_cs);
385 unlock_thread (MonoInternalThread *thread)
387 mono_coop_mutex_unlock (thread->synch_cs);
390 static inline gboolean
391 is_appdomainunloaded_exception (MonoClass *klass)
393 return klass == mono_class_get_appdomain_unloaded_exception_class ();
396 static inline gboolean
397 is_threadabort_exception (MonoClass *klass)
399 return klass == mono_defaults.threadabortexception_class;
403 * NOTE: this function can be called also for threads different from the current one:
404 * make sure no code called from it will ever assume it is run on the thread that is
405 * getting cleaned up.
407 static void thread_cleanup (MonoInternalThread *thread)
409 g_assert (thread != NULL);
411 if (thread->abort_state_handle) {
412 mono_gchandle_free (thread->abort_state_handle);
413 thread->abort_state_handle = 0;
415 thread->abort_exc = NULL;
416 thread->current_appcontext = NULL;
419 * This is necessary because otherwise we might have
420 * cross-domain references which will not get cleaned up when
421 * the target domain is unloaded.
423 if (thread->cached_culture_info) {
425 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
426 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
430 * thread->synch_cs can be NULL if this was called after
431 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
432 * This can happen only during shutdown.
433 * The shutting_down flag is not always set, so we can't assert on it.
435 if (thread->synch_cs)
436 LOCK_THREAD (thread);
438 thread->state |= ThreadState_Stopped;
439 thread->state &= ~ThreadState_Background;
441 if (thread->synch_cs)
442 UNLOCK_THREAD (thread);
445 An interruption request has leaked to cleanup. Adjust the global counter.
447 This can happen is the abort source thread finds the abortee (this) thread
448 in unmanaged code. If this thread never trips back to managed code or check
449 the local flag it will be left set and positively unbalance the global counter.
451 Leaving the counter unbalanced will cause a performance degradation since all threads
452 will now keep checking their local flags all the time.
454 if (InterlockedExchange (&thread->interruption_requested, 0))
455 InterlockedDecrement (&thread_interruption_requested);
457 /* if the thread is not in the hash it has been removed already */
458 if (!handle_remove (thread)) {
459 if (thread == mono_thread_internal_current ()) {
460 mono_domain_unset ();
461 mono_memory_barrier ();
463 /* This needs to be called even if handle_remove () fails */
464 if (mono_thread_cleanup_fn)
465 mono_thread_cleanup_fn (thread_get_tid (thread));
468 mono_release_type_locks (thread);
470 /* Can happen when we attach the profiler helper thread in order to heapshot. */
471 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
472 mono_profiler_thread_end (thread->tid);
474 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
476 if (thread == mono_thread_internal_current ()) {
478 * This will signal async signal handlers that the thread has exited.
479 * The profiler callback needs this to be set, so it cannot be done earlier.
481 mono_domain_unset ();
482 mono_memory_barrier ();
485 if (thread == mono_thread_internal_current ())
486 mono_thread_pop_appdomain_ref ();
488 thread->cached_culture_info = NULL;
490 mono_free_static_data (thread->static_data);
491 thread->static_data = NULL;
492 ref_stack_destroy (thread->appdomain_refs);
493 thread->appdomain_refs = NULL;
495 if (mono_thread_cleanup_fn)
496 mono_thread_cleanup_fn (thread_get_tid (thread));
498 if (mono_gc_is_moving ()) {
499 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
500 thread->thread_pinning_ref = NULL;
506 * A special static data offset (guint32) consists of 3 parts:
508 * [0] 6-bit index into the array of chunks.
509 * [6] 25-bit offset into the array.
510 * [31] Bit indicating thread or context static.
515 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
526 } SpecialStaticOffset;
528 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
529 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
531 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
532 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
533 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
534 (((SpecialStaticOffset *) &(x))->fields.f)
537 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
539 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
541 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
542 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
544 return ((char *) thread->static_data [idx]) + off;
548 get_context_static_data (MonoAppContext *ctx, guint32 offset)
550 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
552 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
553 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
555 return ((char *) ctx->static_data [idx]) + off;
559 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
561 static MonoClassField *current_thread_field = NULL;
565 if (!current_thread_field) {
566 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
567 g_assert (current_thread_field);
570 mono_class_vtable (domain, mono_defaults.thread_class);
571 mono_domain_lock (domain);
572 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
573 mono_domain_unlock (domain);
576 return (MonoThread **)get_thread_static_data (thread, offset);
580 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
582 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
584 g_assert (current->obj.vtable->domain == domain);
586 g_assert (!*current_thread_ptr);
587 *current_thread_ptr = current;
591 create_thread_object (MonoDomain *domain)
594 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
595 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, &error);
596 /* only possible failure mode is OOM, from which we don't expect to recover. */
597 mono_error_assert_ok (&error);
602 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
606 thread = create_thread_object (domain);
607 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
609 MONO_OBJECT_SETREF (thread, internal_thread, internal);
614 static MonoInternalThread*
615 create_internal_thread (void)
618 MonoInternalThread *thread;
621 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
622 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
623 /* only possible failure mode is OOM, from which we don't exect to recover */
624 mono_error_assert_ok (&error);
626 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
627 mono_coop_mutex_init_recursive (thread->synch_cs);
629 thread->apartment_state = ThreadApartmentState_Unknown;
630 thread->managed_id = get_next_managed_thread_id ();
631 if (mono_gc_is_moving ()) {
632 thread->thread_pinning_ref = thread;
633 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
640 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
642 MonoDomain *domain = mono_get_root_domain ();
644 if (!candidate || candidate->obj.vtable->domain != domain) {
645 candidate = new_thread_with_internal (domain, thread);
647 set_current_thread_for_domain (domain, thread, candidate);
648 g_assert (!thread->root_domain_thread);
649 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
653 static guint32 WINAPI start_wrapper_internal(void *data)
656 MonoThreadInfo *info;
657 StartInfo *start_info = (StartInfo *)data;
658 guint32 (*start_func)(void *);
662 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
665 MonoInternalThread *internal = start_info->obj->internal_thread;
666 MonoObject *start_delegate = start_info->delegate;
667 MonoDomain *domain = start_info->obj->obj.vtable->domain;
669 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
671 /* We can be sure start_info->obj->tid and
672 * start_info->obj->handle have been set, because the thread
673 * was created suspended, and these values were set before the
677 info = mono_thread_info_current ();
679 internal->thread_info = info;
680 internal->small_id = info->small_id;
684 SET_CURRENT_OBJECT (internal);
686 /* Every thread references the appdomain which created it */
687 mono_thread_push_appdomain_ref (domain);
689 if (!mono_domain_set (domain, FALSE)) {
690 /* No point in raising an appdomain_unloaded exception here */
691 /* FIXME: Cleanup here */
692 mono_thread_pop_appdomain_ref ();
696 start_func = start_info->func;
697 start_arg = start_info->obj->start_obj;
699 start_arg = start_info->start_arg;
701 /* We have to do this here because mono_thread_new_init()
702 requires that root_domain_thread is set up. */
703 thread_adjust_static_data (internal);
704 init_root_domain_thread (internal, start_info->obj);
706 /* This MUST be called before any managed code can be
707 * executed, as it calls the callback function that (for the
708 * jit) sets the lmf marker.
710 mono_thread_new_init (tid, &tid, start_func);
711 internal->stack_ptr = &tid;
712 if (domain != mono_get_root_domain ())
713 set_current_thread_for_domain (domain, internal, start_info->obj);
715 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
717 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
719 /* On 2.0 profile (and higher), set explicitly since state might have been
721 if (internal->apartment_state == ThreadApartmentState_Unknown)
722 internal->apartment_state = ThreadApartmentState_MTA;
724 mono_thread_init_apartment_state ();
726 if (internal->start_notify)
727 /* Let the thread that called Start() know we're
730 mono_coop_sem_post (internal->start_notify);
732 if (InterlockedDecrement ((gint32*)&internal->start_notify_refcount) == 0) {
733 mono_coop_sem_destroy (internal->start_notify);
734 g_free (internal->start_notify);
735 internal->start_notify = NULL;
739 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
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_arg);
762 g_assert (start_delegate != NULL);
763 args [0] = start_arg;
764 /* we may want to handle the exception here. See comment below on unhandled exceptions */
765 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
767 if (!mono_error_ok (&error)) {
768 MonoException *ex = mono_error_convert_to_exception (&error);
770 g_assert (ex != NULL);
771 MonoClass *klass = mono_object_get_class (&ex->object);
772 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
773 !is_threadabort_exception (klass)) {
774 mono_unhandled_exception (&ex->object);
775 mono_invoke_unhandled_exception_hook (&ex->object);
776 g_assert_not_reached ();
779 mono_error_cleanup (&error);
783 /* If the thread calls ExitThread at all, this remaining code
784 * will not be executed, but the main thread will eventually
785 * call thread_cleanup() on this thread's behalf.
788 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
790 /* Do any cleanup needed for apartment state. This
791 * cannot be done in thread_cleanup since thread_cleanup could be
792 * called for a thread other than the current thread.
793 * mono_thread_cleanup_apartment_state cleans up apartment
794 * for the current thead */
795 mono_thread_cleanup_apartment_state ();
797 thread_cleanup (internal);
801 /* Remove the reference to the thread object in the TLS data,
802 * so the thread object can be finalized. This won't be
803 * reached if the thread threw an uncaught exception, so those
804 * thread handles will stay referenced :-( (This is due to
805 * missing support for scanning thread-specific data in the
806 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
809 SET_CURRENT_OBJECT (NULL);
814 static gsize WINAPI start_wrapper(void *data)
818 /* Avoid scanning the frames above this frame during a GC */
819 mono_gc_set_stack_end ((void*)&dummy);
821 return start_wrapper_internal (data);
827 * Common thread creation code.
828 * LOCKING: Acquires the threads lock.
831 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
834 HANDLE thread_handle;
835 MonoNativeThreadId tid;
839 * Join joinable threads to prevent running out of threads since the finalizer
840 * thread might be blocked/backlogged.
842 mono_threads_join_threads ();
844 mono_error_init (error);
846 mono_threads_lock ();
849 mono_threads_unlock ();
852 if (threads_starting_up == NULL) {
853 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
854 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
856 mono_g_hash_table_insert (threads_starting_up, thread, thread);
857 mono_threads_unlock ();
859 internal->start_notify = g_new0 (MonoCoopSem, 1);
860 mono_coop_sem_init (internal->start_notify, 0);
861 internal->start_notify_refcount = 2;
864 stack_size = default_stacksize_for_thread (internal);
866 /* Create suspended, so we can do some housekeeping before the thread
869 tp.priority = thread->priority;
870 tp.stack_size = stack_size;
871 tp.creation_flags = CREATE_SUSPENDED;
873 thread_handle = mono_threads_create_thread (start_wrapper, start_info, &tp, &tid);
875 if (thread_handle == NULL) {
876 /* The thread couldn't be created, so set an exception */
877 mono_threads_lock ();
878 mono_g_hash_table_remove (threads_starting_up, thread);
879 mono_threads_unlock ();
881 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
884 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
886 internal->handle = thread_handle;
887 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
889 internal->threadpool_thread = threadpool_thread;
890 if (threadpool_thread)
891 mono_thread_set_state (internal, ThreadState_Background);
893 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
895 /* Only store the handle when the thread is about to be
896 * launched, to avoid the main thread deadlocking while trying
897 * to clean up a thread that will never be signalled.
899 if (!handle_store (thread, FALSE))
902 mono_thread_info_resume (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
910 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
912 mono_coop_sem_wait (internal->start_notify, MONO_SEM_FLAGS_NONE);
913 if (InterlockedDecrement ((gint32*)&internal->start_notify_refcount) == 0) {
914 mono_coop_sem_destroy (internal->start_notify);
915 g_free (internal->start_notify);
916 internal->start_notify = NULL;
919 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));
924 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
926 if (mono_thread_start_cb) {
927 mono_thread_start_cb (tid, stack_start, func);
931 void mono_threads_set_default_stacksize (guint32 stacksize)
933 default_stacksize = stacksize;
936 guint32 mono_threads_get_default_stacksize (void)
938 return default_stacksize;
942 * mono_thread_create_internal:
944 * ARG should not be a GC reference.
947 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
950 MonoInternalThread *internal;
951 StartInfo *start_info;
954 mono_error_init (error);
956 thread = create_thread_object (domain);
957 thread->priority = MONO_THREAD_PRIORITY_NORMAL;
959 internal = create_internal_thread ();
961 MONO_OBJECT_SETREF (thread, internal_thread, internal);
963 start_info = g_new0 (StartInfo, 1);
964 start_info->func = (guint32 (*)(void *))func;
965 start_info->obj = thread;
966 start_info->start_arg = arg;
968 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, error);
969 return_val_if_nok (error, NULL);
971 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
972 #ifndef MONO_CROSS_COMPILE
973 if (mono_check_corlib_version () == NULL)
974 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
981 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
984 if (!mono_thread_create_checked (domain, func, arg, &error))
985 mono_error_cleanup (&error);
989 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
991 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
995 mono_thread_attach (MonoDomain *domain)
997 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1003 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1005 MonoThreadInfo *info;
1006 MonoInternalThread *thread;
1007 MonoThread *current_thread;
1008 HANDLE thread_handle;
1009 MonoNativeThreadId tid;
1011 if ((thread = mono_thread_internal_current ())) {
1012 if (domain != mono_domain_get ())
1013 mono_domain_set (domain, TRUE);
1014 /* Already attached */
1015 return mono_thread_current ();
1018 if (!mono_gc_register_thread (&domain)) {
1019 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 ());
1022 thread = create_internal_thread ();
1024 thread_handle = mono_thread_info_open_handle ();
1025 g_assert (thread_handle);
1027 tid=mono_native_thread_id_get ();
1029 thread->handle = thread_handle;
1030 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
1031 thread->stack_ptr = &tid;
1033 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
1035 info = mono_thread_info_current ();
1037 thread->thread_info = info;
1038 thread->small_id = info->small_id;
1040 current_thread = new_thread_with_internal (domain, thread);
1042 if (!handle_store (current_thread, force_attach)) {
1043 /* Mono is shutting down, so just wait for the end */
1045 mono_thread_info_sleep (10000, NULL);
1048 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
1050 SET_CURRENT_OBJECT (thread);
1051 mono_domain_set (domain, TRUE);
1053 thread_adjust_static_data (thread);
1055 init_root_domain_thread (thread, current_thread);
1057 if (domain != mono_get_root_domain ())
1058 set_current_thread_for_domain (domain, thread, current_thread);
1061 if (mono_thread_attach_cb) {
1065 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1068 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1070 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1073 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1074 if (!info->tools_thread)
1075 // FIXME: Need a separate callback
1076 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1078 return current_thread;
1082 mono_thread_detach_internal (MonoInternalThread *thread)
1084 g_return_if_fail (thread != NULL);
1086 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1088 thread_cleanup (thread);
1090 SET_CURRENT_OBJECT (NULL);
1091 mono_domain_unset ();
1093 /* Don't need to CloseHandle this thread, even though we took a
1094 * reference in mono_thread_attach (), because the GC will do it
1095 * when the Thread object is finalised.
1100 mono_thread_detach (MonoThread *thread)
1103 mono_thread_detach_internal (thread->internal_thread);
1107 * mono_thread_detach_if_exiting:
1109 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1110 * This should be used at the end of embedding code which calls into managed code, and which
1111 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1114 mono_thread_detach_if_exiting (void)
1116 if (mono_thread_info_is_exiting ()) {
1117 MonoInternalThread *thread;
1119 thread = mono_thread_internal_current ();
1121 mono_thread_detach_internal (thread);
1122 mono_thread_info_detach ();
1130 mono_thread_exit (void)
1132 MonoInternalThread *thread = mono_thread_internal_current ();
1134 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1136 thread_cleanup (thread);
1137 SET_CURRENT_OBJECT (NULL);
1138 mono_domain_unset ();
1140 /* we could add a callback here for embedders to use. */
1141 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1142 exit (mono_environment_exitcode_get ());
1143 mono_thread_info_exit ();
1147 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1149 MonoInternalThread *internal;
1151 internal = create_internal_thread ();
1153 internal->state = ThreadState_Unstarted;
1155 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1159 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1163 StartInfo *start_info;
1164 MonoInternalThread *internal;
1167 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1169 if (!this_obj->internal_thread)
1170 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1171 internal = this_obj->internal_thread;
1173 LOCK_THREAD (internal);
1175 if ((internal->state & ThreadState_Unstarted) == 0) {
1176 UNLOCK_THREAD (internal);
1177 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1181 if ((internal->state & ThreadState_Aborted) != 0) {
1182 UNLOCK_THREAD (internal);
1185 /* This is freed in start_wrapper */
1186 start_info = g_new0 (StartInfo, 1);
1187 start_info->func = NULL;
1188 start_info->start_arg = NULL;
1189 start_info->delegate = start;
1190 start_info->obj = this_obj;
1191 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1193 res = create_thread (this_obj, internal, start_info, FALSE, 0, &error);
1195 mono_error_cleanup (&error);
1196 UNLOCK_THREAD (internal);
1200 internal->state &= ~ThreadState_Unstarted;
1202 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1204 UNLOCK_THREAD (internal);
1205 return internal->handle;
1209 * This is called from the finalizer of the internal thread object.
1212 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1214 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1217 * Since threads keep a reference to their thread object while running, by the time this function is called,
1218 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1219 * when thread_cleanup () can be called after this.
1222 CloseHandle (thread);
1224 if (this_obj->synch_cs) {
1225 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1226 this_obj->synch_cs = NULL;
1227 mono_coop_mutex_destroy (synch_cs);
1231 if (this_obj->name) {
1232 void *name = this_obj->name;
1233 this_obj->name = NULL;
1239 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1242 MonoInternalThread *thread = mono_thread_internal_current ();
1244 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1246 if (mono_thread_current_check_pending_interrupt ())
1250 gboolean alerted = FALSE;
1252 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1254 res = mono_thread_info_sleep (ms, &alerted);
1256 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1259 MonoException* exc = mono_thread_execute_interruption ();
1261 mono_raise_exception (exc);
1273 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1278 ves_icall_System_Threading_Thread_GetDomainID (void)
1280 return mono_domain_get()->domain_id;
1284 ves_icall_System_Threading_Thread_Yield (void)
1286 return mono_thread_info_yield ();
1290 * mono_thread_get_name:
1292 * Return the name of the thread. NAME_LEN is set to the length of the name.
1293 * Return NULL if the thread has no name. The returned memory is owned by the
1297 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1301 LOCK_THREAD (this_obj);
1303 if (!this_obj->name) {
1307 *name_len = this_obj->name_len;
1308 res = g_new (gunichar2, this_obj->name_len);
1309 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1312 UNLOCK_THREAD (this_obj);
1318 * mono_thread_get_name_utf8:
1320 * Return the name of the thread in UTF-8.
1321 * Return NULL if the thread has no name.
1322 * The returned memory is owned by the caller.
1325 mono_thread_get_name_utf8 (MonoThread *thread)
1330 MonoInternalThread *internal = thread->internal_thread;
1331 if (internal == NULL)
1334 LOCK_THREAD (internal);
1336 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1338 UNLOCK_THREAD (internal);
1344 * mono_thread_get_managed_id:
1346 * Return the Thread.ManagedThreadId value of `thread`.
1347 * Returns -1 if `thread` is NULL.
1350 mono_thread_get_managed_id (MonoThread *thread)
1355 MonoInternalThread *internal = thread->internal_thread;
1356 if (internal == NULL)
1359 int32_t id = internal->managed_id;
1365 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1370 mono_error_init (&error);
1372 LOCK_THREAD (this_obj);
1374 if (!this_obj->name)
1377 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1379 UNLOCK_THREAD (this_obj);
1381 if (mono_error_set_pending_exception (&error))
1388 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1390 LOCK_THREAD (this_obj);
1392 mono_error_init (error);
1394 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1395 UNLOCK_THREAD (this_obj);
1397 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1400 if (this_obj->name) {
1401 g_free (this_obj->name);
1402 this_obj->name_len = 0;
1405 this_obj->name = g_new (gunichar2, mono_string_length (name));
1406 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1407 this_obj->name_len = mono_string_length (name);
1410 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1413 this_obj->name = NULL;
1416 UNLOCK_THREAD (this_obj);
1418 if (this_obj->name && this_obj->tid) {
1419 char *tname = mono_string_to_utf8_checked (name, error);
1420 return_if_nok (error);
1421 mono_profiler_thread_name (this_obj->tid, tname);
1422 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1428 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1431 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1432 mono_error_set_pending_exception (&error);
1436 * ves_icall_System_Threading_Thread_GetPriority_internal:
1437 * @param this_obj: The MonoInternalThread on which to operate.
1439 * Gets the priority of the given thread.
1440 * @return: The priority of the given thread.
1443 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1446 MonoInternalThread *internal = this_obj->internal_thread;
1448 LOCK_THREAD (internal);
1449 if (internal->handle != NULL)
1450 priority = mono_thread_info_get_priority ((MonoThreadInfo*) internal->thread_info);
1452 priority = this_obj->priority;
1453 UNLOCK_THREAD (internal);
1458 * ves_icall_System_Threading_Thread_SetPriority_internal:
1459 * @param this_obj: The MonoInternalThread on which to operate.
1460 * @param priority: The priority to set.
1462 * Sets the priority of the given thread.
1465 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1467 MonoInternalThread *internal = this_obj->internal_thread;
1469 LOCK_THREAD (internal);
1470 this_obj->priority = priority;
1471 if (internal->handle != NULL)
1472 mono_thread_info_set_priority ((MonoThreadInfo*) internal->thread_info, this_obj->priority);
1473 UNLOCK_THREAD (internal);
1476 /* If the array is already in the requested domain, we just return it,
1477 otherwise we return a copy in that domain. */
1479 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1483 mono_error_init (error);
1487 if (mono_object_domain (arr) == domain)
1490 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1491 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1496 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1499 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1500 mono_error_set_pending_exception (&error);
1505 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1508 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1509 mono_error_set_pending_exception (&error);
1514 mono_thread_current (void)
1516 MonoDomain *domain = mono_domain_get ();
1517 MonoInternalThread *internal = mono_thread_internal_current ();
1518 MonoThread **current_thread_ptr;
1520 g_assert (internal);
1521 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1523 if (!*current_thread_ptr) {
1524 g_assert (domain != mono_get_root_domain ());
1525 *current_thread_ptr = new_thread_with_internal (domain, internal);
1527 return *current_thread_ptr;
1530 /* Return the thread object belonging to INTERNAL in the current domain */
1532 mono_thread_current_for_thread (MonoInternalThread *internal)
1534 MonoDomain *domain = mono_domain_get ();
1535 MonoThread **current_thread_ptr;
1537 g_assert (internal);
1538 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1540 if (!*current_thread_ptr) {
1541 g_assert (domain != mono_get_root_domain ());
1542 *current_thread_ptr = new_thread_with_internal (domain, internal);
1544 return *current_thread_ptr;
1548 mono_thread_internal_current (void)
1550 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1551 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1556 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1558 MonoInternalThread *thread = this_obj->internal_thread;
1559 HANDLE handle = thread->handle;
1560 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1563 if (mono_thread_current_check_pending_interrupt ())
1566 LOCK_THREAD (thread);
1568 if ((thread->state & ThreadState_Unstarted) != 0) {
1569 UNLOCK_THREAD (thread);
1571 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1575 UNLOCK_THREAD (thread);
1580 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1582 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1585 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1588 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1590 if(ret==WAIT_OBJECT_0) {
1591 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1596 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1601 #define MANAGED_WAIT_FAILED 0x7fffffff
1604 map_native_wait_result_to_managed (gint32 val)
1606 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1607 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1611 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1619 mono_error_init (error);
1621 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1624 if (numhandles != 1)
1625 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1627 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1630 if (ret != WAIT_IO_COMPLETION)
1633 exc = mono_thread_execute_interruption ();
1635 mono_error_set_exception_instance (error, exc);
1642 /* Re-calculate ms according to the time passed */
1643 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1644 if (diff_ms >= ms) {
1648 wait = ms - diff_ms;
1654 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1661 MonoObject *waitHandle;
1662 MonoInternalThread *thread = mono_thread_internal_current ();
1664 /* Do this WaitSleepJoin check before creating objects */
1665 if (mono_thread_current_check_pending_interrupt ())
1666 return map_native_wait_result_to_managed (WAIT_FAILED);
1668 /* We fail in managed if the array has more than 64 elements */
1669 numhandles = (guint32)mono_array_length(mono_handles);
1670 handles = g_new0(HANDLE, numhandles);
1672 for(i = 0; i < numhandles; i++) {
1673 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1674 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1681 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1683 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1685 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1689 mono_error_set_pending_exception (&error);
1691 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1692 return map_native_wait_result_to_managed (ret);
1695 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1698 HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1699 uintptr_t numhandles;
1702 MonoObject *waitHandle;
1703 MonoInternalThread *thread = mono_thread_internal_current ();
1705 /* Do this WaitSleepJoin check before creating objects */
1706 if (mono_thread_current_check_pending_interrupt ())
1707 return map_native_wait_result_to_managed (WAIT_FAILED);
1709 numhandles = mono_array_length(mono_handles);
1710 if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1711 return map_native_wait_result_to_managed (WAIT_FAILED);
1713 for(i = 0; i < numhandles; i++) {
1714 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1715 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1722 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1724 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1726 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1728 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1730 mono_error_set_pending_exception (&error);
1732 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1734 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1735 return map_native_wait_result_to_managed (ret - WAIT_OBJECT_0);
1737 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1738 return map_native_wait_result_to_managed (ret - WAIT_ABANDONED_0);
1741 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1742 return map_native_wait_result_to_managed (ret);
1746 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1750 MonoInternalThread *thread = mono_thread_internal_current ();
1752 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1758 if (mono_thread_current_check_pending_interrupt ())
1759 return map_native_wait_result_to_managed (WAIT_FAILED);
1761 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1763 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1765 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1767 mono_error_set_pending_exception (&error);
1768 return map_native_wait_result_to_managed (ret);
1772 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1775 MonoInternalThread *thread = mono_thread_internal_current ();
1780 if (mono_thread_current_check_pending_interrupt ())
1781 return map_native_wait_result_to_managed (WAIT_FAILED);
1783 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1786 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1789 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1791 return map_native_wait_result_to_managed (ret);
1794 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1801 mutex = CreateMutex (NULL, owned, NULL);
1803 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1805 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1813 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1814 return(ReleaseMutex (handle));
1817 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1823 *error = ERROR_SUCCESS;
1825 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1827 *error = GetLastError ();
1834 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, gint32 *error)
1839 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1841 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1842 mono_string_chars (name));
1845 *error = GetLastError ();
1850 MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, gint32 *prevcount)
1852 return ReleaseSemaphore (handle, releaseCount, prevcount);
1855 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1859 sem = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1861 *error = GetLastError ();
1866 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, gint32 *error)
1871 event = CreateEvent (NULL, manual, initial, NULL);
1873 event = CreateEvent (NULL, manual, initial,
1874 mono_string_chars (name));
1877 *error = GetLastError ();
1882 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1883 return (SetEvent(handle));
1886 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1887 return (ResetEvent(handle));
1891 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1892 CloseHandle (handle);
1895 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1901 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1903 *error = GetLastError ();
1905 *error = ERROR_SUCCESS;
1911 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1913 return InterlockedIncrement (location);
1916 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1918 #if SIZEOF_VOID_P == 4
1919 if (G_UNLIKELY ((size_t)location & 0x7)) {
1921 mono_interlocked_lock ();
1924 mono_interlocked_unlock ();
1928 return InterlockedIncrement64 (location);
1931 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1933 return InterlockedDecrement(location);
1936 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1938 #if SIZEOF_VOID_P == 4
1939 if (G_UNLIKELY ((size_t)location & 0x7)) {
1941 mono_interlocked_lock ();
1944 mono_interlocked_unlock ();
1948 return InterlockedDecrement64 (location);
1951 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1953 return InterlockedExchange(location, value);
1956 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1959 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1960 mono_gc_wbarrier_generic_nostore (location);
1964 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1966 return InterlockedExchangePointer(location, value);
1969 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1971 IntFloatUnion val, ret;
1974 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1980 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1982 #if SIZEOF_VOID_P == 4
1983 if (G_UNLIKELY ((size_t)location & 0x7)) {
1985 mono_interlocked_lock ();
1988 mono_interlocked_unlock ();
1992 return InterlockedExchange64 (location, value);
1996 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1998 LongDoubleUnion val, ret;
2001 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
2006 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
2008 return InterlockedCompareExchange(location, value, comparand);
2011 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
2013 gint32 r = InterlockedCompareExchange(location, value, comparand);
2014 *success = r == comparand;
2018 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
2021 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
2022 mono_gc_wbarrier_generic_nostore (location);
2026 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
2028 return InterlockedCompareExchangePointer(location, value, comparand);
2031 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2033 IntFloatUnion val, ret, cmp;
2036 cmp.fval = comparand;
2037 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2043 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2045 #if SIZEOF_VOID_P == 8
2046 LongDoubleUnion val, comp, ret;
2049 comp.fval = comparand;
2050 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2056 mono_interlocked_lock ();
2058 if (old == comparand)
2060 mono_interlocked_unlock ();
2067 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2069 #if SIZEOF_VOID_P == 4
2070 if (G_UNLIKELY ((size_t)location & 0x7)) {
2072 mono_interlocked_lock ();
2074 if (old == comparand)
2076 mono_interlocked_unlock ();
2080 return InterlockedCompareExchange64 (location, value, comparand);
2084 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2087 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2088 mono_gc_wbarrier_generic_nostore (location);
2093 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2096 MONO_CHECK_NULL (location, NULL);
2097 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2098 mono_gc_wbarrier_generic_nostore (location);
2103 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2105 return InterlockedAdd (location, value);
2109 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2111 #if SIZEOF_VOID_P == 4
2112 if (G_UNLIKELY ((size_t)location & 0x7)) {
2114 mono_interlocked_lock ();
2117 mono_interlocked_unlock ();
2121 return InterlockedAdd64 (location, value);
2125 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2127 #if SIZEOF_VOID_P == 4
2128 if (G_UNLIKELY ((size_t)location & 0x7)) {
2130 mono_interlocked_lock ();
2132 mono_interlocked_unlock ();
2136 return InterlockedRead64 (location);
2140 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2142 mono_memory_barrier ();
2146 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2148 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2150 if (state & ThreadState_Background) {
2151 /* If the thread changes the background mode, the main thread has to
2152 * be notified, since it has to rebuild the list of threads to
2155 SetEvent (background_change_event);
2160 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2162 mono_thread_set_state (this_obj, (MonoThreadState)state);
2164 if (state & ThreadState_Background) {
2165 /* If the thread changes the background mode, the main thread has to
2166 * be notified, since it has to rebuild the list of threads to
2169 SetEvent (background_change_event);
2174 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2178 LOCK_THREAD (this_obj);
2180 state = this_obj->state;
2182 UNLOCK_THREAD (this_obj);
2187 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2189 MonoInternalThread *current;
2191 MonoInternalThread *thread = this_obj->internal_thread;
2193 LOCK_THREAD (thread);
2195 current = mono_thread_internal_current ();
2197 thread->thread_interrupt_requested = TRUE;
2198 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2200 UNLOCK_THREAD (thread);
2203 async_abort_internal (thread, FALSE);
2208 * mono_thread_current_check_pending_interrupt:
2210 * Checks if there's a interruption request and set the pending exception if so.
2212 * @returns true if a pending exception was set
2215 mono_thread_current_check_pending_interrupt (void)
2217 MonoInternalThread *thread = mono_thread_internal_current ();
2218 gboolean throw_ = FALSE;
2220 LOCK_THREAD (thread);
2222 if (thread->thread_interrupt_requested) {
2224 thread->thread_interrupt_requested = FALSE;
2227 UNLOCK_THREAD (thread);
2230 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2235 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2237 LOCK_THREAD (thread);
2239 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2240 (thread->state & ThreadState_StopRequested) != 0 ||
2241 (thread->state & ThreadState_Stopped) != 0)
2243 UNLOCK_THREAD (thread);
2247 if ((thread->state & ThreadState_Unstarted) != 0) {
2248 thread->state |= ThreadState_Aborted;
2249 UNLOCK_THREAD (thread);
2253 thread->state |= ThreadState_AbortRequested;
2254 if (thread->abort_state_handle)
2255 mono_gchandle_free (thread->abort_state_handle);
2257 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2258 g_assert (thread->abort_state_handle);
2260 thread->abort_state_handle = 0;
2262 thread->abort_exc = NULL;
2264 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));
2266 /* During shutdown, we can't wait for other threads */
2268 /* Make sure the thread is awake */
2269 mono_thread_resume (thread);
2271 UNLOCK_THREAD (thread);
2276 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2278 if (!request_thread_abort (thread, state))
2281 if (thread == mono_thread_internal_current ()) {
2283 self_abort_internal (&error);
2284 mono_error_set_pending_exception (&error);
2286 async_abort_internal (thread, TRUE);
2291 * mono_thread_internal_abort:
2293 * Request thread @thread to be aborted.
2295 * @thread MUST NOT be the current thread.
2298 mono_thread_internal_abort (MonoInternalThread *thread)
2300 g_assert (thread != mono_thread_internal_current ());
2302 if (!request_thread_abort (thread, NULL))
2304 async_abort_internal (thread, TRUE);
2308 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2310 MonoInternalThread *thread = mono_thread_internal_current ();
2311 gboolean was_aborting;
2313 LOCK_THREAD (thread);
2314 was_aborting = thread->state & ThreadState_AbortRequested;
2315 thread->state &= ~ThreadState_AbortRequested;
2316 UNLOCK_THREAD (thread);
2318 if (!was_aborting) {
2319 const char *msg = "Unable to reset abort because no abort was requested";
2320 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2323 thread->abort_exc = NULL;
2324 if (thread->abort_state_handle) {
2325 mono_gchandle_free (thread->abort_state_handle);
2326 /* This is actually not necessary - the handle
2327 only counts if the exception is set */
2328 thread->abort_state_handle = 0;
2333 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2335 LOCK_THREAD (thread);
2337 thread->state &= ~ThreadState_AbortRequested;
2339 if (thread->abort_exc) {
2340 thread->abort_exc = NULL;
2341 if (thread->abort_state_handle) {
2342 mono_gchandle_free (thread->abort_state_handle);
2343 /* This is actually not necessary - the handle
2344 only counts if the exception is set */
2345 thread->abort_state_handle = 0;
2349 UNLOCK_THREAD (thread);
2353 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2356 MonoInternalThread *thread = this_obj->internal_thread;
2357 MonoObject *state, *deserialized = NULL;
2360 if (!thread->abort_state_handle)
2363 state = mono_gchandle_get_target (thread->abort_state_handle);
2366 domain = mono_domain_get ();
2367 if (mono_object_domain (state) == domain)
2370 deserialized = mono_object_xdomain_representation (state, domain, &error);
2372 if (!deserialized) {
2373 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2374 if (!is_ok (&error)) {
2375 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2376 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2378 mono_set_pending_exception (invalid_op_exc);
2382 return deserialized;
2386 mono_thread_suspend (MonoInternalThread *thread)
2388 LOCK_THREAD (thread);
2390 if ((thread->state & ThreadState_Unstarted) != 0 ||
2391 (thread->state & ThreadState_Aborted) != 0 ||
2392 (thread->state & ThreadState_Stopped) != 0)
2394 UNLOCK_THREAD (thread);
2398 if ((thread->state & ThreadState_Suspended) != 0 ||
2399 (thread->state & ThreadState_SuspendRequested) != 0 ||
2400 (thread->state & ThreadState_StopRequested) != 0)
2402 UNLOCK_THREAD (thread);
2406 thread->state |= ThreadState_SuspendRequested;
2408 if (thread == mono_thread_internal_current ()) {
2409 /* calls UNLOCK_THREAD (thread) */
2410 self_suspend_internal ();
2412 /* calls UNLOCK_THREAD (thread) */
2413 async_suspend_internal (thread, FALSE);
2420 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2422 if (!mono_thread_suspend (this_obj->internal_thread)) {
2423 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2428 /* LOCKING: LOCK_THREAD(thread) must be held */
2430 mono_thread_resume (MonoInternalThread *thread)
2432 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2433 thread->state &= ~ThreadState_SuspendRequested;
2437 if ((thread->state & ThreadState_Suspended) == 0 ||
2438 (thread->state & ThreadState_Unstarted) != 0 ||
2439 (thread->state & ThreadState_Aborted) != 0 ||
2440 (thread->state & ThreadState_Stopped) != 0)
2445 UNLOCK_THREAD (thread);
2447 /* Awake the thread */
2448 if (!mono_thread_info_resume (thread_get_tid (thread)))
2451 LOCK_THREAD (thread);
2453 thread->state &= ~ThreadState_Suspended;
2459 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2461 if (!thread->internal_thread) {
2462 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2464 LOCK_THREAD (thread->internal_thread);
2465 if (!mono_thread_resume (thread->internal_thread))
2466 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2467 UNLOCK_THREAD (thread->internal_thread);
2472 mono_threads_is_critical_method (MonoMethod *method)
2474 switch (method->wrapper_type) {
2475 case MONO_WRAPPER_RUNTIME_INVOKE:
2476 case MONO_WRAPPER_XDOMAIN_INVOKE:
2477 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2484 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2489 if (mono_threads_is_critical_method (m)) {
2490 *((gboolean*)data) = TRUE;
2497 is_running_protected_wrapper (void)
2499 gboolean found = FALSE;
2500 mono_stack_walk (find_wrapper, &found);
2505 request_thread_stop (MonoInternalThread *thread)
2507 LOCK_THREAD (thread);
2509 if ((thread->state & ThreadState_StopRequested) != 0 ||
2510 (thread->state & ThreadState_Stopped) != 0)
2512 UNLOCK_THREAD (thread);
2516 /* Make sure the thread is awake */
2517 mono_thread_resume (thread);
2519 thread->state |= ThreadState_StopRequested;
2520 thread->state &= ~ThreadState_AbortRequested;
2522 UNLOCK_THREAD (thread);
2527 * mono_thread_internal_stop:
2529 * Request thread @thread to stop.
2531 * @thread MUST NOT be the current thread.
2534 mono_thread_internal_stop (MonoInternalThread *thread)
2536 g_assert (thread != mono_thread_internal_current ());
2538 if (!request_thread_stop (thread))
2541 async_abort_internal (thread, TRUE);
2544 void mono_thread_stop (MonoThread *thread)
2546 MonoInternalThread *internal = thread->internal_thread;
2548 if (!request_thread_stop (internal))
2551 if (internal == mono_thread_internal_current ()) {
2553 self_abort_internal (&error);
2555 This function is part of the embeding API and has no way to return the exception
2556 to be thrown. So what we do is keep the old behavior and raise the exception.
2558 mono_error_raise_exception (&error); /* OK to throw, see note */
2560 async_abort_internal (internal, TRUE);
2565 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2567 gint8 tmp = *(volatile gint8 *)ptr;
2568 mono_memory_barrier ();
2573 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2575 gint16 tmp = *(volatile gint16 *)ptr;
2576 mono_memory_barrier ();
2581 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2583 gint32 tmp = *(volatile gint32 *)ptr;
2584 mono_memory_barrier ();
2589 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2591 gint64 tmp = *(volatile gint64 *)ptr;
2592 mono_memory_barrier ();
2597 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2599 volatile void *tmp = *(volatile void **)ptr;
2600 mono_memory_barrier ();
2601 return (void *) tmp;
2605 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2607 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2608 mono_memory_barrier ();
2609 return (MonoObject *) tmp;
2613 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2615 double tmp = *(volatile double *)ptr;
2616 mono_memory_barrier ();
2621 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2623 float tmp = *(volatile float *)ptr;
2624 mono_memory_barrier ();
2629 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2631 return InterlockedRead8 ((volatile gint8 *)ptr);
2635 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2637 return InterlockedRead16 ((volatile gint16 *)ptr);
2641 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2643 return InterlockedRead ((volatile gint32 *)ptr);
2647 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2649 #if SIZEOF_VOID_P == 4
2650 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2652 mono_interlocked_lock ();
2653 val = *(gint64*)ptr;
2654 mono_interlocked_unlock ();
2658 return InterlockedRead64 ((volatile gint64 *)ptr);
2662 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2664 return InterlockedReadPointer ((volatile gpointer *)ptr);
2668 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2672 #if SIZEOF_VOID_P == 4
2673 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2675 mono_interlocked_lock ();
2676 val = *(double*)ptr;
2677 mono_interlocked_unlock ();
2682 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2688 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2692 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2698 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2700 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2704 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2706 mono_memory_barrier ();
2707 *(volatile gint8 *)ptr = value;
2711 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2713 mono_memory_barrier ();
2714 *(volatile gint16 *)ptr = value;
2718 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2720 mono_memory_barrier ();
2721 *(volatile gint32 *)ptr = value;
2725 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2727 mono_memory_barrier ();
2728 *(volatile gint64 *)ptr = value;
2732 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2734 mono_memory_barrier ();
2735 *(volatile void **)ptr = value;
2739 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2741 mono_memory_barrier ();
2742 mono_gc_wbarrier_generic_store (ptr, value);
2746 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2748 mono_memory_barrier ();
2749 *(volatile double *)ptr = value;
2753 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2755 mono_memory_barrier ();
2756 *(volatile float *)ptr = value;
2760 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2762 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2766 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2768 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2772 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2774 InterlockedWrite ((volatile gint32 *)ptr, value);
2778 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2780 #if SIZEOF_VOID_P == 4
2781 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2782 mono_interlocked_lock ();
2783 *(gint64*)ptr = value;
2784 mono_interlocked_unlock ();
2789 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2793 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2795 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2799 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2803 #if SIZEOF_VOID_P == 4
2804 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2805 mono_interlocked_lock ();
2806 *(double*)ptr = value;
2807 mono_interlocked_unlock ();
2814 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2818 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2824 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2828 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2830 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2834 free_context (void *user_data)
2836 ContextStaticData *data = user_data;
2838 mono_threads_lock ();
2841 * There is no guarantee that, by the point this reference queue callback
2842 * has been invoked, the GC handle associated with the object will fail to
2843 * resolve as one might expect. So if we don't free and remove the GC
2844 * handle here, free_context_static_data_helper () could end up resolving
2845 * a GC handle to an actually-dead context which would contain a pointer
2846 * to an already-freed static data segment, resulting in a crash when
2849 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2851 mono_threads_unlock ();
2853 mono_gchandle_free (data->gc_handle);
2854 mono_free_static_data (data->static_data);
2859 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2861 mono_threads_lock ();
2863 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2866 contexts = g_hash_table_new (NULL, NULL);
2869 context_queue = mono_gc_reference_queue_new (free_context);
2871 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2872 g_hash_table_insert (contexts, gch, gch);
2875 * We use this intermediate structure to contain a duplicate pointer to
2876 * the static data because we can't rely on being able to resolve the GC
2877 * handle in the reference queue callback.
2879 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2880 data->gc_handle = GPOINTER_TO_UINT (gch);
2883 context_adjust_static_data (ctx);
2884 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2886 mono_threads_unlock ();
2888 mono_profiler_context_loaded (ctx);
2892 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2895 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2896 * cleanup in exceptional circumstances, we don't actually do any
2897 * cleanup work here. We instead do this via a reference queue.
2900 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2902 mono_profiler_context_unloaded (ctx);
2906 mono_thread_init_tls (void)
2908 MONO_FAST_TLS_INIT (tls_current_object);
2909 mono_native_tls_alloc (¤t_object_key, NULL);
2912 void mono_thread_init (MonoThreadStartCB start_cb,
2913 MonoThreadAttachCB attach_cb)
2915 mono_coop_mutex_init_recursive (&threads_mutex);
2917 mono_os_mutex_init_recursive(&interlocked_mutex);
2918 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2920 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2921 g_assert(background_change_event != NULL);
2923 mono_init_static_data_info (&thread_static_info);
2924 mono_init_static_data_info (&context_static_info);
2926 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2928 mono_thread_start_cb = start_cb;
2929 mono_thread_attach_cb = attach_cb;
2931 /* Get a pseudo handle to the current process. This is just a
2932 * kludge so that wapi can build a process handle if needed.
2933 * As a pseudo handle is returned, we don't need to clean
2936 GetCurrentProcess ();
2939 void mono_thread_cleanup (void)
2941 #if !defined(RUN_IN_SUBTHREAD)
2942 /* The main thread must abandon any held mutexes (particularly
2943 * important for named mutexes as they are shared across
2944 * processes, see bug 74680.) This will happen when the
2945 * thread exits, but if it's not running in a subthread it
2946 * won't exit in time.
2948 mono_thread_info_set_exited (mono_thread_info_current ());
2952 /* This stuff needs more testing, it seems one of these
2953 * critical sections can be locked when mono_thread_cleanup is
2956 mono_coop_mutex_destroy (&threads_mutex);
2957 mono_os_mutex_destroy (&interlocked_mutex);
2958 mono_os_mutex_destroy (&delayed_free_table_mutex);
2959 mono_os_mutex_destroy (&small_id_mutex);
2960 CloseHandle (background_change_event);
2963 mono_native_tls_free (current_object_key);
2967 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2969 mono_thread_cleanup_fn = func;
2973 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2975 thread->internal_thread->manage_callback = func;
2979 static void print_tids (gpointer key, gpointer value, gpointer user)
2981 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2982 * sizeof(uint) and a cast to uint would overflow
2984 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2985 * print this as a pointer.
2987 g_message ("Waiting for: %p", key);
2992 HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2993 MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2997 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
3001 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3004 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
3007 if(ret==WAIT_FAILED) {
3008 /* See the comment in build_wait_tids() */
3009 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3013 for(i=0; i<wait->num; i++)
3014 CloseHandle (wait->handles[i]);
3016 if (ret == WAIT_TIMEOUT)
3019 for(i=0; i<wait->num; i++) {
3020 gsize tid = wait->threads[i]->tid;
3023 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
3024 * it can still run io-layer etc. code. So wait for it to really exit.
3025 * FIXME: This won't join threads which are not in the joinable_hash yet.
3027 mono_thread_join ((gpointer)tid);
3029 mono_threads_lock ();
3030 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3031 /* This thread must have been killed, because
3032 * it hasn't cleaned itself up. (It's just
3033 * possible that the thread exited before the
3034 * parent thread had a chance to store the
3035 * handle, and now there is another pointer to
3036 * the already-exited thread stored. In this
3037 * case, we'll just get two
3038 * mono_profiler_thread_end() calls for the
3042 mono_threads_unlock ();
3043 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
3044 thread_cleanup (wait->threads[i]);
3046 mono_threads_unlock ();
3051 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
3053 guint32 i, ret, count;
3055 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3057 /* Add the thread state change event, so it wakes up if a thread changes
3058 * to background mode.
3061 if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3062 wait->handles [count] = background_change_event;
3067 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
3070 if(ret==WAIT_FAILED) {
3071 /* See the comment in build_wait_tids() */
3072 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3076 for(i=0; i<wait->num; i++)
3077 CloseHandle (wait->handles[i]);
3079 if (ret == WAIT_TIMEOUT)
3082 if (ret < wait->num) {
3083 gsize tid = wait->threads[ret]->tid;
3084 mono_threads_lock ();
3085 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3086 /* See comment in wait_for_tids about thread cleanup */
3087 mono_threads_unlock ();
3088 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3089 thread_cleanup (wait->threads [ret]);
3091 mono_threads_unlock ();
3095 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3097 struct wait_data *wait=(struct wait_data *)user;
3099 if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3101 MonoInternalThread *thread=(MonoInternalThread *)value;
3103 /* Ignore background threads, we abort them later */
3104 /* Do not lock here since it is not needed and the caller holds threads_lock */
3105 if (thread->state & ThreadState_Background) {
3106 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3107 return; /* just leave, ignore */
3110 if (mono_gc_is_finalizer_internal_thread (thread)) {
3111 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3115 if (thread == mono_thread_internal_current ()) {
3116 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3120 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3121 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3125 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3126 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3130 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3131 if (handle == NULL) {
3132 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3136 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3137 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3138 wait->handles[wait->num]=handle;
3139 wait->threads[wait->num]=thread;
3142 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3144 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3149 /* Just ignore the rest, we can't do anything with
3156 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3158 struct wait_data *wait=(struct wait_data *)user;
3159 MonoNativeThreadId self = mono_native_thread_id_get ();
3160 MonoInternalThread *thread = (MonoInternalThread *)value;
3163 if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3166 /* The finalizer thread is not a background thread */
3167 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3168 && (thread->state & ThreadState_Background) != 0
3169 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3171 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3175 wait->handles[wait->num] = handle;
3176 wait->threads[wait->num] = thread;
3179 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3180 mono_thread_internal_abort (thread);
3184 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3185 && !mono_gc_is_finalizer_internal_thread (thread);
3189 * mono_threads_set_shutting_down:
3191 * Is called by a thread that wants to shut down Mono. If the runtime is already
3192 * shutting down, the calling thread is suspended/stopped, and this function never
3196 mono_threads_set_shutting_down (void)
3198 MonoInternalThread *current_thread = mono_thread_internal_current ();
3200 mono_threads_lock ();
3202 if (shutting_down) {
3203 mono_threads_unlock ();
3205 /* Make sure we're properly suspended/stopped */
3207 LOCK_THREAD (current_thread);
3209 if ((current_thread->state & ThreadState_SuspendRequested) ||
3210 (current_thread->state & ThreadState_AbortRequested) ||
3211 (current_thread->state & ThreadState_StopRequested)) {
3212 UNLOCK_THREAD (current_thread);
3213 mono_thread_execute_interruption ();
3215 current_thread->state |= ThreadState_Stopped;
3216 UNLOCK_THREAD (current_thread);
3219 /*since we're killing the thread, unset the current domain.*/
3220 mono_domain_unset ();
3222 /* Wake up other threads potentially waiting for us */
3223 mono_thread_info_exit ();
3225 shutting_down = TRUE;
3227 /* Not really a background state change, but this will
3228 * interrupt the main thread if it is waiting for all
3229 * the other threads.
3231 SetEvent (background_change_event);
3233 mono_threads_unlock ();
3237 void mono_thread_manage (void)
3239 struct wait_data wait_data;
3240 struct wait_data *wait = &wait_data;
3242 memset (wait, 0, sizeof (struct wait_data));
3243 /* join each thread that's still running */
3244 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3246 mono_threads_lock ();
3248 THREAD_DEBUG (g_message("%s: No threads", __func__));
3249 mono_threads_unlock ();
3252 mono_threads_unlock ();
3255 mono_threads_lock ();
3256 if (shutting_down) {
3257 /* somebody else is shutting down */
3258 mono_threads_unlock ();
3261 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3262 mono_g_hash_table_foreach (threads, print_tids, NULL));
3264 ResetEvent (background_change_event);
3266 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3267 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3268 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3269 mono_threads_unlock ();
3271 /* Something to wait for */
3272 wait_for_tids_or_state_change (wait, INFINITE);
3274 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3275 } while(wait->num>0);
3277 /* Mono is shutting down, so just wait for the end */
3278 if (!mono_runtime_try_shutdown ()) {
3279 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3280 mono_thread_suspend (mono_thread_internal_current ());
3281 mono_thread_execute_interruption ();
3285 * Remove everything but the finalizer thread and self.
3286 * Also abort all the background threads
3289 mono_threads_lock ();
3292 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3293 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3294 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3296 mono_threads_unlock ();
3298 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3300 /* Something to wait for */
3301 wait_for_tids (wait, INFINITE);
3303 } while (wait->num > 0);
3306 * give the subthreads a chance to really quit (this is mainly needed
3307 * to get correct user and system times from getrusage/wait/time(1)).
3308 * This could be removed if we avoid pthread_detach() and use pthread_join().
3310 mono_thread_info_yield ();
3314 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3316 MonoInternalThread *thread = (MonoInternalThread*)value;
3317 struct wait_data *wait = (struct wait_data*)user_data;
3321 * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3323 * This needs no locking.
3325 if ((thread->state & ThreadState_Suspended) != 0 ||
3326 (thread->state & ThreadState_Stopped) != 0)
3329 if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3330 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3334 wait->handles [wait->num] = handle;
3335 wait->threads [wait->num] = thread;
3341 * mono_thread_suspend_all_other_threads:
3343 * Suspend all managed threads except the finalizer thread and this thread. It is
3344 * not possible to resume them later.
3346 void mono_thread_suspend_all_other_threads (void)
3348 struct wait_data wait_data;
3349 struct wait_data *wait = &wait_data;
3351 MonoNativeThreadId self = mono_native_thread_id_get ();
3352 guint32 eventidx = 0;
3353 gboolean starting, finished;
3355 memset (wait, 0, sizeof (struct wait_data));
3357 * The other threads could be in an arbitrary state at this point, i.e.
3358 * they could be starting up, shutting down etc. This means that there could be
3359 * threads which are not even in the threads hash table yet.
3363 * First we set a barrier which will be checked by all threads before they
3364 * are added to the threads hash table, and they will exit if the flag is set.
3365 * This ensures that no threads could be added to the hash later.
3366 * We will use shutting_down as the barrier for now.
3368 g_assert (shutting_down);
3371 * We make multiple calls to WaitForMultipleObjects since:
3372 * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3373 * - some threads could exit without becoming suspended
3378 * Make a copy of the hashtable since we can't do anything with
3379 * threads while threads_mutex is held.
3382 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3383 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3384 mono_threads_lock ();
3385 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3386 mono_threads_unlock ();
3389 /* Get the suspended events that we'll be waiting for */
3390 for (i = 0; i < wait->num; ++i) {
3391 MonoInternalThread *thread = wait->threads [i];
3393 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3394 || mono_gc_is_finalizer_internal_thread (thread)
3395 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3397 //CloseHandle (wait->handles [i]);
3398 wait->threads [i] = NULL; /* ignore this thread in next loop */
3402 LOCK_THREAD (thread);
3404 if ((thread->state & ThreadState_Suspended) != 0 ||
3405 (thread->state & ThreadState_StopRequested) != 0 ||
3406 (thread->state & ThreadState_Stopped) != 0) {
3407 UNLOCK_THREAD (thread);
3408 CloseHandle (wait->handles [i]);
3409 wait->threads [i] = NULL; /* ignore this thread in next loop */
3415 /* Convert abort requests into suspend requests */
3416 if ((thread->state & ThreadState_AbortRequested) != 0)
3417 thread->state &= ~ThreadState_AbortRequested;
3419 thread->state |= ThreadState_SuspendRequested;
3421 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3422 async_suspend_internal (thread, TRUE);
3424 if (eventidx <= 0) {
3426 * If there are threads which are starting up, we wait until they
3427 * are suspended when they try to register in the threads hash.
3428 * This is guaranteed to finish, since the threads which can create new
3429 * threads get suspended after a while.
3430 * FIXME: The finalizer thread can still create new threads.
3432 mono_threads_lock ();
3433 if (threads_starting_up)
3434 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3437 mono_threads_unlock ();
3439 mono_thread_info_sleep (100, NULL);
3447 MonoInternalThread *thread;
3448 MonoStackFrameInfo *frames;
3449 int nframes, max_frames;
3450 int nthreads, max_threads;
3451 MonoInternalThread **threads;
3452 } ThreadDumpUserData;
3454 static gboolean thread_dump_requested;
3456 /* This needs to be async safe */
3458 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3460 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3462 if (ud->nframes < ud->max_frames) {
3463 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3470 /* This needs to be async safe */
3471 static SuspendThreadResult
3472 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3474 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3475 MonoInternalThread *thread = user_data->thread;
3478 /* This no longer works with remote unwinding */
3479 g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3480 mono_thread_info_describe (info, text);
3481 g_string_append (text, "\n");
3484 if (thread == mono_thread_internal_current ())
3485 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3487 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3489 return MonoResumeThread;
3493 int nthreads, max_threads;
3494 MonoInternalThread **threads;
3495 } CollectThreadsUserData;
3498 collect_thread (gpointer key, gpointer value, gpointer user)
3500 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3501 MonoInternalThread *thread = (MonoInternalThread *)value;
3503 if (ud->nthreads < ud->max_threads)
3504 ud->threads [ud->nthreads ++] = thread;
3508 * Collect running threads into the THREADS array.
3509 * THREADS should be an array allocated on the stack.
3512 collect_threads (MonoInternalThread **thread_array, int max_threads)
3514 CollectThreadsUserData ud;
3516 memset (&ud, 0, sizeof (ud));
3517 /* This array contains refs, but its on the stack, so its ok */
3518 ud.threads = thread_array;
3519 ud.max_threads = max_threads;
3521 mono_threads_lock ();
3522 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3523 mono_threads_unlock ();
3529 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3531 GString* text = g_string_new (0);
3533 GError *error = NULL;
3536 ud->thread = thread;
3539 /* Collect frames for the thread */
3540 if (thread == mono_thread_internal_current ()) {
3541 get_thread_dump (mono_thread_info_current (), ud);
3543 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3547 * Do all the non async-safe work outside of get_thread_dump.
3550 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3552 g_string_append_printf (text, "\n\"%s\"", name);
3555 else if (thread->threadpool_thread) {
3556 g_string_append (text, "\n\"<threadpool thread>\"");
3558 g_string_append (text, "\n\"<unnamed thread>\"");
3561 for (i = 0; i < ud->nframes; ++i) {
3562 MonoStackFrameInfo *frame = &ud->frames [i];
3563 MonoMethod *method = NULL;
3565 if (frame->type == FRAME_TYPE_MANAGED)
3566 method = mono_jit_info_get_method (frame->ji);
3569 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3570 g_string_append_printf (text, " %s\n", location);
3573 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3577 fprintf (stdout, "%s", text->str);
3579 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3580 OutputDebugStringA(text->str);
3583 g_string_free (text, TRUE);
3588 mono_threads_perform_thread_dump (void)
3590 ThreadDumpUserData ud;
3591 MonoInternalThread *thread_array [128];
3592 int tindex, nthreads;
3594 if (!thread_dump_requested)
3597 printf ("Full thread dump:\n");
3599 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3600 nthreads = collect_threads (thread_array, 128);
3602 memset (&ud, 0, sizeof (ud));
3603 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3604 ud.max_frames = 256;
3606 for (tindex = 0; tindex < nthreads; ++tindex)
3607 dump_thread (thread_array [tindex], &ud);
3611 thread_dump_requested = FALSE;
3614 /* Obtain the thread dump of all threads */
3616 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3619 ThreadDumpUserData ud;
3620 MonoInternalThread *thread_array [128];
3621 MonoDomain *domain = mono_domain_get ();
3622 MonoDebugSourceLocation *location;
3623 int tindex, nthreads;
3625 mono_error_init (error);
3627 *out_threads = NULL;
3628 *out_stack_frames = NULL;
3630 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3631 nthreads = collect_threads (thread_array, 128);
3633 memset (&ud, 0, sizeof (ud));
3634 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3635 ud.max_frames = 256;
3637 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3640 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3644 for (tindex = 0; tindex < nthreads; ++tindex) {
3645 MonoInternalThread *thread = thread_array [tindex];
3646 MonoArray *thread_frames;
3652 /* Collect frames for the thread */
3653 if (thread == mono_thread_internal_current ()) {
3654 get_thread_dump (mono_thread_info_current (), &ud);
3656 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3659 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3661 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3664 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3666 for (i = 0; i < ud.nframes; ++i) {
3667 MonoStackFrameInfo *frame = &ud.frames [i];
3668 MonoMethod *method = NULL;
3669 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3673 sf->native_offset = frame->native_offset;
3675 if (frame->type == FRAME_TYPE_MANAGED)
3676 method = mono_jit_info_get_method (frame->ji);
3679 sf->method_address = (gsize) frame->ji->code_start;
3681 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3684 MONO_OBJECT_SETREF (sf, method, rm);
3686 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3688 sf->il_offset = location->il_offset;
3690 if (location && location->source_file) {
3691 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3692 sf->line = location->row;
3693 sf->column = location->column;
3695 mono_debug_free_source_location (location);
3700 mono_array_setref (thread_frames, i, sf);
3706 return is_ok (error);
3710 * mono_threads_request_thread_dump:
3712 * Ask all threads except the current to print their stacktrace to stdout.
3715 mono_threads_request_thread_dump (void)
3717 /*The new thread dump code runs out of the finalizer thread. */
3718 thread_dump_requested = TRUE;
3719 mono_gc_finalize_notify ();
3724 gint allocated; /* +1 so that refs [allocated] == NULL */
3728 typedef struct ref_stack RefStack;
3731 ref_stack_new (gint initial_size)
3735 initial_size = MAX (initial_size, 16) + 1;
3736 rs = g_new0 (RefStack, 1);
3737 rs->refs = g_new0 (gpointer, initial_size);
3738 rs->allocated = initial_size;
3743 ref_stack_destroy (gpointer ptr)
3745 RefStack *rs = (RefStack *)ptr;
3754 ref_stack_push (RefStack *rs, gpointer ptr)
3756 g_assert (rs != NULL);
3758 if (rs->bottom >= rs->allocated) {
3759 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3760 rs->allocated <<= 1;
3761 rs->refs [rs->allocated] = NULL;
3763 rs->refs [rs->bottom++] = ptr;
3767 ref_stack_pop (RefStack *rs)
3769 if (rs == NULL || rs->bottom == 0)
3773 rs->refs [rs->bottom] = NULL;
3777 ref_stack_find (RefStack *rs, gpointer ptr)
3784 for (refs = rs->refs; refs && *refs; refs++) {
3792 * mono_thread_push_appdomain_ref:
3794 * Register that the current thread may have references to objects in domain
3795 * @domain on its stack. Each call to this function should be paired with a
3796 * call to pop_appdomain_ref.
3799 mono_thread_push_appdomain_ref (MonoDomain *domain)
3801 MonoInternalThread *thread = mono_thread_internal_current ();
3804 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3805 SPIN_LOCK (thread->lock_thread_id);
3806 if (thread->appdomain_refs == NULL)
3807 thread->appdomain_refs = ref_stack_new (16);
3808 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3809 SPIN_UNLOCK (thread->lock_thread_id);
3814 mono_thread_pop_appdomain_ref (void)
3816 MonoInternalThread *thread = mono_thread_internal_current ();
3819 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3820 SPIN_LOCK (thread->lock_thread_id);
3821 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3822 SPIN_UNLOCK (thread->lock_thread_id);
3827 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3830 SPIN_LOCK (thread->lock_thread_id);
3831 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3832 SPIN_UNLOCK (thread->lock_thread_id);
3837 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3839 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3842 typedef struct abort_appdomain_data {
3843 struct wait_data wait;
3845 } abort_appdomain_data;
3848 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3850 MonoInternalThread *thread = (MonoInternalThread*)value;
3851 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3852 MonoDomain *domain = data->domain;
3854 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3855 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3857 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3858 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3861 data->wait.handles [data->wait.num] = handle;
3862 data->wait.threads [data->wait.num] = thread;
3865 /* Just ignore the rest, we can't do anything with
3873 * mono_threads_abort_appdomain_threads:
3875 * Abort threads which has references to the given appdomain.
3878 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3880 #ifdef __native_client__
3884 abort_appdomain_data user_data;
3886 int orig_timeout = timeout;
3889 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3891 start_time = mono_msec_ticks ();
3893 mono_threads_lock ();
3895 user_data.domain = domain;
3896 user_data.wait.num = 0;
3897 /* This shouldn't take any locks */
3898 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3899 mono_threads_unlock ();
3901 if (user_data.wait.num > 0) {
3902 /* Abort the threads outside the threads lock */
3903 for (i = 0; i < user_data.wait.num; ++i)
3904 mono_thread_internal_abort (user_data.wait.threads [i]);
3907 * We should wait for the threads either to abort, or to leave the
3908 * domain. We can't do the latter, so we wait with a timeout.
3910 wait_for_tids (&user_data.wait, 100);
3913 /* Update remaining time */
3914 timeout -= mono_msec_ticks () - start_time;
3915 start_time = mono_msec_ticks ();
3917 if (orig_timeout != -1 && timeout < 0)
3920 while (user_data.wait.num > 0);
3922 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3928 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3930 MonoInternalThread *thread = (MonoInternalThread*)value;
3931 MonoDomain *domain = (MonoDomain*)user_data;
3934 /* No locking needed here */
3935 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3937 if (thread->cached_culture_info) {
3938 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3939 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3940 if (obj && obj->vtable->domain == domain)
3941 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3947 * mono_threads_clear_cached_culture:
3949 * Clear the cached_current_culture from all threads if it is in the
3953 mono_threads_clear_cached_culture (MonoDomain *domain)
3955 mono_threads_lock ();
3956 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3957 mono_threads_unlock ();
3961 * mono_thread_get_undeniable_exception:
3963 * Return an exception which needs to be raised when leaving a catch clause.
3964 * This is used for undeniable exception propagation.
3967 mono_thread_get_undeniable_exception (void)
3969 MonoInternalThread *thread = mono_thread_internal_current ();
3971 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3973 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3974 * exception if the thread no longer references a dying appdomain.
3976 thread->abort_exc->trace_ips = NULL;
3977 thread->abort_exc->stack_trace = NULL;
3978 return thread->abort_exc;
3984 #if MONO_SMALL_CONFIG
3985 #define NUM_STATIC_DATA_IDX 4
3986 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3990 #define NUM_STATIC_DATA_IDX 8
3991 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3992 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3996 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3997 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
4000 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
4002 gpointer *static_data = (gpointer *)addr;
4004 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
4005 void **ptr = (void **)static_data [i];
4010 MONO_BITSET_FOREACH (bitmaps [i], idx, {
4011 void **p = ptr + idx;
4014 mark_func ((MonoObject**)p, gc_data);
4020 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4022 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
4026 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4028 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
4032 * mono_alloc_static_data
4034 * Allocate memory blocks for storing threads or context static data
4037 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4039 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4042 gpointer* static_data = *static_data_ptr;
4044 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4045 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4047 if (mono_gc_user_markers_supported ()) {
4048 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4049 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4051 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4052 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4055 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4056 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4057 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4058 *static_data_ptr = static_data;
4059 static_data [0] = static_data;
4062 for (i = 1; i <= idx; ++i) {
4063 if (static_data [i])
4066 if (mono_gc_user_markers_supported ())
4067 static_data [i] = g_malloc0 (static_data_size [i]);
4069 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4070 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4071 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4076 mono_free_static_data (gpointer* static_data)
4079 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4080 gpointer p = static_data [i];
4084 * At this point, the static data pointer array is still registered with the
4085 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4086 * data. Freeing the individual arrays without first nulling their slots
4087 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4088 * such an already freed array. See bug #13813.
4090 static_data [i] = NULL;
4091 mono_memory_write_barrier ();
4092 if (mono_gc_user_markers_supported ())
4095 mono_gc_free_fixed (p);
4097 mono_gc_free_fixed (static_data);
4101 * mono_init_static_data_info
4103 * Initializes static data counters
4105 static void mono_init_static_data_info (StaticDataInfo *static_data)
4107 static_data->idx = 0;
4108 static_data->offset = 0;
4109 static_data->freelist = NULL;
4113 * mono_alloc_static_data_slot
4115 * Generates an offset for static data. static_data contains the counters
4116 * used to generate it.
4119 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4121 if (!static_data->idx && !static_data->offset) {
4123 * we use the first chunk of the first allocation also as
4124 * an array for the rest of the data
4126 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4128 static_data->offset += align - 1;
4129 static_data->offset &= ~(align - 1);
4130 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4131 static_data->idx ++;
4132 g_assert (size <= static_data_size [static_data->idx]);
4133 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4134 static_data->offset = 0;
4136 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4137 static_data->offset += size;
4142 * ensure thread static fields already allocated are valid for thread
4143 * This function is called when a thread is created or on thread attach.
4146 thread_adjust_static_data (MonoInternalThread *thread)
4148 mono_threads_lock ();
4149 if (thread_static_info.offset || thread_static_info.idx > 0) {
4150 /* get the current allocated size */
4151 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
4152 mono_alloc_static_data (&thread->static_data, offset, TRUE);
4154 mono_threads_unlock ();
4158 * LOCKING: requires that threads_mutex is held
4161 context_adjust_static_data (MonoAppContext *ctx)
4163 if (context_static_info.offset || context_static_info.idx > 0) {
4164 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4165 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4166 ctx->data->static_data = ctx->static_data;
4171 * LOCKING: requires that threads_mutex is held
4174 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4176 MonoInternalThread *thread = (MonoInternalThread *)value;
4177 guint32 offset = GPOINTER_TO_UINT (user);
4179 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4183 * LOCKING: requires that threads_mutex is held
4186 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4188 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4193 guint32 offset = GPOINTER_TO_UINT (user);
4194 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4195 ctx->data->static_data = ctx->static_data;
4198 static StaticDataFreeList*
4199 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4201 StaticDataFreeList* prev = NULL;
4202 StaticDataFreeList* tmp = static_data->freelist;
4204 if (tmp->size == size) {
4206 prev->next = tmp->next;
4208 static_data->freelist = tmp->next;
4217 #if SIZEOF_VOID_P == 4
4224 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4226 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4228 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4229 MonoBitSet *rb = sets [idx];
4230 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4231 offset /= sizeof (uintptr_t);
4232 /* offset is now the bitmap offset */
4233 for (int i = 0; i < numbits; ++i) {
4234 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4235 mono_bitset_set_fast (rb, offset + i);
4240 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4242 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4243 MonoBitSet *rb = sets [idx];
4244 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4245 offset /= sizeof (uintptr_t);
4246 /* offset is now the bitmap offset */
4247 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4248 mono_bitset_clear_fast (rb, offset + i);
4252 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4254 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4256 StaticDataInfo *info;
4259 if (static_type == SPECIAL_STATIC_THREAD) {
4260 info = &thread_static_info;
4261 sets = thread_reference_bitmaps;
4263 info = &context_static_info;
4264 sets = context_reference_bitmaps;
4267 mono_threads_lock ();
4269 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4273 offset = item->offset;
4276 offset = mono_alloc_static_data_slot (info, size, align);
4279 update_reference_bitmap (sets, offset, bitmap, numbits);
4281 if (static_type == SPECIAL_STATIC_THREAD) {
4282 /* This can be called during startup */
4283 if (threads != NULL)
4284 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4286 if (contexts != NULL)
4287 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4289 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4292 mono_threads_unlock ();
4298 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4300 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4302 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4303 return get_thread_static_data (thread, offset);
4305 return get_context_static_data (thread->current_appcontext, offset);
4310 mono_get_special_static_data (guint32 offset)
4312 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4321 * LOCKING: requires that threads_mutex is held
4324 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4326 MonoInternalThread *thread = (MonoInternalThread *)value;
4327 OffsetSize *data = (OffsetSize *)user;
4328 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4329 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4332 if (!thread->static_data || !thread->static_data [idx])
4334 ptr = ((char*) thread->static_data [idx]) + off;
4335 mono_gc_bzero_atomic (ptr, data->size);
4339 * LOCKING: requires that threads_mutex is held
4342 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4344 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4349 OffsetSize *data = (OffsetSize *)user;
4350 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4351 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4354 if (!ctx->static_data || !ctx->static_data [idx])
4357 ptr = ((char*) ctx->static_data [idx]) + off;
4358 mono_gc_bzero_atomic (ptr, data->size);
4362 do_free_special_slot (guint32 offset, guint32 size)
4364 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4366 StaticDataInfo *info;
4368 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4369 info = &thread_static_info;
4370 sets = thread_reference_bitmaps;
4372 info = &context_static_info;
4373 sets = context_reference_bitmaps;
4376 guint32 data_offset = offset;
4377 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4378 OffsetSize data = { data_offset, size };
4380 clear_reference_bitmap (sets, data.offset, data.size);
4382 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4383 if (threads != NULL)
4384 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4386 if (contexts != NULL)
4387 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4390 if (!mono_runtime_is_shutting_down ()) {
4391 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4393 item->offset = offset;
4396 item->next = info->freelist;
4397 info->freelist = item;
4402 do_free_special (gpointer key, gpointer value, gpointer data)
4404 MonoClassField *field = (MonoClassField *)key;
4405 guint32 offset = GPOINTER_TO_UINT (value);
4408 size = mono_type_size (field->type, &align);
4409 do_free_special_slot (offset, size);
4413 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4415 mono_threads_lock ();
4417 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4419 mono_threads_unlock ();
4423 static void CALLBACK dummy_apc (ULONG_PTR param)
4429 * mono_thread_execute_interruption
4431 * Performs the operation that the requested thread state requires (abort,
4434 static MonoException*
4435 mono_thread_execute_interruption (void)
4437 MonoInternalThread *thread = mono_thread_internal_current ();
4438 MonoThread *sys_thread = mono_thread_current ();
4440 LOCK_THREAD (thread);
4442 /* MonoThread::interruption_requested can only be changed with atomics */
4443 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4444 /* this will consume pending APC calls */
4446 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4448 InterlockedDecrement (&thread_interruption_requested);
4450 /* Clear the interrupted flag of the thread so it can wait again */
4451 mono_thread_info_clear_self_interrupt ();
4454 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4455 if (sys_thread->pending_exception) {
4458 exc = sys_thread->pending_exception;
4459 sys_thread->pending_exception = NULL;
4461 UNLOCK_THREAD (thread);
4463 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4464 UNLOCK_THREAD (thread);
4465 g_assert (sys_thread->pending_exception == NULL);
4466 if (thread->abort_exc == NULL) {
4468 * This might be racy, but it has to be called outside the lock
4469 * since it calls managed code.
4471 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4473 return thread->abort_exc;
4475 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4476 /* calls UNLOCK_THREAD (thread) */
4477 self_suspend_internal ();
4480 else if ((thread->state & ThreadState_StopRequested) != 0) {
4481 /* FIXME: do this through the JIT? */
4483 UNLOCK_THREAD (thread);
4485 mono_thread_exit ();
4487 } else if (thread->thread_interrupt_requested) {
4489 thread->thread_interrupt_requested = FALSE;
4490 UNLOCK_THREAD (thread);
4492 return(mono_get_exception_thread_interrupted ());
4495 UNLOCK_THREAD (thread);
4501 * mono_thread_request_interruption
4503 * A signal handler can call this method to request the interruption of a
4504 * thread. The result of the interruption will depend on the current state of
4505 * the thread. If the result is an exception that needs to be throw, it is
4506 * provided as return value.
4509 mono_thread_request_interruption (gboolean running_managed)
4511 MonoInternalThread *thread = mono_thread_internal_current ();
4513 /* The thread may already be stopping */
4518 if (thread->interrupt_on_stop &&
4519 thread->state & ThreadState_StopRequested &&
4520 thread->state & ThreadState_Background)
4524 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4526 InterlockedIncrement (&thread_interruption_requested);
4528 if (!running_managed || is_running_protected_wrapper ()) {
4529 /* Can't stop while in unmanaged code. Increase the global interruption
4530 request count. When exiting the unmanaged method the count will be
4531 checked and the thread will be interrupted. */
4533 /* this will awake the thread if it is in WaitForSingleObject
4535 /* Our implementation of this function ignores the func argument */
4537 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4539 mono_thread_info_self_interrupt ();
4544 return mono_thread_execute_interruption ();
4548 /*This function should be called by a thread after it has exited all of
4549 * its handle blocks at interruption time.*/
4551 mono_thread_resume_interruption (void)
4553 MonoInternalThread *thread = mono_thread_internal_current ();
4554 gboolean still_aborting;
4556 /* The thread may already be stopping */
4560 LOCK_THREAD (thread);
4561 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4562 UNLOCK_THREAD (thread);
4564 /*This can happen if the protected block called Thread::ResetAbort*/
4565 if (!still_aborting)
4568 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4570 InterlockedIncrement (&thread_interruption_requested);
4572 mono_thread_info_self_interrupt ();
4574 return mono_thread_execute_interruption ();
4577 gboolean mono_thread_interruption_requested ()
4579 if (thread_interruption_requested) {
4580 MonoInternalThread *thread = mono_thread_internal_current ();
4581 /* The thread may already be stopping */
4583 return (thread->interruption_requested);
4588 static MonoException*
4589 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4591 MonoInternalThread *thread = mono_thread_internal_current ();
4593 /* The thread may already be stopping */
4597 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4598 MonoException* exc = mono_thread_execute_interruption ();
4606 * Performs the interruption of the current thread, if one has been requested,
4607 * and the thread is not running a protected wrapper.
4608 * Return the exception which needs to be thrown, if any.
4611 mono_thread_interruption_checkpoint (void)
4613 return mono_thread_interruption_checkpoint_request (FALSE);
4617 * Performs the interruption of the current thread, if one has been requested.
4618 * Return the exception which needs to be thrown, if any.
4621 mono_thread_force_interruption_checkpoint_noraise (void)
4623 return mono_thread_interruption_checkpoint_request (TRUE);
4627 * mono_set_pending_exception:
4629 * Set the pending exception of the current thread to EXC.
4630 * The exception will be thrown when execution returns to managed code.
4633 mono_set_pending_exception (MonoException *exc)
4635 MonoThread *thread = mono_thread_current ();
4637 /* The thread may already be stopping */
4641 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4643 mono_thread_request_interruption (FALSE);
4647 * mono_thread_interruption_request_flag:
4649 * Returns the address of a flag that will be non-zero if an interruption has
4650 * been requested for a thread. The thread to interrupt may not be the current
4651 * thread, so an additional call to mono_thread_interruption_requested() or
4652 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4655 gint32* mono_thread_interruption_request_flag ()
4657 return &thread_interruption_requested;
4661 mono_thread_init_apartment_state (void)
4664 MonoInternalThread* thread = mono_thread_internal_current ();
4666 /* Positive return value indicates success, either
4667 * S_OK if this is first CoInitialize call, or
4668 * S_FALSE if CoInitialize already called, but with same
4669 * threading model. A negative value indicates failure,
4670 * probably due to trying to change the threading model.
4672 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4673 ? COINIT_APARTMENTTHREADED
4674 : COINIT_MULTITHREADED) < 0) {
4675 thread->apartment_state = ThreadApartmentState_Unknown;
4681 mono_thread_cleanup_apartment_state (void)
4684 MonoInternalThread* thread = mono_thread_internal_current ();
4686 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4693 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4695 LOCK_THREAD (thread);
4696 thread->state |= state;
4697 UNLOCK_THREAD (thread);
4701 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4703 LOCK_THREAD (thread);
4704 thread->state &= ~state;
4705 UNLOCK_THREAD (thread);
4709 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4711 gboolean ret = FALSE;
4713 LOCK_THREAD (thread);
4715 if ((thread->state & test) != 0) {
4719 UNLOCK_THREAD (thread);
4724 static gboolean has_tls_get = FALSE;
4727 mono_runtime_set_has_tls_get (gboolean val)
4733 mono_runtime_has_tls_get (void)
4739 self_interrupt_thread (void *_unused)
4741 MonoThreadInfo *info = mono_thread_info_current ();
4742 MonoException *exc = mono_thread_execute_interruption ();
4743 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4744 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. */
4745 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4749 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4753 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4757 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4759 MonoJitInfo **dest = (MonoJitInfo **)data;
4765 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4767 MonoJitInfo *ji = NULL;
4772 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4773 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4774 * where we hold runtime locks.
4776 if (!mono_threads_is_coop_enabled ())
4777 mono_thread_info_set_is_async_context (TRUE);
4778 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4779 if (!mono_threads_is_coop_enabled ())
4780 mono_thread_info_set_is_async_context (FALSE);
4785 MonoInternalThread *thread;
4786 gboolean install_async_abort;
4787 MonoThreadInfoInterruptToken *interrupt_token;
4790 static SuspendThreadResult
4791 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4793 AbortThreadData *data = (AbortThreadData *)ud;
4794 MonoInternalThread *thread = data->thread;
4795 MonoJitInfo *ji = NULL;
4796 gboolean protected_wrapper;
4797 gboolean running_managed;
4799 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4800 return MonoResumeThread;
4802 /*someone is already interrupting it*/
4803 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4804 return MonoResumeThread;
4806 InterlockedIncrement (&thread_interruption_requested);
4808 ji = mono_thread_info_get_last_managed (info);
4809 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4810 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4812 if (!protected_wrapper && running_managed) {
4813 /*We are in managed code*/
4814 /*Set the thread to call */
4815 if (data->install_async_abort)
4816 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4817 return MonoResumeThread;
4820 * This will cause waits to be broken.
4821 * It will also prevent the thread from entering a wait, so if the thread returns
4822 * from the wait before it receives the abort signal, it will just spin in the wait
4823 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4826 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4828 return MonoResumeThread;
4833 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4835 AbortThreadData data;
4837 g_assert (thread != mono_thread_internal_current ());
4839 data.thread = thread;
4840 data.install_async_abort = install_async_abort;
4841 data.interrupt_token = NULL;
4843 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4844 if (data.interrupt_token)
4845 mono_thread_info_finish_interrupt (data.interrupt_token);
4846 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4850 self_abort_internal (MonoError *error)
4854 mono_error_init (error);
4856 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4857 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4859 exc = mono_thread_request_interruption (TRUE);
4861 mono_error_set_exception_instance (error, exc);
4863 mono_thread_info_self_interrupt ();
4867 MonoInternalThread *thread;
4869 MonoThreadInfoInterruptToken *interrupt_token;
4870 } SuspendThreadData;
4872 static SuspendThreadResult
4873 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4875 SuspendThreadData *data = (SuspendThreadData *)ud;
4876 MonoInternalThread *thread = data->thread;
4877 MonoJitInfo *ji = NULL;
4878 gboolean protected_wrapper;
4879 gboolean running_managed;
4881 ji = mono_thread_info_get_last_managed (info);
4882 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4883 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4885 if (running_managed && !protected_wrapper) {
4886 thread->state &= ~ThreadState_SuspendRequested;
4887 thread->state |= ThreadState_Suspended;
4888 return KeepSuspended;
4890 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4891 InterlockedIncrement (&thread_interruption_requested);
4892 if (data->interrupt)
4893 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4895 return MonoResumeThread;
4899 /* LOCKING: called with @thread synch_cs held, and releases it */
4901 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4903 SuspendThreadData data;
4905 g_assert (thread != mono_thread_internal_current ());
4907 data.thread = thread;
4908 data.interrupt = interrupt;
4909 data.interrupt_token = NULL;
4911 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4912 if (data.interrupt_token)
4913 mono_thread_info_finish_interrupt (data.interrupt_token);
4915 UNLOCK_THREAD (thread);
4918 /* LOCKING: called with @thread synch_cs held, and releases it */
4920 self_suspend_internal (void)
4922 MonoInternalThread *thread;
4924 thread = mono_thread_internal_current ();
4926 mono_thread_info_begin_self_suspend ();
4927 thread->state &= ~ThreadState_SuspendRequested;
4928 thread->state |= ThreadState_Suspended;
4930 UNLOCK_THREAD (thread);
4932 mono_thread_info_end_self_suspend ();
4936 * mono_thread_is_foreign:
4937 * @thread: the thread to query
4939 * This function allows one to determine if a thread was created by the mono runtime and has
4940 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4942 * Returns: TRUE if @thread was not created by the runtime.
4945 mono_thread_is_foreign (MonoThread *thread)
4947 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4948 return info->runtime_thread == FALSE;
4952 * mono_add_joinable_thread:
4954 * Add TID to the list of joinable threads.
4955 * LOCKING: Acquires the threads lock.
4958 mono_threads_add_joinable_thread (gpointer tid)
4962 * We cannot detach from threads because it causes problems like
4963 * 2fd16f60/r114307. So we collect them and join them when
4964 * we have time (in he finalizer thread).
4966 joinable_threads_lock ();
4967 if (!joinable_threads)
4968 joinable_threads = g_hash_table_new (NULL, NULL);
4969 g_hash_table_insert (joinable_threads, tid, tid);
4970 joinable_thread_count ++;
4971 joinable_threads_unlock ();
4973 mono_gc_finalize_notify ();
4978 * mono_threads_join_threads:
4980 * Join all joinable threads. This is called from the finalizer thread.
4981 * LOCKING: Acquires the threads lock.
4984 mono_threads_join_threads (void)
4987 GHashTableIter iter;
4994 if (!joinable_thread_count)
4998 joinable_threads_lock ();
5000 if (g_hash_table_size (joinable_threads)) {
5001 g_hash_table_iter_init (&iter, joinable_threads);
5002 g_hash_table_iter_next (&iter, &key, (void**)&tid);
5003 thread = (pthread_t)tid;
5004 g_hash_table_remove (joinable_threads, key);
5005 joinable_thread_count --;
5008 joinable_threads_unlock ();
5010 if (thread != pthread_self ()) {
5012 /* This shouldn't block */
5013 pthread_join (thread, NULL);
5026 * Wait for thread TID to exit.
5027 * LOCKING: Acquires the threads lock.
5030 mono_thread_join (gpointer tid)
5034 gboolean found = FALSE;
5036 joinable_threads_lock ();
5037 if (!joinable_threads)
5038 joinable_threads = g_hash_table_new (NULL, NULL);
5039 if (g_hash_table_lookup (joinable_threads, tid)) {
5040 g_hash_table_remove (joinable_threads, tid);
5041 joinable_thread_count --;
5044 joinable_threads_unlock ();
5047 thread = (pthread_t)tid;
5049 pthread_join (thread, NULL);
5055 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
5057 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
5058 mono_thread_interruption_checkpoint ();
5062 mono_thread_internal_unhandled_exception (MonoObject* exc)
5064 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5065 MonoClass *klass = exc->vtable->klass;
5066 if (is_threadabort_exception (klass)) {
5067 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5068 } else if (!is_appdomainunloaded_exception (klass)) {
5069 mono_unhandled_exception (exc);
5070 if (mono_environment_exitcode_get () == 1) {
5071 mono_environment_exitcode_set (255);
5072 mono_invoke_unhandled_exception_hook (exc);
5073 g_assert_not_reached ();
5080 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5083 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5084 mono_error_set_pending_exception (&error);
5088 * mono_threads_attach_coop: called by native->managed wrappers
5092 * - @return: the original domain which needs to be restored, or NULL.
5095 * - @dummy: contains the original domain
5096 * - @return: a cookie containing current MonoThreadInfo*.
5099 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5102 gboolean fresh_thread = FALSE;
5105 /* Happens when called from AOTed code which is only used in the root domain. */
5106 domain = mono_get_root_domain ();
5111 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5112 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5113 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5114 * we're only responsible for making the cookie. */
5115 if (mono_threads_is_coop_enabled ()) {
5116 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5117 fresh_thread = !info || !mono_thread_info_is_live (info);
5120 if (!mono_thread_internal_current ()) {
5121 mono_thread_attach_full (domain, FALSE);
5124 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5127 orig = mono_domain_get ();
5129 mono_domain_set (domain, TRUE);
5131 if (!mono_threads_is_coop_enabled ())
5132 return orig != domain ? orig : NULL;
5136 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5137 * return the right cookie. */
5138 return mono_threads_enter_gc_unsafe_region_cookie ();
5141 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5142 return mono_threads_enter_gc_unsafe_region (dummy);
5147 * mono_threads_detach_coop: called by native->managed wrappers
5150 * - @cookie: the original domain which needs to be restored, or NULL.
5154 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5155 * - @dummy: contains the original domain
5158 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5160 MonoDomain *domain, *orig;
5162 if (!mono_threads_is_coop_enabled ()) {
5163 orig = (MonoDomain*) cookie;
5165 mono_domain_set (orig, TRUE);
5167 orig = (MonoDomain*) *dummy;
5169 domain = mono_domain_get ();
5172 /* it won't do anything if cookie is NULL
5173 * thread state RUNNING -> (RUNNING|BLOCKING) */
5174 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5176 if (orig != domain) {
5178 mono_domain_unset ();
5180 mono_domain_set (orig, TRUE);