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/hazard-pointer.h>
41 #include <mono/utils/mono-tls.h>
42 #include <mono/utils/atomic.h>
43 #include <mono/utils/mono-memory-model.h>
45 #include <mono/metadata/gc-internals.h>
46 #include <mono/metadata/reflection-internals.h>
52 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
53 #define USE_TKILL_ON_ANDROID 1
56 #ifdef PLATFORM_ANDROID
59 #ifdef USE_TKILL_ON_ANDROID
60 extern int tkill (pid_t tid, int signal);
64 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_DEBUG(a)
66 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
67 #define THREAD_WAIT_DEBUG(a)
68 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
69 #define LIBGC_DEBUG(a)
71 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
72 #define SPIN_LOCK(i) do { \
73 if (SPIN_TRYLOCK (i)) \
77 #define SPIN_UNLOCK(i) i = 0
79 #define LOCK_THREAD(thread) lock_thread((thread))
80 #define UNLOCK_THREAD(thread) unlock_thread((thread))
82 /* Provide this for systems with glib < 2.6 */
83 #ifndef G_GSIZE_FORMAT
84 # if GLIB_SIZEOF_LONG == 8
85 # define G_GSIZE_FORMAT "lu"
87 # define G_GSIZE_FORMAT "u"
93 guint32 (*func)(void *);
109 typedef struct _StaticDataFreeList StaticDataFreeList;
110 struct _StaticDataFreeList {
111 StaticDataFreeList *next;
119 StaticDataFreeList *freelist;
122 /* Number of cached culture objects in the MonoThread->cached_culture_info array
123 * (per-type): we use the first NUM entries for CultureInfo and the last for
124 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
126 #define NUM_CACHED_CULTURES 4
127 #define CULTURES_START_IDX 0
128 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
130 /* Controls access to the 'threads' hash table */
131 static void mono_threads_lock (void);
132 static void mono_threads_unlock (void);
133 static MonoCoopMutex threads_mutex;
135 /* Controls access to the 'joinable_threads' hash table */
136 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
137 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
138 static mono_mutex_t joinable_threads_mutex;
140 /* Holds current status of static data heap */
141 static StaticDataInfo thread_static_info;
142 static StaticDataInfo context_static_info;
144 /* The hash of existing threads (key is thread ID, value is
145 * MonoInternalThread*) that need joining before exit
147 static MonoGHashTable *threads=NULL;
149 /* List of app context GC handles.
150 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
152 static GHashTable *contexts = NULL;
154 /* Cleanup queue for contexts. */
155 static MonoReferenceQueue *context_queue;
158 * Threads which are starting up and they are not in the 'threads' hash yet.
159 * When handle_store is called for a thread, it will be removed from this hash table.
160 * Protected by mono_threads_lock ().
162 static MonoGHashTable *threads_starting_up = NULL;
164 /* The TLS key that holds the MonoObject assigned to each thread */
165 static MonoNativeTlsKey current_object_key;
168 /* Protected by the threads lock */
169 static GHashTable *joinable_threads;
170 static int joinable_thread_count;
172 #ifdef MONO_HAVE_FAST_TLS
173 /* we need to use both the Tls* functions and __thread because
174 * the gc needs to see all the threads
176 MONO_FAST_TLS_DECLARE(tls_current_object);
177 #define SET_CURRENT_OBJECT(x) do { \
178 MONO_FAST_TLS_SET (tls_current_object, x); \
179 mono_native_tls_set_value (current_object_key, x); \
181 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
183 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
184 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
187 /* function called at thread start */
188 static MonoThreadStartCB mono_thread_start_cb = NULL;
190 /* function called at thread attach */
191 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
193 /* function called at thread cleanup */
194 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
196 /* The default stack size for each thread */
197 static guint32 default_stacksize = 0;
198 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
200 static void thread_adjust_static_data (MonoInternalThread *thread);
201 static void context_adjust_static_data (MonoAppContext *ctx);
202 static void mono_free_static_data (gpointer* static_data);
203 static void mono_init_static_data_info (StaticDataInfo *static_data);
204 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
205 static gboolean mono_thread_resume (MonoInternalThread* thread);
206 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
207 static void self_abort_internal (void);
208 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
209 static void self_suspend_internal (void);
211 static MonoException* mono_thread_execute_interruption (void);
212 static void ref_stack_destroy (gpointer rs);
214 /* Spin lock for InterlockedXXX 64 bit functions */
215 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
216 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
217 static mono_mutex_t interlocked_mutex;
219 /* global count of thread interruptions requested */
220 static gint32 thread_interruption_requested = 0;
222 /* Event signaled when a thread changes its background mode */
223 static HANDLE background_change_event;
225 static gboolean shutting_down = FALSE;
227 static gint32 managed_thread_id_counter = 0;
229 /* Class lazy loading functions */
230 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
233 mono_threads_lock (void)
235 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
239 mono_threads_unlock (void)
241 mono_locks_coop_release (&threads_mutex, ThreadsLock);
246 get_next_managed_thread_id (void)
248 return InterlockedIncrement (&managed_thread_id_counter);
252 mono_thread_get_tls_key (void)
254 return current_object_key;
258 mono_thread_get_tls_offset (void)
261 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
265 static inline MonoNativeThreadId
266 thread_get_tid (MonoInternalThread *thread)
268 /* We store the tid as a guint64 to keep the object layout constant between platforms */
269 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
272 /* handle_store() and handle_remove() manage the array of threads that
273 * still need to be waited for when the main thread exits.
275 * If handle_store() returns FALSE the thread must not be started
276 * because Mono is shutting down.
278 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
280 mono_threads_lock ();
282 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
284 if (threads_starting_up)
285 mono_g_hash_table_remove (threads_starting_up, thread);
287 if (shutting_down && !force_attach) {
288 mono_threads_unlock ();
293 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
294 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
297 /* We don't need to duplicate thread->handle, because it is
298 * only closed when the thread object is finalized by the GC.
300 g_assert (thread->internal_thread);
301 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
302 thread->internal_thread);
304 mono_threads_unlock ();
309 static gboolean handle_remove(MonoInternalThread *thread)
312 gsize tid = thread->tid;
314 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
316 mono_threads_lock ();
319 /* We have to check whether the thread object for the
320 * tid is still the same in the table because the
321 * thread might have been destroyed and the tid reused
322 * in the meantime, in which case the tid would be in
323 * the table, but with another thread object.
325 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
326 mono_g_hash_table_remove (threads, (gpointer)tid);
335 mono_threads_unlock ();
337 /* Don't close the handle here, wait for the object finalizer
338 * to do it. Otherwise, the following race condition applies:
340 * 1) Thread exits (and handle_remove() closes the handle)
342 * 2) Some other handle is reassigned the same slot
344 * 3) Another thread tries to join the first thread, and
345 * blocks waiting for the reassigned handle to be signalled
346 * (which might never happen). This is possible, because the
347 * thread calling Join() still has a reference to the first
353 static void ensure_synch_cs_set (MonoInternalThread *thread)
355 MonoCoopMutex *synch_cs;
357 if (thread->synch_cs != NULL) {
361 synch_cs = g_new0 (MonoCoopMutex, 1);
362 mono_coop_mutex_init_recursive (synch_cs);
364 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
365 synch_cs, NULL) != NULL) {
366 /* Another thread must have installed this CS */
367 mono_coop_mutex_destroy (synch_cs);
373 lock_thread (MonoInternalThread *thread)
375 if (!thread->synch_cs)
376 ensure_synch_cs_set (thread);
378 g_assert (thread->synch_cs);
380 mono_coop_mutex_lock (thread->synch_cs);
384 unlock_thread (MonoInternalThread *thread)
386 mono_coop_mutex_unlock (thread->synch_cs);
390 * NOTE: this function can be called also for threads different from the current one:
391 * make sure no code called from it will ever assume it is run on the thread that is
392 * getting cleaned up.
394 static void thread_cleanup (MonoInternalThread *thread)
396 g_assert (thread != NULL);
398 if (thread->abort_state_handle) {
399 mono_gchandle_free (thread->abort_state_handle);
400 thread->abort_state_handle = 0;
402 thread->abort_exc = NULL;
403 thread->current_appcontext = NULL;
406 * This is necessary because otherwise we might have
407 * cross-domain references which will not get cleaned up when
408 * the target domain is unloaded.
410 if (thread->cached_culture_info) {
412 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
413 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
417 * thread->synch_cs can be NULL if this was called after
418 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
419 * This can happen only during shutdown.
420 * The shutting_down flag is not always set, so we can't assert on it.
422 if (thread->synch_cs)
423 LOCK_THREAD (thread);
425 thread->state |= ThreadState_Stopped;
426 thread->state &= ~ThreadState_Background;
428 if (thread->synch_cs)
429 UNLOCK_THREAD (thread);
432 An interruption request has leaked to cleanup. Adjust the global counter.
434 This can happen is the abort source thread finds the abortee (this) thread
435 in unmanaged code. If this thread never trips back to managed code or check
436 the local flag it will be left set and positively unbalance the global counter.
438 Leaving the counter unbalanced will cause a performance degradation since all threads
439 will now keep checking their local flags all the time.
441 if (InterlockedExchange (&thread->interruption_requested, 0))
442 InterlockedDecrement (&thread_interruption_requested);
444 /* if the thread is not in the hash it has been removed already */
445 if (!handle_remove (thread)) {
446 if (thread == mono_thread_internal_current ()) {
447 mono_domain_unset ();
448 mono_memory_barrier ();
450 /* This needs to be called even if handle_remove () fails */
451 if (mono_thread_cleanup_fn)
452 mono_thread_cleanup_fn (thread_get_tid (thread));
455 mono_release_type_locks (thread);
457 /* Can happen when we attach the profiler helper thread in order to heapshot. */
458 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
459 mono_profiler_thread_end (thread->tid);
461 if (thread == mono_thread_internal_current ()) {
463 * This will signal async signal handlers that the thread has exited.
464 * The profiler callback needs this to be set, so it cannot be done earlier.
466 mono_domain_unset ();
467 mono_memory_barrier ();
470 if (thread == mono_thread_internal_current ())
471 mono_thread_pop_appdomain_ref ();
473 thread->cached_culture_info = NULL;
475 mono_free_static_data (thread->static_data);
476 thread->static_data = NULL;
477 ref_stack_destroy (thread->appdomain_refs);
478 thread->appdomain_refs = NULL;
480 if (mono_thread_cleanup_fn)
481 mono_thread_cleanup_fn (thread_get_tid (thread));
483 if (mono_gc_is_moving ()) {
484 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
485 thread->thread_pinning_ref = NULL;
491 * A special static data offset (guint32) consists of 3 parts:
493 * [0] 6-bit index into the array of chunks.
494 * [6] 25-bit offset into the array.
495 * [31] Bit indicating thread or context static.
500 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
511 } SpecialStaticOffset;
513 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
514 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
516 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
517 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
518 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
519 (((SpecialStaticOffset *) &(x))->fields.f)
522 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
524 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
526 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
527 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
529 return ((char *) thread->static_data [idx]) + off;
533 get_context_static_data (MonoAppContext *ctx, guint32 offset)
535 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
537 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
538 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
540 return ((char *) ctx->static_data [idx]) + off;
544 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
546 static MonoClassField *current_thread_field = NULL;
550 if (!current_thread_field) {
551 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
552 g_assert (current_thread_field);
555 mono_class_vtable (domain, mono_defaults.thread_class);
556 mono_domain_lock (domain);
557 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
558 mono_domain_unlock (domain);
561 return (MonoThread **)get_thread_static_data (thread, offset);
565 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
567 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
569 g_assert (current->obj.vtable->domain == domain);
571 g_assert (!*current_thread_ptr);
572 *current_thread_ptr = current;
576 create_thread_object (MonoDomain *domain, MonoError *error)
578 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
579 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, error);
584 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal, MonoError *error)
588 thread = create_thread_object (domain, error);
589 if (!mono_error_ok (error))
592 MONO_OBJECT_SETREF (thread, internal_thread, internal);
597 static MonoInternalThread*
598 create_internal_thread (MonoError *error)
600 MonoInternalThread *thread;
603 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
604 thread = (MonoInternalThread*) mono_object_new_mature (vt, error);
605 if (!mono_error_ok (error))
608 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
609 mono_coop_mutex_init_recursive (thread->synch_cs);
611 thread->apartment_state = ThreadApartmentState_Unknown;
612 thread->managed_id = get_next_managed_thread_id ();
613 if (mono_gc_is_moving ()) {
614 thread->thread_pinning_ref = thread;
615 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
622 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate, MonoError *error)
624 MonoDomain *domain = mono_get_root_domain ();
626 mono_error_init (error);
627 if (!candidate || candidate->obj.vtable->domain != domain) {
628 candidate = new_thread_with_internal (domain, thread, error);
629 return_val_if_nok (error, FALSE);
631 set_current_thread_for_domain (domain, thread, candidate);
632 g_assert (!thread->root_domain_thread);
633 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
637 static guint32 WINAPI start_wrapper_internal(void *data)
640 MonoThreadInfo *info;
641 StartInfo *start_info = (StartInfo *)data;
642 guint32 (*start_func)(void *);
646 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
649 MonoInternalThread *internal = start_info->obj->internal_thread;
650 MonoObject *start_delegate = start_info->delegate;
651 MonoDomain *domain = start_info->obj->obj.vtable->domain;
653 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
655 /* We can be sure start_info->obj->tid and
656 * start_info->obj->handle have been set, because the thread
657 * was created suspended, and these values were set before the
661 info = mono_thread_info_current ();
663 internal->thread_info = info;
664 internal->small_id = info->small_id;
668 SET_CURRENT_OBJECT (internal);
670 /* Every thread references the appdomain which created it */
671 mono_thread_push_appdomain_ref (domain);
673 if (!mono_domain_set (domain, FALSE)) {
674 /* No point in raising an appdomain_unloaded exception here */
675 /* FIXME: Cleanup here */
676 mono_thread_pop_appdomain_ref ();
680 start_func = start_info->func;
681 start_arg = start_info->obj->start_obj;
683 start_arg = start_info->start_arg;
685 /* We have to do this here because mono_thread_new_init()
686 requires that root_domain_thread is set up. */
687 thread_adjust_static_data (internal);
688 init_root_domain_thread (internal, start_info->obj, &error);
689 mono_error_raise_exception (&error); /* FIXME don't raise here */
691 /* This MUST be called before any managed code can be
692 * executed, as it calls the callback function that (for the
693 * jit) sets the lmf marker.
695 mono_thread_new_init (tid, &tid, start_func);
696 internal->stack_ptr = &tid;
697 if (domain != mono_get_root_domain ())
698 set_current_thread_for_domain (domain, internal, start_info->obj);
700 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
702 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
704 /* On 2.0 profile (and higher), set explicitly since state might have been
706 if (internal->apartment_state == ThreadApartmentState_Unknown)
707 internal->apartment_state = ThreadApartmentState_MTA;
709 mono_thread_init_apartment_state ();
711 if(internal->start_notify!=NULL) {
712 /* Let the thread that called Start() know we're
715 ReleaseSemaphore (internal->start_notify, 1, NULL);
719 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
723 * Call this after calling start_notify, since the profiler callback might want
724 * to lock the thread, and the lock is held by thread_start () which waits for
727 mono_profiler_thread_start (tid);
729 /* if the name was set before starting, we didn't invoke the profiler callback */
730 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
731 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
732 mono_profiler_thread_name (internal->tid, tname);
733 mono_thread_info_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
736 /* start_func is set only for unmanaged start functions */
738 start_func (start_arg);
741 g_assert (start_delegate != NULL);
742 args [0] = start_arg;
743 /* we may want to handle the exception here. See comment below on unhandled exceptions */
744 mono_runtime_delegate_invoke (start_delegate, args, NULL);
747 /* If the thread calls ExitThread at all, this remaining code
748 * will not be executed, but the main thread will eventually
749 * call thread_cleanup() on this thread's behalf.
752 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
754 /* Do any cleanup needed for apartment state. This
755 * cannot be done in thread_cleanup since thread_cleanup could be
756 * called for a thread other than the current thread.
757 * mono_thread_cleanup_apartment_state cleans up apartment
758 * for the current thead */
759 mono_thread_cleanup_apartment_state ();
761 thread_cleanup (internal);
765 /* Remove the reference to the thread object in the TLS data,
766 * so the thread object can be finalized. This won't be
767 * reached if the thread threw an uncaught exception, so those
768 * thread handles will stay referenced :-( (This is due to
769 * missing support for scanning thread-specific data in the
770 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
773 SET_CURRENT_OBJECT (NULL);
778 static guint32 WINAPI start_wrapper(void *data)
782 /* Avoid scanning the frames above this frame during a GC */
783 mono_gc_set_stack_end ((void*)&dummy);
785 return start_wrapper_internal (data);
791 * Common thread creation code.
792 * LOCKING: Acquires the threads lock.
795 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
798 HANDLE thread_handle;
799 MonoNativeThreadId tid;
800 guint32 create_flags;
803 * Join joinable threads to prevent running out of threads since the finalizer
804 * thread might be blocked/backlogged.
806 mono_threads_join_threads ();
808 mono_error_init (error);
810 mono_threads_lock ();
813 mono_threads_unlock ();
816 if (threads_starting_up == NULL) {
817 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
818 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
820 mono_g_hash_table_insert (threads_starting_up, thread, thread);
821 mono_threads_unlock ();
823 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
824 if (!internal->start_notify) {
825 mono_threads_lock ();
826 mono_g_hash_table_remove (threads_starting_up, thread);
827 mono_threads_unlock ();
828 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
834 stack_size = default_stacksize_for_thread (internal);
836 /* Create suspended, so we can do some housekeeping before the thread
839 create_flags = CREATE_SUSPENDED;
841 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
842 stack_size, create_flags, &tid);
844 if (thread_handle == NULL) {
845 /* The thread couldn't be created, so set an exception */
846 mono_threads_lock ();
847 mono_g_hash_table_remove (threads_starting_up, thread);
848 mono_threads_unlock ();
850 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
853 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
855 internal->handle = thread_handle;
856 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
858 internal->threadpool_thread = threadpool_thread;
859 if (threadpool_thread)
860 mono_thread_set_state (internal, ThreadState_Background);
862 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
864 /* Only store the handle when the thread is about to be
865 * launched, to avoid the main thread deadlocking while trying
866 * to clean up a thread that will never be signalled.
868 if (!handle_store (thread, FALSE))
871 mono_thread_info_resume (tid);
873 if (internal->start_notify) {
875 * Wait for the thread to set up its TLS data etc, so
876 * theres no potential race condition if someone tries
877 * to look up the data believing the thread has
880 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));
882 MONO_PREPARE_BLOCKING;
883 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
884 MONO_FINISH_BLOCKING;
886 CloseHandle (internal->start_notify);
887 internal->start_notify = NULL;
890 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));
895 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
897 if (mono_thread_start_cb) {
898 mono_thread_start_cb (tid, stack_start, func);
902 void mono_threads_set_default_stacksize (guint32 stacksize)
904 default_stacksize = stacksize;
907 guint32 mono_threads_get_default_stacksize (void)
909 return default_stacksize;
913 * mono_thread_create_internal:
915 * ARG should not be a GC reference.
918 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
921 MonoInternalThread *internal;
922 StartInfo *start_info;
925 mono_error_init (error);
927 thread = create_thread_object (domain, error);
928 return_val_if_nok (error, NULL);
930 internal = create_internal_thread (error);
931 return_val_if_nok (error, NULL);
933 MONO_OBJECT_SETREF (thread, internal_thread, internal);
935 start_info = g_new0 (StartInfo, 1);
936 start_info->func = (guint32 (*)(void *))func;
937 start_info->obj = thread;
938 start_info->start_arg = arg;
940 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, error);
941 return_val_if_nok (error, NULL);
943 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
944 #ifndef MONO_CROSS_COMPILE
945 if (mono_check_corlib_version () == NULL)
946 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
953 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
956 if (!mono_thread_create_checked (domain, func, arg, &error))
957 mono_error_cleanup (&error);
961 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
963 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
967 mono_thread_attach (MonoDomain *domain)
970 MonoThread *thread = mono_thread_attach_full (domain, FALSE, &error);
971 mono_error_raise_exception (&error);
977 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach, MonoError *error)
979 MonoThreadInfo *info;
980 MonoInternalThread *thread;
981 MonoThread *current_thread;
982 HANDLE thread_handle;
983 MonoNativeThreadId tid;
985 mono_error_init (error);
987 if ((thread = mono_thread_internal_current ())) {
988 if (domain != mono_domain_get ())
989 mono_domain_set (domain, TRUE);
990 /* Already attached */
991 return mono_thread_current ();
994 if (!mono_gc_register_thread (&domain)) {
995 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 ());
998 thread = create_internal_thread (error);
999 if (!mono_error_ok (error))
1002 thread_handle = mono_thread_info_open_handle ();
1003 g_assert (thread_handle);
1005 tid=mono_native_thread_id_get ();
1007 thread->handle = thread_handle;
1008 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
1009 thread->stack_ptr = &tid;
1011 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
1013 info = mono_thread_info_current ();
1015 thread->thread_info = info;
1016 thread->small_id = info->small_id;
1018 current_thread = new_thread_with_internal (domain, thread, error);
1019 if (!mono_error_ok (error))
1022 if (!handle_store (current_thread, force_attach)) {
1023 /* Mono is shutting down, so just wait for the end */
1025 mono_thread_info_sleep (10000, NULL);
1028 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
1030 SET_CURRENT_OBJECT (thread);
1031 mono_domain_set (domain, TRUE);
1033 thread_adjust_static_data (thread);
1035 init_root_domain_thread (thread, current_thread, error);
1036 return_val_if_nok (error, NULL);
1038 if (domain != mono_get_root_domain ())
1039 set_current_thread_for_domain (domain, thread, current_thread);
1042 if (mono_thread_attach_cb) {
1046 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1049 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1051 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1054 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1055 if (!info->tools_thread)
1056 // FIXME: Need a separate callback
1057 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1059 return current_thread;
1063 mono_thread_detach_internal (MonoInternalThread *thread)
1065 g_return_if_fail (thread != NULL);
1067 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1069 thread_cleanup (thread);
1071 SET_CURRENT_OBJECT (NULL);
1072 mono_domain_unset ();
1074 /* Don't need to CloseHandle this thread, even though we took a
1075 * reference in mono_thread_attach (), because the GC will do it
1076 * when the Thread object is finalised.
1081 mono_thread_detach (MonoThread *thread)
1084 mono_thread_detach_internal (thread->internal_thread);
1088 * mono_thread_detach_if_exiting:
1090 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1091 * This should be used at the end of embedding code which calls into managed code, and which
1092 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1095 mono_thread_detach_if_exiting (void)
1097 if (mono_thread_info_is_exiting ()) {
1098 MonoInternalThread *thread;
1100 thread = mono_thread_internal_current ();
1102 mono_thread_detach_internal (thread);
1103 mono_thread_info_detach ();
1111 MonoInternalThread *thread = mono_thread_internal_current ();
1113 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1115 thread_cleanup (thread);
1116 SET_CURRENT_OBJECT (NULL);
1117 mono_domain_unset ();
1119 /* we could add a callback here for embedders to use. */
1120 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1121 exit (mono_environment_exitcode_get ());
1122 mono_thread_info_exit ();
1126 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1129 MonoInternalThread *internal;
1131 internal = create_internal_thread (&error);
1132 mono_error_raise_exception (&error);
1134 internal->state = ThreadState_Unstarted;
1136 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1140 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1144 StartInfo *start_info;
1145 MonoInternalThread *internal;
1148 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1150 if (!this_obj->internal_thread)
1151 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1152 internal = this_obj->internal_thread;
1154 LOCK_THREAD (internal);
1156 if ((internal->state & ThreadState_Unstarted) == 0) {
1157 UNLOCK_THREAD (internal);
1158 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1162 if ((internal->state & ThreadState_Aborted) != 0) {
1163 UNLOCK_THREAD (internal);
1166 /* This is freed in start_wrapper */
1167 start_info = g_new0 (StartInfo, 1);
1168 start_info->func = NULL;
1169 start_info->start_arg = NULL;
1170 start_info->delegate = start;
1171 start_info->obj = this_obj;
1172 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1174 res = create_thread (this_obj, internal, start_info, FALSE, 0, &error);
1176 mono_error_cleanup (&error);
1177 UNLOCK_THREAD (internal);
1181 internal->state &= ~ThreadState_Unstarted;
1183 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1185 UNLOCK_THREAD (internal);
1186 return internal->handle;
1190 * This is called from the finalizer of the internal thread object.
1193 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1195 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1198 * Since threads keep a reference to their thread object while running, by the time this function is called,
1199 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1200 * when thread_cleanup () can be called after this.
1203 CloseHandle (thread);
1205 if (this_obj->synch_cs) {
1206 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1207 this_obj->synch_cs = NULL;
1208 mono_coop_mutex_destroy (synch_cs);
1212 if (this_obj->name) {
1213 void *name = this_obj->name;
1214 this_obj->name = NULL;
1220 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1223 MonoInternalThread *thread = mono_thread_internal_current ();
1225 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1227 mono_thread_current_check_pending_interrupt ();
1230 gboolean alerted = FALSE;
1232 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1234 res = mono_thread_info_sleep (ms, &alerted);
1236 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1239 MonoException* exc = mono_thread_execute_interruption ();
1241 mono_raise_exception (exc);
1253 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1258 ves_icall_System_Threading_Thread_GetDomainID (void)
1260 return mono_domain_get()->domain_id;
1264 ves_icall_System_Threading_Thread_Yield (void)
1266 return mono_thread_info_yield ();
1270 * mono_thread_get_name:
1272 * Return the name of the thread. NAME_LEN is set to the length of the name.
1273 * Return NULL if the thread has no name. The returned memory is owned by the
1277 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1281 LOCK_THREAD (this_obj);
1283 if (!this_obj->name) {
1287 *name_len = this_obj->name_len;
1288 res = g_new (gunichar2, this_obj->name_len);
1289 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1292 UNLOCK_THREAD (this_obj);
1298 * mono_thread_get_name_utf8:
1300 * Return the name of the thread in UTF-8.
1301 * Return NULL if the thread has no name.
1302 * The returned memory is owned by the caller.
1305 mono_thread_get_name_utf8 (MonoThread *thread)
1310 MonoInternalThread *internal = thread->internal_thread;
1311 if (internal == NULL)
1314 LOCK_THREAD (internal);
1316 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1318 UNLOCK_THREAD (internal);
1324 * mono_thread_get_managed_id:
1326 * Return the Thread.ManagedThreadId value of `thread`.
1327 * Returns -1 if `thread` is NULL.
1330 mono_thread_get_managed_id (MonoThread *thread)
1335 MonoInternalThread *internal = thread->internal_thread;
1336 if (internal == NULL)
1339 int32_t id = internal->managed_id;
1345 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1350 mono_error_init (&error);
1352 LOCK_THREAD (this_obj);
1354 if (!this_obj->name)
1357 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1359 UNLOCK_THREAD (this_obj);
1361 mono_error_raise_exception (&error);
1367 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed, MonoError *error)
1369 LOCK_THREAD (this_obj);
1371 mono_error_init (error);
1373 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1374 UNLOCK_THREAD (this_obj);
1376 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1379 if (this_obj->name) {
1380 g_free (this_obj->name);
1381 this_obj->name_len = 0;
1384 this_obj->name = g_new (gunichar2, mono_string_length (name));
1385 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1386 this_obj->name_len = mono_string_length (name);
1389 this_obj->name = NULL;
1392 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1394 UNLOCK_THREAD (this_obj);
1396 if (this_obj->name && this_obj->tid) {
1397 char *tname = mono_string_to_utf8 (name);
1398 mono_profiler_thread_name (this_obj->tid, tname);
1399 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1405 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1408 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1409 mono_error_set_pending_exception (&error);
1413 * ves_icall_System_Threading_Thread_GetPriority_internal:
1414 * @param this_obj: The MonoInternalThread on which to operate.
1416 * Gets the priority of the given thread.
1417 * @return: The priority of the given thread.
1420 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1423 MonoInternalThread *internal = this_obj->internal_thread;
1425 LOCK_THREAD (internal);
1426 priority = GetThreadPriority (internal->handle) + 2;
1427 UNLOCK_THREAD (internal);
1432 * ves_icall_System_Threading_Thread_SetPriority_internal:
1433 * @param this_obj: The MonoInternalThread on which to operate.
1434 * @param priority: The priority to set.
1436 * Sets the priority of the given thread.
1439 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1441 MonoInternalThread *internal = this_obj->internal_thread;
1443 LOCK_THREAD (internal);
1444 SetThreadPriority (internal->handle, priority - 2);
1445 UNLOCK_THREAD (internal);
1448 /* If the array is already in the requested domain, we just return it,
1449 otherwise we return a copy in that domain. */
1451 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1455 mono_error_init (error);
1459 if (mono_object_domain (arr) == domain)
1462 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1463 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1468 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1471 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1472 mono_error_set_pending_exception (&error);
1477 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1480 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1481 mono_error_set_pending_exception (&error);
1486 mono_thread_current (void)
1489 MonoDomain *domain = mono_domain_get ();
1490 MonoInternalThread *internal = mono_thread_internal_current ();
1491 MonoThread **current_thread_ptr;
1493 g_assert (internal);
1494 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1496 if (!*current_thread_ptr) {
1497 g_assert (domain != mono_get_root_domain ());
1498 *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
1499 mono_error_raise_exception (&error); /* FIXME don't raise here */
1501 return *current_thread_ptr;
1504 /* Return the thread object belonging to INTERNAL in the current domain */
1506 mono_thread_current_for_thread (MonoInternalThread *internal)
1509 MonoDomain *domain = mono_domain_get ();
1510 MonoThread **current_thread_ptr;
1512 g_assert (internal);
1513 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1515 if (!*current_thread_ptr) {
1516 g_assert (domain != mono_get_root_domain ());
1517 *current_thread_ptr = new_thread_with_internal (domain, internal, &error);
1518 mono_error_raise_exception (&error); /* FIXME don't raise here */
1520 return *current_thread_ptr;
1524 mono_thread_internal_current (void)
1526 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1527 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1532 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1534 MonoInternalThread *thread = this_obj->internal_thread;
1535 HANDLE handle = thread->handle;
1536 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1539 mono_thread_current_check_pending_interrupt ();
1541 LOCK_THREAD (thread);
1543 if ((thread->state & ThreadState_Unstarted) != 0) {
1544 UNLOCK_THREAD (thread);
1546 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1550 UNLOCK_THREAD (thread);
1555 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1557 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1559 MONO_PREPARE_BLOCKING;
1560 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1561 MONO_FINISH_BLOCKING;
1563 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1565 if(ret==WAIT_OBJECT_0) {
1566 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1571 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1577 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1585 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1587 MONO_PREPARE_BLOCKING;
1589 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1591 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1592 MONO_FINISH_BLOCKING;
1594 if (ret != WAIT_IO_COMPLETION)
1597 exc = mono_thread_execute_interruption ();
1599 mono_raise_exception (exc);
1604 /* Re-calculate ms according to the time passed */
1605 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1606 if (diff_ms >= ms) {
1610 wait = ms - diff_ms;
1616 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1622 MonoObject *waitHandle;
1623 MonoInternalThread *thread = mono_thread_internal_current ();
1625 /* Do this WaitSleepJoin check before creating objects */
1626 mono_thread_current_check_pending_interrupt ();
1628 /* We fail in managed if the array has more than 64 elements */
1629 numhandles = (guint32)mono_array_length(mono_handles);
1630 handles = g_new0(HANDLE, numhandles);
1632 for(i = 0; i < numhandles; i++) {
1633 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1634 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1641 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1643 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1645 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1649 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1650 return ret == WAIT_FAILED ? 0x7fffffff : ret;
1653 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1655 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1656 uintptr_t numhandles;
1659 MonoObject *waitHandle;
1660 MonoInternalThread *thread = mono_thread_internal_current ();
1662 /* Do this WaitSleepJoin check before creating objects */
1663 mono_thread_current_check_pending_interrupt ();
1665 numhandles = mono_array_length(mono_handles);
1666 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1669 for(i = 0; i < numhandles; i++) {
1670 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1671 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1678 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1680 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1682 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1684 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1687 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1689 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1690 return ret - WAIT_OBJECT_0;
1692 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1693 return ret - WAIT_ABANDONED_0;
1696 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1697 return ret == WAIT_FAILED ? 0x7fffffff : ret;
1701 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1704 MonoInternalThread *thread = mono_thread_internal_current ();
1706 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1712 mono_thread_current_check_pending_interrupt ();
1714 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1716 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1718 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1720 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1721 return ret == WAIT_FAILED ? 0x7fffffff : ret;
1725 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1728 MonoInternalThread *thread = mono_thread_internal_current ();
1733 mono_thread_current_check_pending_interrupt ();
1735 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1737 MONO_PREPARE_BLOCKING;
1738 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1739 MONO_FINISH_BLOCKING;
1741 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1743 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1744 return ret == WAIT_FAILED ? 0x7fffffff : ret;
1747 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1754 mutex = CreateMutex (NULL, owned, NULL);
1756 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1758 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1766 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1767 return(ReleaseMutex (handle));
1770 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1776 *error = ERROR_SUCCESS;
1778 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1780 *error = GetLastError ();
1787 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1794 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1796 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1797 mono_string_chars (name));
1799 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1807 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1811 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1816 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1820 *error = ERROR_SUCCESS;
1822 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1824 *error = GetLastError ();
1830 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1837 event = CreateEvent (NULL, manual, initial, NULL);
1839 event = CreateEvent (NULL, manual, initial,
1840 mono_string_chars (name));
1842 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1850 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1851 return (SetEvent(handle));
1854 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1855 return (ResetEvent(handle));
1859 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1860 CloseHandle (handle);
1863 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1869 *error = ERROR_SUCCESS;
1871 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1873 *error = GetLastError ();
1879 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1881 return InterlockedIncrement (location);
1884 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1886 #if SIZEOF_VOID_P == 4
1887 if (G_UNLIKELY ((size_t)location & 0x7)) {
1889 mono_interlocked_lock ();
1892 mono_interlocked_unlock ();
1896 return InterlockedIncrement64 (location);
1899 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1901 return InterlockedDecrement(location);
1904 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1906 #if SIZEOF_VOID_P == 4
1907 if (G_UNLIKELY ((size_t)location & 0x7)) {
1909 mono_interlocked_lock ();
1912 mono_interlocked_unlock ();
1916 return InterlockedDecrement64 (location);
1919 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1921 return InterlockedExchange(location, value);
1924 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1927 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1928 mono_gc_wbarrier_generic_nostore (location);
1932 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1934 return InterlockedExchangePointer(location, value);
1937 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1939 IntFloatUnion val, ret;
1942 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1948 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1950 #if SIZEOF_VOID_P == 4
1951 if (G_UNLIKELY ((size_t)location & 0x7)) {
1953 mono_interlocked_lock ();
1956 mono_interlocked_unlock ();
1960 return InterlockedExchange64 (location, value);
1964 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1966 LongDoubleUnion val, ret;
1969 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1974 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1976 return InterlockedCompareExchange(location, value, comparand);
1979 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1981 gint32 r = InterlockedCompareExchange(location, value, comparand);
1982 *success = r == comparand;
1986 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1989 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1990 mono_gc_wbarrier_generic_nostore (location);
1994 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1996 return InterlockedCompareExchangePointer(location, value, comparand);
1999 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2001 IntFloatUnion val, ret, cmp;
2004 cmp.fval = comparand;
2005 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2011 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2013 #if SIZEOF_VOID_P == 8
2014 LongDoubleUnion val, comp, ret;
2017 comp.fval = comparand;
2018 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2024 mono_interlocked_lock ();
2026 if (old == comparand)
2028 mono_interlocked_unlock ();
2035 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2037 #if SIZEOF_VOID_P == 4
2038 if (G_UNLIKELY ((size_t)location & 0x7)) {
2040 mono_interlocked_lock ();
2042 if (old == comparand)
2044 mono_interlocked_unlock ();
2048 return InterlockedCompareExchange64 (location, value, comparand);
2052 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2055 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2056 mono_gc_wbarrier_generic_nostore (location);
2061 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2064 MONO_CHECK_NULL (location, NULL);
2065 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2066 mono_gc_wbarrier_generic_nostore (location);
2071 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2073 return InterlockedAdd (location, value);
2077 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2079 #if SIZEOF_VOID_P == 4
2080 if (G_UNLIKELY ((size_t)location & 0x7)) {
2082 mono_interlocked_lock ();
2085 mono_interlocked_unlock ();
2089 return InterlockedAdd64 (location, value);
2093 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2095 #if SIZEOF_VOID_P == 4
2096 if (G_UNLIKELY ((size_t)location & 0x7)) {
2098 mono_interlocked_lock ();
2100 mono_interlocked_unlock ();
2104 return InterlockedRead64 (location);
2108 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2110 mono_memory_barrier ();
2114 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2116 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2118 if (state & ThreadState_Background) {
2119 /* If the thread changes the background mode, the main thread has to
2120 * be notified, since it has to rebuild the list of threads to
2123 SetEvent (background_change_event);
2128 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2130 mono_thread_set_state (this_obj, (MonoThreadState)state);
2132 if (state & ThreadState_Background) {
2133 /* If the thread changes the background mode, the main thread has to
2134 * be notified, since it has to rebuild the list of threads to
2137 SetEvent (background_change_event);
2142 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2146 LOCK_THREAD (this_obj);
2148 state = this_obj->state;
2150 UNLOCK_THREAD (this_obj);
2155 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2157 MonoInternalThread *current;
2159 MonoInternalThread *thread = this_obj->internal_thread;
2161 LOCK_THREAD (thread);
2163 current = mono_thread_internal_current ();
2165 thread->thread_interrupt_requested = TRUE;
2166 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2168 UNLOCK_THREAD (thread);
2171 async_abort_internal (thread, FALSE);
2175 void mono_thread_current_check_pending_interrupt ()
2177 MonoInternalThread *thread = mono_thread_internal_current ();
2178 gboolean throw_ = FALSE;
2180 LOCK_THREAD (thread);
2182 if (thread->thread_interrupt_requested) {
2184 thread->thread_interrupt_requested = FALSE;
2187 UNLOCK_THREAD (thread);
2190 mono_raise_exception (mono_get_exception_thread_interrupted ());
2195 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2197 LOCK_THREAD (thread);
2199 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2200 (thread->state & ThreadState_StopRequested) != 0 ||
2201 (thread->state & ThreadState_Stopped) != 0)
2203 UNLOCK_THREAD (thread);
2207 if ((thread->state & ThreadState_Unstarted) != 0) {
2208 thread->state |= ThreadState_Aborted;
2209 UNLOCK_THREAD (thread);
2213 thread->state |= ThreadState_AbortRequested;
2214 if (thread->abort_state_handle)
2215 mono_gchandle_free (thread->abort_state_handle);
2217 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2218 g_assert (thread->abort_state_handle);
2220 thread->abort_state_handle = 0;
2222 thread->abort_exc = NULL;
2224 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));
2226 /* During shutdown, we can't wait for other threads */
2228 /* Make sure the thread is awake */
2229 mono_thread_resume (thread);
2231 UNLOCK_THREAD (thread);
2233 if (thread == mono_thread_internal_current ())
2234 self_abort_internal ();
2236 async_abort_internal (thread, TRUE);
2240 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2242 MonoInternalThread *thread = mono_thread_internal_current ();
2243 gboolean was_aborting;
2245 LOCK_THREAD (thread);
2246 was_aborting = thread->state & ThreadState_AbortRequested;
2247 thread->state &= ~ThreadState_AbortRequested;
2248 UNLOCK_THREAD (thread);
2250 if (!was_aborting) {
2251 const char *msg = "Unable to reset abort because no abort was requested";
2252 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2255 thread->abort_exc = NULL;
2256 if (thread->abort_state_handle) {
2257 mono_gchandle_free (thread->abort_state_handle);
2258 /* This is actually not necessary - the handle
2259 only counts if the exception is set */
2260 thread->abort_state_handle = 0;
2265 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2267 LOCK_THREAD (thread);
2269 thread->state &= ~ThreadState_AbortRequested;
2271 if (thread->abort_exc) {
2272 thread->abort_exc = NULL;
2273 if (thread->abort_state_handle) {
2274 mono_gchandle_free (thread->abort_state_handle);
2275 /* This is actually not necessary - the handle
2276 only counts if the exception is set */
2277 thread->abort_state_handle = 0;
2281 UNLOCK_THREAD (thread);
2285 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2288 MonoInternalThread *thread = this_obj->internal_thread;
2289 MonoObject *state, *deserialized = NULL;
2292 if (!thread->abort_state_handle)
2295 state = mono_gchandle_get_target (thread->abort_state_handle);
2298 domain = mono_domain_get ();
2299 if (mono_object_domain (state) == domain)
2302 deserialized = mono_object_xdomain_representation (state, domain, &error);
2304 if (!deserialized) {
2305 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2306 if (!is_ok (&error)) {
2307 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2308 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2310 mono_set_pending_exception (invalid_op_exc);
2314 return deserialized;
2318 mono_thread_suspend (MonoInternalThread *thread)
2320 LOCK_THREAD (thread);
2322 if ((thread->state & ThreadState_Unstarted) != 0 ||
2323 (thread->state & ThreadState_Aborted) != 0 ||
2324 (thread->state & ThreadState_Stopped) != 0)
2326 UNLOCK_THREAD (thread);
2330 if ((thread->state & ThreadState_Suspended) != 0 ||
2331 (thread->state & ThreadState_SuspendRequested) != 0 ||
2332 (thread->state & ThreadState_StopRequested) != 0)
2334 UNLOCK_THREAD (thread);
2338 thread->state |= ThreadState_SuspendRequested;
2340 if (thread == mono_thread_internal_current ()) {
2341 /* calls UNLOCK_THREAD (thread) */
2342 self_suspend_internal ();
2344 /* calls UNLOCK_THREAD (thread) */
2345 async_suspend_internal (thread, FALSE);
2352 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2354 if (!mono_thread_suspend (this_obj->internal_thread)) {
2355 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2360 /* LOCKING: LOCK_THREAD(thread) must be held */
2362 mono_thread_resume (MonoInternalThread *thread)
2364 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2365 thread->state &= ~ThreadState_SuspendRequested;
2369 if ((thread->state & ThreadState_Suspended) == 0 ||
2370 (thread->state & ThreadState_Unstarted) != 0 ||
2371 (thread->state & ThreadState_Aborted) != 0 ||
2372 (thread->state & ThreadState_Stopped) != 0)
2377 UNLOCK_THREAD (thread);
2379 /* Awake the thread */
2380 if (!mono_thread_info_resume (thread_get_tid (thread)))
2383 LOCK_THREAD (thread);
2385 thread->state &= ~ThreadState_Suspended;
2391 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2393 if (!thread->internal_thread) {
2394 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2396 LOCK_THREAD (thread->internal_thread);
2397 if (!mono_thread_resume (thread->internal_thread))
2398 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2399 UNLOCK_THREAD (thread->internal_thread);
2404 mono_threads_is_critical_method (MonoMethod *method)
2406 switch (method->wrapper_type) {
2407 case MONO_WRAPPER_RUNTIME_INVOKE:
2408 case MONO_WRAPPER_XDOMAIN_INVOKE:
2409 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2416 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2421 if (mono_threads_is_critical_method (m)) {
2422 *((gboolean*)data) = TRUE;
2429 is_running_protected_wrapper (void)
2431 gboolean found = FALSE;
2432 mono_stack_walk (find_wrapper, &found);
2436 void mono_thread_internal_stop (MonoInternalThread *thread)
2438 LOCK_THREAD (thread);
2440 if ((thread->state & ThreadState_StopRequested) != 0 ||
2441 (thread->state & ThreadState_Stopped) != 0)
2443 UNLOCK_THREAD (thread);
2447 /* Make sure the thread is awake */
2448 mono_thread_resume (thread);
2450 thread->state |= ThreadState_StopRequested;
2451 thread->state &= ~ThreadState_AbortRequested;
2453 UNLOCK_THREAD (thread);
2455 if (thread == mono_thread_internal_current ())
2456 self_abort_internal ();
2458 async_abort_internal (thread, TRUE);
2461 void mono_thread_stop (MonoThread *thread)
2463 mono_thread_internal_stop (thread->internal_thread);
2467 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2469 gint8 tmp = *(volatile gint8 *)ptr;
2470 mono_memory_barrier ();
2475 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2477 gint16 tmp = *(volatile gint16 *)ptr;
2478 mono_memory_barrier ();
2483 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2485 gint32 tmp = *(volatile gint32 *)ptr;
2486 mono_memory_barrier ();
2491 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2493 gint64 tmp = *(volatile gint64 *)ptr;
2494 mono_memory_barrier ();
2499 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2501 volatile void *tmp = *(volatile void **)ptr;
2502 mono_memory_barrier ();
2503 return (void *) tmp;
2507 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2509 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2510 mono_memory_barrier ();
2511 return (MonoObject *) tmp;
2515 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2517 double tmp = *(volatile double *)ptr;
2518 mono_memory_barrier ();
2523 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2525 float tmp = *(volatile float *)ptr;
2526 mono_memory_barrier ();
2531 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2533 return InterlockedRead8 ((volatile gint8 *)ptr);
2537 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2539 return InterlockedRead16 ((volatile gint16 *)ptr);
2543 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2545 return InterlockedRead ((volatile gint32 *)ptr);
2549 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2551 #if SIZEOF_VOID_P == 4
2552 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2554 mono_interlocked_lock ();
2555 val = *(gint64*)ptr;
2556 mono_interlocked_unlock ();
2560 return InterlockedRead64 ((volatile gint64 *)ptr);
2564 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2566 return InterlockedReadPointer ((volatile gpointer *)ptr);
2570 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2574 #if SIZEOF_VOID_P == 4
2575 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2577 mono_interlocked_lock ();
2578 val = *(double*)ptr;
2579 mono_interlocked_unlock ();
2584 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2590 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2594 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2600 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2602 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2606 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2608 mono_memory_barrier ();
2609 *(volatile gint8 *)ptr = value;
2613 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2615 mono_memory_barrier ();
2616 *(volatile gint16 *)ptr = value;
2620 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2622 mono_memory_barrier ();
2623 *(volatile gint32 *)ptr = value;
2627 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2629 mono_memory_barrier ();
2630 *(volatile gint64 *)ptr = value;
2634 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2636 mono_memory_barrier ();
2637 *(volatile void **)ptr = value;
2641 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2643 mono_memory_barrier ();
2644 mono_gc_wbarrier_generic_store (ptr, value);
2648 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2650 mono_memory_barrier ();
2651 *(volatile double *)ptr = value;
2655 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2657 mono_memory_barrier ();
2658 *(volatile float *)ptr = value;
2662 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2664 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2668 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2670 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2674 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2676 InterlockedWrite ((volatile gint32 *)ptr, value);
2680 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2682 #if SIZEOF_VOID_P == 4
2683 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2684 mono_interlocked_lock ();
2685 *(gint64*)ptr = value;
2686 mono_interlocked_unlock ();
2691 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2695 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2697 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2701 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2705 #if SIZEOF_VOID_P == 4
2706 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2707 mono_interlocked_lock ();
2708 *(double*)ptr = value;
2709 mono_interlocked_unlock ();
2716 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2720 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2726 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2730 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2732 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2736 free_context (void *user_data)
2738 ContextStaticData *data = user_data;
2740 mono_threads_lock ();
2743 * There is no guarantee that, by the point this reference queue callback
2744 * has been invoked, the GC handle associated with the object will fail to
2745 * resolve as one might expect. So if we don't free and remove the GC
2746 * handle here, free_context_static_data_helper () could end up resolving
2747 * a GC handle to an actually-dead context which would contain a pointer
2748 * to an already-freed static data segment, resulting in a crash when
2751 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2753 mono_threads_unlock ();
2755 mono_gchandle_free (data->gc_handle);
2756 mono_free_static_data (data->static_data);
2761 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2763 mono_threads_lock ();
2765 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2768 contexts = g_hash_table_new (NULL, NULL);
2771 context_queue = mono_gc_reference_queue_new (free_context);
2773 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2774 g_hash_table_insert (contexts, gch, gch);
2777 * We use this intermediate structure to contain a duplicate pointer to
2778 * the static data because we can't rely on being able to resolve the GC
2779 * handle in the reference queue callback.
2781 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2782 data->gc_handle = GPOINTER_TO_UINT (gch);
2785 context_adjust_static_data (ctx);
2786 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2788 mono_threads_unlock ();
2790 mono_profiler_context_loaded (ctx);
2794 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2797 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2798 * cleanup in exceptional circumstances, we don't actually do any
2799 * cleanup work here. We instead do this via a reference queue.
2802 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2804 mono_profiler_context_unloaded (ctx);
2808 mono_thread_init_tls (void)
2810 MONO_FAST_TLS_INIT (tls_current_object);
2811 mono_native_tls_alloc (¤t_object_key, NULL);
2814 void mono_thread_init (MonoThreadStartCB start_cb,
2815 MonoThreadAttachCB attach_cb)
2817 mono_coop_mutex_init_recursive (&threads_mutex);
2819 mono_os_mutex_init_recursive(&interlocked_mutex);
2820 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2822 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2823 g_assert(background_change_event != NULL);
2825 mono_init_static_data_info (&thread_static_info);
2826 mono_init_static_data_info (&context_static_info);
2828 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2830 mono_thread_start_cb = start_cb;
2831 mono_thread_attach_cb = attach_cb;
2833 /* Get a pseudo handle to the current process. This is just a
2834 * kludge so that wapi can build a process handle if needed.
2835 * As a pseudo handle is returned, we don't need to clean
2838 GetCurrentProcess ();
2841 void mono_thread_cleanup (void)
2843 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2844 MonoThreadInfo *info;
2846 /* The main thread must abandon any held mutexes (particularly
2847 * important for named mutexes as they are shared across
2848 * processes, see bug 74680.) This will happen when the
2849 * thread exits, but if it's not running in a subthread it
2850 * won't exit in time.
2852 info = mono_thread_info_current ();
2853 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2857 /* This stuff needs more testing, it seems one of these
2858 * critical sections can be locked when mono_thread_cleanup is
2861 mono_coop_mutex_destroy (&threads_mutex);
2862 mono_os_mutex_destroy (&interlocked_mutex);
2863 mono_os_mutex_destroy (&delayed_free_table_mutex);
2864 mono_os_mutex_destroy (&small_id_mutex);
2865 CloseHandle (background_change_event);
2868 mono_native_tls_free (current_object_key);
2872 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2874 mono_thread_cleanup_fn = func;
2878 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2880 thread->internal_thread->manage_callback = func;
2884 static void print_tids (gpointer key, gpointer value, gpointer user)
2886 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2887 * sizeof(uint) and a cast to uint would overflow
2889 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2890 * print this as a pointer.
2892 g_message ("Waiting for: %p", key);
2897 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2898 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2902 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2906 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2908 MONO_PREPARE_BLOCKING;
2909 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2910 MONO_FINISH_BLOCKING;
2912 if(ret==WAIT_FAILED) {
2913 /* See the comment in build_wait_tids() */
2914 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2918 for(i=0; i<wait->num; i++)
2919 CloseHandle (wait->handles[i]);
2921 if (ret == WAIT_TIMEOUT)
2924 for(i=0; i<wait->num; i++) {
2925 gsize tid = wait->threads[i]->tid;
2928 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2929 * it can still run io-layer etc. code. So wait for it to really exit.
2930 * FIXME: This won't join threads which are not in the joinable_hash yet.
2932 mono_thread_join ((gpointer)tid);
2934 mono_threads_lock ();
2935 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2936 /* This thread must have been killed, because
2937 * it hasn't cleaned itself up. (It's just
2938 * possible that the thread exited before the
2939 * parent thread had a chance to store the
2940 * handle, and now there is another pointer to
2941 * the already-exited thread stored. In this
2942 * case, we'll just get two
2943 * mono_profiler_thread_end() calls for the
2947 mono_threads_unlock ();
2948 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2949 thread_cleanup (wait->threads[i]);
2951 mono_threads_unlock ();
2956 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2958 guint32 i, ret, count;
2960 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2962 /* Add the thread state change event, so it wakes up if a thread changes
2963 * to background mode.
2966 if (count < MAXIMUM_WAIT_OBJECTS) {
2967 wait->handles [count] = background_change_event;
2971 MONO_PREPARE_BLOCKING;
2972 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2973 MONO_FINISH_BLOCKING;
2975 if(ret==WAIT_FAILED) {
2976 /* See the comment in build_wait_tids() */
2977 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2981 for(i=0; i<wait->num; i++)
2982 CloseHandle (wait->handles[i]);
2984 if (ret == WAIT_TIMEOUT)
2987 if (ret < wait->num) {
2988 gsize tid = wait->threads[ret]->tid;
2989 mono_threads_lock ();
2990 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2991 /* See comment in wait_for_tids about thread cleanup */
2992 mono_threads_unlock ();
2993 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2994 thread_cleanup (wait->threads [ret]);
2996 mono_threads_unlock ();
3000 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3002 struct wait_data *wait=(struct wait_data *)user;
3004 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
3006 MonoInternalThread *thread=(MonoInternalThread *)value;
3008 /* Ignore background threads, we abort them later */
3009 /* Do not lock here since it is not needed and the caller holds threads_lock */
3010 if (thread->state & ThreadState_Background) {
3011 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3012 return; /* just leave, ignore */
3015 if (mono_gc_is_finalizer_internal_thread (thread)) {
3016 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3020 if (thread == mono_thread_internal_current ()) {
3021 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3025 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3026 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3030 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3031 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3035 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3036 if (handle == NULL) {
3037 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3041 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3042 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3043 wait->handles[wait->num]=handle;
3044 wait->threads[wait->num]=thread;
3047 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3049 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3054 /* Just ignore the rest, we can't do anything with
3061 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3063 struct wait_data *wait=(struct wait_data *)user;
3064 MonoNativeThreadId self = mono_native_thread_id_get ();
3065 MonoInternalThread *thread = (MonoInternalThread *)value;
3068 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
3071 /* The finalizer thread is not a background thread */
3072 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3073 && (thread->state & ThreadState_Background) != 0
3074 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3076 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3080 /* printf ("A: %d\n", wait->num); */
3081 wait->handles[wait->num]=thread->handle;
3082 wait->threads[wait->num]=thread;
3085 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3086 mono_thread_internal_stop (thread);
3090 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3091 && !mono_gc_is_finalizer_internal_thread (thread);
3095 * mono_threads_set_shutting_down:
3097 * Is called by a thread that wants to shut down Mono. If the runtime is already
3098 * shutting down, the calling thread is suspended/stopped, and this function never
3102 mono_threads_set_shutting_down (void)
3104 MonoInternalThread *current_thread = mono_thread_internal_current ();
3106 mono_threads_lock ();
3108 if (shutting_down) {
3109 mono_threads_unlock ();
3111 /* Make sure we're properly suspended/stopped */
3113 LOCK_THREAD (current_thread);
3115 if ((current_thread->state & ThreadState_SuspendRequested) ||
3116 (current_thread->state & ThreadState_AbortRequested) ||
3117 (current_thread->state & ThreadState_StopRequested)) {
3118 UNLOCK_THREAD (current_thread);
3119 mono_thread_execute_interruption ();
3121 current_thread->state |= ThreadState_Stopped;
3122 UNLOCK_THREAD (current_thread);
3125 /*since we're killing the thread, unset the current domain.*/
3126 mono_domain_unset ();
3128 /* Wake up other threads potentially waiting for us */
3129 mono_thread_info_exit ();
3131 shutting_down = TRUE;
3133 /* Not really a background state change, but this will
3134 * interrupt the main thread if it is waiting for all
3135 * the other threads.
3137 SetEvent (background_change_event);
3139 mono_threads_unlock ();
3143 void mono_thread_manage (void)
3145 struct wait_data wait_data;
3146 struct wait_data *wait = &wait_data;
3148 memset (wait, 0, sizeof (struct wait_data));
3149 /* join each thread that's still running */
3150 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3152 mono_threads_lock ();
3154 THREAD_DEBUG (g_message("%s: No threads", __func__));
3155 mono_threads_unlock ();
3158 mono_threads_unlock ();
3161 mono_threads_lock ();
3162 if (shutting_down) {
3163 /* somebody else is shutting down */
3164 mono_threads_unlock ();
3167 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3168 mono_g_hash_table_foreach (threads, print_tids, NULL));
3170 ResetEvent (background_change_event);
3172 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3173 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3174 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3175 mono_threads_unlock ();
3177 /* Something to wait for */
3178 wait_for_tids_or_state_change (wait, INFINITE);
3180 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3181 } while(wait->num>0);
3183 /* Mono is shutting down, so just wait for the end */
3184 if (!mono_runtime_try_shutdown ()) {
3185 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3186 mono_thread_suspend (mono_thread_internal_current ());
3187 mono_thread_execute_interruption ();
3191 * Remove everything but the finalizer thread and self.
3192 * Also abort all the background threads
3195 mono_threads_lock ();
3198 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3199 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3200 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3202 mono_threads_unlock ();
3204 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3206 /* Something to wait for */
3207 wait_for_tids (wait, INFINITE);
3209 } while (wait->num > 0);
3212 * give the subthreads a chance to really quit (this is mainly needed
3213 * to get correct user and system times from getrusage/wait/time(1)).
3214 * This could be removed if we avoid pthread_detach() and use pthread_join().
3216 mono_thread_info_yield ();
3220 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3222 MonoInternalThread *thread = (MonoInternalThread*)value;
3223 struct wait_data *wait = (struct wait_data*)user_data;
3227 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3229 * This needs no locking.
3231 if ((thread->state & ThreadState_Suspended) != 0 ||
3232 (thread->state & ThreadState_Stopped) != 0)
3235 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3236 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3240 wait->handles [wait->num] = handle;
3241 wait->threads [wait->num] = thread;
3247 * mono_thread_suspend_all_other_threads:
3249 * Suspend all managed threads except the finalizer thread and this thread. It is
3250 * not possible to resume them later.
3252 void mono_thread_suspend_all_other_threads (void)
3254 struct wait_data wait_data;
3255 struct wait_data *wait = &wait_data;
3257 MonoNativeThreadId self = mono_native_thread_id_get ();
3258 guint32 eventidx = 0;
3259 gboolean starting, finished;
3261 memset (wait, 0, sizeof (struct wait_data));
3263 * The other threads could be in an arbitrary state at this point, i.e.
3264 * they could be starting up, shutting down etc. This means that there could be
3265 * threads which are not even in the threads hash table yet.
3269 * First we set a barrier which will be checked by all threads before they
3270 * are added to the threads hash table, and they will exit if the flag is set.
3271 * This ensures that no threads could be added to the hash later.
3272 * We will use shutting_down as the barrier for now.
3274 g_assert (shutting_down);
3277 * We make multiple calls to WaitForMultipleObjects since:
3278 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3279 * - some threads could exit without becoming suspended
3284 * Make a copy of the hashtable since we can't do anything with
3285 * threads while threads_mutex is held.
3288 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3289 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3290 mono_threads_lock ();
3291 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3292 mono_threads_unlock ();
3295 /* Get the suspended events that we'll be waiting for */
3296 for (i = 0; i < wait->num; ++i) {
3297 MonoInternalThread *thread = wait->threads [i];
3299 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3300 || mono_gc_is_finalizer_internal_thread (thread)
3301 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3303 //CloseHandle (wait->handles [i]);
3304 wait->threads [i] = NULL; /* ignore this thread in next loop */
3308 LOCK_THREAD (thread);
3310 if ((thread->state & ThreadState_Suspended) != 0 ||
3311 (thread->state & ThreadState_StopRequested) != 0 ||
3312 (thread->state & ThreadState_Stopped) != 0) {
3313 UNLOCK_THREAD (thread);
3314 CloseHandle (wait->handles [i]);
3315 wait->threads [i] = NULL; /* ignore this thread in next loop */
3321 /* Convert abort requests into suspend requests */
3322 if ((thread->state & ThreadState_AbortRequested) != 0)
3323 thread->state &= ~ThreadState_AbortRequested;
3325 thread->state |= ThreadState_SuspendRequested;
3327 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3328 async_suspend_internal (thread, TRUE);
3330 if (eventidx <= 0) {
3332 * If there are threads which are starting up, we wait until they
3333 * are suspended when they try to register in the threads hash.
3334 * This is guaranteed to finish, since the threads which can create new
3335 * threads get suspended after a while.
3336 * FIXME: The finalizer thread can still create new threads.
3338 mono_threads_lock ();
3339 if (threads_starting_up)
3340 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3343 mono_threads_unlock ();
3345 mono_thread_info_sleep (100, NULL);
3353 MonoInternalThread *thread;
3354 MonoStackFrameInfo *frames;
3355 int nframes, max_frames;
3356 int nthreads, max_threads;
3357 MonoInternalThread **threads;
3358 } ThreadDumpUserData;
3360 static gboolean thread_dump_requested;
3362 /* This needs to be async safe */
3364 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3366 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3368 if (ud->nframes < ud->max_frames) {
3369 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3376 /* This needs to be async safe */
3377 static SuspendThreadResult
3378 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3380 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3381 MonoInternalThread *thread = user_data->thread;
3384 /* This no longer works with remote unwinding */
3386 wapi_desc = wapi_current_thread_desc ();
3387 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3392 if (thread == mono_thread_internal_current ())
3393 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3395 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3397 return MonoResumeThread;
3401 int nthreads, max_threads;
3402 MonoInternalThread **threads;
3403 } CollectThreadsUserData;
3406 collect_thread (gpointer key, gpointer value, gpointer user)
3408 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3409 MonoInternalThread *thread = (MonoInternalThread *)value;
3411 if (ud->nthreads < ud->max_threads)
3412 ud->threads [ud->nthreads ++] = thread;
3416 * Collect running threads into the THREADS array.
3417 * THREADS should be an array allocated on the stack.
3420 collect_threads (MonoInternalThread **thread_array, int max_threads)
3422 CollectThreadsUserData ud;
3424 memset (&ud, 0, sizeof (ud));
3425 /* This array contains refs, but its on the stack, so its ok */
3426 ud.threads = thread_array;
3427 ud.max_threads = max_threads;
3429 mono_threads_lock ();
3430 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3431 mono_threads_unlock ();
3437 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3439 GString* text = g_string_new (0);
3441 GError *error = NULL;
3444 ud->thread = thread;
3447 /* Collect frames for the thread */
3448 if (thread == mono_thread_internal_current ()) {
3449 get_thread_dump (mono_thread_info_current (), ud);
3451 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3455 * Do all the non async-safe work outside of get_thread_dump.
3458 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3460 g_string_append_printf (text, "\n\"%s\"", name);
3463 else if (thread->threadpool_thread) {
3464 g_string_append (text, "\n\"<threadpool thread>\"");
3466 g_string_append (text, "\n\"<unnamed thread>\"");
3469 for (i = 0; i < ud->nframes; ++i) {
3470 MonoStackFrameInfo *frame = &ud->frames [i];
3471 MonoMethod *method = NULL;
3473 if (frame->type == FRAME_TYPE_MANAGED)
3474 method = mono_jit_info_get_method (frame->ji);
3477 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3478 g_string_append_printf (text, " %s\n", location);
3481 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3485 fprintf (stdout, "%s", text->str);
3487 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3488 OutputDebugStringA(text->str);
3491 g_string_free (text, TRUE);
3496 mono_threads_perform_thread_dump (void)
3498 ThreadDumpUserData ud;
3499 MonoInternalThread *thread_array [128];
3500 int tindex, nthreads;
3502 if (!thread_dump_requested)
3505 printf ("Full thread dump:\n");
3507 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3508 nthreads = collect_threads (thread_array, 128);
3510 memset (&ud, 0, sizeof (ud));
3511 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3512 ud.max_frames = 256;
3514 for (tindex = 0; tindex < nthreads; ++tindex)
3515 dump_thread (thread_array [tindex], &ud);
3519 thread_dump_requested = FALSE;
3522 /* Obtain the thread dump of all threads */
3524 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames)
3528 ThreadDumpUserData ud;
3529 MonoInternalThread *thread_array [128];
3530 MonoDomain *domain = mono_domain_get ();
3531 MonoDebugSourceLocation *location;
3532 int tindex, nthreads;
3534 mono_error_init (&error);
3536 *out_threads = NULL;
3537 *out_stack_frames = NULL;
3539 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3540 nthreads = collect_threads (thread_array, 128);
3542 memset (&ud, 0, sizeof (ud));
3543 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3544 ud.max_frames = 256;
3546 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, &error);
3547 if (!is_ok (&error))
3549 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, &error);
3550 if (!is_ok (&error))
3553 for (tindex = 0; tindex < nthreads; ++tindex) {
3554 MonoInternalThread *thread = thread_array [tindex];
3555 MonoArray *thread_frames;
3561 /* Collect frames for the thread */
3562 if (thread == mono_thread_internal_current ()) {
3563 get_thread_dump (mono_thread_info_current (), &ud);
3565 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3568 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3570 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, &error);
3571 if (!is_ok (&error))
3573 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3575 for (i = 0; i < ud.nframes; ++i) {
3576 MonoStackFrameInfo *frame = &ud.frames [i];
3577 MonoMethod *method = NULL;
3578 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, &error);
3579 if (!mono_error_ok (&error))
3582 sf->native_offset = frame->native_offset;
3584 if (frame->type == FRAME_TYPE_MANAGED)
3585 method = mono_jit_info_get_method (frame->ji);
3588 sf->method_address = (gsize) frame->ji->code_start;
3590 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
3591 mono_error_raise_exception (&error); /* FIXME don't raise here */
3592 MONO_OBJECT_SETREF (sf, method, rm);
3594 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3596 sf->il_offset = location->il_offset;
3598 if (location && location->source_file) {
3599 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3600 sf->line = location->row;
3601 sf->column = location->column;
3603 mono_debug_free_source_location (location);
3608 mono_array_setref (thread_frames, i, sf);
3614 mono_error_raise_exception (&error); /* FIXME don't raise here */
3618 * mono_threads_request_thread_dump:
3620 * Ask all threads except the current to print their stacktrace to stdout.
3623 mono_threads_request_thread_dump (void)
3625 /*The new thread dump code runs out of the finalizer thread. */
3626 thread_dump_requested = TRUE;
3627 mono_gc_finalize_notify ();
3632 gint allocated; /* +1 so that refs [allocated] == NULL */
3636 typedef struct ref_stack RefStack;
3639 ref_stack_new (gint initial_size)
3643 initial_size = MAX (initial_size, 16) + 1;
3644 rs = g_new0 (RefStack, 1);
3645 rs->refs = g_new0 (gpointer, initial_size);
3646 rs->allocated = initial_size;
3651 ref_stack_destroy (gpointer ptr)
3653 RefStack *rs = (RefStack *)ptr;
3662 ref_stack_push (RefStack *rs, gpointer ptr)
3664 g_assert (rs != NULL);
3666 if (rs->bottom >= rs->allocated) {
3667 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3668 rs->allocated <<= 1;
3669 rs->refs [rs->allocated] = NULL;
3671 rs->refs [rs->bottom++] = ptr;
3675 ref_stack_pop (RefStack *rs)
3677 if (rs == NULL || rs->bottom == 0)
3681 rs->refs [rs->bottom] = NULL;
3685 ref_stack_find (RefStack *rs, gpointer ptr)
3692 for (refs = rs->refs; refs && *refs; refs++) {
3700 * mono_thread_push_appdomain_ref:
3702 * Register that the current thread may have references to objects in domain
3703 * @domain on its stack. Each call to this function should be paired with a
3704 * call to pop_appdomain_ref.
3707 mono_thread_push_appdomain_ref (MonoDomain *domain)
3709 MonoInternalThread *thread = mono_thread_internal_current ();
3712 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3713 SPIN_LOCK (thread->lock_thread_id);
3714 if (thread->appdomain_refs == NULL)
3715 thread->appdomain_refs = ref_stack_new (16);
3716 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3717 SPIN_UNLOCK (thread->lock_thread_id);
3722 mono_thread_pop_appdomain_ref (void)
3724 MonoInternalThread *thread = mono_thread_internal_current ();
3727 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3728 SPIN_LOCK (thread->lock_thread_id);
3729 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3730 SPIN_UNLOCK (thread->lock_thread_id);
3735 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3738 SPIN_LOCK (thread->lock_thread_id);
3739 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3740 SPIN_UNLOCK (thread->lock_thread_id);
3745 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3747 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3750 typedef struct abort_appdomain_data {
3751 struct wait_data wait;
3753 } abort_appdomain_data;
3756 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3758 MonoInternalThread *thread = (MonoInternalThread*)value;
3759 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3760 MonoDomain *domain = data->domain;
3762 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3763 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3765 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3766 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3769 data->wait.handles [data->wait.num] = handle;
3770 data->wait.threads [data->wait.num] = thread;
3773 /* Just ignore the rest, we can't do anything with
3781 * mono_threads_abort_appdomain_threads:
3783 * Abort threads which has references to the given appdomain.
3786 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3788 #ifdef __native_client__
3792 abort_appdomain_data user_data;
3794 int orig_timeout = timeout;
3797 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3799 start_time = mono_msec_ticks ();
3801 mono_threads_lock ();
3803 user_data.domain = domain;
3804 user_data.wait.num = 0;
3805 /* This shouldn't take any locks */
3806 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3807 mono_threads_unlock ();
3809 if (user_data.wait.num > 0) {
3810 /* Abort the threads outside the threads lock */
3811 for (i = 0; i < user_data.wait.num; ++i)
3812 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3815 * We should wait for the threads either to abort, or to leave the
3816 * domain. We can't do the latter, so we wait with a timeout.
3818 wait_for_tids (&user_data.wait, 100);
3821 /* Update remaining time */
3822 timeout -= mono_msec_ticks () - start_time;
3823 start_time = mono_msec_ticks ();
3825 if (orig_timeout != -1 && timeout < 0)
3828 while (user_data.wait.num > 0);
3830 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3836 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3838 MonoInternalThread *thread = (MonoInternalThread*)value;
3839 MonoDomain *domain = (MonoDomain*)user_data;
3842 /* No locking needed here */
3843 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3845 if (thread->cached_culture_info) {
3846 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3847 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3848 if (obj && obj->vtable->domain == domain)
3849 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3855 * mono_threads_clear_cached_culture:
3857 * Clear the cached_current_culture from all threads if it is in the
3861 mono_threads_clear_cached_culture (MonoDomain *domain)
3863 mono_threads_lock ();
3864 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3865 mono_threads_unlock ();
3869 * mono_thread_get_undeniable_exception:
3871 * Return an exception which needs to be raised when leaving a catch clause.
3872 * This is used for undeniable exception propagation.
3875 mono_thread_get_undeniable_exception (void)
3877 MonoInternalThread *thread = mono_thread_internal_current ();
3879 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3881 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3882 * exception if the thread no longer references a dying appdomain.
3884 thread->abort_exc->trace_ips = NULL;
3885 thread->abort_exc->stack_trace = NULL;
3886 return thread->abort_exc;
3892 #if MONO_SMALL_CONFIG
3893 #define NUM_STATIC_DATA_IDX 4
3894 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3898 #define NUM_STATIC_DATA_IDX 8
3899 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3900 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3904 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3905 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3908 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3910 gpointer *static_data = (gpointer *)addr;
3912 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3913 void **ptr = (void **)static_data [i];
3918 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3919 void **p = ptr + idx;
3922 mark_func ((MonoObject**)p, gc_data);
3928 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3930 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3934 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3936 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3940 * mono_alloc_static_data
3942 * Allocate memory blocks for storing threads or context static data
3945 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3947 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3950 gpointer* static_data = *static_data_ptr;
3952 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3953 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3955 if (mono_gc_user_markers_supported ()) {
3956 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3957 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3959 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3960 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3963 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3964 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3965 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3966 *static_data_ptr = static_data;
3967 static_data [0] = static_data;
3970 for (i = 1; i <= idx; ++i) {
3971 if (static_data [i])
3974 if (mono_gc_user_markers_supported ())
3975 static_data [i] = g_malloc0 (static_data_size [i]);
3977 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3978 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3979 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3984 mono_free_static_data (gpointer* static_data)
3987 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3988 gpointer p = static_data [i];
3992 * At this point, the static data pointer array is still registered with the
3993 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3994 * data. Freeing the individual arrays without first nulling their slots
3995 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3996 * such an already freed array. See bug #13813.
3998 static_data [i] = NULL;
3999 mono_memory_write_barrier ();
4000 if (mono_gc_user_markers_supported ())
4003 mono_gc_free_fixed (p);
4005 mono_gc_free_fixed (static_data);
4009 * mono_init_static_data_info
4011 * Initializes static data counters
4013 static void mono_init_static_data_info (StaticDataInfo *static_data)
4015 static_data->idx = 0;
4016 static_data->offset = 0;
4017 static_data->freelist = NULL;
4021 * mono_alloc_static_data_slot
4023 * Generates an offset for static data. static_data contains the counters
4024 * used to generate it.
4027 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4029 if (!static_data->idx && !static_data->offset) {
4031 * we use the first chunk of the first allocation also as
4032 * an array for the rest of the data
4034 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4036 static_data->offset += align - 1;
4037 static_data->offset &= ~(align - 1);
4038 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4039 static_data->idx ++;
4040 g_assert (size <= static_data_size [static_data->idx]);
4041 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4042 static_data->offset = 0;
4044 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4045 static_data->offset += size;
4050 * ensure thread static fields already allocated are valid for thread
4051 * This function is called when a thread is created or on thread attach.
4054 thread_adjust_static_data (MonoInternalThread *thread)
4056 mono_threads_lock ();
4057 if (thread_static_info.offset || thread_static_info.idx > 0) {
4058 /* get the current allocated size */
4059 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
4060 mono_alloc_static_data (&thread->static_data, offset, TRUE);
4062 mono_threads_unlock ();
4066 * LOCKING: requires that threads_mutex is held
4069 context_adjust_static_data (MonoAppContext *ctx)
4071 if (context_static_info.offset || context_static_info.idx > 0) {
4072 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4073 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4074 ctx->data->static_data = ctx->static_data;
4079 * LOCKING: requires that threads_mutex is held
4082 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4084 MonoInternalThread *thread = (MonoInternalThread *)value;
4085 guint32 offset = GPOINTER_TO_UINT (user);
4087 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4091 * LOCKING: requires that threads_mutex is held
4094 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4096 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4101 guint32 offset = GPOINTER_TO_UINT (user);
4102 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4103 ctx->data->static_data = ctx->static_data;
4106 static StaticDataFreeList*
4107 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4109 StaticDataFreeList* prev = NULL;
4110 StaticDataFreeList* tmp = static_data->freelist;
4112 if (tmp->size == size) {
4114 prev->next = tmp->next;
4116 static_data->freelist = tmp->next;
4125 #if SIZEOF_VOID_P == 4
4132 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4134 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4136 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4137 MonoBitSet *rb = sets [idx];
4138 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4139 offset /= sizeof (uintptr_t);
4140 /* offset is now the bitmap offset */
4141 for (int i = 0; i < numbits; ++i) {
4142 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4143 mono_bitset_set_fast (rb, offset + i);
4148 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4150 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4151 MonoBitSet *rb = sets [idx];
4152 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4153 offset /= sizeof (uintptr_t);
4154 /* offset is now the bitmap offset */
4155 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4156 mono_bitset_clear_fast (rb, offset + i);
4160 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4162 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4164 StaticDataInfo *info;
4167 if (static_type == SPECIAL_STATIC_THREAD) {
4168 info = &thread_static_info;
4169 sets = thread_reference_bitmaps;
4171 info = &context_static_info;
4172 sets = context_reference_bitmaps;
4175 mono_threads_lock ();
4177 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4181 offset = item->offset;
4184 offset = mono_alloc_static_data_slot (info, size, align);
4187 update_reference_bitmap (sets, offset, bitmap, numbits);
4189 if (static_type == SPECIAL_STATIC_THREAD) {
4190 /* This can be called during startup */
4191 if (threads != NULL)
4192 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4194 if (contexts != NULL)
4195 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4197 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4200 mono_threads_unlock ();
4206 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4208 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4210 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4211 return get_thread_static_data (thread, offset);
4213 return get_context_static_data (thread->current_appcontext, offset);
4218 mono_get_special_static_data (guint32 offset)
4220 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4229 * LOCKING: requires that threads_mutex is held
4232 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4234 MonoInternalThread *thread = (MonoInternalThread *)value;
4235 OffsetSize *data = (OffsetSize *)user;
4236 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4237 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4240 if (!thread->static_data || !thread->static_data [idx])
4242 ptr = ((char*) thread->static_data [idx]) + off;
4243 mono_gc_bzero_atomic (ptr, data->size);
4247 * LOCKING: requires that threads_mutex is held
4250 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4252 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4257 OffsetSize *data = (OffsetSize *)user;
4258 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4259 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4262 if (!ctx->static_data || !ctx->static_data [idx])
4265 ptr = ((char*) ctx->static_data [idx]) + off;
4266 mono_gc_bzero_atomic (ptr, data->size);
4270 do_free_special_slot (guint32 offset, guint32 size)
4272 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4274 StaticDataInfo *info;
4276 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4277 info = &thread_static_info;
4278 sets = thread_reference_bitmaps;
4280 info = &context_static_info;
4281 sets = context_reference_bitmaps;
4284 guint32 data_offset = offset;
4285 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4286 OffsetSize data = { data_offset, size };
4288 clear_reference_bitmap (sets, data.offset, data.size);
4290 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4291 if (threads != NULL)
4292 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4294 if (contexts != NULL)
4295 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4298 if (!mono_runtime_is_shutting_down ()) {
4299 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4301 item->offset = offset;
4304 item->next = info->freelist;
4305 info->freelist = item;
4310 do_free_special (gpointer key, gpointer value, gpointer data)
4312 MonoClassField *field = (MonoClassField *)key;
4313 guint32 offset = GPOINTER_TO_UINT (value);
4316 size = mono_type_size (field->type, &align);
4317 do_free_special_slot (offset, size);
4321 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4323 mono_threads_lock ();
4325 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4327 mono_threads_unlock ();
4331 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4333 /* Only ever called for ThreadLocal instances */
4334 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
4336 mono_threads_lock ();
4337 do_free_special_slot (offset, size);
4338 mono_threads_unlock ();
4342 static void CALLBACK dummy_apc (ULONG_PTR param)
4348 * mono_thread_execute_interruption
4350 * Performs the operation that the requested thread state requires (abort,
4353 static MonoException*
4354 mono_thread_execute_interruption (void)
4356 MonoInternalThread *thread = mono_thread_internal_current ();
4357 MonoThread *sys_thread = mono_thread_current ();
4359 LOCK_THREAD (thread);
4361 /* MonoThread::interruption_requested can only be changed with atomics */
4362 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4363 /* this will consume pending APC calls */
4365 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4367 InterlockedDecrement (&thread_interruption_requested);
4369 /* Clear the interrupted flag of the thread so it can wait again */
4370 mono_thread_info_clear_self_interrupt ();
4373 if ((thread->state & ThreadState_AbortRequested) != 0) {
4374 UNLOCK_THREAD (thread);
4375 if (thread->abort_exc == NULL) {
4377 * This might be racy, but it has to be called outside the lock
4378 * since it calls managed code.
4380 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4382 return thread->abort_exc;
4384 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4385 /* calls UNLOCK_THREAD (thread) */
4386 self_suspend_internal ();
4389 else if ((thread->state & ThreadState_StopRequested) != 0) {
4390 /* FIXME: do this through the JIT? */
4392 UNLOCK_THREAD (thread);
4394 mono_thread_exit ();
4396 } else if (sys_thread->pending_exception) {
4399 exc = sys_thread->pending_exception;
4400 sys_thread->pending_exception = NULL;
4402 UNLOCK_THREAD (thread);
4404 } else if (thread->thread_interrupt_requested) {
4406 thread->thread_interrupt_requested = FALSE;
4407 UNLOCK_THREAD (thread);
4409 return(mono_get_exception_thread_interrupted ());
4412 UNLOCK_THREAD (thread);
4418 * mono_thread_request_interruption
4420 * A signal handler can call this method to request the interruption of a
4421 * thread. The result of the interruption will depend on the current state of
4422 * the thread. If the result is an exception that needs to be throw, it is
4423 * provided as return value.
4426 mono_thread_request_interruption (gboolean running_managed)
4428 MonoInternalThread *thread = mono_thread_internal_current ();
4430 /* The thread may already be stopping */
4435 if (thread->interrupt_on_stop &&
4436 thread->state & ThreadState_StopRequested &&
4437 thread->state & ThreadState_Background)
4441 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4443 InterlockedIncrement (&thread_interruption_requested);
4445 if (!running_managed || is_running_protected_wrapper ()) {
4446 /* Can't stop while in unmanaged code. Increase the global interruption
4447 request count. When exiting the unmanaged method the count will be
4448 checked and the thread will be interrupted. */
4450 /* this will awake the thread if it is in WaitForSingleObject
4452 /* Our implementation of this function ignores the func argument */
4454 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4456 mono_thread_info_self_interrupt ();
4461 return mono_thread_execute_interruption ();
4465 /*This function should be called by a thread after it has exited all of
4466 * its handle blocks at interruption time.*/
4468 mono_thread_resume_interruption (void)
4470 MonoInternalThread *thread = mono_thread_internal_current ();
4471 gboolean still_aborting;
4473 /* The thread may already be stopping */
4477 LOCK_THREAD (thread);
4478 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4479 UNLOCK_THREAD (thread);
4481 /*This can happen if the protected block called Thread::ResetAbort*/
4482 if (!still_aborting)
4485 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4487 InterlockedIncrement (&thread_interruption_requested);
4489 mono_thread_info_self_interrupt ();
4491 return mono_thread_execute_interruption ();
4494 gboolean mono_thread_interruption_requested ()
4496 if (thread_interruption_requested) {
4497 MonoInternalThread *thread = mono_thread_internal_current ();
4498 /* The thread may already be stopping */
4500 return (thread->interruption_requested);
4505 static MonoException*
4506 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4508 MonoInternalThread *thread = mono_thread_internal_current ();
4510 /* The thread may already be stopping */
4514 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4515 MonoException* exc = mono_thread_execute_interruption ();
4523 * Performs the interruption of the current thread, if one has been requested,
4524 * and the thread is not running a protected wrapper.
4525 * Return the exception which needs to be thrown, if any.
4528 mono_thread_interruption_checkpoint (void)
4530 return mono_thread_interruption_checkpoint_request (FALSE);
4534 * Performs the interruption of the current thread, if one has been requested.
4535 * Return the exception which needs to be thrown, if any.
4538 mono_thread_force_interruption_checkpoint_noraise (void)
4540 return mono_thread_interruption_checkpoint_request (TRUE);
4544 * mono_thread_get_and_clear_pending_exception:
4546 * Return any pending exceptions for the current thread and clear it as a side effect.
4549 mono_thread_get_and_clear_pending_exception (void)
4551 MonoInternalThread *thread = mono_thread_internal_current ();
4552 MonoThread *sys_thread = mono_thread_current ();
4554 /* The thread may already be stopping */
4558 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4559 return mono_thread_execute_interruption ();
4562 if (sys_thread->pending_exception) {
4563 MonoException *exc = sys_thread->pending_exception;
4565 sys_thread->pending_exception = NULL;
4573 * mono_set_pending_exception:
4575 * Set the pending exception of the current thread to EXC.
4576 * The exception will be thrown when execution returns to managed code.
4579 mono_set_pending_exception (MonoException *exc)
4581 MonoThread *thread = mono_thread_current ();
4583 /* The thread may already be stopping */
4587 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4589 mono_thread_request_interruption (FALSE);
4593 * mono_thread_interruption_request_flag:
4595 * Returns the address of a flag that will be non-zero if an interruption has
4596 * been requested for a thread. The thread to interrupt may not be the current
4597 * thread, so an additional call to mono_thread_interruption_requested() or
4598 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4601 gint32* mono_thread_interruption_request_flag ()
4603 return &thread_interruption_requested;
4607 mono_thread_init_apartment_state (void)
4610 MonoInternalThread* thread = mono_thread_internal_current ();
4612 /* Positive return value indicates success, either
4613 * S_OK if this is first CoInitialize call, or
4614 * S_FALSE if CoInitialize already called, but with same
4615 * threading model. A negative value indicates failure,
4616 * probably due to trying to change the threading model.
4618 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4619 ? COINIT_APARTMENTTHREADED
4620 : COINIT_MULTITHREADED) < 0) {
4621 thread->apartment_state = ThreadApartmentState_Unknown;
4627 mono_thread_cleanup_apartment_state (void)
4630 MonoInternalThread* thread = mono_thread_internal_current ();
4632 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4639 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4641 LOCK_THREAD (thread);
4642 thread->state |= state;
4643 UNLOCK_THREAD (thread);
4647 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4649 LOCK_THREAD (thread);
4650 thread->state &= ~state;
4651 UNLOCK_THREAD (thread);
4655 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4657 gboolean ret = FALSE;
4659 LOCK_THREAD (thread);
4661 if ((thread->state & test) != 0) {
4665 UNLOCK_THREAD (thread);
4670 static gboolean has_tls_get = FALSE;
4673 mono_runtime_set_has_tls_get (gboolean val)
4679 mono_runtime_has_tls_get (void)
4685 self_interrupt_thread (void *_unused)
4687 MonoThreadInfo *info = mono_thread_info_current ();
4688 MonoException *exc = mono_thread_execute_interruption ();
4689 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4690 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. */
4691 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4695 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4699 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4703 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4705 MonoJitInfo **dest = (MonoJitInfo **)data;
4711 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4713 MonoJitInfo *ji = NULL;
4718 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4719 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4720 * where we hold runtime locks.
4722 if (!mono_threads_is_coop_enabled ())
4723 mono_thread_info_set_is_async_context (TRUE);
4724 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4725 if (!mono_threads_is_coop_enabled ())
4726 mono_thread_info_set_is_async_context (FALSE);
4731 MonoInternalThread *thread;
4732 gboolean install_async_abort;
4733 MonoThreadInfoInterruptToken *interrupt_token;
4736 static SuspendThreadResult
4737 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4739 AbortThreadData *data = (AbortThreadData *)ud;
4740 MonoInternalThread *thread = data->thread;
4741 MonoJitInfo *ji = NULL;
4742 gboolean protected_wrapper;
4743 gboolean running_managed;
4745 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4746 return MonoResumeThread;
4748 /*someone is already interrupting it*/
4749 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4750 return MonoResumeThread;
4752 InterlockedIncrement (&thread_interruption_requested);
4754 ji = mono_thread_info_get_last_managed (info);
4755 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4756 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4758 if (!protected_wrapper && running_managed) {
4759 /*We are in managed code*/
4760 /*Set the thread to call */
4761 if (data->install_async_abort)
4762 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4763 return MonoResumeThread;
4766 * This will cause waits to be broken.
4767 * It will also prevent the thread from entering a wait, so if the thread returns
4768 * from the wait before it receives the abort signal, it will just spin in the wait
4769 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4772 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4774 return MonoResumeThread;
4779 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4781 AbortThreadData data;
4783 g_assert (thread != mono_thread_internal_current ());
4785 data.thread = thread;
4786 data.install_async_abort = install_async_abort;
4787 data.interrupt_token = NULL;
4789 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4790 if (data.interrupt_token)
4791 mono_thread_info_finish_interrupt (data.interrupt_token);
4792 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4796 self_abort_internal (void)
4800 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4801 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4803 exc = mono_thread_request_interruption (TRUE);
4805 mono_raise_exception (exc);
4807 mono_thread_info_self_interrupt ();
4811 MonoInternalThread *thread;
4813 MonoThreadInfoInterruptToken *interrupt_token;
4814 } SuspendThreadData;
4816 static SuspendThreadResult
4817 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4819 SuspendThreadData *data = (SuspendThreadData *)ud;
4820 MonoInternalThread *thread = data->thread;
4821 MonoJitInfo *ji = NULL;
4822 gboolean protected_wrapper;
4823 gboolean running_managed;
4825 ji = mono_thread_info_get_last_managed (info);
4826 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4827 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4829 if (running_managed && !protected_wrapper) {
4830 thread->state &= ~ThreadState_SuspendRequested;
4831 thread->state |= ThreadState_Suspended;
4832 return KeepSuspended;
4834 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4835 InterlockedIncrement (&thread_interruption_requested);
4836 if (data->interrupt)
4837 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4839 return MonoResumeThread;
4843 /* LOCKING: called with @thread synch_cs held, and releases it */
4845 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4847 SuspendThreadData data;
4849 g_assert (thread != mono_thread_internal_current ());
4851 data.thread = thread;
4852 data.interrupt = interrupt;
4853 data.interrupt_token = NULL;
4855 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4856 if (data.interrupt_token)
4857 mono_thread_info_finish_interrupt (data.interrupt_token);
4859 UNLOCK_THREAD (thread);
4862 /* LOCKING: called with @thread synch_cs held, and releases it */
4864 self_suspend_internal (void)
4866 MonoInternalThread *thread;
4868 thread = mono_thread_internal_current ();
4870 mono_thread_info_begin_self_suspend ();
4871 thread->state &= ~ThreadState_SuspendRequested;
4872 thread->state |= ThreadState_Suspended;
4874 UNLOCK_THREAD (thread);
4876 mono_thread_info_end_self_suspend ();
4880 * mono_thread_is_foreign:
4881 * @thread: the thread to query
4883 * This function allows one to determine if a thread was created by the mono runtime and has
4884 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4886 * Returns: TRUE if @thread was not created by the runtime.
4889 mono_thread_is_foreign (MonoThread *thread)
4891 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4892 return info->runtime_thread == FALSE;
4896 * mono_add_joinable_thread:
4898 * Add TID to the list of joinable threads.
4899 * LOCKING: Acquires the threads lock.
4902 mono_threads_add_joinable_thread (gpointer tid)
4906 * We cannot detach from threads because it causes problems like
4907 * 2fd16f60/r114307. So we collect them and join them when
4908 * we have time (in he finalizer thread).
4910 joinable_threads_lock ();
4911 if (!joinable_threads)
4912 joinable_threads = g_hash_table_new (NULL, NULL);
4913 g_hash_table_insert (joinable_threads, tid, tid);
4914 joinable_thread_count ++;
4915 joinable_threads_unlock ();
4917 mono_gc_finalize_notify ();
4922 * mono_threads_join_threads:
4924 * Join all joinable threads. This is called from the finalizer thread.
4925 * LOCKING: Acquires the threads lock.
4928 mono_threads_join_threads (void)
4931 GHashTableIter iter;
4938 if (!joinable_thread_count)
4942 joinable_threads_lock ();
4944 if (g_hash_table_size (joinable_threads)) {
4945 g_hash_table_iter_init (&iter, joinable_threads);
4946 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4947 thread = (pthread_t)tid;
4948 g_hash_table_remove (joinable_threads, key);
4949 joinable_thread_count --;
4952 joinable_threads_unlock ();
4954 if (thread != pthread_self ())
4955 /* This shouldn't block */
4956 pthread_join (thread, NULL);
4967 * Wait for thread TID to exit.
4968 * LOCKING: Acquires the threads lock.
4971 mono_thread_join (gpointer tid)
4975 gboolean found = FALSE;
4977 joinable_threads_lock ();
4978 if (!joinable_threads)
4979 joinable_threads = g_hash_table_new (NULL, NULL);
4980 if (g_hash_table_lookup (joinable_threads, tid)) {
4981 g_hash_table_remove (joinable_threads, tid);
4982 joinable_thread_count --;
4985 joinable_threads_unlock ();
4988 thread = (pthread_t)tid;
4989 pthread_join (thread, NULL);
4994 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4996 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4997 mono_thread_interruption_checkpoint ();
5000 static inline gboolean
5001 is_appdomainunloaded_exception (MonoClass *klass)
5003 return klass == mono_class_get_appdomain_unloaded_exception_class ();
5006 static inline gboolean
5007 is_threadabort_exception (MonoClass *klass)
5009 return klass == mono_defaults.threadabortexception_class;
5013 mono_thread_internal_unhandled_exception (MonoObject* exc)
5015 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5016 MonoClass *klass = exc->vtable->klass;
5017 if (is_threadabort_exception (klass)) {
5018 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5019 } else if (!is_appdomainunloaded_exception (klass)) {
5020 mono_unhandled_exception (exc);
5021 if (mono_environment_exitcode_get () == 1)
5028 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5030 mono_threads_get_thread_dump (out_threads, out_stack_traces);