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)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threadpool.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-internal.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/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internal.h>
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64)
51 #define USE_TKILL_ON_ANDROID 1
54 #ifdef PLATFORM_ANDROID
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid, int signal);
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func)(void *);
107 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
108 struct _MonoThreadDomainTls {
109 MonoThreadDomainTls *next;
117 MonoThreadDomainTls *freelist;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 #define mono_threads_lock() mono_mutex_lock (&threads_mutex)
130 #define mono_threads_unlock() mono_mutex_unlock (&threads_mutex)
131 static mono_mutex_t threads_mutex;
133 /* Controls access to context static data */
134 #define mono_contexts_lock() mono_mutex_lock (&contexts_mutex)
135 #define mono_contexts_unlock() mono_mutex_unlock (&contexts_mutex)
136 static mono_mutex_t contexts_mutex;
138 /* Controls access to the 'joinable_threads' hash table */
139 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
140 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
141 static mono_mutex_t joinable_threads_mutex;
143 /* Holds current status of static data heap */
144 static StaticDataInfo thread_static_info;
145 static StaticDataInfo context_static_info;
147 /* The hash of existing threads (key is thread ID, value is
148 * MonoInternalThread*) that need joining before exit
150 static MonoGHashTable *threads=NULL;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable *threads_starting_up = NULL;
159 /* Maps a MonoThread to its start argument */
160 /* Protected by mono_threads_lock () */
161 static MonoGHashTable *thread_start_args = NULL;
163 /* The TLS key that holds the MonoObject assigned to each thread */
164 static MonoNativeTlsKey current_object_key;
167 /* Protected by the threads lock */
168 static GHashTable *joinable_threads;
169 static int joinable_thread_count;
171 #ifdef MONO_HAVE_FAST_TLS
172 /* we need to use both the Tls* functions and __thread because
173 * the gc needs to see all the threads
175 MONO_FAST_TLS_DECLARE(tls_current_object);
176 #define SET_CURRENT_OBJECT(x) do { \
177 MONO_FAST_TLS_SET (tls_current_object, x); \
178 mono_native_tls_set_value (current_object_key, x); \
180 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
182 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
183 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
186 /* function called at thread start */
187 static MonoThreadStartCB mono_thread_start_cb = NULL;
189 /* function called at thread attach */
190 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
192 /* function called at thread cleanup */
193 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
195 /* function called to notify the runtime about a pending exception on the current thread */
196 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
198 /* The default stack size for each thread */
199 static guint32 default_stacksize = 0;
200 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
202 static void thread_adjust_static_data (MonoInternalThread *thread);
203 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
204 static void mono_init_static_data_info (StaticDataInfo *static_data);
205 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
206 static gboolean mono_thread_resume (MonoInternalThread* thread);
207 static void signal_thread_state_change (MonoInternalThread *thread);
208 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
209 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
210 static void self_suspend_internal (MonoInternalThread *thread);
211 static gboolean resume_thread_internal (MonoInternalThread *thread);
213 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
214 static void ref_stack_destroy (gpointer rs);
216 /* Spin lock for InterlockedXXX 64 bit functions */
217 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
218 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
219 static mono_mutex_t interlocked_mutex;
221 /* global count of thread interruptions requested */
222 static gint32 thread_interruption_requested = 0;
224 /* Event signaled when a thread changes its background mode */
225 static HANDLE background_change_event;
227 static gboolean shutting_down = FALSE;
229 static gint32 managed_thread_id_counter = 0;
232 get_next_managed_thread_id (void)
234 return InterlockedIncrement (&managed_thread_id_counter);
238 mono_thread_get_tls_key (void)
240 return current_object_key;
244 mono_thread_get_tls_offset (void)
247 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
251 static inline MonoNativeThreadId
252 thread_get_tid (MonoInternalThread *thread)
254 /* We store the tid as a guint64 to keep the object layout constant between platforms */
255 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
258 /* handle_store() and handle_remove() manage the array of threads that
259 * still need to be waited for when the main thread exits.
261 * If handle_store() returns FALSE the thread must not be started
262 * because Mono is shutting down.
264 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
266 mono_threads_lock ();
268 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
270 if (threads_starting_up)
271 mono_g_hash_table_remove (threads_starting_up, thread);
273 if (shutting_down && !force_attach) {
274 mono_threads_unlock ();
279 MONO_GC_REGISTER_ROOT_FIXED (threads);
280 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
283 /* We don't need to duplicate thread->handle, because it is
284 * only closed when the thread object is finalized by the GC.
286 g_assert (thread->internal_thread);
287 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
288 thread->internal_thread);
290 mono_threads_unlock ();
295 static gboolean handle_remove(MonoInternalThread *thread)
298 gsize tid = thread->tid;
300 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
302 mono_threads_lock ();
305 /* We have to check whether the thread object for the
306 * tid is still the same in the table because the
307 * thread might have been destroyed and the tid reused
308 * in the meantime, in which case the tid would be in
309 * the table, but with another thread object.
311 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
312 mono_g_hash_table_remove (threads, (gpointer)tid);
321 mono_threads_unlock ();
323 /* Don't close the handle here, wait for the object finalizer
324 * to do it. Otherwise, the following race condition applies:
326 * 1) Thread exits (and handle_remove() closes the handle)
328 * 2) Some other handle is reassigned the same slot
330 * 3) Another thread tries to join the first thread, and
331 * blocks waiting for the reassigned handle to be signalled
332 * (which might never happen). This is possible, because the
333 * thread calling Join() still has a reference to the first
339 static void ensure_synch_cs_set (MonoInternalThread *thread)
341 mono_mutex_t *synch_cs;
343 if (thread->synch_cs != NULL) {
347 synch_cs = g_new0 (mono_mutex_t, 1);
348 mono_mutex_init_recursive (synch_cs);
350 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
351 synch_cs, NULL) != NULL) {
352 /* Another thread must have installed this CS */
353 mono_mutex_destroy (synch_cs);
359 lock_thread (MonoInternalThread *thread)
361 if (!thread->synch_cs)
362 ensure_synch_cs_set (thread);
364 g_assert (thread->synch_cs);
365 mono_mutex_lock (thread->synch_cs);
369 unlock_thread (MonoInternalThread *thread)
371 mono_mutex_unlock (thread->synch_cs);
375 * NOTE: this function can be called also for threads different from the current one:
376 * make sure no code called from it will ever assume it is run on the thread that is
377 * getting cleaned up.
379 static void thread_cleanup (MonoInternalThread *thread)
381 g_assert (thread != NULL);
383 if (thread->abort_state_handle) {
384 mono_gchandle_free (thread->abort_state_handle);
385 thread->abort_state_handle = 0;
387 thread->abort_exc = NULL;
388 thread->current_appcontext = NULL;
391 * This is necessary because otherwise we might have
392 * cross-domain references which will not get cleaned up when
393 * the target domain is unloaded.
395 if (thread->cached_culture_info) {
397 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
398 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
402 * thread->synch_cs can be NULL if this was called after
403 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
404 * This can happen only during shutdown.
405 * The shutting_down flag is not always set, so we can't assert on it.
407 if (thread->synch_cs)
408 LOCK_THREAD (thread);
410 thread->state |= ThreadState_Stopped;
411 thread->state &= ~ThreadState_Background;
413 if (thread->synch_cs)
414 UNLOCK_THREAD (thread);
417 An interruption request has leaked to cleanup. Adjust the global counter.
419 This can happen is the abort source thread finds the abortee (this) thread
420 in unmanaged code. If this thread never trips back to managed code or check
421 the local flag it will be left set and positively unbalance the global counter.
423 Leaving the counter unbalanced will cause a performance degradation since all threads
424 will now keep checking their local flags all the time.
426 if (InterlockedExchange (&thread->interruption_requested, 0))
427 InterlockedDecrement (&thread_interruption_requested);
429 /* if the thread is not in the hash it has been removed already */
430 if (!handle_remove (thread)) {
431 if (thread == mono_thread_internal_current ()) {
432 mono_domain_unset ();
433 mono_memory_barrier ();
435 /* This needs to be called even if handle_remove () fails */
436 if (mono_thread_cleanup_fn)
437 mono_thread_cleanup_fn (thread);
440 mono_release_type_locks (thread);
442 mono_profiler_thread_end (thread->tid);
444 if (thread == mono_thread_internal_current ()) {
446 * This will signal async signal handlers that the thread has exited.
447 * The profiler callback needs this to be set, so it cannot be done earlier.
449 mono_domain_unset ();
450 mono_memory_barrier ();
453 if (thread == mono_thread_internal_current ())
454 mono_thread_pop_appdomain_ref ();
456 thread->cached_culture_info = NULL;
458 mono_free_static_data (thread->static_data, TRUE);
459 thread->static_data = NULL;
460 ref_stack_destroy (thread->appdomain_refs);
461 thread->appdomain_refs = NULL;
463 if (mono_thread_cleanup_fn)
464 mono_thread_cleanup_fn (thread);
466 if (mono_gc_is_moving ()) {
467 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
468 thread->thread_pinning_ref = NULL;
473 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
476 g_assert ((offset & 0x80000000) == 0);
477 offset &= 0x7fffffff;
478 idx = (offset >> 24) - 1;
479 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
483 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
485 static MonoClassField *current_thread_field = NULL;
489 if (!current_thread_field) {
490 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
491 g_assert (current_thread_field);
494 mono_class_vtable (domain, mono_defaults.thread_class);
495 mono_domain_lock (domain);
496 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
497 mono_domain_unlock (domain);
500 return get_thread_static_data (thread, offset);
504 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
506 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
508 g_assert (current->obj.vtable->domain == domain);
510 g_assert (!*current_thread_ptr);
511 *current_thread_ptr = current;
515 create_thread_object (MonoDomain *domain)
517 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
518 return (MonoThread*)mono_gc_alloc_mature (vt);
522 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
524 MonoThread *thread = create_thread_object (domain);
525 MONO_OBJECT_SETREF (thread, internal_thread, internal);
529 static MonoInternalThread*
530 create_internal_thread (void)
532 MonoInternalThread *thread;
535 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
536 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
538 thread->synch_cs = g_new0 (mono_mutex_t, 1);
539 mono_mutex_init_recursive (thread->synch_cs);
541 thread->apartment_state = ThreadApartmentState_Unknown;
542 thread->managed_id = get_next_managed_thread_id ();
543 if (mono_gc_is_moving ()) {
544 thread->thread_pinning_ref = thread;
545 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
552 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
554 MonoDomain *domain = mono_get_root_domain ();
556 if (!candidate || candidate->obj.vtable->domain != domain)
557 candidate = new_thread_with_internal (domain, thread);
558 set_current_thread_for_domain (domain, thread, candidate);
559 g_assert (!thread->root_domain_thread);
560 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
563 static guint32 WINAPI start_wrapper_internal(void *data)
565 MonoThreadInfo *info;
566 StartInfo *start_info = (StartInfo *)data;
567 guint32 (*start_func)(void *);
571 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
574 MonoInternalThread *internal = start_info->obj->internal_thread;
575 MonoObject *start_delegate = start_info->delegate;
576 MonoDomain *domain = start_info->obj->obj.vtable->domain;
578 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
580 /* We can be sure start_info->obj->tid and
581 * start_info->obj->handle have been set, because the thread
582 * was created suspended, and these values were set before the
586 info = mono_thread_info_current ();
588 internal->thread_info = info;
593 SET_CURRENT_OBJECT (internal);
595 mono_monitor_init_tls ();
597 /* Every thread references the appdomain which created it */
598 mono_thread_push_appdomain_ref (domain);
600 if (!mono_domain_set (domain, FALSE)) {
601 /* No point in raising an appdomain_unloaded exception here */
602 /* FIXME: Cleanup here */
603 mono_thread_pop_appdomain_ref ();
607 start_func = start_info->func;
608 start_arg = start_info->start_arg;
610 /* We have to do this here because mono_thread_new_init()
611 requires that root_domain_thread is set up. */
612 thread_adjust_static_data (internal);
613 init_root_domain_thread (internal, start_info->obj);
615 /* This MUST be called before any managed code can be
616 * executed, as it calls the callback function that (for the
617 * jit) sets the lmf marker.
619 mono_thread_new_init (tid, &tid, start_func);
620 internal->stack_ptr = &tid;
622 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
624 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
626 /* On 2.0 profile (and higher), set explicitly since state might have been
628 if (internal->apartment_state == ThreadApartmentState_Unknown)
629 internal->apartment_state = ThreadApartmentState_MTA;
631 mono_thread_init_apartment_state ();
633 if(internal->start_notify!=NULL) {
634 /* Let the thread that called Start() know we're
637 ReleaseSemaphore (internal->start_notify, 1, NULL);
640 mono_threads_lock ();
641 mono_g_hash_table_remove (thread_start_args, start_info->obj);
642 mono_threads_unlock ();
644 mono_thread_set_execution_context (start_info->obj->ec_to_set);
645 start_info->obj->ec_to_set = NULL;
648 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
652 * Call this after calling start_notify, since the profiler callback might want
653 * to lock the thread, and the lock is held by thread_start () which waits for
656 mono_profiler_thread_start (tid);
658 /* if the name was set before starting, we didn't invoke the profiler callback */
659 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
660 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
661 mono_profiler_thread_name (internal->tid, tname);
664 /* start_func is set only for unmanaged start functions */
666 start_func (start_arg);
669 g_assert (start_delegate != NULL);
670 args [0] = start_arg;
671 /* we may want to handle the exception here. See comment below on unhandled exceptions */
672 mono_runtime_delegate_invoke (start_delegate, args, NULL);
675 /* If the thread calls ExitThread at all, this remaining code
676 * will not be executed, but the main thread will eventually
677 * call thread_cleanup() on this thread's behalf.
680 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
682 /* Do any cleanup needed for apartment state. This
683 * cannot be done in thread_cleanup since thread_cleanup could be
684 * called for a thread other than the current thread.
685 * mono_thread_cleanup_apartment_state cleans up apartment
686 * for the current thead */
687 mono_thread_cleanup_apartment_state ();
689 thread_cleanup (internal);
693 /* Remove the reference to the thread object in the TLS data,
694 * so the thread object can be finalized. This won't be
695 * reached if the thread threw an uncaught exception, so those
696 * thread handles will stay referenced :-( (This is due to
697 * missing support for scanning thread-specific data in the
698 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
701 SET_CURRENT_OBJECT (NULL);
706 static guint32 WINAPI start_wrapper(void *data)
710 /* Avoid scanning the frames above this frame during a GC */
711 mono_gc_set_stack_end ((void*)&dummy);
713 return start_wrapper_internal (data);
719 * Common thread creation code.
720 * LOCKING: Acquires the threads lock.
723 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
724 gboolean throw_on_failure)
726 HANDLE thread_handle;
727 MonoNativeThreadId tid;
728 guint32 create_flags;
731 * Join joinable threads to prevent running out of threads since the finalizer
732 * thread might be blocked/backlogged.
734 mono_threads_join_threads ();
736 mono_threads_lock ();
739 mono_threads_unlock ();
743 * The thread start argument may be an object reference, and there is
744 * no ref to keep it alive when the new thread is started but not yet
745 * registered with the collector. So we store it in a GC tracked hash
748 if (thread_start_args == NULL) {
749 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
750 thread_start_args = mono_g_hash_table_new (NULL, NULL);
752 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
753 if (threads_starting_up == NULL) {
754 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
755 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
757 mono_g_hash_table_insert (threads_starting_up, thread, thread);
758 mono_threads_unlock ();
760 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
761 if (!internal->start_notify) {
762 mono_threads_lock ();
763 mono_g_hash_table_remove (threads_starting_up, thread);
764 mono_threads_unlock ();
765 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
771 stack_size = default_stacksize_for_thread (internal);
773 /* Create suspended, so we can do some housekeeping before the thread
776 create_flags = CREATE_SUSPENDED;
777 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
778 stack_size, create_flags, &tid);
779 if (thread_handle == NULL) {
780 /* The thread couldn't be created, so throw an exception */
781 mono_threads_lock ();
782 mono_g_hash_table_remove (threads_starting_up, thread);
783 mono_threads_unlock ();
785 if (throw_on_failure)
786 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
788 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
791 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
793 internal->handle = thread_handle;
794 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
796 internal->threadpool_thread = threadpool_thread;
797 if (threadpool_thread)
798 mono_thread_set_state (internal, ThreadState_Background);
800 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
802 /* Only store the handle when the thread is about to be
803 * launched, to avoid the main thread deadlocking while trying
804 * to clean up a thread that will never be signalled.
806 if (!handle_store (thread, FALSE))
809 mono_thread_info_resume (tid);
811 if (internal->start_notify) {
813 * Wait for the thread to set up its TLS data etc, so
814 * theres no potential race condition if someone tries
815 * to look up the data believing the thread has
818 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
820 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
821 CloseHandle (internal->start_notify);
822 internal->start_notify = NULL;
825 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
830 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
832 if (mono_thread_start_cb) {
833 mono_thread_start_cb (tid, stack_start, func);
837 void mono_threads_set_default_stacksize (guint32 stacksize)
839 default_stacksize = stacksize;
842 guint32 mono_threads_get_default_stacksize (void)
844 return default_stacksize;
848 * mono_thread_create_internal:
852 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
855 MonoInternalThread *internal;
856 StartInfo *start_info;
859 thread = create_thread_object (domain);
860 internal = create_internal_thread ();
861 MONO_OBJECT_SETREF (thread, internal_thread, internal);
863 start_info = g_new0 (StartInfo, 1);
864 start_info->func = func;
865 start_info->obj = thread;
866 start_info->start_arg = arg;
868 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
872 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
873 if (mono_check_corlib_version () == NULL)
874 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
880 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
882 mono_thread_create_internal (domain, func, arg, FALSE, 0);
886 mono_thread_attach (MonoDomain *domain)
888 return mono_thread_attach_full (domain, FALSE);
892 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
894 MonoThreadInfo *info;
895 MonoInternalThread *thread;
896 MonoThread *current_thread;
897 HANDLE thread_handle;
900 if ((thread = mono_thread_internal_current ())) {
901 if (domain != mono_domain_get ())
902 mono_domain_set (domain, TRUE);
903 /* Already attached */
904 return mono_thread_current ();
907 if (!mono_gc_register_thread (&domain)) {
908 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.", GetCurrentThreadId ());
911 thread = create_internal_thread ();
913 thread_handle = mono_thread_info_open_handle ();
914 g_assert (thread_handle);
916 tid=GetCurrentThreadId ();
918 thread->handle=thread_handle;
920 #ifdef PLATFORM_ANDROID
921 thread->android_tid = (gpointer) gettid ();
923 thread->stack_ptr = &tid;
925 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
927 info = mono_thread_info_current ();
929 thread->thread_info = info;
931 current_thread = new_thread_with_internal (domain, thread);
933 if (!handle_store (current_thread, force_attach)) {
934 /* Mono is shutting down, so just wait for the end */
939 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
941 SET_CURRENT_OBJECT (thread);
942 mono_domain_set (domain, TRUE);
944 mono_monitor_init_tls ();
946 thread_adjust_static_data (thread);
948 init_root_domain_thread (thread, current_thread);
949 if (domain != mono_get_root_domain ())
950 set_current_thread_for_domain (domain, thread, current_thread);
953 if (mono_thread_attach_cb) {
957 mono_thread_info_get_stack_bounds (&staddr, &stsize);
960 mono_thread_attach_cb (tid, &tid);
962 mono_thread_attach_cb (tid, staddr + stsize);
965 // FIXME: Need a separate callback
966 mono_profiler_thread_start (tid);
968 return current_thread;
972 mono_thread_detach_internal (MonoInternalThread *thread)
974 g_return_if_fail (thread != NULL);
976 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
978 thread_cleanup (thread);
980 SET_CURRENT_OBJECT (NULL);
981 mono_domain_unset ();
983 /* Don't need to CloseHandle this thread, even though we took a
984 * reference in mono_thread_attach (), because the GC will do it
985 * when the Thread object is finalised.
990 mono_thread_detach (MonoThread *thread)
993 mono_thread_detach_internal (thread->internal_thread);
997 * mono_thread_detach_if_exiting:
999 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1000 * This should be used at the end of embedding code which calls into managed code, and which
1001 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1004 mono_thread_detach_if_exiting (void)
1006 if (mono_thread_info_is_exiting ()) {
1007 MonoInternalThread *thread;
1009 thread = mono_thread_internal_current ();
1011 mono_thread_detach_internal (thread);
1012 mono_thread_info_detach ();
1020 MonoInternalThread *thread = mono_thread_internal_current ();
1022 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1024 thread_cleanup (thread);
1025 SET_CURRENT_OBJECT (NULL);
1026 mono_domain_unset ();
1028 /* we could add a callback here for embedders to use. */
1029 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1030 exit (mono_environment_exitcode_get ());
1031 mono_thread_info_exit ();
1035 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1037 MonoInternalThread *internal = create_internal_thread ();
1039 internal->state = ThreadState_Unstarted;
1041 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1045 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
1048 StartInfo *start_info;
1049 MonoInternalThread *internal;
1052 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1054 if (!this->internal_thread)
1055 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1056 internal = this->internal_thread;
1058 LOCK_THREAD (internal);
1060 if ((internal->state & ThreadState_Unstarted) == 0) {
1061 UNLOCK_THREAD (internal);
1062 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1066 if ((internal->state & ThreadState_Aborted) != 0) {
1067 UNLOCK_THREAD (internal);
1070 /* This is freed in start_wrapper */
1071 start_info = g_new0 (StartInfo, 1);
1072 start_info->func = NULL;
1073 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1074 start_info->delegate = start;
1075 start_info->obj = this;
1076 g_assert (this->obj.vtable->domain == mono_domain_get ());
1078 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1080 UNLOCK_THREAD (internal);
1084 internal->state &= ~ThreadState_Unstarted;
1086 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1088 UNLOCK_THREAD (internal);
1089 return internal->handle;
1093 * This is called from the finalizer of the internal thread object.
1096 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1098 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1101 * Since threads keep a reference to their thread object while running, by the time this function is called,
1102 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1103 * when thread_cleanup () can be called after this.
1106 CloseHandle (thread);
1108 if (this->synch_cs) {
1109 mono_mutex_t *synch_cs = this->synch_cs;
1110 this->synch_cs = NULL;
1111 mono_mutex_destroy (synch_cs);
1116 void *name = this->name;
1122 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1125 MonoInternalThread *thread = mono_thread_internal_current ();
1127 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1129 mono_thread_current_check_pending_interrupt ();
1132 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1134 res = SleepEx(ms,TRUE);
1136 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1138 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1139 MonoException* exc = mono_thread_execute_interruption (thread);
1141 mono_raise_exception (exc);
1153 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1158 ves_icall_System_Threading_Thread_GetDomainID (void)
1160 return mono_domain_get()->domain_id;
1164 ves_icall_System_Threading_Thread_Yield (void)
1166 return mono_thread_info_yield ();
1170 * mono_thread_get_name:
1172 * Return the name of the thread. NAME_LEN is set to the length of the name.
1173 * Return NULL if the thread has no name. The returned memory is owned by the
1177 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1181 LOCK_THREAD (this_obj);
1183 if (!this_obj->name) {
1187 *name_len = this_obj->name_len;
1188 res = g_new (gunichar2, this_obj->name_len);
1189 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1192 UNLOCK_THREAD (this_obj);
1198 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1202 LOCK_THREAD (this_obj);
1204 if (!this_obj->name)
1207 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1209 UNLOCK_THREAD (this_obj);
1215 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1217 LOCK_THREAD (this_obj);
1219 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1220 UNLOCK_THREAD (this_obj);
1222 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1225 if (this_obj->name) {
1226 g_free (this_obj->name);
1227 this_obj->name_len = 0;
1230 this_obj->name = g_new (gunichar2, mono_string_length (name));
1231 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1232 this_obj->name_len = mono_string_length (name);
1235 this_obj->name = NULL;
1238 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1240 UNLOCK_THREAD (this_obj);
1242 if (this_obj->name && this_obj->tid) {
1243 char *tname = mono_string_to_utf8 (name);
1244 mono_profiler_thread_name (this_obj->tid, tname);
1245 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1251 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1253 mono_thread_set_name_internal (this_obj, name, TRUE);
1256 /* If the array is already in the requested domain, we just return it,
1257 otherwise we return a copy in that domain. */
1259 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1266 if (mono_object_domain (arr) == domain)
1269 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1270 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1275 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1277 return byte_array_to_domain (arr, mono_get_root_domain ());
1281 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1283 return byte_array_to_domain (arr, mono_domain_get ());
1287 mono_thread_current (void)
1289 MonoDomain *domain = mono_domain_get ();
1290 MonoInternalThread *internal = mono_thread_internal_current ();
1291 MonoThread **current_thread_ptr;
1293 g_assert (internal);
1294 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1296 if (!*current_thread_ptr) {
1297 g_assert (domain != mono_get_root_domain ());
1298 *current_thread_ptr = new_thread_with_internal (domain, internal);
1300 return *current_thread_ptr;
1304 mono_thread_internal_current (void)
1306 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1307 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1311 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1312 int ms, HANDLE thread)
1314 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1317 mono_thread_current_check_pending_interrupt ();
1321 if ((this->state & ThreadState_Unstarted) != 0) {
1322 UNLOCK_THREAD (this);
1324 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1328 UNLOCK_THREAD (this);
1333 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1335 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1337 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1339 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1341 if(ret==WAIT_OBJECT_0) {
1342 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1347 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1353 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1361 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1364 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1366 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1368 if (ret != WAIT_IO_COMPLETION)
1371 exc = mono_thread_execute_interruption (thread);
1373 mono_raise_exception (exc);
1378 /* Re-calculate ms according to the time passed */
1379 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1380 if (diff_ms >= ms) {
1384 wait = ms - diff_ms;
1390 /* FIXME: exitContext isnt documented */
1391 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1397 MonoObject *waitHandle;
1398 MonoInternalThread *thread = mono_thread_internal_current ();
1400 /* Do this WaitSleepJoin check before creating objects */
1401 mono_thread_current_check_pending_interrupt ();
1403 /* We fail in managed if the array has more than 64 elements */
1404 numhandles = (guint32)mono_array_length(mono_handles);
1405 handles = g_new0(HANDLE, numhandles);
1407 for(i = 0; i < numhandles; i++) {
1408 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1409 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1416 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1418 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1420 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1424 if(ret==WAIT_FAILED) {
1425 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1427 } else if(ret==WAIT_TIMEOUT) {
1428 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1435 /* FIXME: exitContext isnt documented */
1436 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1438 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1439 uintptr_t numhandles;
1442 MonoObject *waitHandle;
1443 MonoInternalThread *thread = mono_thread_internal_current ();
1445 /* Do this WaitSleepJoin check before creating objects */
1446 mono_thread_current_check_pending_interrupt ();
1448 numhandles = mono_array_length(mono_handles);
1449 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1452 for(i = 0; i < numhandles; i++) {
1453 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1454 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1461 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1463 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1465 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1467 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1470 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1472 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1473 return ret - WAIT_OBJECT_0;
1475 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1476 return ret - WAIT_ABANDONED_0;
1483 /* FIXME: exitContext isnt documented */
1484 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1487 MonoInternalThread *thread = mono_thread_internal_current ();
1489 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1495 mono_thread_current_check_pending_interrupt ();
1497 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1499 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1501 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1503 if(ret==WAIT_FAILED) {
1504 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1506 } else if(ret==WAIT_TIMEOUT) {
1507 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1515 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1518 MonoInternalThread *thread = mono_thread_internal_current ();
1523 mono_thread_current_check_pending_interrupt ();
1525 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1527 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1529 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1531 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1534 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1541 mutex = CreateMutex (NULL, owned, NULL);
1543 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1545 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1553 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1554 return(ReleaseMutex (handle));
1557 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1563 *error = ERROR_SUCCESS;
1565 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1567 *error = GetLastError ();
1574 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1581 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1583 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1584 mono_string_chars (name));
1586 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1594 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1598 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1603 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1607 *error = ERROR_SUCCESS;
1609 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1611 *error = GetLastError ();
1617 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1624 event = CreateEvent (NULL, manual, initial, NULL);
1626 event = CreateEvent (NULL, manual, initial,
1627 mono_string_chars (name));
1629 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1637 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1638 return (SetEvent(handle));
1641 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1642 return (ResetEvent(handle));
1646 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1647 CloseHandle (handle);
1650 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1656 *error = ERROR_SUCCESS;
1658 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1660 *error = GetLastError ();
1666 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1668 return InterlockedIncrement (location);
1671 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1673 #if SIZEOF_VOID_P == 4
1674 if (G_UNLIKELY ((size_t)location & 0x7)) {
1676 mono_interlocked_lock ();
1679 mono_interlocked_unlock ();
1683 return InterlockedIncrement64 (location);
1686 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1688 return InterlockedDecrement(location);
1691 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1693 #if SIZEOF_VOID_P == 4
1694 if (G_UNLIKELY ((size_t)location & 0x7)) {
1696 mono_interlocked_lock ();
1699 mono_interlocked_unlock ();
1703 return InterlockedDecrement64 (location);
1706 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1708 return InterlockedExchange(location, value);
1711 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1714 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1715 mono_gc_wbarrier_generic_nostore (location);
1719 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1721 return InterlockedExchangePointer(location, value);
1724 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1726 IntFloatUnion val, ret;
1729 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1735 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1737 #if SIZEOF_VOID_P == 4
1738 if (G_UNLIKELY ((size_t)location & 0x7)) {
1740 mono_interlocked_lock ();
1743 mono_interlocked_unlock ();
1747 return InterlockedExchange64 (location, value);
1751 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1753 LongDoubleUnion val, ret;
1756 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1761 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1763 return InterlockedCompareExchange(location, value, comparand);
1766 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1769 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1770 mono_gc_wbarrier_generic_nostore (location);
1774 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1776 return InterlockedCompareExchangePointer(location, value, comparand);
1779 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1781 IntFloatUnion val, ret, cmp;
1784 cmp.fval = comparand;
1785 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1791 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1793 #if SIZEOF_VOID_P == 8
1794 LongDoubleUnion val, comp, ret;
1797 comp.fval = comparand;
1798 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1804 mono_interlocked_lock ();
1806 if (old == comparand)
1808 mono_interlocked_unlock ();
1815 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1817 #if SIZEOF_VOID_P == 4
1818 if (G_UNLIKELY ((size_t)location & 0x7)) {
1820 mono_interlocked_lock ();
1822 if (old == comparand)
1824 mono_interlocked_unlock ();
1828 return InterlockedCompareExchange64 (location, value, comparand);
1832 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1835 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1836 mono_gc_wbarrier_generic_nostore (location);
1841 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1844 res = InterlockedExchangePointer ((gpointer *)location, value);
1845 mono_gc_wbarrier_generic_nostore (location);
1850 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1852 return InterlockedAdd (location, value);
1856 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1858 #if SIZEOF_VOID_P == 4
1859 if (G_UNLIKELY ((size_t)location & 0x7)) {
1861 mono_interlocked_lock ();
1864 mono_interlocked_unlock ();
1868 return InterlockedAdd64 (location, value);
1872 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1874 #if SIZEOF_VOID_P == 4
1875 if (G_UNLIKELY ((size_t)location & 0x7)) {
1877 mono_interlocked_lock ();
1879 mono_interlocked_unlock ();
1883 return InterlockedRead64 (location);
1887 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1889 mono_memory_barrier ();
1893 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1895 mono_thread_clr_state (this, state);
1897 if (state & ThreadState_Background) {
1898 /* If the thread changes the background mode, the main thread has to
1899 * be notified, since it has to rebuild the list of threads to
1902 SetEvent (background_change_event);
1907 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1909 mono_thread_set_state (this, state);
1911 if (state & ThreadState_Background) {
1912 /* If the thread changes the background mode, the main thread has to
1913 * be notified, since it has to rebuild the list of threads to
1916 SetEvent (background_change_event);
1921 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1927 state = this->state;
1929 UNLOCK_THREAD (this);
1934 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
1936 MonoInternalThread *current;
1941 current = mono_thread_internal_current ();
1943 this->thread_interrupt_requested = TRUE;
1944 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
1946 UNLOCK_THREAD (this);
1949 abort_thread_internal (this, TRUE, FALSE);
1953 void mono_thread_current_check_pending_interrupt ()
1955 MonoInternalThread *thread = mono_thread_internal_current ();
1956 gboolean throw = FALSE;
1958 LOCK_THREAD (thread);
1960 if (thread->thread_interrupt_requested) {
1962 thread->thread_interrupt_requested = FALSE;
1965 UNLOCK_THREAD (thread);
1968 mono_raise_exception (mono_get_exception_thread_interrupted ());
1973 mono_thread_get_abort_signal (void)
1977 #elif defined(PLATFORM_ANDROID)
1979 #elif !defined (SIGRTMIN)
1984 #endif /* SIGUSR1 */
1986 static int abort_signum = -1;
1988 if (abort_signum != -1)
1989 return abort_signum;
1990 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
1991 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
1992 struct sigaction sinfo;
1993 sigaction (i, NULL, &sinfo);
1994 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
1999 /* fallback to the old way */
2001 #endif /* HOST_WIN32 */
2005 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2007 MonoException* exc = mono_thread_request_interruption (FALSE);
2008 if (exc) mono_raise_exception (exc);
2010 #endif /* HOST_WIN32 */
2013 * signal_thread_state_change
2015 * Tells the thread that his state has changed and it has to enter the new
2016 * state as soon as possible.
2018 static void signal_thread_state_change (MonoInternalThread *thread)
2021 gpointer wait_handle;
2024 if (thread == mono_thread_internal_current ()) {
2025 /* Do it synchronously */
2026 MonoException *exc = mono_thread_request_interruption (FALSE);
2028 mono_raise_exception (exc);
2032 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, (ULONG_PTR)NULL);
2035 * This will cause waits to be broken.
2036 * It will also prevent the thread from entering a wait, so if the thread returns
2037 * from the wait before it receives the abort signal, it will just spin in the wait
2038 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2041 wait_handle = mono_thread_info_prepare_interrupt (thread->handle);
2043 /* fixme: store the state somewhere */
2044 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2046 mono_thread_info_finish_interrupt (wait_handle);
2047 #endif /* HOST_WIN32 */
2051 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2053 LOCK_THREAD (thread);
2055 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2056 (thread->state & ThreadState_StopRequested) != 0 ||
2057 (thread->state & ThreadState_Stopped) != 0)
2059 UNLOCK_THREAD (thread);
2063 if ((thread->state & ThreadState_Unstarted) != 0) {
2064 thread->state |= ThreadState_Aborted;
2065 UNLOCK_THREAD (thread);
2069 thread->state |= ThreadState_AbortRequested;
2070 if (thread->abort_state_handle)
2071 mono_gchandle_free (thread->abort_state_handle);
2073 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2074 g_assert (thread->abort_state_handle);
2076 thread->abort_state_handle = 0;
2078 thread->abort_exc = NULL;
2081 * abort_exc is set in mono_thread_execute_interruption(),
2082 * triggered by the call to signal_thread_state_change(),
2083 * below. There's a point between where we have
2084 * abort_state_handle set, but abort_exc NULL, but that's not
2088 UNLOCK_THREAD (thread);
2090 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2092 /* During shutdown, we can't wait for other threads */
2094 /* Make sure the thread is awake */
2095 mono_thread_resume (thread);
2097 abort_thread_internal (thread, TRUE, TRUE);
2101 ves_icall_System_Threading_Thread_ResetAbort (void)
2103 MonoInternalThread *thread = mono_thread_internal_current ();
2104 gboolean was_aborting;
2106 LOCK_THREAD (thread);
2107 was_aborting = thread->state & ThreadState_AbortRequested;
2108 thread->state &= ~ThreadState_AbortRequested;
2109 UNLOCK_THREAD (thread);
2111 if (!was_aborting) {
2112 const char *msg = "Unable to reset abort because no abort was requested";
2113 mono_raise_exception (mono_get_exception_thread_state (msg));
2115 thread->abort_exc = NULL;
2116 if (thread->abort_state_handle) {
2117 mono_gchandle_free (thread->abort_state_handle);
2118 /* This is actually not necessary - the handle
2119 only counts if the exception is set */
2120 thread->abort_state_handle = 0;
2125 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2127 LOCK_THREAD (thread);
2129 thread->state &= ~ThreadState_AbortRequested;
2131 if (thread->abort_exc) {
2132 thread->abort_exc = NULL;
2133 if (thread->abort_state_handle) {
2134 mono_gchandle_free (thread->abort_state_handle);
2135 /* This is actually not necessary - the handle
2136 only counts if the exception is set */
2137 thread->abort_state_handle = 0;
2141 UNLOCK_THREAD (thread);
2145 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2147 MonoInternalThread *thread = this->internal_thread;
2148 MonoObject *state, *deserialized = NULL, *exc;
2151 if (!thread->abort_state_handle)
2154 state = mono_gchandle_get_target (thread->abort_state_handle);
2157 domain = mono_domain_get ();
2158 if (mono_object_domain (state) == domain)
2161 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2163 if (!deserialized) {
2164 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2166 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2167 mono_raise_exception (invalid_op_exc);
2170 return deserialized;
2174 mono_thread_suspend (MonoInternalThread *thread)
2176 LOCK_THREAD (thread);
2178 if ((thread->state & ThreadState_Unstarted) != 0 ||
2179 (thread->state & ThreadState_Aborted) != 0 ||
2180 (thread->state & ThreadState_Stopped) != 0)
2182 UNLOCK_THREAD (thread);
2186 if ((thread->state & ThreadState_Suspended) != 0 ||
2187 (thread->state & ThreadState_SuspendRequested) != 0 ||
2188 (thread->state & ThreadState_StopRequested) != 0)
2190 UNLOCK_THREAD (thread);
2194 thread->state |= ThreadState_SuspendRequested;
2196 UNLOCK_THREAD (thread);
2198 suspend_thread_internal (thread, FALSE);
2203 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2205 if (!mono_thread_suspend (thread))
2206 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2210 mono_thread_resume (MonoInternalThread *thread)
2212 LOCK_THREAD (thread);
2214 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2215 thread->state &= ~ThreadState_SuspendRequested;
2216 UNLOCK_THREAD (thread);
2220 if ((thread->state & ThreadState_Suspended) == 0 ||
2221 (thread->state & ThreadState_Unstarted) != 0 ||
2222 (thread->state & ThreadState_Aborted) != 0 ||
2223 (thread->state & ThreadState_Stopped) != 0)
2225 UNLOCK_THREAD (thread);
2229 return resume_thread_internal (thread);
2233 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2235 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2236 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2240 mono_threads_is_critical_method (MonoMethod *method)
2242 switch (method->wrapper_type) {
2243 case MONO_WRAPPER_RUNTIME_INVOKE:
2244 case MONO_WRAPPER_XDOMAIN_INVOKE:
2245 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2252 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2257 if (mono_threads_is_critical_method (m)) {
2258 *((gboolean*)data) = TRUE;
2265 is_running_protected_wrapper (void)
2267 gboolean found = FALSE;
2268 mono_stack_walk (find_wrapper, &found);
2272 void mono_thread_internal_stop (MonoInternalThread *thread)
2274 LOCK_THREAD (thread);
2276 if ((thread->state & ThreadState_StopRequested) != 0 ||
2277 (thread->state & ThreadState_Stopped) != 0)
2279 UNLOCK_THREAD (thread);
2283 /* Make sure the thread is awake */
2284 mono_thread_resume (thread);
2286 thread->state |= ThreadState_StopRequested;
2287 thread->state &= ~ThreadState_AbortRequested;
2289 UNLOCK_THREAD (thread);
2291 abort_thread_internal (thread, TRUE, TRUE);
2294 void mono_thread_stop (MonoThread *thread)
2296 mono_thread_internal_stop (thread->internal_thread);
2300 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2303 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2308 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2311 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2316 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2319 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2324 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2327 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2332 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2335 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2336 return (void *) tmp;
2340 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2342 volatile MonoObject *tmp;
2343 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2344 return (MonoObject *) tmp;
2348 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2351 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2356 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2359 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2364 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2366 return InterlockedRead8 (ptr);
2370 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2372 return InterlockedRead16 (ptr);
2376 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2378 return InterlockedRead (ptr);
2382 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2384 #if SIZEOF_VOID_P == 4
2385 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2387 mono_interlocked_lock ();
2388 val = *(gint64*)ptr;
2389 mono_interlocked_unlock ();
2393 return InterlockedRead64 (ptr);
2397 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2399 return InterlockedReadPointer (ptr);
2403 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2407 #if SIZEOF_VOID_P == 4
2408 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2410 mono_interlocked_lock ();
2411 val = *(double*)ptr;
2412 mono_interlocked_unlock ();
2417 u.ival = InterlockedRead64 (ptr);
2423 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2427 u.ival = InterlockedRead (ptr);
2433 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2435 return InterlockedReadPointer (ptr);
2439 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2441 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2445 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2447 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2451 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2453 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2457 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2459 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2463 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2465 mono_atomic_store_release ((volatile void **) ptr, value);
2469 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2471 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2475 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2477 mono_atomic_store_release ((volatile double *) ptr, value);
2481 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2483 mono_atomic_store_release ((volatile float *) ptr, value);
2487 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2489 InterlockedWrite8 (ptr, value);
2493 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2495 InterlockedWrite16 (ptr, value);
2499 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2501 InterlockedWrite (ptr, value);
2505 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2507 #if SIZEOF_VOID_P == 4
2508 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2509 mono_interlocked_lock ();
2510 *(gint64*)ptr = value;
2511 mono_interlocked_unlock ();
2516 InterlockedWrite64 (ptr, value);
2520 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2522 InterlockedWritePointer (ptr, value);
2526 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2530 #if SIZEOF_VOID_P == 4
2531 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2532 mono_interlocked_lock ();
2533 *(double*)ptr = value;
2534 mono_interlocked_unlock ();
2541 InterlockedWrite64 (ptr, u.ival);
2545 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2551 InterlockedWrite (ptr, u.ival);
2555 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2557 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2561 mono_thread_init_tls (void)
2563 MONO_FAST_TLS_INIT (tls_current_object);
2564 mono_native_tls_alloc (¤t_object_key, NULL);
2567 void mono_thread_init (MonoThreadStartCB start_cb,
2568 MonoThreadAttachCB attach_cb)
2570 mono_mutex_init_recursive(&threads_mutex);
2571 mono_mutex_init_recursive(&interlocked_mutex);
2572 mono_mutex_init_recursive(&contexts_mutex);
2573 mono_mutex_init_recursive(&joinable_threads_mutex);
2575 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2576 g_assert(background_change_event != NULL);
2578 mono_init_static_data_info (&thread_static_info);
2579 mono_init_static_data_info (&context_static_info);
2581 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2583 mono_thread_start_cb = start_cb;
2584 mono_thread_attach_cb = attach_cb;
2586 /* Get a pseudo handle to the current process. This is just a
2587 * kludge so that wapi can build a process handle if needed.
2588 * As a pseudo handle is returned, we don't need to clean
2591 GetCurrentProcess ();
2594 void mono_thread_cleanup (void)
2596 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2597 MonoThreadInfo *info;
2599 /* The main thread must abandon any held mutexes (particularly
2600 * important for named mutexes as they are shared across
2601 * processes, see bug 74680.) This will happen when the
2602 * thread exits, but if it's not running in a subthread it
2603 * won't exit in time.
2605 info = mono_thread_info_current ();
2606 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2610 /* This stuff needs more testing, it seems one of these
2611 * critical sections can be locked when mono_thread_cleanup is
2614 mono_mutex_destroy (&threads_mutex);
2615 mono_mutex_destroy (&interlocked_mutex);
2616 mono_mutex_destroy (&contexts_mutex);
2617 mono_mutex_destroy (&delayed_free_table_mutex);
2618 mono_mutex_destroy (&small_id_mutex);
2619 CloseHandle (background_change_event);
2622 mono_native_tls_free (current_object_key);
2626 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2628 mono_thread_cleanup_fn = func;
2632 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2634 thread->internal_thread->manage_callback = func;
2637 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2639 mono_thread_notify_pending_exc_fn = func;
2643 static void print_tids (gpointer key, gpointer value, gpointer user)
2645 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2646 * sizeof(uint) and a cast to uint would overflow
2648 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2649 * print this as a pointer.
2651 g_message ("Waiting for: %p", key);
2656 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2657 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2661 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2665 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2667 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2669 if(ret==WAIT_FAILED) {
2670 /* See the comment in build_wait_tids() */
2671 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2675 for(i=0; i<wait->num; i++)
2676 CloseHandle (wait->handles[i]);
2678 if (ret == WAIT_TIMEOUT)
2681 for(i=0; i<wait->num; i++) {
2682 gsize tid = wait->threads[i]->tid;
2685 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2686 * it can still run io-layer etc. code. So wait for it to really exit.
2687 * FIXME: This won't join threads which are not in the joinable_hash yet.
2689 mono_thread_join ((gpointer)tid);
2691 mono_threads_lock ();
2692 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2693 /* This thread must have been killed, because
2694 * it hasn't cleaned itself up. (It's just
2695 * possible that the thread exited before the
2696 * parent thread had a chance to store the
2697 * handle, and now there is another pointer to
2698 * the already-exited thread stored. In this
2699 * case, we'll just get two
2700 * mono_profiler_thread_end() calls for the
2704 mono_threads_unlock ();
2705 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2706 thread_cleanup (wait->threads[i]);
2708 mono_threads_unlock ();
2713 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2715 guint32 i, ret, count;
2717 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2719 /* Add the thread state change event, so it wakes up if a thread changes
2720 * to background mode.
2723 if (count < MAXIMUM_WAIT_OBJECTS) {
2724 wait->handles [count] = background_change_event;
2728 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2730 if(ret==WAIT_FAILED) {
2731 /* See the comment in build_wait_tids() */
2732 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2736 for(i=0; i<wait->num; i++)
2737 CloseHandle (wait->handles[i]);
2739 if (ret == WAIT_TIMEOUT)
2742 if (ret < wait->num) {
2743 gsize tid = wait->threads[ret]->tid;
2744 mono_threads_lock ();
2745 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2746 /* See comment in wait_for_tids about thread cleanup */
2747 mono_threads_unlock ();
2748 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2749 thread_cleanup (wait->threads [ret]);
2751 mono_threads_unlock ();
2755 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2757 struct wait_data *wait=(struct wait_data *)user;
2759 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2761 MonoInternalThread *thread=(MonoInternalThread *)value;
2763 /* Ignore background threads, we abort them later */
2764 /* Do not lock here since it is not needed and the caller holds threads_lock */
2765 if (thread->state & ThreadState_Background) {
2766 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2767 return; /* just leave, ignore */
2770 if (mono_gc_is_finalizer_internal_thread (thread)) {
2771 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2775 if (thread == mono_thread_internal_current ()) {
2776 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2780 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2781 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2785 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2786 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2790 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2791 if (handle == NULL) {
2792 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2796 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2797 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2798 wait->handles[wait->num]=handle;
2799 wait->threads[wait->num]=thread;
2802 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2804 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2809 /* Just ignore the rest, we can't do anything with
2816 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2818 struct wait_data *wait=(struct wait_data *)user;
2819 gsize self = GetCurrentThreadId ();
2820 MonoInternalThread *thread = value;
2823 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2826 /* The finalizer thread is not a background thread */
2827 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2828 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2830 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2834 /* printf ("A: %d\n", wait->num); */
2835 wait->handles[wait->num]=thread->handle;
2836 wait->threads[wait->num]=thread;
2839 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2840 mono_thread_internal_stop (thread);
2844 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2848 * mono_threads_set_shutting_down:
2850 * Is called by a thread that wants to shut down Mono. If the runtime is already
2851 * shutting down, the calling thread is suspended/stopped, and this function never
2855 mono_threads_set_shutting_down (void)
2857 MonoInternalThread *current_thread = mono_thread_internal_current ();
2859 mono_threads_lock ();
2861 if (shutting_down) {
2862 mono_threads_unlock ();
2864 /* Make sure we're properly suspended/stopped */
2866 LOCK_THREAD (current_thread);
2868 if ((current_thread->state & ThreadState_SuspendRequested) ||
2869 (current_thread->state & ThreadState_AbortRequested) ||
2870 (current_thread->state & ThreadState_StopRequested)) {
2871 UNLOCK_THREAD (current_thread);
2872 mono_thread_execute_interruption (current_thread);
2874 current_thread->state |= ThreadState_Stopped;
2875 UNLOCK_THREAD (current_thread);
2878 /*since we're killing the thread, unset the current domain.*/
2879 mono_domain_unset ();
2881 /* Wake up other threads potentially waiting for us */
2882 mono_thread_info_exit ();
2884 shutting_down = TRUE;
2886 /* Not really a background state change, but this will
2887 * interrupt the main thread if it is waiting for all
2888 * the other threads.
2890 SetEvent (background_change_event);
2892 mono_threads_unlock ();
2896 void mono_thread_manage (void)
2898 struct wait_data wait_data;
2899 struct wait_data *wait = &wait_data;
2901 memset (wait, 0, sizeof (struct wait_data));
2902 /* join each thread that's still running */
2903 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2905 mono_threads_lock ();
2907 THREAD_DEBUG (g_message("%s: No threads", __func__));
2908 mono_threads_unlock ();
2911 mono_threads_unlock ();
2914 mono_threads_lock ();
2915 if (shutting_down) {
2916 /* somebody else is shutting down */
2917 mono_threads_unlock ();
2920 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2921 mono_g_hash_table_foreach (threads, print_tids, NULL));
2923 ResetEvent (background_change_event);
2925 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2926 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2927 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2928 mono_threads_unlock ();
2930 /* Something to wait for */
2931 wait_for_tids_or_state_change (wait, INFINITE);
2933 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2934 } while(wait->num>0);
2936 /* Mono is shutting down, so just wait for the end */
2937 if (!mono_runtime_try_shutdown ()) {
2938 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2939 mono_thread_suspend (mono_thread_internal_current ());
2940 mono_thread_execute_interruption (mono_thread_internal_current ());
2944 * Remove everything but the finalizer thread and self.
2945 * Also abort all the background threads
2948 mono_threads_lock ();
2951 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2952 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2953 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2955 mono_threads_unlock ();
2957 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2959 /* Something to wait for */
2960 wait_for_tids (wait, INFINITE);
2962 } while (wait->num > 0);
2965 * give the subthreads a chance to really quit (this is mainly needed
2966 * to get correct user and system times from getrusage/wait/time(1)).
2967 * This could be removed if we avoid pthread_detach() and use pthread_join().
2969 mono_thread_info_yield ();
2972 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2974 MonoInternalThread *thread=(MonoInternalThread *)value;
2976 if(thread->tid != (gsize)user) {
2977 /*TerminateThread (thread->handle, -1);*/
2981 void mono_thread_abort_all_other_threads (void)
2983 gsize self = GetCurrentThreadId ();
2985 mono_threads_lock ();
2986 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2987 mono_g_hash_table_size (threads));
2988 mono_g_hash_table_foreach (threads, print_tids, NULL));
2990 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2992 mono_threads_unlock ();
2996 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2998 MonoInternalThread *thread = (MonoInternalThread*)value;
2999 struct wait_data *wait = (struct wait_data*)user_data;
3003 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3005 * This needs no locking.
3007 if ((thread->state & ThreadState_Suspended) != 0 ||
3008 (thread->state & ThreadState_Stopped) != 0)
3011 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3012 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3016 wait->handles [wait->num] = handle;
3017 wait->threads [wait->num] = thread;
3023 * mono_thread_suspend_all_other_threads:
3025 * Suspend all managed threads except the finalizer thread and this thread. It is
3026 * not possible to resume them later.
3028 void mono_thread_suspend_all_other_threads (void)
3030 struct wait_data wait_data;
3031 struct wait_data *wait = &wait_data;
3033 gsize self = GetCurrentThreadId ();
3035 guint32 eventidx = 0;
3036 gboolean starting, finished;
3038 memset (wait, 0, sizeof (struct wait_data));
3040 * The other threads could be in an arbitrary state at this point, i.e.
3041 * they could be starting up, shutting down etc. This means that there could be
3042 * threads which are not even in the threads hash table yet.
3046 * First we set a barrier which will be checked by all threads before they
3047 * are added to the threads hash table, and they will exit if the flag is set.
3048 * This ensures that no threads could be added to the hash later.
3049 * We will use shutting_down as the barrier for now.
3051 g_assert (shutting_down);
3054 * We make multiple calls to WaitForMultipleObjects since:
3055 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3056 * - some threads could exit without becoming suspended
3061 * Make a copy of the hashtable since we can't do anything with
3062 * threads while threads_mutex is held.
3065 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3066 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3067 mono_threads_lock ();
3068 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3069 mono_threads_unlock ();
3071 events = g_new0 (gpointer, wait->num);
3073 /* Get the suspended events that we'll be waiting for */
3074 for (i = 0; i < wait->num; ++i) {
3075 MonoInternalThread *thread = wait->threads [i];
3076 gboolean signal_suspend = FALSE;
3078 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3079 //CloseHandle (wait->handles [i]);
3080 wait->threads [i] = NULL; /* ignore this thread in next loop */
3084 LOCK_THREAD (thread);
3086 if (thread->suspended_event == NULL) {
3087 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3088 if (thread->suspended_event == NULL) {
3089 /* Forget this one and go on to the next */
3090 UNLOCK_THREAD (thread);
3095 if ((thread->state & ThreadState_Suspended) != 0 ||
3096 (thread->state & ThreadState_StopRequested) != 0 ||
3097 (thread->state & ThreadState_Stopped) != 0) {
3098 UNLOCK_THREAD (thread);
3099 CloseHandle (wait->handles [i]);
3100 wait->threads [i] = NULL; /* ignore this thread in next loop */
3104 if ((thread->state & ThreadState_SuspendRequested) == 0)
3105 signal_suspend = TRUE;
3107 events [eventidx++] = thread->suspended_event;
3109 /* Convert abort requests into suspend requests */
3110 if ((thread->state & ThreadState_AbortRequested) != 0)
3111 thread->state &= ~ThreadState_AbortRequested;
3113 thread->state |= ThreadState_SuspendRequested;
3115 UNLOCK_THREAD (thread);
3117 /* Signal the thread to suspend */
3118 if (mono_thread_info_new_interrupt_enabled ())
3119 suspend_thread_internal (thread, TRUE);
3120 else if (signal_suspend)
3121 signal_thread_state_change (thread);
3124 /*Only wait on the suspend event if we are using the old path */
3125 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3126 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3127 for (i = 0; i < wait->num; ++i) {
3128 MonoInternalThread *thread = wait->threads [i];
3133 LOCK_THREAD (thread);
3134 if ((thread->state & ThreadState_Suspended) != 0) {
3135 CloseHandle (thread->suspended_event);
3136 thread->suspended_event = NULL;
3138 UNLOCK_THREAD (thread);
3142 if (eventidx <= 0) {
3144 * If there are threads which are starting up, we wait until they
3145 * are suspended when they try to register in the threads hash.
3146 * This is guaranteed to finish, since the threads which can create new
3147 * threads get suspended after a while.
3148 * FIXME: The finalizer thread can still create new threads.
3150 mono_threads_lock ();
3151 if (threads_starting_up)
3152 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3155 mono_threads_unlock ();
3167 collect_threads (gpointer key, gpointer value, gpointer user_data)
3169 MonoInternalThread *thread = (MonoInternalThread*)value;
3170 struct wait_data *wait = (struct wait_data*)user_data;
3173 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3174 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3178 wait->handles [wait->num] = handle;
3179 wait->threads [wait->num] = thread;
3184 static gboolean thread_dump_requested;
3186 static G_GNUC_UNUSED gboolean
3187 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3189 GString *p = (GString*)data;
3190 MonoMethod *method = NULL;
3192 method = mono_jit_info_get_method (frame->ji);
3195 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3196 g_string_append_printf (p, " %s\n", location);
3199 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3205 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3207 GString* text = g_string_new (0);
3209 GError *error = NULL;
3212 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3214 g_string_append_printf (text, "\n\"%s\"", name);
3217 else if (thread->threadpool_thread)
3218 g_string_append (text, "\n\"<threadpool thread>\"");
3220 g_string_append (text, "\n\"<unnamed thread>\"");
3223 /* This no longer works with remote unwinding */
3225 wapi_desc = wapi_current_thread_desc ();
3226 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3231 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3232 mono_thread_info_finish_suspend_and_resume (info);
3234 fprintf (stdout, "%s", text->str);
3236 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3237 OutputDebugStringA(text->str);
3240 g_string_free (text, TRUE);
3245 dump_thread (gpointer key, gpointer value, gpointer user)
3247 MonoInternalThread *thread = (MonoInternalThread *)value;
3248 MonoThreadInfo *info;
3250 if (thread == mono_thread_internal_current ())
3254 FIXME This still can hang if we stop a thread during malloc.
3255 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3256 that takes a callback and runs it with the target suspended.
3257 We probably should loop a bit around trying to get it to either managed code
3260 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3265 print_thread_dump (thread, info);
3269 mono_threads_perform_thread_dump (void)
3271 if (!thread_dump_requested)
3274 printf ("Full thread dump:\n");
3276 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3277 something needs then in the process.
3279 mono_loader_lock ();
3280 mono_domain_lock (mono_get_root_domain ());
3282 mono_threads_lock ();
3283 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3284 mono_threads_unlock ();
3286 mono_domain_unlock (mono_get_root_domain ());
3287 mono_loader_unlock ();
3289 thread_dump_requested = FALSE;
3293 * mono_threads_request_thread_dump:
3295 * Ask all threads except the current to print their stacktrace to stdout.
3298 mono_threads_request_thread_dump (void)
3300 struct wait_data wait_data;
3301 struct wait_data *wait = &wait_data;
3304 /*The new thread dump code runs out of the finalizer thread. */
3305 if (mono_thread_info_new_interrupt_enabled ()) {
3306 thread_dump_requested = TRUE;
3307 mono_gc_finalize_notify ();
3312 memset (wait, 0, sizeof (struct wait_data));
3315 * Make a copy of the hashtable since we can't do anything with
3316 * threads while threads_mutex is held.
3318 mono_threads_lock ();
3319 mono_g_hash_table_foreach (threads, collect_threads, wait);
3320 mono_threads_unlock ();
3322 for (i = 0; i < wait->num; ++i) {
3323 MonoInternalThread *thread = wait->threads [i];
3325 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3326 (thread != mono_thread_internal_current ()) &&
3327 !thread->thread_dump_requested) {
3328 thread->thread_dump_requested = TRUE;
3330 signal_thread_state_change (thread);
3333 CloseHandle (wait->handles [i]);
3339 gint allocated; /* +1 so that refs [allocated] == NULL */
3343 typedef struct ref_stack RefStack;
3346 ref_stack_new (gint initial_size)
3350 initial_size = MAX (initial_size, 16) + 1;
3351 rs = g_new0 (RefStack, 1);
3352 rs->refs = g_new0 (gpointer, initial_size);
3353 rs->allocated = initial_size;
3358 ref_stack_destroy (gpointer ptr)
3369 ref_stack_push (RefStack *rs, gpointer ptr)
3371 g_assert (rs != NULL);
3373 if (rs->bottom >= rs->allocated) {
3374 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3375 rs->allocated <<= 1;
3376 rs->refs [rs->allocated] = NULL;
3378 rs->refs [rs->bottom++] = ptr;
3382 ref_stack_pop (RefStack *rs)
3384 if (rs == NULL || rs->bottom == 0)
3388 rs->refs [rs->bottom] = NULL;
3392 ref_stack_find (RefStack *rs, gpointer ptr)
3399 for (refs = rs->refs; refs && *refs; refs++) {
3407 * mono_thread_push_appdomain_ref:
3409 * Register that the current thread may have references to objects in domain
3410 * @domain on its stack. Each call to this function should be paired with a
3411 * call to pop_appdomain_ref.
3414 mono_thread_push_appdomain_ref (MonoDomain *domain)
3416 MonoInternalThread *thread = mono_thread_internal_current ();
3419 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3420 SPIN_LOCK (thread->lock_thread_id);
3421 if (thread->appdomain_refs == NULL)
3422 thread->appdomain_refs = ref_stack_new (16);
3423 ref_stack_push (thread->appdomain_refs, domain);
3424 SPIN_UNLOCK (thread->lock_thread_id);
3429 mono_thread_pop_appdomain_ref (void)
3431 MonoInternalThread *thread = mono_thread_internal_current ();
3434 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3435 SPIN_LOCK (thread->lock_thread_id);
3436 ref_stack_pop (thread->appdomain_refs);
3437 SPIN_UNLOCK (thread->lock_thread_id);
3442 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3445 SPIN_LOCK (thread->lock_thread_id);
3446 res = ref_stack_find (thread->appdomain_refs, domain);
3447 SPIN_UNLOCK (thread->lock_thread_id);
3452 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3454 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3457 typedef struct abort_appdomain_data {
3458 struct wait_data wait;
3460 } abort_appdomain_data;
3463 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3465 MonoInternalThread *thread = (MonoInternalThread*)value;
3466 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3467 MonoDomain *domain = data->domain;
3469 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3470 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3472 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3473 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3476 data->wait.handles [data->wait.num] = handle;
3477 data->wait.threads [data->wait.num] = thread;
3480 /* Just ignore the rest, we can't do anything with
3488 * mono_threads_abort_appdomain_threads:
3490 * Abort threads which has references to the given appdomain.
3493 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3495 #ifdef __native_client__
3499 abort_appdomain_data user_data;
3501 int orig_timeout = timeout;
3504 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3506 start_time = mono_msec_ticks ();
3508 mono_threads_lock ();
3510 user_data.domain = domain;
3511 user_data.wait.num = 0;
3512 /* This shouldn't take any locks */
3513 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3514 mono_threads_unlock ();
3516 if (user_data.wait.num > 0) {
3517 /* Abort the threads outside the threads lock */
3518 for (i = 0; i < user_data.wait.num; ++i)
3519 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3522 * We should wait for the threads either to abort, or to leave the
3523 * domain. We can't do the latter, so we wait with a timeout.
3525 wait_for_tids (&user_data.wait, 100);
3528 /* Update remaining time */
3529 timeout -= mono_msec_ticks () - start_time;
3530 start_time = mono_msec_ticks ();
3532 if (orig_timeout != -1 && timeout < 0)
3535 while (user_data.wait.num > 0);
3537 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3543 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3545 MonoInternalThread *thread = (MonoInternalThread*)value;
3546 MonoDomain *domain = (MonoDomain*)user_data;
3549 /* No locking needed here */
3550 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3552 if (thread->cached_culture_info) {
3553 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3554 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3555 if (obj && obj->vtable->domain == domain)
3556 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3562 * mono_threads_clear_cached_culture:
3564 * Clear the cached_current_culture from all threads if it is in the
3568 mono_threads_clear_cached_culture (MonoDomain *domain)
3570 mono_threads_lock ();
3571 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3572 mono_threads_unlock ();
3576 * mono_thread_get_undeniable_exception:
3578 * Return an exception which needs to be raised when leaving a catch clause.
3579 * This is used for undeniable exception propagation.
3582 mono_thread_get_undeniable_exception (void)
3584 MonoInternalThread *thread = mono_thread_internal_current ();
3586 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3588 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3589 * exception if the thread no longer references a dying appdomain.
3591 thread->abort_exc->trace_ips = NULL;
3592 thread->abort_exc->stack_trace = NULL;
3593 return thread->abort_exc;
3599 #if MONO_SMALL_CONFIG
3600 #define NUM_STATIC_DATA_IDX 4
3601 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3605 #define NUM_STATIC_DATA_IDX 8
3606 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3607 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3611 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3614 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3617 gpointer *static_data = addr;
3618 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3621 if (!static_data [i])
3623 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3624 ptr = static_data [i];
3625 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3626 uintptr_t bmap = static_reference_bitmaps [i][j];
3629 if ((bmap & 1) && *p) {
3630 mark_func (p, gc_data);
3640 * mono_alloc_static_data
3642 * Allocate memory blocks for storing threads or context static data
3645 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3647 guint idx = (offset >> 24) - 1;
3650 gpointer* static_data = *static_data_ptr;
3652 static void* tls_desc = NULL;
3653 if (mono_gc_user_markers_supported () && !tls_desc)
3654 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3655 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3656 *static_data_ptr = static_data;
3657 static_data [0] = static_data;
3660 for (i = 1; i <= idx; ++i) {
3661 if (static_data [i])
3663 if (mono_gc_user_markers_supported () && threadlocal)
3664 static_data [i] = g_malloc0 (static_data_size [i]);
3666 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3671 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3674 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3675 gpointer p = static_data [i];
3679 * At this point, the static data pointer array is still registered with the
3680 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3681 * data. Freeing the individual arrays without first nulling their slots
3682 * would make it possible for mark_tls_slots() to encounter a pointer to
3683 * such an already freed array. See bug #13813.
3685 static_data [i] = NULL;
3686 mono_memory_write_barrier ();
3687 if (mono_gc_user_markers_supported () && threadlocal)
3690 mono_gc_free_fixed (p);
3692 mono_gc_free_fixed (static_data);
3696 * mono_init_static_data_info
3698 * Initializes static data counters
3700 static void mono_init_static_data_info (StaticDataInfo *static_data)
3702 static_data->idx = 0;
3703 static_data->offset = 0;
3704 static_data->freelist = NULL;
3708 * mono_alloc_static_data_slot
3710 * Generates an offset for static data. static_data contains the counters
3711 * used to generate it.
3714 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3718 if (!static_data->idx && !static_data->offset) {
3720 * we use the first chunk of the first allocation also as
3721 * an array for the rest of the data
3723 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3725 static_data->offset += align - 1;
3726 static_data->offset &= ~(align - 1);
3727 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3728 static_data->idx ++;
3729 g_assert (size <= static_data_size [static_data->idx]);
3730 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3731 static_data->offset = 0;
3733 offset = static_data->offset | ((static_data->idx + 1) << 24);
3734 static_data->offset += size;
3739 * ensure thread static fields already allocated are valid for thread
3740 * This function is called when a thread is created or on thread attach.
3743 thread_adjust_static_data (MonoInternalThread *thread)
3747 mono_threads_lock ();
3748 if (thread_static_info.offset || thread_static_info.idx > 0) {
3749 /* get the current allocated size */
3750 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3751 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3753 mono_threads_unlock ();
3757 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3759 MonoInternalThread *thread = value;
3760 guint32 offset = GPOINTER_TO_UINT (user);
3762 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3765 static MonoThreadDomainTls*
3766 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3768 MonoThreadDomainTls* prev = NULL;
3769 MonoThreadDomainTls* tmp = static_data->freelist;
3771 if (tmp->size == size) {
3773 prev->next = tmp->next;
3775 static_data->freelist = tmp->next;
3784 #if SIZEOF_VOID_P == 4
3791 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3794 int idx = (offset >> 24) - 1;
3796 if (!static_reference_bitmaps [idx])
3797 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3798 rb = static_reference_bitmaps [idx];
3800 offset /= sizeof (gpointer);
3801 /* offset is now the bitmap offset */
3802 for (i = 0; i < numbits; ++i) {
3803 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3804 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (ONE_P << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3809 clear_reference_bitmap (guint32 offset, guint32 size)
3811 int idx = (offset >> 24) - 1;
3813 rb = static_reference_bitmaps [idx];
3815 offset /= sizeof (gpointer);
3816 size /= sizeof (gpointer);
3818 /* offset is now the bitmap offset */
3819 for (; offset < size; ++offset)
3820 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3824 * The offset for a special static variable is composed of three parts:
3825 * a bit that indicates the type of static data (0:thread, 1:context),
3826 * an index in the array of chunks of memory for the thread (thread->static_data)
3827 * and an offset in that chunk of mem. This allows allocating less memory in the
3832 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3835 if (static_type == SPECIAL_STATIC_THREAD) {
3836 MonoThreadDomainTls *item;
3837 mono_threads_lock ();
3838 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3839 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3841 offset = item->offset;
3844 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3846 update_tls_reference_bitmap (offset, bitmap, numbits);
3847 /* This can be called during startup */
3848 if (threads != NULL)
3849 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3850 mono_threads_unlock ();
3852 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3853 mono_contexts_lock ();
3854 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3855 mono_contexts_unlock ();
3856 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3862 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3864 /* The high bit means either thread (0) or static (1) data. */
3866 guint32 static_type = (offset & 0x80000000);
3869 offset &= 0x7fffffff;
3870 idx = (offset >> 24) - 1;
3872 if (static_type == 0) {
3873 return get_thread_static_data (thread, offset);
3875 /* Allocate static data block under demand, since we don't have a list
3878 MonoAppContext *context = mono_context_get ();
3879 if (!context->static_data || !context->static_data [idx]) {
3880 mono_contexts_lock ();
3881 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3882 mono_contexts_unlock ();
3884 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3889 mono_get_special_static_data (guint32 offset)
3891 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3900 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3902 MonoInternalThread *thread = value;
3903 TlsOffsetSize *data = user;
3904 int idx = (data->offset >> 24) - 1;
3907 if (!thread->static_data || !thread->static_data [idx])
3909 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3910 mono_gc_bzero_atomic (ptr, data->size);
3914 do_free_special_slot (guint32 offset, guint32 size)
3916 guint32 static_type = (offset & 0x80000000);
3917 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3918 if (static_type == 0) {
3920 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3921 data.offset = offset & 0x7fffffff;
3923 clear_reference_bitmap (data.offset, data.size);
3924 if (threads != NULL)
3925 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3926 item->offset = offset;
3929 if (!mono_runtime_is_shutting_down ()) {
3930 item->next = thread_static_info.freelist;
3931 thread_static_info.freelist = item;
3933 /* We could be called during shutdown after mono_thread_cleanup () is called */
3937 /* FIXME: free context static data as well */
3942 do_free_special (gpointer key, gpointer value, gpointer data)
3944 MonoClassField *field = key;
3945 guint32 offset = GPOINTER_TO_UINT (value);
3948 size = mono_type_size (field->type, &align);
3949 do_free_special_slot (offset, size);
3953 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3955 mono_threads_lock ();
3956 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3957 mono_threads_unlock ();
3961 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3963 mono_threads_lock ();
3964 do_free_special_slot (offset, size);
3965 mono_threads_unlock ();
3969 * allocates room in the thread local area for storing an instance of the struct type
3970 * the allocation is kept track of in domain->tlsrec_list.
3973 mono_thread_alloc_tls (MonoReflectionType *type)
3975 MonoDomain *domain = mono_domain_get ();
3977 MonoTlsDataRecord *tlsrec;
3980 gsize default_bitmap [4] = {0};
3981 uint32_t tls_offset;
3985 klass = mono_class_from_mono_type (type->type);
3986 /* TlsDatum is a struct, so we subtract the object header size offset */
3987 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3988 size = mono_type_size (type->type, &align);
3989 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3990 if (bitmap != default_bitmap)
3992 tlsrec = g_new0 (MonoTlsDataRecord, 1);
3993 tlsrec->tls_offset = tls_offset;
3994 tlsrec->size = size;
3995 mono_domain_lock (domain);
3996 tlsrec->next = domain->tlsrec_list;
3997 domain->tlsrec_list = tlsrec;
3998 mono_domain_unlock (domain);
4003 destroy_tls (MonoDomain *domain, uint32_t tls_offset)
4005 MonoTlsDataRecord *prev = NULL;
4006 MonoTlsDataRecord *cur;
4009 mono_domain_lock (domain);
4010 cur = domain->tlsrec_list;
4012 if (cur->tls_offset == tls_offset) {
4014 prev->next = cur->next;
4016 domain->tlsrec_list = cur->next;
4024 mono_domain_unlock (domain);
4026 mono_special_static_data_free_slot (tls_offset, size);
4030 mono_thread_destroy_tls (uint32_t tls_offset)
4032 destroy_tls (mono_domain_get (), tls_offset);
4036 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
4039 mono_thread_destroy_domain_tls (MonoDomain *domain)
4041 while (domain->tlsrec_list)
4042 destroy_tls (domain, domain->tlsrec_list->tls_offset);
4045 static MonoClassField *local_slots = NULL;
4048 /* local tls data to get locals_slot from a thread */
4051 /* index in the locals_slot array */
4056 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4058 LocalSlotID *sid = user_data;
4059 MonoInternalThread *thread = (MonoInternalThread*)value;
4060 MonoArray *slots_array;
4062 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4063 * it is for the right domain, so we need to check if it is allocated an initialized
4064 * for the current thread.
4066 /*g_print ("handling thread %p\n", thread);*/
4067 if (!thread->static_data || !thread->static_data [sid->idx])
4069 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4070 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4072 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4076 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4084 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4086 g_warning ("local_slots field not found in Thread class");
4090 domain = mono_domain_get ();
4091 mono_domain_lock (domain);
4092 if (domain->special_static_fields)
4093 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4094 mono_domain_unlock (domain);
4097 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4098 sid.offset = GPOINTER_TO_UINT (addr);
4099 sid.offset &= 0x7fffffff;
4100 sid.idx = (sid.offset >> 24) - 1;
4101 mono_threads_lock ();
4102 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4103 mono_threads_unlock ();
4105 /* FIXME: clear the slot for MonoAppContexts, too */
4110 static void CALLBACK dummy_apc (ULONG_PTR param)
4116 * mono_thread_execute_interruption
4118 * Performs the operation that the requested thread state requires (abort,
4121 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4123 LOCK_THREAD (thread);
4125 /* MonoThread::interruption_requested can only be changed with atomics */
4126 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4127 /* this will consume pending APC calls */
4129 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4131 InterlockedDecrement (&thread_interruption_requested);
4132 /* Clear the interrupted flag of the thread so it can wait again */
4133 mono_thread_info_clear_interruption ();
4136 if ((thread->state & ThreadState_AbortRequested) != 0) {
4137 UNLOCK_THREAD (thread);
4138 if (thread->abort_exc == NULL) {
4140 * This might be racy, but it has to be called outside the lock
4141 * since it calls managed code.
4143 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4145 return thread->abort_exc;
4147 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4148 self_suspend_internal (thread);
4151 else if ((thread->state & ThreadState_StopRequested) != 0) {
4152 /* FIXME: do this through the JIT? */
4154 UNLOCK_THREAD (thread);
4156 mono_thread_exit ();
4158 } else if (thread->pending_exception) {
4161 exc = thread->pending_exception;
4162 thread->pending_exception = NULL;
4164 UNLOCK_THREAD (thread);
4166 } else if (thread->thread_interrupt_requested) {
4168 thread->thread_interrupt_requested = FALSE;
4169 UNLOCK_THREAD (thread);
4171 return(mono_get_exception_thread_interrupted ());
4174 UNLOCK_THREAD (thread);
4180 * mono_thread_request_interruption
4182 * A signal handler can call this method to request the interruption of a
4183 * thread. The result of the interruption will depend on the current state of
4184 * the thread. If the result is an exception that needs to be throw, it is
4185 * provided as return value.
4188 mono_thread_request_interruption (gboolean running_managed)
4190 MonoInternalThread *thread = mono_thread_internal_current ();
4192 /* The thread may already be stopping */
4197 if (thread->interrupt_on_stop &&
4198 thread->state & ThreadState_StopRequested &&
4199 thread->state & ThreadState_Background)
4203 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4205 InterlockedIncrement (&thread_interruption_requested);
4207 if (!running_managed || is_running_protected_wrapper ()) {
4208 /* Can't stop while in unmanaged code. Increase the global interruption
4209 request count. When exiting the unmanaged method the count will be
4210 checked and the thread will be interrupted. */
4212 if (mono_thread_notify_pending_exc_fn && !running_managed)
4213 /* The JIT will notify the thread about the interruption */
4214 /* This shouldn't take any locks */
4215 mono_thread_notify_pending_exc_fn (NULL);
4217 /* this will awake the thread if it is in WaitForSingleObject
4219 /* Our implementation of this function ignores the func argument */
4221 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4223 mono_thread_info_self_interrupt ();
4228 return mono_thread_execute_interruption (thread);
4232 /*This function should be called by a thread after it has exited all of
4233 * its handle blocks at interruption time.*/
4235 mono_thread_resume_interruption (void)
4237 MonoInternalThread *thread = mono_thread_internal_current ();
4238 gboolean still_aborting;
4240 /* The thread may already be stopping */
4244 LOCK_THREAD (thread);
4245 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4246 UNLOCK_THREAD (thread);
4248 /*This can happen if the protected block called Thread::ResetAbort*/
4249 if (!still_aborting)
4252 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4254 InterlockedIncrement (&thread_interruption_requested);
4256 mono_thread_info_self_interrupt ();
4258 return mono_thread_execute_interruption (thread);
4261 gboolean mono_thread_interruption_requested ()
4263 if (thread_interruption_requested) {
4264 MonoInternalThread *thread = mono_thread_internal_current ();
4265 /* The thread may already be stopping */
4267 return (thread->interruption_requested);
4272 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4274 MonoInternalThread *thread = mono_thread_internal_current ();
4276 /* The thread may already be stopping */
4280 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4281 MonoException* exc = mono_thread_execute_interruption (thread);
4282 if (exc) mono_raise_exception (exc);
4287 * Performs the interruption of the current thread, if one has been requested,
4288 * and the thread is not running a protected wrapper.
4290 void mono_thread_interruption_checkpoint ()
4292 mono_thread_interruption_checkpoint_request (FALSE);
4296 * Performs the interruption of the current thread, if one has been requested.
4298 void mono_thread_force_interruption_checkpoint ()
4300 mono_thread_interruption_checkpoint_request (TRUE);
4304 * mono_thread_get_and_clear_pending_exception:
4306 * Return any pending exceptions for the current thread and clear it as a side effect.
4309 mono_thread_get_and_clear_pending_exception (void)
4311 MonoInternalThread *thread = mono_thread_internal_current ();
4313 /* The thread may already be stopping */
4317 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4318 return mono_thread_execute_interruption (thread);
4321 if (thread->pending_exception) {
4322 MonoException *exc = thread->pending_exception;
4324 thread->pending_exception = NULL;
4332 * mono_set_pending_exception:
4334 * Set the pending exception of the current thread to EXC.
4335 * The exception will be thrown when execution returns to managed code.
4338 mono_set_pending_exception (MonoException *exc)
4340 MonoInternalThread *thread = mono_thread_internal_current ();
4342 /* The thread may already be stopping */
4346 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4348 mono_thread_request_interruption (FALSE);
4352 * mono_thread_interruption_request_flag:
4354 * Returns the address of a flag that will be non-zero if an interruption has
4355 * been requested for a thread. The thread to interrupt may not be the current
4356 * thread, so an additional call to mono_thread_interruption_requested() or
4357 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4360 gint32* mono_thread_interruption_request_flag ()
4362 return &thread_interruption_requested;
4366 mono_thread_init_apartment_state (void)
4369 MonoInternalThread* thread = mono_thread_internal_current ();
4371 /* Positive return value indicates success, either
4372 * S_OK if this is first CoInitialize call, or
4373 * S_FALSE if CoInitialize already called, but with same
4374 * threading model. A negative value indicates failure,
4375 * probably due to trying to change the threading model.
4377 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4378 ? COINIT_APARTMENTTHREADED
4379 : COINIT_MULTITHREADED) < 0) {
4380 thread->apartment_state = ThreadApartmentState_Unknown;
4386 mono_thread_cleanup_apartment_state (void)
4389 MonoInternalThread* thread = mono_thread_internal_current ();
4391 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4398 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4400 LOCK_THREAD (thread);
4401 thread->state |= state;
4402 UNLOCK_THREAD (thread);
4406 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4408 LOCK_THREAD (thread);
4409 thread->state &= ~state;
4410 UNLOCK_THREAD (thread);
4414 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4416 gboolean ret = FALSE;
4418 LOCK_THREAD (thread);
4420 if ((thread->state & test) != 0) {
4424 UNLOCK_THREAD (thread);
4429 //static MonoClassField *execution_context_field;
4432 get_execution_context_addr (void)
4434 MonoDomain *domain = mono_domain_get ();
4435 guint32 offset = domain->execution_context_field_offset;
4438 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4441 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4443 mono_domain_lock (domain);
4444 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4445 mono_domain_unlock (domain);
4448 domain->execution_context_field_offset = offset;
4451 return (MonoObject**) mono_get_special_static_data (offset);
4455 mono_thread_get_execution_context (void)
4457 return *get_execution_context_addr ();
4461 mono_thread_set_execution_context (MonoObject *ec)
4463 *get_execution_context_addr () = ec;
4466 static gboolean has_tls_get = FALSE;
4469 mono_runtime_set_has_tls_get (gboolean val)
4475 mono_runtime_has_tls_get (void)
4481 mono_thread_kill (MonoInternalThread *thread, int signal)
4483 #ifdef __native_client__
4484 /* Workaround pthread_kill abort() in NaCl glibc. */
4488 /* Win32 uses QueueUserAPC and callers of this are guarded */
4489 g_assert_not_reached ();
4491 # ifdef PTHREAD_POINTER_ID
4492 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4494 # ifdef USE_TKILL_ON_ANDROID
4495 if (thread->android_tid != 0) {
4497 int old_errno = errno;
4499 ret = tkill ((pid_t) thread->android_tid, signal);
4508 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4510 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4517 self_interrupt_thread (void *_unused)
4519 MonoThreadInfo *info = mono_thread_info_current ();
4520 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4521 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4522 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4523 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4527 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4531 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4535 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4537 MonoJitInfo **dest = data;
4543 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4545 MonoJitInfo *ji = NULL;
4548 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4553 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4556 MonoThreadInfo *info = NULL;
4557 gboolean protected_wrapper;
4558 gboolean running_managed;
4560 if (!mono_thread_info_new_interrupt_enabled ()) {
4561 signal_thread_state_change (thread);
4566 FIXME this is insanely broken, it doesn't cause interruption to happen
4567 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4569 if (thread == mono_thread_internal_current ()) {
4570 /* Do it synchronously */
4571 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4573 mono_raise_exception (exc);
4574 mono_thread_info_interrupt (thread->handle);
4578 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4579 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4583 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4584 mono_thread_info_finish_suspend_and_resume (info);
4588 /*someone is already interrupting it*/
4589 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4590 mono_thread_info_finish_suspend_and_resume (info);
4593 InterlockedIncrement (&thread_interruption_requested);
4595 ji = mono_thread_info_get_last_managed (info);
4596 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4597 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4599 if (!protected_wrapper && running_managed) {
4600 /*We are in managed code*/
4601 /*Set the thread to call */
4602 if (install_async_abort)
4603 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4604 mono_thread_info_finish_suspend_and_resume (info);
4607 * This will cause waits to be broken.
4608 * It will also prevent the thread from entering a wait, so if the thread returns
4609 * from the wait before it receives the abort signal, it will just spin in the wait
4610 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4613 gpointer interrupt_handle;
4615 if (mono_thread_notify_pending_exc_fn)
4616 /* The JIT will notify the thread about the interruption */
4617 mono_thread_notify_pending_exc_fn (info);
4619 interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4620 mono_thread_info_finish_suspend_and_resume (info);
4621 mono_thread_info_finish_interrupt (interrupt_handle);
4623 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4627 transition_to_suspended (MonoInternalThread *thread, MonoThreadInfo *info)
4629 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4630 g_assert (0); /*FIXME we should not reach this */
4631 /*Make sure we balance the suspend count.*/
4633 mono_thread_info_finish_suspend_and_resume (info);
4635 thread->state &= ~ThreadState_SuspendRequested;
4636 thread->state |= ThreadState_Suspended;
4638 mono_thread_info_finish_suspend (info);
4640 UNLOCK_THREAD (thread);
4644 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4646 if (!mono_thread_info_new_interrupt_enabled ()) {
4647 signal_thread_state_change (thread);
4651 LOCK_THREAD (thread);
4652 if (thread == mono_thread_internal_current ()) {
4653 transition_to_suspended (thread, NULL);
4654 mono_thread_info_self_suspend ();
4656 MonoThreadInfo *info;
4658 gboolean protected_wrapper;
4659 gboolean running_managed;
4661 /*A null info usually means the thread is already dead. */
4662 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
4663 UNLOCK_THREAD (thread);
4667 ji = mono_thread_info_get_last_managed (info);
4668 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4669 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4671 if (running_managed && !protected_wrapper) {
4672 transition_to_suspended (thread, info);
4674 gpointer interrupt_handle;
4676 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4677 InterlockedIncrement (&thread_interruption_requested);
4679 interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4680 if (mono_thread_notify_pending_exc_fn && !running_managed)
4681 /* The JIT will notify the thread about the interruption */
4682 mono_thread_notify_pending_exc_fn (info);
4683 mono_thread_info_finish_suspend_and_resume (info);
4685 mono_thread_info_finish_interrupt (interrupt_handle);
4686 UNLOCK_THREAD (thread);
4691 /*This is called with @thread synch_cs held and it must release it*/
4693 self_suspend_internal (MonoInternalThread *thread)
4695 if (!mono_thread_info_new_interrupt_enabled ()) {
4696 thread->state &= ~ThreadState_SuspendRequested;
4697 thread->state |= ThreadState_Suspended;
4698 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4699 if (thread->suspend_event == NULL) {
4700 UNLOCK_THREAD (thread);
4703 if (thread->suspended_event)
4704 SetEvent (thread->suspended_event);
4706 UNLOCK_THREAD (thread);
4708 if (shutting_down) {
4709 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4714 WaitForSingleObject (thread->suspend_event, INFINITE);
4716 LOCK_THREAD (thread);
4718 CloseHandle (thread->suspend_event);
4719 thread->suspend_event = NULL;
4720 thread->state &= ~ThreadState_Suspended;
4722 /* The thread that requested the resume will have replaced this event
4723 * and will be waiting for it
4725 SetEvent (thread->resume_event);
4727 UNLOCK_THREAD (thread);
4731 transition_to_suspended (thread, NULL);
4732 mono_thread_info_self_suspend ();
4735 /*This is called with @thread synch_cs held and it must release it*/
4737 resume_thread_internal (MonoInternalThread *thread)
4739 if (!mono_thread_info_new_interrupt_enabled ()) {
4740 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4741 if (thread->resume_event == NULL) {
4742 UNLOCK_THREAD (thread);
4746 /* Awake the thread */
4747 SetEvent (thread->suspend_event);
4749 UNLOCK_THREAD (thread);
4751 /* Wait for the thread to awake */
4752 WaitForSingleObject (thread->resume_event, INFINITE);
4753 CloseHandle (thread->resume_event);
4754 thread->resume_event = NULL;
4758 UNLOCK_THREAD (thread);
4759 /* Awake the thread */
4760 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4762 LOCK_THREAD (thread);
4763 thread->state &= ~ThreadState_Suspended;
4764 UNLOCK_THREAD (thread);
4770 * mono_thread_is_foreign:
4771 * @thread: the thread to query
4773 * This function allows one to determine if a thread was created by the mono runtime and has
4774 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4776 * Returns: true if @thread was not created by the runtime.
4779 mono_thread_is_foreign (MonoThread *thread)
4781 MonoThreadInfo *info = thread->internal_thread->thread_info;
4782 return info->runtime_thread == FALSE;
4786 * mono_add_joinable_thread:
4788 * Add TID to the list of joinable threads.
4789 * LOCKING: Acquires the threads lock.
4792 mono_threads_add_joinable_thread (gpointer tid)
4796 * We cannot detach from threads because it causes problems like
4797 * 2fd16f60/r114307. So we collect them and join them when
4798 * we have time (in he finalizer thread).
4800 joinable_threads_lock ();
4801 if (!joinable_threads)
4802 joinable_threads = g_hash_table_new (NULL, NULL);
4803 g_hash_table_insert (joinable_threads, tid, tid);
4804 joinable_thread_count ++;
4805 joinable_threads_unlock ();
4807 mono_gc_finalize_notify ();
4812 * mono_threads_join_threads:
4814 * Join all joinable threads. This is called from the finalizer thread.
4815 * LOCKING: Acquires the threads lock.
4818 mono_threads_join_threads (void)
4821 GHashTableIter iter;
4828 if (!joinable_thread_count)
4832 joinable_threads_lock ();
4834 if (g_hash_table_size (joinable_threads)) {
4835 g_hash_table_iter_init (&iter, joinable_threads);
4836 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4837 thread = (pthread_t)tid;
4838 g_hash_table_remove (joinable_threads, key);
4839 joinable_thread_count --;
4842 joinable_threads_unlock ();
4844 if (thread != pthread_self ())
4845 /* This shouldn't block */
4846 pthread_join (thread, NULL);
4857 * Wait for thread TID to exit.
4858 * LOCKING: Acquires the threads lock.
4861 mono_thread_join (gpointer tid)
4865 gboolean found = FALSE;
4867 joinable_threads_lock ();
4868 if (!joinable_threads)
4869 joinable_threads = g_hash_table_new (NULL, NULL);
4870 if (g_hash_table_lookup (joinable_threads, tid)) {
4871 g_hash_table_remove (joinable_threads, tid);
4872 joinable_thread_count --;
4875 joinable_threads_unlock ();
4878 thread = (pthread_t)tid;
4879 pthread_join (thread, NULL);