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)
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/threads.h>
24 #include <mono/metadata/threadpool.h>
25 #include <mono/metadata/threads-types.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/environment.h>
28 #include <mono/metadata/monitor.h>
29 #include <mono/metadata/gc-internal.h>
30 #include <mono/metadata/marshal.h>
31 #include <mono/metadata/runtime.h>
32 #include <mono/io-layer/io-layer.h>
34 #include <mono/io-layer/threads.h>
36 #include <mono/metadata/object-internals.h>
37 #include <mono/metadata/mono-debug-debugger.h>
38 #include <mono/utils/mono-compiler.h>
39 #include <mono/utils/mono-mmap.h>
40 #include <mono/utils/mono-membar.h>
41 #include <mono/utils/mono-time.h>
42 #include <mono/utils/mono-threads.h>
43 #include <mono/utils/hazard-pointer.h>
44 #include <mono/utils/mono-tls.h>
45 #include <mono/utils/atomic.h>
46 #include <mono/utils/mono-memory-model.h>
48 #include <mono/metadata/gc-internal.h>
50 #ifdef PLATFORM_ANDROID
53 extern int tkill (pid_t tid, int signal);
56 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
57 #define THREAD_DEBUG(a)
58 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
59 #define THREAD_WAIT_DEBUG(a)
60 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
61 #define LIBGC_DEBUG(a)
63 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
64 #define SPIN_LOCK(i) do { \
65 if (SPIN_TRYLOCK (i)) \
69 #define SPIN_UNLOCK(i) i = 0
71 #define LOCK_THREAD(thread) lock_thread((thread))
72 #define UNLOCK_THREAD(thread) unlock_thread((thread))
74 /* Provide this for systems with glib < 2.6 */
75 #ifndef G_GSIZE_FORMAT
76 # if GLIB_SIZEOF_LONG == 8
77 # define G_GSIZE_FORMAT "lu"
79 # define G_GSIZE_FORMAT "u"
85 guint32 (*func)(void *);
101 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
102 struct _MonoThreadDomainTls {
103 MonoThreadDomainTls *next;
111 MonoThreadDomainTls *freelist;
114 /* Number of cached culture objects in the MonoThread->cached_culture_info array
115 * (per-type): we use the first NUM entries for CultureInfo and the last for
116 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
118 #define NUM_CACHED_CULTURES 4
119 #define CULTURES_START_IDX 0
120 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
122 /* Controls access to the 'threads' hash table */
123 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
124 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
125 static CRITICAL_SECTION threads_mutex;
127 /* Controls access to context static data */
128 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
129 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
130 static CRITICAL_SECTION contexts_mutex;
132 /* Controls access to the 'joinable_threads' hash table */
133 #define joinable_threads_lock() EnterCriticalSection (&joinable_threads_mutex)
134 #define joinable_threads_unlock() LeaveCriticalSection (&joinable_threads_mutex)
135 static CRITICAL_SECTION joinable_threads_mutex;
137 /* Holds current status of static data heap */
138 static StaticDataInfo thread_static_info;
139 static StaticDataInfo context_static_info;
141 /* The hash of existing threads (key is thread ID, value is
142 * MonoInternalThread*) that need joining before exit
144 static MonoGHashTable *threads=NULL;
147 * Threads which are starting up and they are not in the 'threads' hash yet.
148 * When handle_store is called for a thread, it will be removed from this hash table.
149 * Protected by mono_threads_lock ().
151 static MonoGHashTable *threads_starting_up = NULL;
153 /* Maps a MonoThread to its start argument */
154 /* Protected by mono_threads_lock () */
155 static MonoGHashTable *thread_start_args = NULL;
157 /* The TLS key that holds the MonoObject assigned to each thread */
158 static MonoNativeTlsKey current_object_key;
161 /* Protected by the threads lock */
162 static GHashTable *joinable_threads;
163 static int joinable_thread_count;
165 #ifdef MONO_HAVE_FAST_TLS
166 /* we need to use both the Tls* functions and __thread because
167 * the gc needs to see all the threads
169 MONO_FAST_TLS_DECLARE(tls_current_object);
170 #define SET_CURRENT_OBJECT(x) do { \
171 MONO_FAST_TLS_SET (tls_current_object, x); \
172 mono_native_tls_set_value (current_object_key, x); \
174 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
176 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
177 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
180 /* function called at thread start */
181 static MonoThreadStartCB mono_thread_start_cb = NULL;
183 /* function called at thread attach */
184 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
186 /* function called at thread cleanup */
187 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
189 /* function called to notify the runtime about a pending exception on the current thread */
190 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
192 /* The default stack size for each thread */
193 static guint32 default_stacksize = 0;
194 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
196 static void thread_adjust_static_data (MonoInternalThread *thread);
197 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
198 static void mono_init_static_data_info (StaticDataInfo *static_data);
199 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
200 static gboolean mono_thread_resume (MonoInternalThread* thread);
201 static void signal_thread_state_change (MonoInternalThread *thread);
202 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
203 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
204 static void self_suspend_internal (MonoInternalThread *thread);
205 static gboolean resume_thread_internal (MonoInternalThread *thread);
207 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
208 static void ref_stack_destroy (gpointer rs);
210 /* Spin lock for InterlockedXXX 64 bit functions */
211 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
212 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
213 static CRITICAL_SECTION interlocked_mutex;
215 /* global count of thread interruptions requested */
216 static gint32 thread_interruption_requested = 0;
218 /* Event signaled when a thread changes its background mode */
219 static HANDLE background_change_event;
221 static gboolean shutting_down = FALSE;
223 static gint32 managed_thread_id_counter = 0;
226 get_next_managed_thread_id (void)
228 return InterlockedIncrement (&managed_thread_id_counter);
232 mono_thread_get_tls_key (void)
234 return current_object_key;
238 mono_thread_get_tls_offset (void)
241 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
245 /* handle_store() and handle_remove() manage the array of threads that
246 * still need to be waited for when the main thread exits.
248 * If handle_store() returns FALSE the thread must not be started
249 * because Mono is shutting down.
251 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
253 mono_threads_lock ();
255 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
257 if (threads_starting_up)
258 mono_g_hash_table_remove (threads_starting_up, thread);
260 if (shutting_down && !force_attach) {
261 mono_threads_unlock ();
266 MONO_GC_REGISTER_ROOT_FIXED (threads);
267 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
270 /* We don't need to duplicate thread->handle, because it is
271 * only closed when the thread object is finalized by the GC.
273 g_assert (thread->internal_thread);
274 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
275 thread->internal_thread);
277 mono_threads_unlock ();
282 static gboolean handle_remove(MonoInternalThread *thread)
285 gsize tid = thread->tid;
287 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
289 mono_threads_lock ();
292 /* We have to check whether the thread object for the
293 * tid is still the same in the table because the
294 * thread might have been destroyed and the tid reused
295 * in the meantime, in which case the tid would be in
296 * the table, but with another thread object.
298 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
299 mono_g_hash_table_remove (threads, (gpointer)tid);
308 mono_threads_unlock ();
310 /* Don't close the handle here, wait for the object finalizer
311 * to do it. Otherwise, the following race condition applies:
313 * 1) Thread exits (and handle_remove() closes the handle)
315 * 2) Some other handle is reassigned the same slot
317 * 3) Another thread tries to join the first thread, and
318 * blocks waiting for the reassigned handle to be signalled
319 * (which might never happen). This is possible, because the
320 * thread calling Join() still has a reference to the first
326 static void ensure_synch_cs_set (MonoInternalThread *thread)
328 CRITICAL_SECTION *synch_cs;
330 if (thread->synch_cs != NULL) {
334 synch_cs = g_new0 (CRITICAL_SECTION, 1);
335 InitializeCriticalSection (synch_cs);
337 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
338 synch_cs, NULL) != NULL) {
339 /* Another thread must have installed this CS */
340 DeleteCriticalSection (synch_cs);
346 lock_thread (MonoInternalThread *thread)
348 if (!thread->synch_cs)
349 ensure_synch_cs_set (thread);
351 g_assert (thread->synch_cs);
352 EnterCriticalSection (thread->synch_cs);
356 unlock_thread (MonoInternalThread *thread)
358 LeaveCriticalSection (thread->synch_cs);
362 * NOTE: this function can be called also for threads different from the current one:
363 * make sure no code called from it will ever assume it is run on the thread that is
364 * getting cleaned up.
366 static void thread_cleanup (MonoInternalThread *thread)
368 g_assert (thread != NULL);
370 if (thread->abort_state_handle) {
371 mono_gchandle_free (thread->abort_state_handle);
372 thread->abort_state_handle = 0;
374 thread->abort_exc = NULL;
375 thread->current_appcontext = NULL;
378 * This is necessary because otherwise we might have
379 * cross-domain references which will not get cleaned up when
380 * the target domain is unloaded.
382 if (thread->cached_culture_info) {
384 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
385 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
389 * thread->synch_cs can be NULL if this was called after
390 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
391 * This can happen only during shutdown.
392 * The shutting_down flag is not always set, so we can't assert on it.
394 if (thread->synch_cs)
395 LOCK_THREAD (thread);
397 thread->state |= ThreadState_Stopped;
398 thread->state &= ~ThreadState_Background;
400 if (thread->synch_cs)
401 UNLOCK_THREAD (thread);
404 An interruption request has leaked to cleanup. Adjust the global counter.
406 This can happen is the abort source thread finds the abortee (this) thread
407 in unmanaged code. If this thread never trips back to managed code or check
408 the local flag it will be left set and positively unbalance the global counter.
410 Leaving the counter unbalanced will cause a performance degradation since all threads
411 will now keep checking their local flags all the time.
413 if (InterlockedExchange (&thread->interruption_requested, 0))
414 InterlockedDecrement (&thread_interruption_requested);
416 /* if the thread is not in the hash it has been removed already */
417 if (!handle_remove (thread)) {
418 if (thread == mono_thread_internal_current ()) {
419 mono_domain_unset ();
420 mono_memory_barrier ();
422 /* This needs to be called even if handle_remove () fails */
423 if (mono_thread_cleanup_fn)
424 mono_thread_cleanup_fn (thread);
427 mono_release_type_locks (thread);
429 mono_profiler_thread_end (thread->tid);
431 if (thread == mono_thread_internal_current ()) {
433 * This will signal async signal handlers that the thread has exited.
434 * The profiler callback needs this to be set, so it cannot be done earlier.
436 mono_domain_unset ();
437 mono_memory_barrier ();
440 if (thread == mono_thread_internal_current ())
441 mono_thread_pop_appdomain_ref ();
443 thread->cached_culture_info = NULL;
445 mono_free_static_data (thread->static_data, TRUE);
446 thread->static_data = NULL;
447 ref_stack_destroy (thread->appdomain_refs);
448 thread->appdomain_refs = NULL;
450 if (mono_thread_cleanup_fn)
451 mono_thread_cleanup_fn (thread);
453 if (mono_gc_is_moving ()) {
454 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
455 thread->thread_pinning_ref = NULL;
460 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
463 g_assert ((offset & 0x80000000) == 0);
464 offset &= 0x7fffffff;
465 idx = (offset >> 24) - 1;
466 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
470 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
472 static MonoClassField *current_thread_field = NULL;
476 if (!current_thread_field) {
477 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
478 g_assert (current_thread_field);
481 mono_class_vtable (domain, mono_defaults.thread_class);
482 mono_domain_lock (domain);
483 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
484 mono_domain_unlock (domain);
487 return get_thread_static_data (thread, offset);
491 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
493 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
495 g_assert (current->obj.vtable->domain == domain);
497 g_assert (!*current_thread_ptr);
498 *current_thread_ptr = current;
502 create_thread_object (MonoDomain *domain)
504 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
505 return (MonoThread*)mono_gc_alloc_mature (vt);
509 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
511 MonoThread *thread = create_thread_object (domain);
512 MONO_OBJECT_SETREF (thread, internal_thread, internal);
516 static MonoInternalThread*
517 create_internal_thread (void)
519 MonoInternalThread *thread;
522 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
523 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
525 thread->synch_cs = g_new0 (CRITICAL_SECTION, 1);
526 InitializeCriticalSection (thread->synch_cs);
528 thread->apartment_state = ThreadApartmentState_Unknown;
529 thread->managed_id = get_next_managed_thread_id ();
530 if (mono_gc_is_moving ()) {
531 thread->thread_pinning_ref = thread;
532 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
539 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
541 MonoDomain *domain = mono_get_root_domain ();
543 if (!candidate || candidate->obj.vtable->domain != domain)
544 candidate = new_thread_with_internal (domain, thread);
545 set_current_thread_for_domain (domain, thread, candidate);
546 g_assert (!thread->root_domain_thread);
547 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
550 static guint32 WINAPI start_wrapper_internal(void *data)
552 MonoThreadInfo *info;
553 StartInfo *start_info = (StartInfo *)data;
554 guint32 (*start_func)(void *);
558 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
561 MonoInternalThread *internal = start_info->obj->internal_thread;
562 MonoObject *start_delegate = start_info->delegate;
563 MonoDomain *domain = start_info->obj->obj.vtable->domain;
565 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
567 /* We can be sure start_info->obj->tid and
568 * start_info->obj->handle have been set, because the thread
569 * was created suspended, and these values were set before the
573 info = mono_thread_info_current ();
575 internal->thread_info = info;
580 SET_CURRENT_OBJECT (internal);
582 mono_monitor_init_tls ();
584 /* Every thread references the appdomain which created it */
585 mono_thread_push_appdomain_ref (domain);
587 if (!mono_domain_set (domain, FALSE)) {
588 /* No point in raising an appdomain_unloaded exception here */
589 /* FIXME: Cleanup here */
590 mono_thread_pop_appdomain_ref ();
594 start_func = start_info->func;
595 start_arg = start_info->start_arg;
597 /* We have to do this here because mono_thread_new_init()
598 requires that root_domain_thread is set up. */
599 thread_adjust_static_data (internal);
600 init_root_domain_thread (internal, start_info->obj);
602 /* This MUST be called before any managed code can be
603 * executed, as it calls the callback function that (for the
604 * jit) sets the lmf marker.
606 mono_thread_new_init (tid, &tid, start_func);
607 internal->stack_ptr = &tid;
609 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
611 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
613 /* On 2.0 profile (and higher), set explicitly since state might have been
615 if (internal->apartment_state == ThreadApartmentState_Unknown)
616 internal->apartment_state = ThreadApartmentState_MTA;
618 mono_thread_init_apartment_state ();
620 if(internal->start_notify!=NULL) {
621 /* Let the thread that called Start() know we're
624 ReleaseSemaphore (internal->start_notify, 1, NULL);
627 mono_threads_lock ();
628 mono_g_hash_table_remove (thread_start_args, start_info->obj);
629 mono_threads_unlock ();
631 mono_thread_set_execution_context (start_info->obj->ec_to_set);
632 start_info->obj->ec_to_set = NULL;
635 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
639 * Call this after calling start_notify, since the profiler callback might want
640 * to lock the thread, and the lock is held by thread_start () which waits for
643 mono_profiler_thread_start (tid);
645 /* if the name was set before starting, we didn't invoke the profiler callback */
646 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
647 char *tname = g_utf16_to_utf8 (internal->name, -1, NULL, NULL, NULL);
648 mono_profiler_thread_name (internal->tid, tname);
651 /* start_func is set only for unmanaged start functions */
653 start_func (start_arg);
656 g_assert (start_delegate != NULL);
657 args [0] = start_arg;
658 /* we may want to handle the exception here. See comment below on unhandled exceptions */
659 mono_runtime_delegate_invoke (start_delegate, args, NULL);
662 /* If the thread calls ExitThread at all, this remaining code
663 * will not be executed, but the main thread will eventually
664 * call thread_cleanup() on this thread's behalf.
667 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
669 /* Do any cleanup needed for apartment state. This
670 * cannot be done in thread_cleanup since thread_cleanup could be
671 * called for a thread other than the current thread.
672 * mono_thread_cleanup_apartment_state cleans up apartment
673 * for the current thead */
674 mono_thread_cleanup_apartment_state ();
676 thread_cleanup (internal);
680 /* Remove the reference to the thread object in the TLS data,
681 * so the thread object can be finalized. This won't be
682 * reached if the thread threw an uncaught exception, so those
683 * thread handles will stay referenced :-( (This is due to
684 * missing support for scanning thread-specific data in the
685 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
688 SET_CURRENT_OBJECT (NULL);
693 static guint32 WINAPI start_wrapper(void *data)
697 /* Avoid scanning the frames above this frame during a GC */
698 mono_gc_set_stack_end ((void*)&dummy);
700 return start_wrapper_internal (data);
706 * Common thread creation code.
707 * LOCKING: Acquires the threads lock.
710 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
711 gboolean throw_on_failure)
713 HANDLE thread_handle;
714 MonoNativeThreadId tid;
715 guint32 create_flags;
717 mono_threads_lock ();
720 mono_threads_unlock ();
724 * The thread start argument may be an object reference, and there is
725 * no ref to keep it alive when the new thread is started but not yet
726 * registered with the collector. So we store it in a GC tracked hash
729 if (thread_start_args == NULL) {
730 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
731 thread_start_args = mono_g_hash_table_new (NULL, NULL);
733 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
734 if (threads_starting_up == NULL) {
735 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
736 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
738 mono_g_hash_table_insert (threads_starting_up, thread, thread);
739 mono_threads_unlock ();
741 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
742 if (!internal->start_notify) {
743 mono_threads_lock ();
744 mono_g_hash_table_remove (threads_starting_up, thread);
745 mono_threads_unlock ();
746 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
752 stack_size = default_stacksize_for_thread (internal);
754 /* Create suspended, so we can do some housekeeping before the thread
757 create_flags = CREATE_SUSPENDED;
758 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
759 stack_size, create_flags, &tid);
760 if (thread_handle == NULL) {
761 /* The thread couldn't be created, so throw an exception */
762 mono_threads_lock ();
763 mono_g_hash_table_remove (threads_starting_up, thread);
764 mono_threads_unlock ();
766 if (throw_on_failure)
767 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
769 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
772 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
774 internal->handle = thread_handle;
775 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
777 internal->threadpool_thread = threadpool_thread;
778 if (threadpool_thread)
779 mono_thread_set_state (internal, ThreadState_Background);
781 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
783 /* Only store the handle when the thread is about to be
784 * launched, to avoid the main thread deadlocking while trying
785 * to clean up a thread that will never be signalled.
787 if (!handle_store (thread, FALSE))
790 mono_thread_info_resume (tid);
792 if (internal->start_notify) {
794 * Wait for the thread to set up its TLS data etc, so
795 * theres no potential race condition if someone tries
796 * to look up the data believing the thread has
799 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
801 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
802 CloseHandle (internal->start_notify);
803 internal->start_notify = NULL;
806 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
811 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
813 if (mono_thread_start_cb) {
814 mono_thread_start_cb (tid, stack_start, func);
818 void mono_threads_set_default_stacksize (guint32 stacksize)
820 default_stacksize = stacksize;
823 guint32 mono_threads_get_default_stacksize (void)
825 return default_stacksize;
829 * mono_thread_create_internal:
833 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
836 MonoInternalThread *internal;
837 StartInfo *start_info;
840 thread = create_thread_object (domain);
841 internal = create_internal_thread ();
842 MONO_OBJECT_SETREF (thread, internal_thread, internal);
844 start_info = g_new0 (StartInfo, 1);
845 start_info->func = func;
846 start_info->obj = thread;
847 start_info->start_arg = arg;
849 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
853 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
854 if (mono_check_corlib_version () == NULL)
855 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
861 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
863 mono_thread_create_internal (domain, func, arg, FALSE, 0);
867 mono_thread_attach (MonoDomain *domain)
869 return mono_thread_attach_full (domain, FALSE);
873 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
875 MonoThreadInfo *info;
876 MonoInternalThread *thread;
877 MonoThread *current_thread;
878 HANDLE thread_handle;
881 if ((thread = mono_thread_internal_current ())) {
882 if (domain != mono_domain_get ())
883 mono_domain_set (domain, TRUE);
884 /* Already attached */
885 return mono_thread_current ();
888 if (!mono_gc_register_thread (&domain)) {
889 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 ());
892 thread = create_internal_thread ();
894 thread_handle = mono_thread_info_open_handle ();
895 g_assert (thread_handle);
897 tid=GetCurrentThreadId ();
899 thread->handle=thread_handle;
901 #ifdef PLATFORM_ANDROID
902 thread->android_tid = (gpointer) gettid ();
904 thread->stack_ptr = &tid;
906 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
908 info = mono_thread_info_current ();
910 thread->thread_info = info;
912 current_thread = new_thread_with_internal (domain, thread);
914 if (!handle_store (current_thread, force_attach)) {
915 /* Mono is shutting down, so just wait for the end */
920 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
922 SET_CURRENT_OBJECT (thread);
923 mono_domain_set (domain, TRUE);
925 mono_monitor_init_tls ();
927 thread_adjust_static_data (thread);
929 init_root_domain_thread (thread, current_thread);
930 if (domain != mono_get_root_domain ())
931 set_current_thread_for_domain (domain, thread, current_thread);
934 if (mono_thread_attach_cb) {
938 mono_thread_info_get_stack_bounds (&staddr, &stsize);
941 mono_thread_attach_cb (tid, &tid);
943 mono_thread_attach_cb (tid, staddr + stsize);
946 // FIXME: Need a separate callback
947 mono_profiler_thread_start (tid);
949 return current_thread;
953 mono_thread_detach (MonoThread *thread)
955 g_return_if_fail (thread != NULL);
957 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
959 thread_cleanup (thread->internal_thread);
961 SET_CURRENT_OBJECT (NULL);
962 mono_domain_unset ();
964 /* Don't need to CloseHandle this thread, even though we took a
965 * reference in mono_thread_attach (), because the GC will do it
966 * when the Thread object is finalised.
973 MonoInternalThread *thread = mono_thread_internal_current ();
975 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
977 thread_cleanup (thread);
978 SET_CURRENT_OBJECT (NULL);
979 mono_domain_unset ();
981 /* we could add a callback here for embedders to use. */
982 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
983 exit (mono_environment_exitcode_get ());
984 mono_thread_info_exit ();
988 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
990 MonoInternalThread *internal = create_internal_thread ();
992 internal->state = ThreadState_Unstarted;
994 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
998 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
1001 StartInfo *start_info;
1002 MonoInternalThread *internal;
1005 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1007 if (!this->internal_thread)
1008 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1009 internal = this->internal_thread;
1011 LOCK_THREAD (internal);
1013 if ((internal->state & ThreadState_Unstarted) == 0) {
1014 UNLOCK_THREAD (internal);
1015 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1019 if ((internal->state & ThreadState_Aborted) != 0) {
1020 UNLOCK_THREAD (internal);
1023 /* This is freed in start_wrapper */
1024 start_info = g_new0 (StartInfo, 1);
1025 start_info->func = NULL;
1026 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1027 start_info->delegate = start;
1028 start_info->obj = this;
1029 g_assert (this->obj.vtable->domain == mono_domain_get ());
1031 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1033 UNLOCK_THREAD (internal);
1037 internal->state &= ~ThreadState_Unstarted;
1039 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1041 UNLOCK_THREAD (internal);
1042 return internal->handle;
1046 * This is called from the finalizer of the internal thread object.
1049 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1051 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1054 * Since threads keep a reference to their thread object while running, by the time this function is called,
1055 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1056 * when thread_cleanup () can be called after this.
1059 CloseHandle (thread);
1061 if (this->synch_cs) {
1062 CRITICAL_SECTION *synch_cs = this->synch_cs;
1063 this->synch_cs = NULL;
1064 DeleteCriticalSection (synch_cs);
1069 void *name = this->name;
1075 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1078 MonoInternalThread *thread = mono_thread_internal_current ();
1080 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1082 mono_thread_current_check_pending_interrupt ();
1085 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1087 res = SleepEx(ms,TRUE);
1089 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1091 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1092 MonoException* exc = mono_thread_execute_interruption (thread);
1094 mono_raise_exception (exc);
1106 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1111 ves_icall_System_Threading_Thread_GetDomainID (void)
1113 return mono_domain_get()->domain_id;
1117 ves_icall_System_Threading_Thread_Yield (void)
1119 return mono_thread_info_yield ();
1123 * mono_thread_get_name:
1125 * Return the name of the thread. NAME_LEN is set to the length of the name.
1126 * Return NULL if the thread has no name. The returned memory is owned by the
1130 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1134 LOCK_THREAD (this_obj);
1136 if (!this_obj->name) {
1140 *name_len = this_obj->name_len;
1141 res = g_new (gunichar2, this_obj->name_len);
1142 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1145 UNLOCK_THREAD (this_obj);
1151 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1155 LOCK_THREAD (this_obj);
1157 if (!this_obj->name)
1160 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1162 UNLOCK_THREAD (this_obj);
1168 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1170 LOCK_THREAD (this_obj);
1172 if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1173 UNLOCK_THREAD (this_obj);
1175 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1179 this_obj->name = g_new (gunichar2, mono_string_length (name));
1180 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1181 this_obj->name_len = mono_string_length (name);
1184 this_obj->name = NULL;
1187 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1189 UNLOCK_THREAD (this_obj);
1191 if (this_obj->name && this_obj->tid) {
1192 char *tname = mono_string_to_utf8 (name);
1193 mono_profiler_thread_name (this_obj->tid, tname);
1194 mono_thread_info_set_name (this_obj->tid, tname);
1200 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1202 mono_thread_set_name_internal (this_obj, name, TRUE);
1205 /* If the array is already in the requested domain, we just return it,
1206 otherwise we return a copy in that domain. */
1208 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1215 if (mono_object_domain (arr) == domain)
1218 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1219 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1224 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1226 return byte_array_to_domain (arr, mono_get_root_domain ());
1230 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1232 return byte_array_to_domain (arr, mono_domain_get ());
1236 mono_thread_current (void)
1238 MonoDomain *domain = mono_domain_get ();
1239 MonoInternalThread *internal = mono_thread_internal_current ();
1240 MonoThread **current_thread_ptr;
1242 g_assert (internal);
1243 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1245 if (!*current_thread_ptr) {
1246 g_assert (domain != mono_get_root_domain ());
1247 *current_thread_ptr = new_thread_with_internal (domain, internal);
1249 return *current_thread_ptr;
1253 mono_thread_internal_current (void)
1255 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1256 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1260 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1261 int ms, HANDLE thread)
1263 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1266 mono_thread_current_check_pending_interrupt ();
1270 if ((this->state & ThreadState_Unstarted) != 0) {
1271 UNLOCK_THREAD (this);
1273 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1277 UNLOCK_THREAD (this);
1282 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1284 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1286 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1288 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1290 if(ret==WAIT_OBJECT_0) {
1291 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1296 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1302 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1310 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1313 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1315 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1317 if (ret != WAIT_IO_COMPLETION)
1320 exc = mono_thread_execute_interruption (thread);
1322 mono_raise_exception (exc);
1327 /* Re-calculate ms according to the time passed */
1328 diff_ms = (mono_100ns_ticks () - start) / 10000;
1329 if (diff_ms >= ms) {
1333 wait = ms - diff_ms;
1339 /* FIXME: exitContext isnt documented */
1340 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1346 MonoObject *waitHandle;
1347 MonoInternalThread *thread = mono_thread_internal_current ();
1349 /* Do this WaitSleepJoin check before creating objects */
1350 mono_thread_current_check_pending_interrupt ();
1352 numhandles = mono_array_length(mono_handles);
1353 handles = g_new0(HANDLE, numhandles);
1355 for(i = 0; i < numhandles; i++) {
1356 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1357 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1364 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1366 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1368 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1372 if(ret==WAIT_FAILED) {
1373 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1375 } else if(ret==WAIT_TIMEOUT) {
1376 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1383 /* FIXME: exitContext isnt documented */
1384 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1386 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1390 MonoObject *waitHandle;
1391 MonoInternalThread *thread = mono_thread_internal_current ();
1393 /* Do this WaitSleepJoin check before creating objects */
1394 mono_thread_current_check_pending_interrupt ();
1396 numhandles = mono_array_length(mono_handles);
1397 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1400 for(i = 0; i < numhandles; i++) {
1401 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1402 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1409 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1411 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1413 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1415 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1418 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1420 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1421 return ret - WAIT_OBJECT_0;
1423 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1424 return ret - WAIT_ABANDONED_0;
1431 /* FIXME: exitContext isnt documented */
1432 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1435 MonoInternalThread *thread = mono_thread_internal_current ();
1437 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1443 mono_thread_current_check_pending_interrupt ();
1445 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1447 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1449 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1451 if(ret==WAIT_FAILED) {
1452 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1454 } else if(ret==WAIT_TIMEOUT) {
1455 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1463 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1466 MonoInternalThread *thread = mono_thread_internal_current ();
1471 mono_thread_current_check_pending_interrupt ();
1473 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1475 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1477 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1479 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1482 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1489 mutex = CreateMutex (NULL, owned, NULL);
1491 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1493 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1501 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1502 return(ReleaseMutex (handle));
1505 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1511 *error = ERROR_SUCCESS;
1513 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1515 *error = GetLastError ();
1522 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1529 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1531 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1532 mono_string_chars (name));
1534 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1542 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1546 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1551 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1555 *error = ERROR_SUCCESS;
1557 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1559 *error = GetLastError ();
1565 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1572 event = CreateEvent (NULL, manual, initial, NULL);
1574 event = CreateEvent (NULL, manual, initial,
1575 mono_string_chars (name));
1577 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1585 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1586 return (SetEvent(handle));
1589 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1590 return (ResetEvent(handle));
1594 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1595 CloseHandle (handle);
1598 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1604 *error = ERROR_SUCCESS;
1606 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1608 *error = GetLastError ();
1614 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1616 return InterlockedIncrement (location);
1619 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1621 #if SIZEOF_VOID_P == 4
1622 if (G_UNLIKELY ((size_t)location & 0x7)) {
1624 mono_interlocked_lock ();
1627 mono_interlocked_unlock ();
1631 return InterlockedIncrement64 (location);
1634 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1636 return InterlockedDecrement(location);
1639 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1641 #if SIZEOF_VOID_P == 4
1642 if (G_UNLIKELY ((size_t)location & 0x7)) {
1644 mono_interlocked_lock ();
1647 mono_interlocked_unlock ();
1651 return InterlockedDecrement64 (location);
1654 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1656 return InterlockedExchange(location, value);
1659 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1662 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1663 mono_gc_wbarrier_generic_nostore (location);
1667 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1669 return InterlockedExchangePointer(location, value);
1672 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1674 IntFloatUnion val, ret;
1677 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1683 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1685 #if SIZEOF_VOID_P == 4
1686 if (G_UNLIKELY ((size_t)location & 0x7)) {
1688 mono_interlocked_lock ();
1691 mono_interlocked_unlock ();
1695 return InterlockedExchange64 (location, value);
1699 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1701 LongDoubleUnion val, ret;
1704 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1709 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1711 return InterlockedCompareExchange(location, value, comparand);
1714 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1717 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1718 mono_gc_wbarrier_generic_nostore (location);
1722 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1724 return InterlockedCompareExchangePointer(location, value, comparand);
1727 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1729 IntFloatUnion val, ret, cmp;
1732 cmp.fval = comparand;
1733 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1739 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1741 #if SIZEOF_VOID_P == 8
1742 LongDoubleUnion val, comp, ret;
1745 comp.fval = comparand;
1746 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1752 mono_interlocked_lock ();
1754 if (old == comparand)
1756 mono_interlocked_unlock ();
1763 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1765 #if SIZEOF_VOID_P == 4
1766 if (G_UNLIKELY ((size_t)location & 0x7)) {
1768 mono_interlocked_lock ();
1770 if (old == comparand)
1772 mono_interlocked_unlock ();
1776 return InterlockedCompareExchange64 (location, value, comparand);
1780 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1783 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1784 mono_gc_wbarrier_generic_nostore (location);
1789 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1792 res = InterlockedExchangePointer ((gpointer *)location, value);
1793 mono_gc_wbarrier_generic_nostore (location);
1798 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1800 return InterlockedAdd (location, value);
1804 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1806 #if SIZEOF_VOID_P == 4
1807 if (G_UNLIKELY ((size_t)location & 0x7)) {
1809 mono_interlocked_lock ();
1812 mono_interlocked_unlock ();
1816 return InterlockedAdd64 (location, value);
1820 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1822 #if SIZEOF_VOID_P == 4
1823 if (G_UNLIKELY ((size_t)location & 0x7)) {
1825 mono_interlocked_lock ();
1827 mono_interlocked_unlock ();
1831 return InterlockedRead64 (location);
1835 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1837 mono_memory_barrier ();
1841 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1843 mono_thread_clr_state (this, state);
1845 if (state & ThreadState_Background) {
1846 /* If the thread changes the background mode, the main thread has to
1847 * be notified, since it has to rebuild the list of threads to
1850 SetEvent (background_change_event);
1855 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1857 mono_thread_set_state (this, state);
1859 if (state & ThreadState_Background) {
1860 /* If the thread changes the background mode, the main thread has to
1861 * be notified, since it has to rebuild the list of threads to
1864 SetEvent (background_change_event);
1869 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1875 state = this->state;
1877 UNLOCK_THREAD (this);
1882 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
1884 MonoInternalThread *current;
1889 current = mono_thread_internal_current ();
1891 this->thread_interrupt_requested = TRUE;
1892 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
1894 UNLOCK_THREAD (this);
1897 abort_thread_internal (this, TRUE, FALSE);
1901 void mono_thread_current_check_pending_interrupt ()
1903 MonoInternalThread *thread = mono_thread_internal_current ();
1904 gboolean throw = FALSE;
1906 LOCK_THREAD (thread);
1908 if (thread->thread_interrupt_requested) {
1910 thread->thread_interrupt_requested = FALSE;
1913 UNLOCK_THREAD (thread);
1916 mono_raise_exception (mono_get_exception_thread_interrupted ());
1921 mono_thread_get_abort_signal (void)
1925 #elif defined(PLATFORM_ANDROID)
1927 #elif !defined (SIGRTMIN)
1932 #endif /* SIGUSR1 */
1934 static int abort_signum = -1;
1936 if (abort_signum != -1)
1937 return abort_signum;
1938 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
1939 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
1940 struct sigaction sinfo;
1941 sigaction (i, NULL, &sinfo);
1942 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
1947 /* fallback to the old way */
1949 #endif /* HOST_WIN32 */
1953 static void CALLBACK interruption_request_apc (ULONG_PTR param)
1955 MonoException* exc = mono_thread_request_interruption (FALSE);
1956 if (exc) mono_raise_exception (exc);
1958 #endif /* HOST_WIN32 */
1961 * signal_thread_state_change
1963 * Tells the thread that his state has changed and it has to enter the new
1964 * state as soon as possible.
1966 static void signal_thread_state_change (MonoInternalThread *thread)
1968 if (thread == mono_thread_internal_current ()) {
1969 /* Do it synchronously */
1970 MonoException *exc = mono_thread_request_interruption (FALSE);
1972 mono_raise_exception (exc);
1976 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
1978 /* fixme: store the state somewhere */
1979 mono_thread_kill (thread, mono_thread_get_abort_signal ());
1982 * This will cause waits to be broken.
1983 * It will also prevent the thread from entering a wait, so if the thread returns
1984 * from the wait before it receives the abort signal, it will just spin in the wait
1985 * functions in the io-layer until the signal handler calls QueueUserAPC which will
1988 wapi_interrupt_thread (thread->handle);
1989 #endif /* HOST_WIN32 */
1993 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
1995 LOCK_THREAD (thread);
1997 if ((thread->state & ThreadState_AbortRequested) != 0 ||
1998 (thread->state & ThreadState_StopRequested) != 0 ||
1999 (thread->state & ThreadState_Stopped) != 0)
2001 UNLOCK_THREAD (thread);
2005 if ((thread->state & ThreadState_Unstarted) != 0) {
2006 thread->state |= ThreadState_Aborted;
2007 UNLOCK_THREAD (thread);
2011 thread->state |= ThreadState_AbortRequested;
2012 if (thread->abort_state_handle)
2013 mono_gchandle_free (thread->abort_state_handle);
2015 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2016 g_assert (thread->abort_state_handle);
2018 thread->abort_state_handle = 0;
2020 thread->abort_exc = NULL;
2023 * abort_exc is set in mono_thread_execute_interruption(),
2024 * triggered by the call to signal_thread_state_change(),
2025 * below. There's a point between where we have
2026 * abort_state_handle set, but abort_exc NULL, but that's not
2030 UNLOCK_THREAD (thread);
2032 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2034 /* During shutdown, we can't wait for other threads */
2036 /* Make sure the thread is awake */
2037 mono_thread_resume (thread);
2039 abort_thread_internal (thread, TRUE, TRUE);
2043 ves_icall_System_Threading_Thread_ResetAbort (void)
2045 MonoInternalThread *thread = mono_thread_internal_current ();
2046 gboolean was_aborting;
2048 LOCK_THREAD (thread);
2049 was_aborting = thread->state & ThreadState_AbortRequested;
2050 thread->state &= ~ThreadState_AbortRequested;
2051 UNLOCK_THREAD (thread);
2053 if (!was_aborting) {
2054 const char *msg = "Unable to reset abort because no abort was requested";
2055 mono_raise_exception (mono_get_exception_thread_state (msg));
2057 thread->abort_exc = NULL;
2058 if (thread->abort_state_handle) {
2059 mono_gchandle_free (thread->abort_state_handle);
2060 /* This is actually not necessary - the handle
2061 only counts if the exception is set */
2062 thread->abort_state_handle = 0;
2067 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2069 LOCK_THREAD (thread);
2071 thread->state &= ~ThreadState_AbortRequested;
2073 if (thread->abort_exc) {
2074 thread->abort_exc = NULL;
2075 if (thread->abort_state_handle) {
2076 mono_gchandle_free (thread->abort_state_handle);
2077 /* This is actually not necessary - the handle
2078 only counts if the exception is set */
2079 thread->abort_state_handle = 0;
2083 UNLOCK_THREAD (thread);
2087 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2089 MonoInternalThread *thread = this->internal_thread;
2090 MonoObject *state, *deserialized = NULL, *exc;
2093 if (!thread->abort_state_handle)
2096 state = mono_gchandle_get_target (thread->abort_state_handle);
2099 domain = mono_domain_get ();
2100 if (mono_object_domain (state) == domain)
2103 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2105 if (!deserialized) {
2106 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2108 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2109 mono_raise_exception (invalid_op_exc);
2112 return deserialized;
2116 mono_thread_suspend (MonoInternalThread *thread)
2118 LOCK_THREAD (thread);
2120 if ((thread->state & ThreadState_Unstarted) != 0 ||
2121 (thread->state & ThreadState_Aborted) != 0 ||
2122 (thread->state & ThreadState_Stopped) != 0)
2124 UNLOCK_THREAD (thread);
2128 if ((thread->state & ThreadState_Suspended) != 0 ||
2129 (thread->state & ThreadState_SuspendRequested) != 0 ||
2130 (thread->state & ThreadState_StopRequested) != 0)
2132 UNLOCK_THREAD (thread);
2136 thread->state |= ThreadState_SuspendRequested;
2138 UNLOCK_THREAD (thread);
2140 suspend_thread_internal (thread, FALSE);
2145 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2147 if (!mono_thread_suspend (thread))
2148 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2152 mono_thread_resume (MonoInternalThread *thread)
2154 LOCK_THREAD (thread);
2156 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2157 thread->state &= ~ThreadState_SuspendRequested;
2158 UNLOCK_THREAD (thread);
2162 if ((thread->state & ThreadState_Suspended) == 0 ||
2163 (thread->state & ThreadState_Unstarted) != 0 ||
2164 (thread->state & ThreadState_Aborted) != 0 ||
2165 (thread->state & ThreadState_Stopped) != 0)
2167 UNLOCK_THREAD (thread);
2171 return resume_thread_internal (thread);
2175 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2177 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2178 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2182 mono_threads_is_critical_method (MonoMethod *method)
2184 switch (method->wrapper_type) {
2185 case MONO_WRAPPER_RUNTIME_INVOKE:
2186 case MONO_WRAPPER_XDOMAIN_INVOKE:
2187 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2194 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2199 if (mono_threads_is_critical_method (m)) {
2200 *((gboolean*)data) = TRUE;
2207 is_running_protected_wrapper (void)
2209 gboolean found = FALSE;
2210 mono_stack_walk (find_wrapper, &found);
2214 void mono_thread_internal_stop (MonoInternalThread *thread)
2216 LOCK_THREAD (thread);
2218 if ((thread->state & ThreadState_StopRequested) != 0 ||
2219 (thread->state & ThreadState_Stopped) != 0)
2221 UNLOCK_THREAD (thread);
2225 /* Make sure the thread is awake */
2226 mono_thread_resume (thread);
2228 thread->state |= ThreadState_StopRequested;
2229 thread->state &= ~ThreadState_AbortRequested;
2231 UNLOCK_THREAD (thread);
2233 abort_thread_internal (thread, TRUE, TRUE);
2236 void mono_thread_stop (MonoThread *thread)
2238 mono_thread_internal_stop (thread->internal_thread);
2242 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2245 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2250 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2253 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2258 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2261 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2266 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2269 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2274 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2277 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2278 return (void *) tmp;
2282 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2284 volatile MonoObject *tmp;
2285 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2286 return (MonoObject *) tmp;
2290 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2293 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2298 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2301 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2306 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2308 return InterlockedRead8 (ptr);
2312 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2314 return InterlockedRead16 (ptr);
2318 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2320 return InterlockedRead (ptr);
2324 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2326 #if SIZEOF_VOID_P == 4
2327 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2329 mono_interlocked_lock ();
2330 val = *(gint64*)ptr;
2331 mono_interlocked_unlock ();
2335 return InterlockedRead64 (ptr);
2339 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2341 return InterlockedReadPointer (ptr);
2345 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2349 #if SIZEOF_VOID_P == 4
2350 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2352 mono_interlocked_lock ();
2353 val = *(double*)ptr;
2354 mono_interlocked_unlock ();
2359 u.ival = InterlockedRead64 (ptr);
2365 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2369 u.ival = InterlockedRead (ptr);
2375 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2377 return InterlockedReadPointer (ptr);
2381 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2383 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2387 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2389 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2393 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2395 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2399 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2401 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2405 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2407 mono_atomic_store_release ((volatile void **) ptr, value);
2411 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2413 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2417 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2419 mono_atomic_store_release ((volatile double *) ptr, value);
2423 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2425 mono_atomic_store_release ((volatile float *) ptr, value);
2429 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2431 InterlockedWrite8 (ptr, value);
2435 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2437 InterlockedWrite16 (ptr, value);
2441 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2443 InterlockedWrite (ptr, value);
2447 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2449 #if SIZEOF_VOID_P == 4
2450 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2451 mono_interlocked_lock ();
2452 *(gint64*)ptr = value;
2453 mono_interlocked_unlock ();
2458 InterlockedWrite64 (ptr, value);
2462 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2464 InterlockedWritePointer (ptr, value);
2468 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2472 #if SIZEOF_VOID_P == 4
2473 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2474 mono_interlocked_lock ();
2475 *(double*)ptr = value;
2476 mono_interlocked_unlock ();
2483 InterlockedWrite64 (ptr, u.ival);
2487 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2493 InterlockedWrite (ptr, u.ival);
2497 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2499 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2503 mono_thread_init_tls (void)
2505 MONO_FAST_TLS_INIT (tls_current_object);
2506 mono_native_tls_alloc (¤t_object_key, NULL);
2509 void mono_thread_init (MonoThreadStartCB start_cb,
2510 MonoThreadAttachCB attach_cb)
2512 InitializeCriticalSection(&threads_mutex);
2513 InitializeCriticalSection(&interlocked_mutex);
2514 InitializeCriticalSection(&contexts_mutex);
2515 InitializeCriticalSection(&joinable_threads_mutex);
2517 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2518 g_assert(background_change_event != NULL);
2520 mono_init_static_data_info (&thread_static_info);
2521 mono_init_static_data_info (&context_static_info);
2523 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2525 mono_thread_start_cb = start_cb;
2526 mono_thread_attach_cb = attach_cb;
2528 /* Get a pseudo handle to the current process. This is just a
2529 * kludge so that wapi can build a process handle if needed.
2530 * As a pseudo handle is returned, we don't need to clean
2533 GetCurrentProcess ();
2536 void mono_thread_cleanup (void)
2538 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2539 MonoThreadInfo *info;
2541 /* The main thread must abandon any held mutexes (particularly
2542 * important for named mutexes as they are shared across
2543 * processes, see bug 74680.) This will happen when the
2544 * thread exits, but if it's not running in a subthread it
2545 * won't exit in time.
2547 info = mono_thread_info_current ();
2548 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2552 /* This stuff needs more testing, it seems one of these
2553 * critical sections can be locked when mono_thread_cleanup is
2556 DeleteCriticalSection (&threads_mutex);
2557 DeleteCriticalSection (&interlocked_mutex);
2558 DeleteCriticalSection (&contexts_mutex);
2559 DeleteCriticalSection (&delayed_free_table_mutex);
2560 DeleteCriticalSection (&small_id_mutex);
2561 CloseHandle (background_change_event);
2564 mono_native_tls_free (current_object_key);
2568 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2570 mono_thread_cleanup_fn = func;
2574 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2576 thread->internal_thread->manage_callback = func;
2579 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2581 mono_thread_notify_pending_exc_fn = func;
2585 static void print_tids (gpointer key, gpointer value, gpointer user)
2587 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2588 * sizeof(uint) and a cast to uint would overflow
2590 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2591 * print this as a pointer.
2593 g_message ("Waiting for: %p", key);
2598 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2599 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2603 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2607 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2609 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2611 if(ret==WAIT_FAILED) {
2612 /* See the comment in build_wait_tids() */
2613 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2617 for(i=0; i<wait->num; i++)
2618 CloseHandle (wait->handles[i]);
2620 if (ret == WAIT_TIMEOUT)
2623 for(i=0; i<wait->num; i++) {
2624 gsize tid = wait->threads[i]->tid;
2627 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2628 * it can still run io-layer etc. code. So wait for it to really exit.
2629 * FIXME: This won't join threads which are not in the joinable_hash yet.
2631 mono_thread_join ((gpointer)tid);
2633 mono_threads_lock ();
2634 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2635 /* This thread must have been killed, because
2636 * it hasn't cleaned itself up. (It's just
2637 * possible that the thread exited before the
2638 * parent thread had a chance to store the
2639 * handle, and now there is another pointer to
2640 * the already-exited thread stored. In this
2641 * case, we'll just get two
2642 * mono_profiler_thread_end() calls for the
2646 mono_threads_unlock ();
2647 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2648 thread_cleanup (wait->threads[i]);
2650 mono_threads_unlock ();
2655 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2657 guint32 i, ret, count;
2659 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2661 /* Add the thread state change event, so it wakes up if a thread changes
2662 * to background mode.
2665 if (count < MAXIMUM_WAIT_OBJECTS) {
2666 wait->handles [count] = background_change_event;
2670 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2672 if(ret==WAIT_FAILED) {
2673 /* See the comment in build_wait_tids() */
2674 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2678 for(i=0; i<wait->num; i++)
2679 CloseHandle (wait->handles[i]);
2681 if (ret == WAIT_TIMEOUT)
2684 if (ret < wait->num) {
2685 gsize tid = wait->threads[ret]->tid;
2686 mono_threads_lock ();
2687 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2688 /* See comment in wait_for_tids about thread cleanup */
2689 mono_threads_unlock ();
2690 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2691 thread_cleanup (wait->threads [ret]);
2693 mono_threads_unlock ();
2697 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2699 struct wait_data *wait=(struct wait_data *)user;
2701 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2703 MonoInternalThread *thread=(MonoInternalThread *)value;
2705 /* Ignore background threads, we abort them later */
2706 /* Do not lock here since it is not needed and the caller holds threads_lock */
2707 if (thread->state & ThreadState_Background) {
2708 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2709 return; /* just leave, ignore */
2712 if (mono_gc_is_finalizer_internal_thread (thread)) {
2713 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2717 if (thread == mono_thread_internal_current ()) {
2718 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2722 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2723 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2727 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2728 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2732 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2733 if (handle == NULL) {
2734 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2738 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2739 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2740 wait->handles[wait->num]=handle;
2741 wait->threads[wait->num]=thread;
2744 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2746 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2751 /* Just ignore the rest, we can't do anything with
2758 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2760 struct wait_data *wait=(struct wait_data *)user;
2761 gsize self = GetCurrentThreadId ();
2762 MonoInternalThread *thread = value;
2765 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2768 /* The finalizer thread is not a background thread */
2769 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2770 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2772 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2776 /* printf ("A: %d\n", wait->num); */
2777 wait->handles[wait->num]=thread->handle;
2778 wait->threads[wait->num]=thread;
2781 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2782 mono_thread_internal_stop (thread);
2786 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2790 * mono_threads_set_shutting_down:
2792 * Is called by a thread that wants to shut down Mono. If the runtime is already
2793 * shutting down, the calling thread is suspended/stopped, and this function never
2797 mono_threads_set_shutting_down (void)
2799 MonoInternalThread *current_thread = mono_thread_internal_current ();
2801 mono_threads_lock ();
2803 if (shutting_down) {
2804 mono_threads_unlock ();
2806 /* Make sure we're properly suspended/stopped */
2808 LOCK_THREAD (current_thread);
2810 if ((current_thread->state & ThreadState_SuspendRequested) ||
2811 (current_thread->state & ThreadState_AbortRequested) ||
2812 (current_thread->state & ThreadState_StopRequested)) {
2813 UNLOCK_THREAD (current_thread);
2814 mono_thread_execute_interruption (current_thread);
2816 current_thread->state |= ThreadState_Stopped;
2817 UNLOCK_THREAD (current_thread);
2820 /*since we're killing the thread, unset the current domain.*/
2821 mono_domain_unset ();
2823 /* Wake up other threads potentially waiting for us */
2824 mono_thread_info_exit ();
2826 shutting_down = TRUE;
2828 /* Not really a background state change, but this will
2829 * interrupt the main thread if it is waiting for all
2830 * the other threads.
2832 SetEvent (background_change_event);
2834 mono_threads_unlock ();
2838 void mono_thread_manage (void)
2840 struct wait_data wait_data;
2841 struct wait_data *wait = &wait_data;
2843 memset (wait, 0, sizeof (struct wait_data));
2844 /* join each thread that's still running */
2845 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2847 mono_threads_lock ();
2849 THREAD_DEBUG (g_message("%s: No threads", __func__));
2850 mono_threads_unlock ();
2853 mono_threads_unlock ();
2856 mono_threads_lock ();
2857 if (shutting_down) {
2858 /* somebody else is shutting down */
2859 mono_threads_unlock ();
2862 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2863 mono_g_hash_table_foreach (threads, print_tids, NULL));
2865 ResetEvent (background_change_event);
2867 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2868 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2869 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2870 mono_threads_unlock ();
2872 /* Something to wait for */
2873 wait_for_tids_or_state_change (wait, INFINITE);
2875 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2876 } while(wait->num>0);
2878 /* Mono is shutting down, so just wait for the end */
2879 if (!mono_runtime_try_shutdown ()) {
2880 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2881 mono_thread_suspend (mono_thread_internal_current ());
2882 mono_thread_execute_interruption (mono_thread_internal_current ());
2886 * Remove everything but the finalizer thread and self.
2887 * Also abort all the background threads
2890 mono_threads_lock ();
2893 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2894 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2895 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2897 mono_threads_unlock ();
2899 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2901 /* Something to wait for */
2902 wait_for_tids (wait, INFINITE);
2904 } while (wait->num > 0);
2907 * give the subthreads a chance to really quit (this is mainly needed
2908 * to get correct user and system times from getrusage/wait/time(1)).
2909 * This could be removed if we avoid pthread_detach() and use pthread_join().
2912 mono_thread_info_yield ();
2916 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2918 MonoInternalThread *thread=(MonoInternalThread *)value;
2920 if(thread->tid != (gsize)user) {
2921 /*TerminateThread (thread->handle, -1);*/
2925 void mono_thread_abort_all_other_threads (void)
2927 gsize self = GetCurrentThreadId ();
2929 mono_threads_lock ();
2930 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2931 mono_g_hash_table_size (threads));
2932 mono_g_hash_table_foreach (threads, print_tids, NULL));
2934 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2936 mono_threads_unlock ();
2940 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2942 MonoInternalThread *thread = (MonoInternalThread*)value;
2943 struct wait_data *wait = (struct wait_data*)user_data;
2947 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
2949 * This needs no locking.
2951 if ((thread->state & ThreadState_Suspended) != 0 ||
2952 (thread->state & ThreadState_Stopped) != 0)
2955 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2956 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2960 wait->handles [wait->num] = handle;
2961 wait->threads [wait->num] = thread;
2967 * mono_thread_suspend_all_other_threads:
2969 * Suspend all managed threads except the finalizer thread and this thread. It is
2970 * not possible to resume them later.
2972 void mono_thread_suspend_all_other_threads (void)
2974 struct wait_data wait_data;
2975 struct wait_data *wait = &wait_data;
2977 gsize self = GetCurrentThreadId ();
2979 guint32 eventidx = 0;
2980 gboolean starting, finished;
2982 memset (wait, 0, sizeof (struct wait_data));
2984 * The other threads could be in an arbitrary state at this point, i.e.
2985 * they could be starting up, shutting down etc. This means that there could be
2986 * threads which are not even in the threads hash table yet.
2990 * First we set a barrier which will be checked by all threads before they
2991 * are added to the threads hash table, and they will exit if the flag is set.
2992 * This ensures that no threads could be added to the hash later.
2993 * We will use shutting_down as the barrier for now.
2995 g_assert (shutting_down);
2998 * We make multiple calls to WaitForMultipleObjects since:
2999 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3000 * - some threads could exit without becoming suspended
3005 * Make a copy of the hashtable since we can't do anything with
3006 * threads while threads_mutex is held.
3009 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3010 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3011 mono_threads_lock ();
3012 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3013 mono_threads_unlock ();
3015 events = g_new0 (gpointer, wait->num);
3017 /* Get the suspended events that we'll be waiting for */
3018 for (i = 0; i < wait->num; ++i) {
3019 MonoInternalThread *thread = wait->threads [i];
3020 gboolean signal_suspend = FALSE;
3022 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3023 //CloseHandle (wait->handles [i]);
3024 wait->threads [i] = NULL; /* ignore this thread in next loop */
3028 LOCK_THREAD (thread);
3030 if (thread->suspended_event == NULL) {
3031 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3032 if (thread->suspended_event == NULL) {
3033 /* Forget this one and go on to the next */
3034 UNLOCK_THREAD (thread);
3039 if ((thread->state & ThreadState_Suspended) != 0 ||
3040 (thread->state & ThreadState_StopRequested) != 0 ||
3041 (thread->state & ThreadState_Stopped) != 0) {
3042 UNLOCK_THREAD (thread);
3043 CloseHandle (wait->handles [i]);
3044 wait->threads [i] = NULL; /* ignore this thread in next loop */
3048 if ((thread->state & ThreadState_SuspendRequested) == 0)
3049 signal_suspend = TRUE;
3051 events [eventidx++] = thread->suspended_event;
3053 /* Convert abort requests into suspend requests */
3054 if ((thread->state & ThreadState_AbortRequested) != 0)
3055 thread->state &= ~ThreadState_AbortRequested;
3057 thread->state |= ThreadState_SuspendRequested;
3059 UNLOCK_THREAD (thread);
3061 /* Signal the thread to suspend */
3062 if (mono_thread_info_new_interrupt_enabled ())
3063 suspend_thread_internal (thread, TRUE);
3064 else if (signal_suspend)
3065 signal_thread_state_change (thread);
3068 /*Only wait on the suspend event if we are using the old path */
3069 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3070 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3071 for (i = 0; i < wait->num; ++i) {
3072 MonoInternalThread *thread = wait->threads [i];
3077 LOCK_THREAD (thread);
3078 if ((thread->state & ThreadState_Suspended) != 0) {
3079 CloseHandle (thread->suspended_event);
3080 thread->suspended_event = NULL;
3082 UNLOCK_THREAD (thread);
3086 if (eventidx <= 0) {
3088 * If there are threads which are starting up, we wait until they
3089 * are suspended when they try to register in the threads hash.
3090 * This is guaranteed to finish, since the threads which can create new
3091 * threads get suspended after a while.
3092 * FIXME: The finalizer thread can still create new threads.
3094 mono_threads_lock ();
3095 if (threads_starting_up)
3096 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3099 mono_threads_unlock ();
3111 collect_threads (gpointer key, gpointer value, gpointer user_data)
3113 MonoInternalThread *thread = (MonoInternalThread*)value;
3114 struct wait_data *wait = (struct wait_data*)user_data;
3117 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3118 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3122 wait->handles [wait->num] = handle;
3123 wait->threads [wait->num] = thread;
3128 static gboolean thread_dump_requested;
3130 static G_GNUC_UNUSED gboolean
3131 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3133 GString *p = (GString*)data;
3134 MonoMethod *method = NULL;
3136 method = mono_jit_info_get_method (frame->ji);
3139 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3140 g_string_append_printf (p, " %s\n", location);
3143 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3149 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3151 GString* text = g_string_new (0);
3153 GError *error = NULL;
3156 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3158 g_string_append_printf (text, "\n\"%s\"", name);
3161 else if (thread->threadpool_thread)
3162 g_string_append (text, "\n\"<threadpool thread>\"");
3164 g_string_append (text, "\n\"<unnamed thread>\"");
3167 /* This no longer works with remote unwinding */
3169 wapi_desc = wapi_current_thread_desc ();
3170 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3175 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3176 mono_thread_info_resume (mono_thread_info_get_tid (info));
3178 fprintf (stdout, "%s", text->str);
3180 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3181 OutputDebugStringA(text->str);
3184 g_string_free (text, TRUE);
3189 dump_thread (gpointer key, gpointer value, gpointer user)
3191 MonoInternalThread *thread = (MonoInternalThread *)value;
3192 MonoThreadInfo *info;
3194 if (thread == mono_thread_internal_current ())
3198 FIXME This still can hang if we stop a thread during malloc.
3199 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3200 that takes a callback and runs it with the target suspended.
3201 We probably should loop a bit around trying to get it to either managed code
3204 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3209 print_thread_dump (thread, info);
3213 mono_threads_perform_thread_dump (void)
3215 if (!thread_dump_requested)
3218 printf ("Full thread dump:\n");
3221 * Make a copy of the hashtable since we can't do anything with
3222 * threads while threads_mutex is held.
3224 mono_threads_lock ();
3225 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3226 mono_threads_unlock ();
3228 thread_dump_requested = FALSE;
3232 * mono_threads_request_thread_dump:
3234 * Ask all threads except the current to print their stacktrace to stdout.
3237 mono_threads_request_thread_dump (void)
3239 struct wait_data wait_data;
3240 struct wait_data *wait = &wait_data;
3243 /*The new thread dump code runs out of the finalizer thread. */
3244 if (mono_thread_info_new_interrupt_enabled ()) {
3245 thread_dump_requested = TRUE;
3246 mono_gc_finalize_notify ();
3251 memset (wait, 0, sizeof (struct wait_data));
3254 * Make a copy of the hashtable since we can't do anything with
3255 * threads while threads_mutex is held.
3257 mono_threads_lock ();
3258 mono_g_hash_table_foreach (threads, collect_threads, wait);
3259 mono_threads_unlock ();
3261 for (i = 0; i < wait->num; ++i) {
3262 MonoInternalThread *thread = wait->threads [i];
3264 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3265 (thread != mono_thread_internal_current ()) &&
3266 !thread->thread_dump_requested) {
3267 thread->thread_dump_requested = TRUE;
3269 signal_thread_state_change (thread);
3272 CloseHandle (wait->handles [i]);
3278 gint allocated; /* +1 so that refs [allocated] == NULL */
3282 typedef struct ref_stack RefStack;
3285 ref_stack_new (gint initial_size)
3289 initial_size = MAX (initial_size, 16) + 1;
3290 rs = g_new0 (RefStack, 1);
3291 rs->refs = g_new0 (gpointer, initial_size);
3292 rs->allocated = initial_size;
3297 ref_stack_destroy (gpointer ptr)
3308 ref_stack_push (RefStack *rs, gpointer ptr)
3310 g_assert (rs != NULL);
3312 if (rs->bottom >= rs->allocated) {
3313 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3314 rs->allocated <<= 1;
3315 rs->refs [rs->allocated] = NULL;
3317 rs->refs [rs->bottom++] = ptr;
3321 ref_stack_pop (RefStack *rs)
3323 if (rs == NULL || rs->bottom == 0)
3327 rs->refs [rs->bottom] = NULL;
3331 ref_stack_find (RefStack *rs, gpointer ptr)
3338 for (refs = rs->refs; refs && *refs; refs++) {
3346 * mono_thread_push_appdomain_ref:
3348 * Register that the current thread may have references to objects in domain
3349 * @domain on its stack. Each call to this function should be paired with a
3350 * call to pop_appdomain_ref.
3353 mono_thread_push_appdomain_ref (MonoDomain *domain)
3355 MonoInternalThread *thread = mono_thread_internal_current ();
3358 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3359 SPIN_LOCK (thread->lock_thread_id);
3360 if (thread->appdomain_refs == NULL)
3361 thread->appdomain_refs = ref_stack_new (16);
3362 ref_stack_push (thread->appdomain_refs, domain);
3363 SPIN_UNLOCK (thread->lock_thread_id);
3368 mono_thread_pop_appdomain_ref (void)
3370 MonoInternalThread *thread = mono_thread_internal_current ();
3373 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3374 SPIN_LOCK (thread->lock_thread_id);
3375 ref_stack_pop (thread->appdomain_refs);
3376 SPIN_UNLOCK (thread->lock_thread_id);
3381 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3384 SPIN_LOCK (thread->lock_thread_id);
3385 res = ref_stack_find (thread->appdomain_refs, domain);
3386 SPIN_UNLOCK (thread->lock_thread_id);
3391 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3393 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3396 typedef struct abort_appdomain_data {
3397 struct wait_data wait;
3399 } abort_appdomain_data;
3402 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3404 MonoInternalThread *thread = (MonoInternalThread*)value;
3405 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3406 MonoDomain *domain = data->domain;
3408 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3409 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3411 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3412 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3415 data->wait.handles [data->wait.num] = handle;
3416 data->wait.threads [data->wait.num] = thread;
3419 /* Just ignore the rest, we can't do anything with
3427 * mono_threads_abort_appdomain_threads:
3429 * Abort threads which has references to the given appdomain.
3432 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3434 #ifdef __native_client__
3438 abort_appdomain_data user_data;
3440 int orig_timeout = timeout;
3443 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3445 start_time = mono_msec_ticks ();
3447 mono_threads_lock ();
3449 user_data.domain = domain;
3450 user_data.wait.num = 0;
3451 /* This shouldn't take any locks */
3452 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3453 mono_threads_unlock ();
3455 if (user_data.wait.num > 0) {
3456 /* Abort the threads outside the threads lock */
3457 for (i = 0; i < user_data.wait.num; ++i)
3458 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3461 * We should wait for the threads either to abort, or to leave the
3462 * domain. We can't do the latter, so we wait with a timeout.
3464 wait_for_tids (&user_data.wait, 100);
3467 /* Update remaining time */
3468 timeout -= mono_msec_ticks () - start_time;
3469 start_time = mono_msec_ticks ();
3471 if (orig_timeout != -1 && timeout < 0)
3474 while (user_data.wait.num > 0);
3476 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3482 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3484 MonoInternalThread *thread = (MonoInternalThread*)value;
3485 MonoDomain *domain = (MonoDomain*)user_data;
3488 /* No locking needed here */
3489 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3491 if (thread->cached_culture_info) {
3492 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3493 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3494 if (obj && obj->vtable->domain == domain)
3495 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3501 * mono_threads_clear_cached_culture:
3503 * Clear the cached_current_culture from all threads if it is in the
3507 mono_threads_clear_cached_culture (MonoDomain *domain)
3509 mono_threads_lock ();
3510 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3511 mono_threads_unlock ();
3515 * mono_thread_get_undeniable_exception:
3517 * Return an exception which needs to be raised when leaving a catch clause.
3518 * This is used for undeniable exception propagation.
3521 mono_thread_get_undeniable_exception (void)
3523 MonoInternalThread *thread = mono_thread_internal_current ();
3525 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3527 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3528 * exception if the thread no longer references a dying appdomain.
3530 thread->abort_exc->trace_ips = NULL;
3531 thread->abort_exc->stack_trace = NULL;
3532 return thread->abort_exc;
3538 #if MONO_SMALL_CONFIG
3539 #define NUM_STATIC_DATA_IDX 4
3540 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3544 #define NUM_STATIC_DATA_IDX 8
3545 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3546 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3550 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3553 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
3556 gpointer *static_data = addr;
3557 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3560 if (!static_data [i])
3562 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3563 ptr = static_data [i];
3564 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3565 uintptr_t bmap = static_reference_bitmaps [i][j];
3568 if ((bmap & 1) && *p) {
3579 * mono_alloc_static_data
3581 * Allocate memory blocks for storing threads or context static data
3584 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3586 guint idx = (offset >> 24) - 1;
3589 gpointer* static_data = *static_data_ptr;
3591 static void* tls_desc = NULL;
3592 if (mono_gc_user_markers_supported () && !tls_desc)
3593 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3594 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3595 *static_data_ptr = static_data;
3596 static_data [0] = static_data;
3599 for (i = 1; i <= idx; ++i) {
3600 if (static_data [i])
3602 if (mono_gc_user_markers_supported () && threadlocal)
3603 static_data [i] = g_malloc0 (static_data_size [i]);
3605 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3610 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3613 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3614 gpointer p = static_data [i];
3618 * At this point, the static data pointer array is still registered with the
3619 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3620 * data. Freeing the individual arrays without first nulling their slots
3621 * would make it possible for mark_tls_slots() to encounter a pointer to
3622 * such an already freed array. See bug #13813.
3624 static_data [i] = NULL;
3625 mono_memory_write_barrier ();
3626 if (mono_gc_user_markers_supported () && threadlocal)
3629 mono_gc_free_fixed (p);
3631 mono_gc_free_fixed (static_data);
3635 * mono_init_static_data_info
3637 * Initializes static data counters
3639 static void mono_init_static_data_info (StaticDataInfo *static_data)
3641 static_data->idx = 0;
3642 static_data->offset = 0;
3643 static_data->freelist = NULL;
3647 * mono_alloc_static_data_slot
3649 * Generates an offset for static data. static_data contains the counters
3650 * used to generate it.
3653 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3657 if (!static_data->idx && !static_data->offset) {
3659 * we use the first chunk of the first allocation also as
3660 * an array for the rest of the data
3662 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3664 static_data->offset += align - 1;
3665 static_data->offset &= ~(align - 1);
3666 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3667 static_data->idx ++;
3668 g_assert (size <= static_data_size [static_data->idx]);
3669 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3670 static_data->offset = 0;
3672 offset = static_data->offset | ((static_data->idx + 1) << 24);
3673 static_data->offset += size;
3678 * ensure thread static fields already allocated are valid for thread
3679 * This function is called when a thread is created or on thread attach.
3682 thread_adjust_static_data (MonoInternalThread *thread)
3686 mono_threads_lock ();
3687 if (thread_static_info.offset || thread_static_info.idx > 0) {
3688 /* get the current allocated size */
3689 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3690 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3692 mono_threads_unlock ();
3696 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3698 MonoInternalThread *thread = value;
3699 guint32 offset = GPOINTER_TO_UINT (user);
3701 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3704 static MonoThreadDomainTls*
3705 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3707 MonoThreadDomainTls* prev = NULL;
3708 MonoThreadDomainTls* tmp = static_data->freelist;
3710 if (tmp->size == size) {
3712 prev->next = tmp->next;
3714 static_data->freelist = tmp->next;
3724 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3727 int idx = (offset >> 24) - 1;
3729 if (!static_reference_bitmaps [idx])
3730 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3731 rb = static_reference_bitmaps [idx];
3733 offset /= sizeof (gpointer);
3734 /* offset is now the bitmap offset */
3735 for (i = 0; i < numbits; ++i) {
3736 if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
3737 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3742 clear_reference_bitmap (guint32 offset, guint32 size)
3744 int idx = (offset >> 24) - 1;
3746 rb = static_reference_bitmaps [idx];
3748 offset /= sizeof (gpointer);
3749 size /= sizeof (gpointer);
3751 /* offset is now the bitmap offset */
3752 for (; offset < size; ++offset)
3753 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3757 * The offset for a special static variable is composed of three parts:
3758 * a bit that indicates the type of static data (0:thread, 1:context),
3759 * an index in the array of chunks of memory for the thread (thread->static_data)
3760 * and an offset in that chunk of mem. This allows allocating less memory in the
3765 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3768 if (static_type == SPECIAL_STATIC_THREAD) {
3769 MonoThreadDomainTls *item;
3770 mono_threads_lock ();
3771 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3772 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3774 offset = item->offset;
3777 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3779 update_tls_reference_bitmap (offset, bitmap, numbits);
3780 /* This can be called during startup */
3781 if (threads != NULL)
3782 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3783 mono_threads_unlock ();
3785 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3786 mono_contexts_lock ();
3787 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3788 mono_contexts_unlock ();
3789 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3795 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3797 /* The high bit means either thread (0) or static (1) data. */
3799 guint32 static_type = (offset & 0x80000000);
3802 offset &= 0x7fffffff;
3803 idx = (offset >> 24) - 1;
3805 if (static_type == 0) {
3806 return get_thread_static_data (thread, offset);
3808 /* Allocate static data block under demand, since we don't have a list
3811 MonoAppContext *context = mono_context_get ();
3812 if (!context->static_data || !context->static_data [idx]) {
3813 mono_contexts_lock ();
3814 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3815 mono_contexts_unlock ();
3817 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3822 mono_get_special_static_data (guint32 offset)
3824 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3833 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3835 MonoInternalThread *thread = value;
3836 TlsOffsetSize *data = user;
3837 int idx = (data->offset >> 24) - 1;
3840 if (!thread->static_data || !thread->static_data [idx])
3842 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3843 mono_gc_bzero_atomic (ptr, data->size);
3847 do_free_special_slot (guint32 offset, guint32 size)
3849 guint32 static_type = (offset & 0x80000000);
3850 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3851 if (static_type == 0) {
3853 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3854 data.offset = offset & 0x7fffffff;
3856 clear_reference_bitmap (data.offset, data.size);
3857 if (threads != NULL)
3858 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3859 item->offset = offset;
3862 if (!mono_runtime_is_shutting_down ()) {
3863 item->next = thread_static_info.freelist;
3864 thread_static_info.freelist = item;
3866 /* We could be called during shutdown after mono_thread_cleanup () is called */
3870 /* FIXME: free context static data as well */
3875 do_free_special (gpointer key, gpointer value, gpointer data)
3877 MonoClassField *field = key;
3878 guint32 offset = GPOINTER_TO_UINT (value);
3881 size = mono_type_size (field->type, &align);
3882 do_free_special_slot (offset, size);
3886 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3888 mono_threads_lock ();
3889 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3890 mono_threads_unlock ();
3894 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3896 mono_threads_lock ();
3897 do_free_special_slot (offset, size);
3898 mono_threads_unlock ();
3902 * allocates room in the thread local area for storing an instance of the struct type
3903 * the allocation is kept track of in domain->tlsrec_list.
3906 mono_thread_alloc_tls (MonoReflectionType *type)
3908 MonoDomain *domain = mono_domain_get ();
3910 MonoTlsDataRecord *tlsrec;
3913 gsize default_bitmap [4] = {0};
3914 uint32_t tls_offset;
3918 klass = mono_class_from_mono_type (type->type);
3919 /* TlsDatum is a struct, so we subtract the object header size offset */
3920 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3921 size = mono_type_size (type->type, &align);
3922 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3923 if (bitmap != default_bitmap)
3925 tlsrec = g_new0 (MonoTlsDataRecord, 1);
3926 tlsrec->tls_offset = tls_offset;
3927 tlsrec->size = size;
3928 mono_domain_lock (domain);
3929 tlsrec->next = domain->tlsrec_list;
3930 domain->tlsrec_list = tlsrec;
3931 mono_domain_unlock (domain);
3936 mono_thread_destroy_tls (uint32_t tls_offset)
3938 MonoTlsDataRecord *prev = NULL;
3939 MonoTlsDataRecord *cur;
3941 MonoDomain *domain = mono_domain_get ();
3942 mono_domain_lock (domain);
3943 cur = domain->tlsrec_list;
3945 if (cur->tls_offset == tls_offset) {
3947 prev->next = cur->next;
3949 domain->tlsrec_list = cur->next;
3957 mono_domain_unlock (domain);
3959 mono_special_static_data_free_slot (tls_offset, size);
3963 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
3966 mono_thread_destroy_domain_tls (MonoDomain *domain)
3968 while (domain->tlsrec_list)
3969 mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
3972 static MonoClassField *local_slots = NULL;
3975 /* local tls data to get locals_slot from a thread */
3978 /* index in the locals_slot array */
3983 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
3985 LocalSlotID *sid = user_data;
3986 MonoInternalThread *thread = (MonoInternalThread*)value;
3987 MonoArray *slots_array;
3989 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
3990 * it is for the right domain, so we need to check if it is allocated an initialized
3991 * for the current thread.
3993 /*g_print ("handling thread %p\n", thread);*/
3994 if (!thread->static_data || !thread->static_data [sid->idx])
3996 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
3997 if (!slots_array || sid->slot >= mono_array_length (slots_array))
3999 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4003 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4011 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4013 g_warning ("local_slots field not found in Thread class");
4017 domain = mono_domain_get ();
4018 mono_domain_lock (domain);
4019 if (domain->special_static_fields)
4020 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4021 mono_domain_unlock (domain);
4024 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4025 sid.offset = GPOINTER_TO_UINT (addr);
4026 sid.offset &= 0x7fffffff;
4027 sid.idx = (sid.offset >> 24) - 1;
4028 mono_threads_lock ();
4029 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4030 mono_threads_unlock ();
4032 /* FIXME: clear the slot for MonoAppContexts, too */
4037 static void CALLBACK dummy_apc (ULONG_PTR param)
4043 * mono_thread_execute_interruption
4045 * Performs the operation that the requested thread state requires (abort,
4048 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4050 LOCK_THREAD (thread);
4052 /* MonoThread::interruption_requested can only be changed with atomics */
4053 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4054 /* this will consume pending APC calls */
4056 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4058 InterlockedDecrement (&thread_interruption_requested);
4060 /* Clear the interrupted flag of the thread so it can wait again */
4061 wapi_clear_interruption ();
4065 if ((thread->state & ThreadState_AbortRequested) != 0) {
4066 UNLOCK_THREAD (thread);
4067 if (thread->abort_exc == NULL) {
4069 * This might be racy, but it has to be called outside the lock
4070 * since it calls managed code.
4072 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4074 return thread->abort_exc;
4076 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4077 self_suspend_internal (thread);
4080 else if ((thread->state & ThreadState_StopRequested) != 0) {
4081 /* FIXME: do this through the JIT? */
4083 UNLOCK_THREAD (thread);
4085 mono_thread_exit ();
4087 } else if (thread->pending_exception) {
4090 exc = thread->pending_exception;
4091 thread->pending_exception = NULL;
4093 UNLOCK_THREAD (thread);
4095 } else if (thread->thread_interrupt_requested) {
4097 thread->thread_interrupt_requested = FALSE;
4098 UNLOCK_THREAD (thread);
4100 return(mono_get_exception_thread_interrupted ());
4103 UNLOCK_THREAD (thread);
4109 * mono_thread_request_interruption
4111 * A signal handler can call this method to request the interruption of a
4112 * thread. The result of the interruption will depend on the current state of
4113 * the thread. If the result is an exception that needs to be throw, it is
4114 * provided as return value.
4117 mono_thread_request_interruption (gboolean running_managed)
4119 MonoInternalThread *thread = mono_thread_internal_current ();
4121 /* The thread may already be stopping */
4126 if (thread->interrupt_on_stop &&
4127 thread->state & ThreadState_StopRequested &&
4128 thread->state & ThreadState_Background)
4132 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4134 InterlockedIncrement (&thread_interruption_requested);
4136 if (!running_managed || is_running_protected_wrapper ()) {
4137 /* Can't stop while in unmanaged code. Increase the global interruption
4138 request count. When exiting the unmanaged method the count will be
4139 checked and the thread will be interrupted. */
4141 if (mono_thread_notify_pending_exc_fn && !running_managed)
4142 /* The JIT will notify the thread about the interruption */
4143 /* This shouldn't take any locks */
4144 mono_thread_notify_pending_exc_fn ();
4146 /* this will awake the thread if it is in WaitForSingleObject
4148 /* Our implementation of this function ignores the func argument */
4150 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
4155 return mono_thread_execute_interruption (thread);
4159 /*This function should be called by a thread after it has exited all of
4160 * its handle blocks at interruption time.*/
4162 mono_thread_resume_interruption (void)
4164 MonoInternalThread *thread = mono_thread_internal_current ();
4165 gboolean still_aborting;
4167 /* The thread may already be stopping */
4171 LOCK_THREAD (thread);
4172 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4173 UNLOCK_THREAD (thread);
4175 /*This can happen if the protected block called Thread::ResetAbort*/
4176 if (!still_aborting)
4179 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4181 InterlockedIncrement (&thread_interruption_requested);
4184 wapi_self_interrupt ();
4186 return mono_thread_execute_interruption (thread);
4189 gboolean mono_thread_interruption_requested ()
4191 if (thread_interruption_requested) {
4192 MonoInternalThread *thread = mono_thread_internal_current ();
4193 /* The thread may already be stopping */
4195 return (thread->interruption_requested);
4200 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4202 MonoInternalThread *thread = mono_thread_internal_current ();
4204 /* The thread may already be stopping */
4208 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4209 MonoException* exc = mono_thread_execute_interruption (thread);
4210 if (exc) mono_raise_exception (exc);
4215 * Performs the interruption of the current thread, if one has been requested,
4216 * and the thread is not running a protected wrapper.
4218 void mono_thread_interruption_checkpoint ()
4220 mono_thread_interruption_checkpoint_request (FALSE);
4224 * Performs the interruption of the current thread, if one has been requested.
4226 void mono_thread_force_interruption_checkpoint ()
4228 mono_thread_interruption_checkpoint_request (TRUE);
4232 * mono_thread_get_and_clear_pending_exception:
4234 * Return any pending exceptions for the current thread and clear it as a side effect.
4237 mono_thread_get_and_clear_pending_exception (void)
4239 MonoInternalThread *thread = mono_thread_internal_current ();
4241 /* The thread may already be stopping */
4245 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4246 return mono_thread_execute_interruption (thread);
4249 if (thread->pending_exception) {
4250 MonoException *exc = thread->pending_exception;
4252 thread->pending_exception = NULL;
4260 * mono_set_pending_exception:
4262 * Set the pending exception of the current thread to EXC.
4263 * The exception will be thrown when execution returns to managed code.
4266 mono_set_pending_exception (MonoException *exc)
4268 MonoInternalThread *thread = mono_thread_internal_current ();
4270 /* The thread may already be stopping */
4274 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4276 mono_thread_request_interruption (FALSE);
4280 * mono_thread_interruption_request_flag:
4282 * Returns the address of a flag that will be non-zero if an interruption has
4283 * been requested for a thread. The thread to interrupt may not be the current
4284 * thread, so an additional call to mono_thread_interruption_requested() or
4285 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4288 gint32* mono_thread_interruption_request_flag ()
4290 return &thread_interruption_requested;
4294 mono_thread_init_apartment_state (void)
4297 MonoInternalThread* thread = mono_thread_internal_current ();
4299 /* Positive return value indicates success, either
4300 * S_OK if this is first CoInitialize call, or
4301 * S_FALSE if CoInitialize already called, but with same
4302 * threading model. A negative value indicates failure,
4303 * probably due to trying to change the threading model.
4305 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4306 ? COINIT_APARTMENTTHREADED
4307 : COINIT_MULTITHREADED) < 0) {
4308 thread->apartment_state = ThreadApartmentState_Unknown;
4314 mono_thread_cleanup_apartment_state (void)
4317 MonoInternalThread* thread = mono_thread_internal_current ();
4319 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4326 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4328 LOCK_THREAD (thread);
4329 thread->state |= state;
4330 UNLOCK_THREAD (thread);
4334 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4336 LOCK_THREAD (thread);
4337 thread->state &= ~state;
4338 UNLOCK_THREAD (thread);
4342 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4344 gboolean ret = FALSE;
4346 LOCK_THREAD (thread);
4348 if ((thread->state & test) != 0) {
4352 UNLOCK_THREAD (thread);
4357 //static MonoClassField *execution_context_field;
4360 get_execution_context_addr (void)
4362 MonoDomain *domain = mono_domain_get ();
4363 guint32 offset = domain->execution_context_field_offset;
4366 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4369 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4371 mono_domain_lock (domain);
4372 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4373 mono_domain_unlock (domain);
4376 domain->execution_context_field_offset = offset;
4379 return (MonoObject**) mono_get_special_static_data (offset);
4383 mono_thread_get_execution_context (void)
4385 return *get_execution_context_addr ();
4389 mono_thread_set_execution_context (MonoObject *ec)
4391 *get_execution_context_addr () = ec;
4394 static gboolean has_tls_get = FALSE;
4397 mono_runtime_set_has_tls_get (gboolean val)
4403 mono_runtime_has_tls_get (void)
4409 mono_thread_kill (MonoInternalThread *thread, int signal)
4411 #ifdef __native_client__
4412 /* Workaround pthread_kill abort() in NaCl glibc. */
4416 /* Win32 uses QueueUserAPC and callers of this are guarded */
4417 g_assert_not_reached ();
4419 # ifdef PTHREAD_POINTER_ID
4420 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4422 # ifdef PLATFORM_ANDROID
4423 if (thread->android_tid != 0) {
4425 int old_errno = errno;
4427 ret = tkill ((pid_t) thread->android_tid, signal);
4436 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4438 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4445 self_interrupt_thread (void *_unused)
4447 MonoThreadInfo *info = mono_thread_info_current ();
4448 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4449 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4450 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4451 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4455 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4459 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4463 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4465 MonoJitInfo **dest = data;
4471 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4473 MonoJitInfo *ji = NULL;
4476 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4481 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4484 MonoThreadInfo *info = NULL;
4485 gboolean protected_wrapper;
4486 gboolean running_managed;
4488 if (!mono_thread_info_new_interrupt_enabled ()) {
4489 signal_thread_state_change (thread);
4494 FIXME this is insanely broken, it doesn't cause interruption to happen
4495 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4497 if (thread == mono_thread_internal_current ()) {
4498 /* Do it synchronously */
4499 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4501 mono_raise_exception (exc);
4503 wapi_interrupt_thread (thread->handle);
4508 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4509 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4513 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4514 mono_thread_info_resume (mono_thread_info_get_tid (info));
4518 /*someone is already interrupting it*/
4519 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4520 mono_thread_info_resume (mono_thread_info_get_tid (info));
4523 InterlockedIncrement (&thread_interruption_requested);
4525 ji = mono_thread_info_get_last_managed (info);
4526 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4527 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4529 if (!protected_wrapper && running_managed) {
4530 /*We are in managed code*/
4531 /*Set the thread to call */
4532 if (install_async_abort)
4533 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4534 mono_thread_info_resume (mono_thread_info_get_tid (info));
4536 gpointer interrupt_handle;
4538 * This will cause waits to be broken.
4539 * It will also prevent the thread from entering a wait, so if the thread returns
4540 * from the wait before it receives the abort signal, it will just spin in the wait
4541 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4545 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4547 mono_thread_info_resume (mono_thread_info_get_tid (info));
4549 wapi_finish_interrupt_thread (interrupt_handle);
4552 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4556 transition_to_suspended (MonoInternalThread *thread)
4558 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4559 g_assert (0); /*FIXME we should not reach this */
4560 /*Make sure we balance the suspend count.*/
4561 mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
4563 thread->state &= ~ThreadState_SuspendRequested;
4564 thread->state |= ThreadState_Suspended;
4565 mono_thread_info_finish_suspend ();
4567 UNLOCK_THREAD (thread);
4571 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4573 if (!mono_thread_info_new_interrupt_enabled ()) {
4574 signal_thread_state_change (thread);
4578 LOCK_THREAD (thread);
4579 if (thread == mono_thread_internal_current ()) {
4580 transition_to_suspended (thread);
4581 mono_thread_info_self_suspend ();
4583 MonoThreadInfo *info;
4585 gboolean protected_wrapper;
4586 gboolean running_managed;
4588 /*A null info usually means the thread is already dead. */
4589 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
4590 UNLOCK_THREAD (thread);
4594 ji = mono_thread_info_get_last_managed (info);
4595 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4596 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4598 if (running_managed && !protected_wrapper) {
4599 transition_to_suspended (thread);
4601 gpointer interrupt_handle;
4603 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4604 InterlockedIncrement (&thread_interruption_requested);
4607 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4609 mono_thread_info_resume (mono_thread_info_get_tid (info));
4612 wapi_finish_interrupt_thread (interrupt_handle);
4614 UNLOCK_THREAD (thread);
4619 /*This is called with @thread synch_cs held and it must release it*/
4621 self_suspend_internal (MonoInternalThread *thread)
4623 if (!mono_thread_info_new_interrupt_enabled ()) {
4624 thread->state &= ~ThreadState_SuspendRequested;
4625 thread->state |= ThreadState_Suspended;
4626 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4627 if (thread->suspend_event == NULL) {
4628 UNLOCK_THREAD (thread);
4631 if (thread->suspended_event)
4632 SetEvent (thread->suspended_event);
4634 UNLOCK_THREAD (thread);
4636 if (shutting_down) {
4637 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4642 WaitForSingleObject (thread->suspend_event, INFINITE);
4644 LOCK_THREAD (thread);
4646 CloseHandle (thread->suspend_event);
4647 thread->suspend_event = NULL;
4648 thread->state &= ~ThreadState_Suspended;
4650 /* The thread that requested the resume will have replaced this event
4651 * and will be waiting for it
4653 SetEvent (thread->resume_event);
4655 UNLOCK_THREAD (thread);
4659 transition_to_suspended (thread);
4660 mono_thread_info_self_suspend ();
4663 /*This is called with @thread synch_cs held and it must release it*/
4665 resume_thread_internal (MonoInternalThread *thread)
4667 if (!mono_thread_info_new_interrupt_enabled ()) {
4668 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4669 if (thread->resume_event == NULL) {
4670 UNLOCK_THREAD (thread);
4674 /* Awake the thread */
4675 SetEvent (thread->suspend_event);
4677 UNLOCK_THREAD (thread);
4679 /* Wait for the thread to awake */
4680 WaitForSingleObject (thread->resume_event, INFINITE);
4681 CloseHandle (thread->resume_event);
4682 thread->resume_event = NULL;
4686 UNLOCK_THREAD (thread);
4687 /* Awake the thread */
4688 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4690 LOCK_THREAD (thread);
4691 thread->state &= ~ThreadState_Suspended;
4692 UNLOCK_THREAD (thread);
4698 * mono_thread_is_foreign:
4699 * @thread: the thread to query
4701 * This function allows one to determine if a thread was created by the mono runtime and has
4702 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4704 * Returns: true if @thread was not created by the runtime.
4707 mono_thread_is_foreign (MonoThread *thread)
4709 MonoThreadInfo *info = thread->internal_thread->thread_info;
4710 return info->runtime_thread == FALSE;
4714 * mono_add_joinable_thread:
4716 * Add TID to the list of joinable threads.
4717 * LOCKING: Acquires the threads lock.
4720 mono_threads_add_joinable_thread (gpointer tid)
4724 * We cannot detach from threads because it causes problems like
4725 * 2fd16f60/r114307. So we collect them and join them when
4726 * we have time (in he finalizer thread).
4728 joinable_threads_lock ();
4729 if (!joinable_threads)
4730 joinable_threads = g_hash_table_new (NULL, NULL);
4731 g_hash_table_insert (joinable_threads, tid, tid);
4732 joinable_thread_count ++;
4733 joinable_threads_unlock ();
4735 mono_gc_finalize_notify ();
4740 * mono_threads_join_threads:
4742 * Join all joinable threads. This is called from the finalizer thread.
4743 * LOCKING: Acquires the threads lock.
4746 mono_threads_join_threads (void)
4749 GHashTableIter iter;
4756 if (!joinable_thread_count)
4760 joinable_threads_lock ();
4762 if (g_hash_table_size (joinable_threads)) {
4763 g_hash_table_iter_init (&iter, joinable_threads);
4764 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4765 thread = (pthread_t)tid;
4766 g_hash_table_remove (joinable_threads, key);
4767 joinable_thread_count --;
4770 joinable_threads_unlock ();
4772 if (thread != pthread_self ())
4773 /* This shouldn't block */
4774 pthread_join (thread, NULL);
4785 * Wait for thread TID to exit.
4786 * LOCKING: Acquires the threads lock.
4789 mono_thread_join (gpointer tid)
4793 gboolean found = FALSE;
4795 joinable_threads_lock ();
4796 if (!joinable_threads)
4797 joinable_threads = g_hash_table_new (NULL, NULL);
4798 if (g_hash_table_lookup (joinable_threads, tid)) {
4799 g_hash_table_remove (joinable_threads, tid);
4800 joinable_thread_count --;
4803 joinable_threads_unlock ();
4806 thread = (pthread_t)tid;
4807 pthread_join (thread, NULL);