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 /* start_func is set only for unmanaged start functions */
647 start_func (start_arg);
650 g_assert (start_delegate != NULL);
651 args [0] = start_arg;
652 /* we may want to handle the exception here. See comment below on unhandled exceptions */
653 mono_runtime_delegate_invoke (start_delegate, args, NULL);
656 /* If the thread calls ExitThread at all, this remaining code
657 * will not be executed, but the main thread will eventually
658 * call thread_cleanup() on this thread's behalf.
661 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
663 /* Do any cleanup needed for apartment state. This
664 * cannot be done in thread_cleanup since thread_cleanup could be
665 * called for a thread other than the current thread.
666 * mono_thread_cleanup_apartment_state cleans up apartment
667 * for the current thead */
668 mono_thread_cleanup_apartment_state ();
670 thread_cleanup (internal);
672 /* Remove the reference to the thread object in the TLS data,
673 * so the thread object can be finalized. This won't be
674 * reached if the thread threw an uncaught exception, so those
675 * thread handles will stay referenced :-( (This is due to
676 * missing support for scanning thread-specific data in the
677 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
680 SET_CURRENT_OBJECT (NULL);
685 static guint32 WINAPI start_wrapper(void *data)
689 /* Avoid scanning the frames above this frame during a GC */
690 mono_gc_set_stack_end ((void*)&dummy);
692 return start_wrapper_internal (data);
698 * Common thread creation code.
699 * LOCKING: Acquires the threads lock.
702 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
703 gboolean throw_on_failure)
705 HANDLE thread_handle;
706 MonoNativeThreadId tid;
707 guint32 create_flags;
709 mono_threads_lock ();
712 mono_threads_unlock ();
716 * The thread start argument may be an object reference, and there is
717 * no ref to keep it alive when the new thread is started but not yet
718 * registered with the collector. So we store it in a GC tracked hash
721 if (thread_start_args == NULL) {
722 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
723 thread_start_args = mono_g_hash_table_new (NULL, NULL);
725 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
726 if (threads_starting_up == NULL) {
727 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
728 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
730 mono_g_hash_table_insert (threads_starting_up, thread, thread);
731 mono_threads_unlock ();
733 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
734 if (!internal->start_notify) {
735 mono_threads_lock ();
736 mono_g_hash_table_remove (threads_starting_up, thread);
737 mono_threads_unlock ();
738 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
744 stack_size = default_stacksize_for_thread (internal);
746 /* Create suspended, so we can do some housekeeping before the thread
749 create_flags = CREATE_SUSPENDED;
750 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
751 stack_size, create_flags, &tid);
752 if (thread_handle == NULL) {
753 /* The thread couldn't be created, so throw an exception */
754 mono_threads_lock ();
755 mono_g_hash_table_remove (threads_starting_up, thread);
756 mono_threads_unlock ();
758 if (throw_on_failure)
759 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
761 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
764 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
766 internal->handle = thread_handle;
767 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
769 internal->threadpool_thread = threadpool_thread;
770 if (threadpool_thread)
771 mono_thread_set_state (internal, ThreadState_Background);
773 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
775 /* Only store the handle when the thread is about to be
776 * launched, to avoid the main thread deadlocking while trying
777 * to clean up a thread that will never be signalled.
779 if (!handle_store (thread, FALSE))
782 mono_thread_info_resume (tid);
784 if (internal->start_notify) {
786 * Wait for the thread to set up its TLS data etc, so
787 * theres no potential race condition if someone tries
788 * to look up the data believing the thread has
791 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
793 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
794 CloseHandle (internal->start_notify);
795 internal->start_notify = NULL;
798 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
803 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
805 if (mono_thread_start_cb) {
806 mono_thread_start_cb (tid, stack_start, func);
810 void mono_threads_set_default_stacksize (guint32 stacksize)
812 default_stacksize = stacksize;
815 guint32 mono_threads_get_default_stacksize (void)
817 return default_stacksize;
821 * mono_thread_create_internal:
825 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
828 MonoInternalThread *internal;
829 StartInfo *start_info;
832 thread = create_thread_object (domain);
833 internal = create_internal_thread ();
834 MONO_OBJECT_SETREF (thread, internal_thread, internal);
836 start_info = g_new0 (StartInfo, 1);
837 start_info->func = func;
838 start_info->obj = thread;
839 start_info->start_arg = arg;
841 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
845 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
846 if (mono_check_corlib_version () == NULL)
847 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
853 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
855 mono_thread_create_internal (domain, func, arg, FALSE, 0);
859 mono_thread_attach (MonoDomain *domain)
861 return mono_thread_attach_full (domain, FALSE);
865 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
867 MonoThreadInfo *info;
868 MonoInternalThread *thread;
869 MonoThread *current_thread;
870 HANDLE thread_handle;
873 if ((thread = mono_thread_internal_current ())) {
874 if (domain != mono_domain_get ())
875 mono_domain_set (domain, TRUE);
876 /* Already attached */
877 return mono_thread_current ();
880 if (!mono_gc_register_thread (&domain)) {
881 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 ());
884 thread = create_internal_thread ();
886 thread_handle = mono_thread_info_open_handle ();
887 g_assert (thread_handle);
889 tid=GetCurrentThreadId ();
891 thread->handle=thread_handle;
893 #ifdef PLATFORM_ANDROID
894 thread->android_tid = (gpointer) gettid ();
896 thread->stack_ptr = &tid;
898 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
900 info = mono_thread_info_current ();
902 thread->thread_info = info;
904 current_thread = new_thread_with_internal (domain, thread);
906 if (!handle_store (current_thread, force_attach)) {
907 /* Mono is shutting down, so just wait for the end */
912 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
914 SET_CURRENT_OBJECT (thread);
915 mono_domain_set (domain, TRUE);
917 mono_monitor_init_tls ();
919 thread_adjust_static_data (thread);
921 init_root_domain_thread (thread, current_thread);
922 if (domain != mono_get_root_domain ())
923 set_current_thread_for_domain (domain, thread, current_thread);
926 if (mono_thread_attach_cb) {
930 mono_thread_info_get_stack_bounds (&staddr, &stsize);
933 mono_thread_attach_cb (tid, &tid);
935 mono_thread_attach_cb (tid, staddr + stsize);
938 // FIXME: Need a separate callback
939 mono_profiler_thread_start (tid);
941 return current_thread;
945 mono_thread_detach (MonoThread *thread)
947 g_return_if_fail (thread != NULL);
949 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
951 thread_cleanup (thread->internal_thread);
953 SET_CURRENT_OBJECT (NULL);
954 mono_domain_unset ();
956 /* Don't need to CloseHandle this thread, even though we took a
957 * reference in mono_thread_attach (), because the GC will do it
958 * when the Thread object is finalised.
965 MonoInternalThread *thread = mono_thread_internal_current ();
967 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
969 thread_cleanup (thread);
970 SET_CURRENT_OBJECT (NULL);
971 mono_domain_unset ();
973 /* we could add a callback here for embedders to use. */
974 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
975 exit (mono_environment_exitcode_get ());
976 mono_thread_info_exit ();
980 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
982 MonoInternalThread *internal = create_internal_thread ();
984 internal->state = ThreadState_Unstarted;
986 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
990 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
993 StartInfo *start_info;
994 MonoInternalThread *internal;
997 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
999 if (!this->internal_thread)
1000 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1001 internal = this->internal_thread;
1003 LOCK_THREAD (internal);
1005 if ((internal->state & ThreadState_Unstarted) == 0) {
1006 UNLOCK_THREAD (internal);
1007 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1011 if ((internal->state & ThreadState_Aborted) != 0) {
1012 UNLOCK_THREAD (internal);
1015 /* This is freed in start_wrapper */
1016 start_info = g_new0 (StartInfo, 1);
1017 start_info->func = NULL;
1018 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1019 start_info->delegate = start;
1020 start_info->obj = this;
1021 g_assert (this->obj.vtable->domain == mono_domain_get ());
1023 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1025 UNLOCK_THREAD (internal);
1029 internal->state &= ~ThreadState_Unstarted;
1031 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1033 UNLOCK_THREAD (internal);
1034 return internal->handle;
1038 * This is called from the finalizer of the internal thread object.
1041 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1043 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1046 * Since threads keep a reference to their thread object while running, by the time this function is called,
1047 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1048 * when thread_cleanup () can be called after this.
1051 CloseHandle (thread);
1053 if (this->synch_cs) {
1054 CRITICAL_SECTION *synch_cs = this->synch_cs;
1055 this->synch_cs = NULL;
1056 DeleteCriticalSection (synch_cs);
1061 void *name = this->name;
1067 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1070 MonoInternalThread *thread = mono_thread_internal_current ();
1072 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1074 mono_thread_current_check_pending_interrupt ();
1077 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1079 res = SleepEx(ms,TRUE);
1081 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1083 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1084 MonoException* exc = mono_thread_execute_interruption (thread);
1086 mono_raise_exception (exc);
1098 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1103 ves_icall_System_Threading_Thread_GetDomainID (void)
1105 return mono_domain_get()->domain_id;
1109 ves_icall_System_Threading_Thread_Yield (void)
1111 return mono_thread_info_yield ();
1115 * mono_thread_get_name:
1117 * Return the name of the thread. NAME_LEN is set to the length of the name.
1118 * Return NULL if the thread has no name. The returned memory is owned by the
1122 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1126 LOCK_THREAD (this_obj);
1128 if (!this_obj->name) {
1132 *name_len = this_obj->name_len;
1133 res = g_new (gunichar2, this_obj->name_len);
1134 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1137 UNLOCK_THREAD (this_obj);
1143 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1147 LOCK_THREAD (this_obj);
1149 if (!this_obj->name)
1152 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1154 UNLOCK_THREAD (this_obj);
1160 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1162 LOCK_THREAD (this_obj);
1164 if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1165 UNLOCK_THREAD (this_obj);
1167 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1171 this_obj->name = g_new (gunichar2, mono_string_length (name));
1172 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1173 this_obj->name_len = mono_string_length (name);
1176 this_obj->name = NULL;
1179 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1181 UNLOCK_THREAD (this_obj);
1183 if (this_obj->name) {
1184 char *tname = mono_string_to_utf8 (name);
1185 mono_profiler_thread_name (this_obj->tid, tname);
1191 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1193 mono_thread_set_name_internal (this_obj, name, TRUE);
1196 /* If the array is already in the requested domain, we just return it,
1197 otherwise we return a copy in that domain. */
1199 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1206 if (mono_object_domain (arr) == domain)
1209 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1210 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1215 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1217 return byte_array_to_domain (arr, mono_get_root_domain ());
1221 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1223 return byte_array_to_domain (arr, mono_domain_get ());
1227 mono_thread_current (void)
1229 MonoDomain *domain = mono_domain_get ();
1230 MonoInternalThread *internal = mono_thread_internal_current ();
1231 MonoThread **current_thread_ptr;
1233 g_assert (internal);
1234 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1236 if (!*current_thread_ptr) {
1237 g_assert (domain != mono_get_root_domain ());
1238 *current_thread_ptr = new_thread_with_internal (domain, internal);
1240 return *current_thread_ptr;
1244 mono_thread_internal_current (void)
1246 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1247 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1251 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1252 int ms, HANDLE thread)
1254 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1257 mono_thread_current_check_pending_interrupt ();
1261 if ((this->state & ThreadState_Unstarted) != 0) {
1262 UNLOCK_THREAD (this);
1264 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1268 UNLOCK_THREAD (this);
1273 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1275 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1277 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1279 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1281 if(ret==WAIT_OBJECT_0) {
1282 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1287 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1293 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1301 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1304 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1306 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1308 if (ret != WAIT_IO_COMPLETION)
1311 exc = mono_thread_execute_interruption (thread);
1313 mono_raise_exception (exc);
1318 /* Re-calculate ms according to the time passed */
1319 diff_ms = (mono_100ns_ticks () - start) / 10000;
1320 if (diff_ms >= ms) {
1324 wait = ms - diff_ms;
1330 /* FIXME: exitContext isnt documented */
1331 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1337 MonoObject *waitHandle;
1338 MonoInternalThread *thread = mono_thread_internal_current ();
1340 /* Do this WaitSleepJoin check before creating objects */
1341 mono_thread_current_check_pending_interrupt ();
1343 numhandles = mono_array_length(mono_handles);
1344 handles = g_new0(HANDLE, numhandles);
1346 for(i = 0; i < numhandles; i++) {
1347 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1348 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1355 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1357 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1359 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1363 if(ret==WAIT_FAILED) {
1364 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1366 } else if(ret==WAIT_TIMEOUT) {
1367 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1374 /* FIXME: exitContext isnt documented */
1375 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1377 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1381 MonoObject *waitHandle;
1382 MonoInternalThread *thread = mono_thread_internal_current ();
1384 /* Do this WaitSleepJoin check before creating objects */
1385 mono_thread_current_check_pending_interrupt ();
1387 numhandles = mono_array_length(mono_handles);
1388 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1391 for(i = 0; i < numhandles; i++) {
1392 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1393 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1400 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1402 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1404 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1406 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1409 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1411 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1412 return ret - WAIT_OBJECT_0;
1414 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1415 return ret - WAIT_ABANDONED_0;
1422 /* FIXME: exitContext isnt documented */
1423 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1426 MonoInternalThread *thread = mono_thread_internal_current ();
1428 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1434 mono_thread_current_check_pending_interrupt ();
1436 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1438 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1440 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1442 if(ret==WAIT_FAILED) {
1443 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1445 } else if(ret==WAIT_TIMEOUT) {
1446 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1454 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1457 MonoInternalThread *thread = mono_thread_internal_current ();
1462 mono_thread_current_check_pending_interrupt ();
1464 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1466 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1468 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1470 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1473 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1480 mutex = CreateMutex (NULL, owned, NULL);
1482 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1484 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1492 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1493 return(ReleaseMutex (handle));
1496 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1502 *error = ERROR_SUCCESS;
1504 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1506 *error = GetLastError ();
1513 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1520 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1522 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1523 mono_string_chars (name));
1525 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1533 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1537 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1542 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1546 *error = ERROR_SUCCESS;
1548 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1550 *error = GetLastError ();
1556 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1563 event = CreateEvent (NULL, manual, initial, NULL);
1565 event = CreateEvent (NULL, manual, initial,
1566 mono_string_chars (name));
1568 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1576 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1577 return (SetEvent(handle));
1580 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1581 return (ResetEvent(handle));
1585 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1586 CloseHandle (handle);
1589 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1595 *error = ERROR_SUCCESS;
1597 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1599 *error = GetLastError ();
1605 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1607 return InterlockedIncrement (location);
1610 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1612 #if SIZEOF_VOID_P == 4
1613 if (G_UNLIKELY ((size_t)location & 0x7)) {
1615 mono_interlocked_lock ();
1618 mono_interlocked_unlock ();
1622 return InterlockedIncrement64 (location);
1625 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1627 return InterlockedDecrement(location);
1630 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1632 #if SIZEOF_VOID_P == 4
1633 if (G_UNLIKELY ((size_t)location & 0x7)) {
1635 mono_interlocked_lock ();
1638 mono_interlocked_unlock ();
1642 return InterlockedDecrement64 (location);
1645 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1647 return InterlockedExchange(location, value);
1650 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1653 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1654 mono_gc_wbarrier_generic_nostore (location);
1658 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1660 return InterlockedExchangePointer(location, value);
1663 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1665 IntFloatUnion val, ret;
1668 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1674 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1676 #if SIZEOF_VOID_P == 4
1677 if (G_UNLIKELY ((size_t)location & 0x7)) {
1679 mono_interlocked_lock ();
1682 mono_interlocked_unlock ();
1686 return InterlockedExchange64 (location, value);
1690 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1692 LongDoubleUnion val, ret;
1695 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1700 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1702 return InterlockedCompareExchange(location, value, comparand);
1705 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1708 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1709 mono_gc_wbarrier_generic_nostore (location);
1713 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1715 return InterlockedCompareExchangePointer(location, value, comparand);
1718 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1720 IntFloatUnion val, ret, cmp;
1723 cmp.fval = comparand;
1724 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1730 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1732 #if SIZEOF_VOID_P == 8
1733 LongDoubleUnion val, comp, ret;
1736 comp.fval = comparand;
1737 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1743 mono_interlocked_lock ();
1745 if (old == comparand)
1747 mono_interlocked_unlock ();
1754 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1756 #if SIZEOF_VOID_P == 4
1757 if (G_UNLIKELY ((size_t)location & 0x7)) {
1759 mono_interlocked_lock ();
1761 if (old == comparand)
1763 mono_interlocked_unlock ();
1767 return InterlockedCompareExchange64 (location, value, comparand);
1771 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1774 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1775 mono_gc_wbarrier_generic_nostore (location);
1780 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1783 res = InterlockedExchangePointer ((gpointer *)location, value);
1784 mono_gc_wbarrier_generic_nostore (location);
1789 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1791 return InterlockedAdd (location, value);
1795 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1797 #if SIZEOF_VOID_P == 4
1798 if (G_UNLIKELY ((size_t)location & 0x7)) {
1800 mono_interlocked_lock ();
1803 mono_interlocked_unlock ();
1807 return InterlockedAdd64 (location, value);
1811 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1813 #if SIZEOF_VOID_P == 4
1814 if (G_UNLIKELY ((size_t)location & 0x7)) {
1816 mono_interlocked_lock ();
1818 mono_interlocked_unlock ();
1822 return InterlockedRead64 (location);
1826 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1828 mono_memory_barrier ();
1832 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1834 mono_thread_clr_state (this, state);
1836 if (state & ThreadState_Background) {
1837 /* If the thread changes the background mode, the main thread has to
1838 * be notified, since it has to rebuild the list of threads to
1841 SetEvent (background_change_event);
1846 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1848 mono_thread_set_state (this, state);
1850 if (state & ThreadState_Background) {
1851 /* If the thread changes the background mode, the main thread has to
1852 * be notified, since it has to rebuild the list of threads to
1855 SetEvent (background_change_event);
1860 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1866 state = this->state;
1868 UNLOCK_THREAD (this);
1873 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
1875 MonoInternalThread *current;
1880 current = mono_thread_internal_current ();
1882 this->thread_interrupt_requested = TRUE;
1883 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
1885 UNLOCK_THREAD (this);
1888 abort_thread_internal (this, TRUE, FALSE);
1892 void mono_thread_current_check_pending_interrupt ()
1894 MonoInternalThread *thread = mono_thread_internal_current ();
1895 gboolean throw = FALSE;
1897 LOCK_THREAD (thread);
1899 if (thread->thread_interrupt_requested) {
1901 thread->thread_interrupt_requested = FALSE;
1904 UNLOCK_THREAD (thread);
1907 mono_raise_exception (mono_get_exception_thread_interrupted ());
1912 mono_thread_get_abort_signal (void)
1916 #elif defined(PLATFORM_ANDROID)
1918 #elif !defined (SIGRTMIN)
1923 #endif /* SIGUSR1 */
1925 static int abort_signum = -1;
1927 if (abort_signum != -1)
1928 return abort_signum;
1929 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
1930 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
1931 struct sigaction sinfo;
1932 sigaction (i, NULL, &sinfo);
1933 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
1938 /* fallback to the old way */
1940 #endif /* HOST_WIN32 */
1944 static void CALLBACK interruption_request_apc (ULONG_PTR param)
1946 MonoException* exc = mono_thread_request_interruption (FALSE);
1947 if (exc) mono_raise_exception (exc);
1949 #endif /* HOST_WIN32 */
1952 * signal_thread_state_change
1954 * Tells the thread that his state has changed and it has to enter the new
1955 * state as soon as possible.
1957 static void signal_thread_state_change (MonoInternalThread *thread)
1959 if (thread == mono_thread_internal_current ()) {
1960 /* Do it synchronously */
1961 MonoException *exc = mono_thread_request_interruption (FALSE);
1963 mono_raise_exception (exc);
1967 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
1969 /* fixme: store the state somewhere */
1970 mono_thread_kill (thread, mono_thread_get_abort_signal ());
1973 * This will cause waits to be broken.
1974 * It will also prevent the thread from entering a wait, so if the thread returns
1975 * from the wait before it receives the abort signal, it will just spin in the wait
1976 * functions in the io-layer until the signal handler calls QueueUserAPC which will
1979 wapi_interrupt_thread (thread->handle);
1980 #endif /* HOST_WIN32 */
1984 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
1986 LOCK_THREAD (thread);
1988 if ((thread->state & ThreadState_AbortRequested) != 0 ||
1989 (thread->state & ThreadState_StopRequested) != 0 ||
1990 (thread->state & ThreadState_Stopped) != 0)
1992 UNLOCK_THREAD (thread);
1996 if ((thread->state & ThreadState_Unstarted) != 0) {
1997 thread->state |= ThreadState_Aborted;
1998 UNLOCK_THREAD (thread);
2002 thread->state |= ThreadState_AbortRequested;
2003 if (thread->abort_state_handle)
2004 mono_gchandle_free (thread->abort_state_handle);
2006 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2007 g_assert (thread->abort_state_handle);
2009 thread->abort_state_handle = 0;
2011 thread->abort_exc = NULL;
2014 * abort_exc is set in mono_thread_execute_interruption(),
2015 * triggered by the call to signal_thread_state_change(),
2016 * below. There's a point between where we have
2017 * abort_state_handle set, but abort_exc NULL, but that's not
2021 UNLOCK_THREAD (thread);
2023 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2025 /* During shutdown, we can't wait for other threads */
2027 /* Make sure the thread is awake */
2028 mono_thread_resume (thread);
2030 abort_thread_internal (thread, TRUE, TRUE);
2034 ves_icall_System_Threading_Thread_ResetAbort (void)
2036 MonoInternalThread *thread = mono_thread_internal_current ();
2037 gboolean was_aborting;
2039 LOCK_THREAD (thread);
2040 was_aborting = thread->state & ThreadState_AbortRequested;
2041 thread->state &= ~ThreadState_AbortRequested;
2042 UNLOCK_THREAD (thread);
2044 if (!was_aborting) {
2045 const char *msg = "Unable to reset abort because no abort was requested";
2046 mono_raise_exception (mono_get_exception_thread_state (msg));
2048 thread->abort_exc = NULL;
2049 if (thread->abort_state_handle) {
2050 mono_gchandle_free (thread->abort_state_handle);
2051 /* This is actually not necessary - the handle
2052 only counts if the exception is set */
2053 thread->abort_state_handle = 0;
2058 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2060 LOCK_THREAD (thread);
2062 thread->state &= ~ThreadState_AbortRequested;
2064 if (thread->abort_exc) {
2065 thread->abort_exc = NULL;
2066 if (thread->abort_state_handle) {
2067 mono_gchandle_free (thread->abort_state_handle);
2068 /* This is actually not necessary - the handle
2069 only counts if the exception is set */
2070 thread->abort_state_handle = 0;
2074 UNLOCK_THREAD (thread);
2078 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2080 MonoInternalThread *thread = this->internal_thread;
2081 MonoObject *state, *deserialized = NULL, *exc;
2084 if (!thread->abort_state_handle)
2087 state = mono_gchandle_get_target (thread->abort_state_handle);
2090 domain = mono_domain_get ();
2091 if (mono_object_domain (state) == domain)
2094 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2096 if (!deserialized) {
2097 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2099 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2100 mono_raise_exception (invalid_op_exc);
2103 return deserialized;
2107 mono_thread_suspend (MonoInternalThread *thread)
2109 LOCK_THREAD (thread);
2111 if ((thread->state & ThreadState_Unstarted) != 0 ||
2112 (thread->state & ThreadState_Aborted) != 0 ||
2113 (thread->state & ThreadState_Stopped) != 0)
2115 UNLOCK_THREAD (thread);
2119 if ((thread->state & ThreadState_Suspended) != 0 ||
2120 (thread->state & ThreadState_SuspendRequested) != 0 ||
2121 (thread->state & ThreadState_StopRequested) != 0)
2123 UNLOCK_THREAD (thread);
2127 thread->state |= ThreadState_SuspendRequested;
2129 UNLOCK_THREAD (thread);
2131 suspend_thread_internal (thread, FALSE);
2136 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2138 if (!mono_thread_suspend (thread))
2139 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2143 mono_thread_resume (MonoInternalThread *thread)
2145 LOCK_THREAD (thread);
2147 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2148 thread->state &= ~ThreadState_SuspendRequested;
2149 UNLOCK_THREAD (thread);
2153 if ((thread->state & ThreadState_Suspended) == 0 ||
2154 (thread->state & ThreadState_Unstarted) != 0 ||
2155 (thread->state & ThreadState_Aborted) != 0 ||
2156 (thread->state & ThreadState_Stopped) != 0)
2158 UNLOCK_THREAD (thread);
2162 return resume_thread_internal (thread);
2166 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2168 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2169 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2173 mono_threads_is_critical_method (MonoMethod *method)
2175 switch (method->wrapper_type) {
2176 case MONO_WRAPPER_RUNTIME_INVOKE:
2177 case MONO_WRAPPER_XDOMAIN_INVOKE:
2178 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2185 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2190 if (mono_threads_is_critical_method (m)) {
2191 *((gboolean*)data) = TRUE;
2198 is_running_protected_wrapper (void)
2200 gboolean found = FALSE;
2201 mono_stack_walk (find_wrapper, &found);
2205 void mono_thread_internal_stop (MonoInternalThread *thread)
2207 LOCK_THREAD (thread);
2209 if ((thread->state & ThreadState_StopRequested) != 0 ||
2210 (thread->state & ThreadState_Stopped) != 0)
2212 UNLOCK_THREAD (thread);
2216 /* Make sure the thread is awake */
2217 mono_thread_resume (thread);
2219 thread->state |= ThreadState_StopRequested;
2220 thread->state &= ~ThreadState_AbortRequested;
2222 UNLOCK_THREAD (thread);
2224 abort_thread_internal (thread, TRUE, TRUE);
2227 void mono_thread_stop (MonoThread *thread)
2229 mono_thread_internal_stop (thread->internal_thread);
2233 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2236 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2241 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2244 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2249 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2252 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2257 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2260 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2265 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2268 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2269 return (void *) tmp;
2273 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2275 volatile MonoObject *tmp;
2276 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2277 return (MonoObject *) tmp;
2281 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2284 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2289 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2292 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2297 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2299 return InterlockedRead8 (ptr);
2303 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2305 return InterlockedRead16 (ptr);
2309 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2311 return InterlockedRead (ptr);
2315 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2317 #if SIZEOF_VOID_P == 4
2318 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2320 mono_interlocked_lock ();
2321 val = *(gint64*)ptr;
2322 mono_interlocked_unlock ();
2326 return InterlockedRead64 (ptr);
2330 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2332 return InterlockedReadPointer (ptr);
2336 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2340 #if SIZEOF_VOID_P == 4
2341 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2343 mono_interlocked_lock ();
2344 val = *(double*)ptr;
2345 mono_interlocked_unlock ();
2350 u.ival = InterlockedRead64 (ptr);
2356 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2360 u.ival = InterlockedRead (ptr);
2366 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2368 return InterlockedReadPointer (ptr);
2372 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2374 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2378 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2380 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2384 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2386 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2390 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2392 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2396 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2398 mono_atomic_store_release ((volatile void **) ptr, value);
2402 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2404 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2408 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2410 mono_atomic_store_release ((volatile double *) ptr, value);
2414 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2416 mono_atomic_store_release ((volatile float *) ptr, value);
2420 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2422 InterlockedWrite8 (ptr, value);
2426 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2428 InterlockedWrite16 (ptr, value);
2432 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2434 InterlockedWrite (ptr, value);
2438 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2440 #if SIZEOF_VOID_P == 4
2441 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2442 mono_interlocked_lock ();
2443 *(gint64*)ptr = value;
2444 mono_interlocked_unlock ();
2449 InterlockedWrite64 (ptr, value);
2453 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2455 InterlockedWritePointer (ptr, value);
2459 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2463 #if SIZEOF_VOID_P == 4
2464 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2465 mono_interlocked_lock ();
2466 *(double*)ptr = value;
2467 mono_interlocked_unlock ();
2474 InterlockedWrite64 (ptr, u.ival);
2478 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2484 InterlockedWrite (ptr, u.ival);
2488 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2490 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2494 mono_thread_init_tls (void)
2496 MONO_FAST_TLS_INIT (tls_current_object);
2497 mono_native_tls_alloc (¤t_object_key, NULL);
2500 void mono_thread_init (MonoThreadStartCB start_cb,
2501 MonoThreadAttachCB attach_cb)
2503 InitializeCriticalSection(&threads_mutex);
2504 InitializeCriticalSection(&interlocked_mutex);
2505 InitializeCriticalSection(&contexts_mutex);
2506 InitializeCriticalSection(&joinable_threads_mutex);
2508 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2509 g_assert(background_change_event != NULL);
2511 mono_init_static_data_info (&thread_static_info);
2512 mono_init_static_data_info (&context_static_info);
2514 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2516 mono_thread_start_cb = start_cb;
2517 mono_thread_attach_cb = attach_cb;
2519 /* Get a pseudo handle to the current process. This is just a
2520 * kludge so that wapi can build a process handle if needed.
2521 * As a pseudo handle is returned, we don't need to clean
2524 GetCurrentProcess ();
2527 void mono_thread_cleanup (void)
2529 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2530 MonoThreadInfo *info;
2532 /* The main thread must abandon any held mutexes (particularly
2533 * important for named mutexes as they are shared across
2534 * processes, see bug 74680.) This will happen when the
2535 * thread exits, but if it's not running in a subthread it
2536 * won't exit in time.
2538 info = mono_thread_info_current ();
2539 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2543 /* This stuff needs more testing, it seems one of these
2544 * critical sections can be locked when mono_thread_cleanup is
2547 DeleteCriticalSection (&threads_mutex);
2548 DeleteCriticalSection (&interlocked_mutex);
2549 DeleteCriticalSection (&contexts_mutex);
2550 DeleteCriticalSection (&delayed_free_table_mutex);
2551 DeleteCriticalSection (&small_id_mutex);
2552 CloseHandle (background_change_event);
2555 mono_native_tls_free (current_object_key);
2559 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2561 mono_thread_cleanup_fn = func;
2565 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2567 thread->internal_thread->manage_callback = func;
2570 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2572 mono_thread_notify_pending_exc_fn = func;
2576 static void print_tids (gpointer key, gpointer value, gpointer user)
2578 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2579 * sizeof(uint) and a cast to uint would overflow
2581 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2582 * print this as a pointer.
2584 g_message ("Waiting for: %p", key);
2589 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2590 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2594 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2598 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2600 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2602 if(ret==WAIT_FAILED) {
2603 /* See the comment in build_wait_tids() */
2604 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2608 for(i=0; i<wait->num; i++)
2609 CloseHandle (wait->handles[i]);
2611 if (ret == WAIT_TIMEOUT)
2614 for(i=0; i<wait->num; i++) {
2615 gsize tid = wait->threads[i]->tid;
2618 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2619 * it can still run io-layer etc. code. So wait for it to really exit.
2620 * FIXME: This won't join threads which are not in the joinable_hash yet.
2622 mono_thread_join ((gpointer)tid);
2624 mono_threads_lock ();
2625 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2626 /* This thread must have been killed, because
2627 * it hasn't cleaned itself up. (It's just
2628 * possible that the thread exited before the
2629 * parent thread had a chance to store the
2630 * handle, and now there is another pointer to
2631 * the already-exited thread stored. In this
2632 * case, we'll just get two
2633 * mono_profiler_thread_end() calls for the
2637 mono_threads_unlock ();
2638 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2639 thread_cleanup (wait->threads[i]);
2641 mono_threads_unlock ();
2646 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2648 guint32 i, ret, count;
2650 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2652 /* Add the thread state change event, so it wakes up if a thread changes
2653 * to background mode.
2656 if (count < MAXIMUM_WAIT_OBJECTS) {
2657 wait->handles [count] = background_change_event;
2661 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2663 if(ret==WAIT_FAILED) {
2664 /* See the comment in build_wait_tids() */
2665 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2669 for(i=0; i<wait->num; i++)
2670 CloseHandle (wait->handles[i]);
2672 if (ret == WAIT_TIMEOUT)
2675 if (ret < wait->num) {
2676 gsize tid = wait->threads[ret]->tid;
2677 mono_threads_lock ();
2678 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2679 /* See comment in wait_for_tids about thread cleanup */
2680 mono_threads_unlock ();
2681 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2682 thread_cleanup (wait->threads [ret]);
2684 mono_threads_unlock ();
2688 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2690 struct wait_data *wait=(struct wait_data *)user;
2692 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2694 MonoInternalThread *thread=(MonoInternalThread *)value;
2696 /* Ignore background threads, we abort them later */
2697 /* Do not lock here since it is not needed and the caller holds threads_lock */
2698 if (thread->state & ThreadState_Background) {
2699 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2700 return; /* just leave, ignore */
2703 if (mono_gc_is_finalizer_internal_thread (thread)) {
2704 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2708 if (thread == mono_thread_internal_current ()) {
2709 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2713 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2714 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2718 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2719 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2723 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2724 if (handle == NULL) {
2725 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2729 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2730 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2731 wait->handles[wait->num]=handle;
2732 wait->threads[wait->num]=thread;
2735 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2737 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2742 /* Just ignore the rest, we can't do anything with
2749 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2751 struct wait_data *wait=(struct wait_data *)user;
2752 gsize self = GetCurrentThreadId ();
2753 MonoInternalThread *thread = value;
2756 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2759 /* The finalizer thread is not a background thread */
2760 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2761 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2763 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2767 /* printf ("A: %d\n", wait->num); */
2768 wait->handles[wait->num]=thread->handle;
2769 wait->threads[wait->num]=thread;
2772 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2773 mono_thread_internal_stop (thread);
2777 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2781 * mono_threads_set_shutting_down:
2783 * Is called by a thread that wants to shut down Mono. If the runtime is already
2784 * shutting down, the calling thread is suspended/stopped, and this function never
2788 mono_threads_set_shutting_down (void)
2790 MonoInternalThread *current_thread = mono_thread_internal_current ();
2792 mono_threads_lock ();
2794 if (shutting_down) {
2795 mono_threads_unlock ();
2797 /* Make sure we're properly suspended/stopped */
2799 LOCK_THREAD (current_thread);
2801 if ((current_thread->state & ThreadState_SuspendRequested) ||
2802 (current_thread->state & ThreadState_AbortRequested) ||
2803 (current_thread->state & ThreadState_StopRequested)) {
2804 UNLOCK_THREAD (current_thread);
2805 mono_thread_execute_interruption (current_thread);
2807 current_thread->state |= ThreadState_Stopped;
2808 UNLOCK_THREAD (current_thread);
2811 /*since we're killing the thread, unset the current domain.*/
2812 mono_domain_unset ();
2814 /* Wake up other threads potentially waiting for us */
2815 mono_thread_info_exit ();
2817 shutting_down = TRUE;
2819 /* Not really a background state change, but this will
2820 * interrupt the main thread if it is waiting for all
2821 * the other threads.
2823 SetEvent (background_change_event);
2825 mono_threads_unlock ();
2829 void mono_thread_manage (void)
2831 struct wait_data wait_data;
2832 struct wait_data *wait = &wait_data;
2834 memset (wait, 0, sizeof (struct wait_data));
2835 /* join each thread that's still running */
2836 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2838 mono_threads_lock ();
2840 THREAD_DEBUG (g_message("%s: No threads", __func__));
2841 mono_threads_unlock ();
2844 mono_threads_unlock ();
2847 mono_threads_lock ();
2848 if (shutting_down) {
2849 /* somebody else is shutting down */
2850 mono_threads_unlock ();
2853 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2854 mono_g_hash_table_foreach (threads, print_tids, NULL));
2856 ResetEvent (background_change_event);
2858 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2859 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2860 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2861 mono_threads_unlock ();
2863 /* Something to wait for */
2864 wait_for_tids_or_state_change (wait, INFINITE);
2866 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2867 } while(wait->num>0);
2869 /* Mono is shutting down, so just wait for the end */
2870 if (!mono_runtime_try_shutdown ()) {
2871 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2872 mono_thread_suspend (mono_thread_internal_current ());
2873 mono_thread_execute_interruption (mono_thread_internal_current ());
2877 * Remove everything but the finalizer thread and self.
2878 * Also abort all the background threads
2881 mono_threads_lock ();
2884 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2885 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2886 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2888 mono_threads_unlock ();
2890 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2892 /* Something to wait for */
2893 wait_for_tids (wait, INFINITE);
2895 } while (wait->num > 0);
2898 * give the subthreads a chance to really quit (this is mainly needed
2899 * to get correct user and system times from getrusage/wait/time(1)).
2900 * This could be removed if we avoid pthread_detach() and use pthread_join().
2903 mono_thread_info_yield ();
2907 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2909 MonoInternalThread *thread=(MonoInternalThread *)value;
2911 if(thread->tid != (gsize)user) {
2912 /*TerminateThread (thread->handle, -1);*/
2916 void mono_thread_abort_all_other_threads (void)
2918 gsize self = GetCurrentThreadId ();
2920 mono_threads_lock ();
2921 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2922 mono_g_hash_table_size (threads));
2923 mono_g_hash_table_foreach (threads, print_tids, NULL));
2925 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2927 mono_threads_unlock ();
2931 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2933 MonoInternalThread *thread = (MonoInternalThread*)value;
2934 struct wait_data *wait = (struct wait_data*)user_data;
2938 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
2940 * This needs no locking.
2942 if ((thread->state & ThreadState_Suspended) != 0 ||
2943 (thread->state & ThreadState_Stopped) != 0)
2946 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2947 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2951 wait->handles [wait->num] = handle;
2952 wait->threads [wait->num] = thread;
2958 * mono_thread_suspend_all_other_threads:
2960 * Suspend all managed threads except the finalizer thread and this thread. It is
2961 * not possible to resume them later.
2963 void mono_thread_suspend_all_other_threads (void)
2965 struct wait_data wait_data;
2966 struct wait_data *wait = &wait_data;
2968 gsize self = GetCurrentThreadId ();
2970 guint32 eventidx = 0;
2971 gboolean starting, finished;
2973 memset (wait, 0, sizeof (struct wait_data));
2975 * The other threads could be in an arbitrary state at this point, i.e.
2976 * they could be starting up, shutting down etc. This means that there could be
2977 * threads which are not even in the threads hash table yet.
2981 * First we set a barrier which will be checked by all threads before they
2982 * are added to the threads hash table, and they will exit if the flag is set.
2983 * This ensures that no threads could be added to the hash later.
2984 * We will use shutting_down as the barrier for now.
2986 g_assert (shutting_down);
2989 * We make multiple calls to WaitForMultipleObjects since:
2990 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
2991 * - some threads could exit without becoming suspended
2996 * Make a copy of the hashtable since we can't do anything with
2997 * threads while threads_mutex is held.
3000 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3001 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3002 mono_threads_lock ();
3003 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3004 mono_threads_unlock ();
3006 events = g_new0 (gpointer, wait->num);
3008 /* Get the suspended events that we'll be waiting for */
3009 for (i = 0; i < wait->num; ++i) {
3010 MonoInternalThread *thread = wait->threads [i];
3011 gboolean signal_suspend = FALSE;
3013 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3014 //CloseHandle (wait->handles [i]);
3015 wait->threads [i] = NULL; /* ignore this thread in next loop */
3019 LOCK_THREAD (thread);
3021 if (thread->suspended_event == NULL) {
3022 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3023 if (thread->suspended_event == NULL) {
3024 /* Forget this one and go on to the next */
3025 UNLOCK_THREAD (thread);
3030 if ((thread->state & ThreadState_Suspended) != 0 ||
3031 (thread->state & ThreadState_StopRequested) != 0 ||
3032 (thread->state & ThreadState_Stopped) != 0) {
3033 UNLOCK_THREAD (thread);
3034 CloseHandle (wait->handles [i]);
3035 wait->threads [i] = NULL; /* ignore this thread in next loop */
3039 if ((thread->state & ThreadState_SuspendRequested) == 0)
3040 signal_suspend = TRUE;
3042 events [eventidx++] = thread->suspended_event;
3044 /* Convert abort requests into suspend requests */
3045 if ((thread->state & ThreadState_AbortRequested) != 0)
3046 thread->state &= ~ThreadState_AbortRequested;
3048 thread->state |= ThreadState_SuspendRequested;
3050 UNLOCK_THREAD (thread);
3052 /* Signal the thread to suspend */
3053 if (mono_thread_info_new_interrupt_enabled ())
3054 suspend_thread_internal (thread, TRUE);
3055 else if (signal_suspend)
3056 signal_thread_state_change (thread);
3059 /*Only wait on the suspend event if we are using the old path */
3060 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3061 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3062 for (i = 0; i < wait->num; ++i) {
3063 MonoInternalThread *thread = wait->threads [i];
3068 LOCK_THREAD (thread);
3069 if ((thread->state & ThreadState_Suspended) != 0) {
3070 CloseHandle (thread->suspended_event);
3071 thread->suspended_event = NULL;
3073 UNLOCK_THREAD (thread);
3077 if (eventidx <= 0) {
3079 * If there are threads which are starting up, we wait until they
3080 * are suspended when they try to register in the threads hash.
3081 * This is guaranteed to finish, since the threads which can create new
3082 * threads get suspended after a while.
3083 * FIXME: The finalizer thread can still create new threads.
3085 mono_threads_lock ();
3086 if (threads_starting_up)
3087 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3090 mono_threads_unlock ();
3102 collect_threads (gpointer key, gpointer value, gpointer user_data)
3104 MonoInternalThread *thread = (MonoInternalThread*)value;
3105 struct wait_data *wait = (struct wait_data*)user_data;
3108 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3109 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3113 wait->handles [wait->num] = handle;
3114 wait->threads [wait->num] = thread;
3119 static gboolean thread_dump_requested;
3121 static G_GNUC_UNUSED gboolean
3122 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3124 GString *p = (GString*)data;
3125 MonoMethod *method = NULL;
3127 method = mono_jit_info_get_method (frame->ji);
3130 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3131 g_string_append_printf (p, " %s\n", location);
3134 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3140 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3142 GString* text = g_string_new (0);
3144 GError *error = NULL;
3147 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3149 g_string_append_printf (text, "\n\"%s\"", name);
3152 else if (thread->threadpool_thread)
3153 g_string_append (text, "\n\"<threadpool thread>\"");
3155 g_string_append (text, "\n\"<unnamed thread>\"");
3158 /* This no longer works with remote unwinding */
3160 wapi_desc = wapi_current_thread_desc ();
3161 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3166 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3167 mono_thread_info_resume (mono_thread_info_get_tid (info));
3169 fprintf (stdout, "%s", text->str);
3171 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3172 OutputDebugStringA(text->str);
3175 g_string_free (text, TRUE);
3180 dump_thread (gpointer key, gpointer value, gpointer user)
3182 MonoInternalThread *thread = (MonoInternalThread *)value;
3183 MonoThreadInfo *info;
3185 if (thread == mono_thread_internal_current ())
3189 FIXME This still can hang if we stop a thread during malloc.
3190 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3191 that takes a callback and runs it with the target suspended.
3192 We probably should loop a bit around trying to get it to either managed code
3195 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3200 print_thread_dump (thread, info);
3204 mono_threads_perform_thread_dump (void)
3206 if (!thread_dump_requested)
3209 printf ("Full thread dump:\n");
3212 * Make a copy of the hashtable since we can't do anything with
3213 * threads while threads_mutex is held.
3215 mono_threads_lock ();
3216 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3217 mono_threads_unlock ();
3219 thread_dump_requested = FALSE;
3223 * mono_threads_request_thread_dump:
3225 * Ask all threads except the current to print their stacktrace to stdout.
3228 mono_threads_request_thread_dump (void)
3230 struct wait_data wait_data;
3231 struct wait_data *wait = &wait_data;
3234 /*The new thread dump code runs out of the finalizer thread. */
3235 if (mono_thread_info_new_interrupt_enabled ()) {
3236 thread_dump_requested = TRUE;
3237 mono_gc_finalize_notify ();
3242 memset (wait, 0, sizeof (struct wait_data));
3245 * Make a copy of the hashtable since we can't do anything with
3246 * threads while threads_mutex is held.
3248 mono_threads_lock ();
3249 mono_g_hash_table_foreach (threads, collect_threads, wait);
3250 mono_threads_unlock ();
3252 for (i = 0; i < wait->num; ++i) {
3253 MonoInternalThread *thread = wait->threads [i];
3255 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3256 (thread != mono_thread_internal_current ()) &&
3257 !thread->thread_dump_requested) {
3258 thread->thread_dump_requested = TRUE;
3260 signal_thread_state_change (thread);
3263 CloseHandle (wait->handles [i]);
3269 gint allocated; /* +1 so that refs [allocated] == NULL */
3273 typedef struct ref_stack RefStack;
3276 ref_stack_new (gint initial_size)
3280 initial_size = MAX (initial_size, 16) + 1;
3281 rs = g_new0 (RefStack, 1);
3282 rs->refs = g_new0 (gpointer, initial_size);
3283 rs->allocated = initial_size;
3288 ref_stack_destroy (gpointer ptr)
3299 ref_stack_push (RefStack *rs, gpointer ptr)
3301 g_assert (rs != NULL);
3303 if (rs->bottom >= rs->allocated) {
3304 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3305 rs->allocated <<= 1;
3306 rs->refs [rs->allocated] = NULL;
3308 rs->refs [rs->bottom++] = ptr;
3312 ref_stack_pop (RefStack *rs)
3314 if (rs == NULL || rs->bottom == 0)
3318 rs->refs [rs->bottom] = NULL;
3322 ref_stack_find (RefStack *rs, gpointer ptr)
3329 for (refs = rs->refs; refs && *refs; refs++) {
3337 * mono_thread_push_appdomain_ref:
3339 * Register that the current thread may have references to objects in domain
3340 * @domain on its stack. Each call to this function should be paired with a
3341 * call to pop_appdomain_ref.
3344 mono_thread_push_appdomain_ref (MonoDomain *domain)
3346 MonoInternalThread *thread = mono_thread_internal_current ();
3349 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3350 SPIN_LOCK (thread->lock_thread_id);
3351 if (thread->appdomain_refs == NULL)
3352 thread->appdomain_refs = ref_stack_new (16);
3353 ref_stack_push (thread->appdomain_refs, domain);
3354 SPIN_UNLOCK (thread->lock_thread_id);
3359 mono_thread_pop_appdomain_ref (void)
3361 MonoInternalThread *thread = mono_thread_internal_current ();
3364 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3365 SPIN_LOCK (thread->lock_thread_id);
3366 ref_stack_pop (thread->appdomain_refs);
3367 SPIN_UNLOCK (thread->lock_thread_id);
3372 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3375 SPIN_LOCK (thread->lock_thread_id);
3376 res = ref_stack_find (thread->appdomain_refs, domain);
3377 SPIN_UNLOCK (thread->lock_thread_id);
3382 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3384 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3387 typedef struct abort_appdomain_data {
3388 struct wait_data wait;
3390 } abort_appdomain_data;
3393 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3395 MonoInternalThread *thread = (MonoInternalThread*)value;
3396 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3397 MonoDomain *domain = data->domain;
3399 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3400 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3402 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3403 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3406 data->wait.handles [data->wait.num] = handle;
3407 data->wait.threads [data->wait.num] = thread;
3410 /* Just ignore the rest, we can't do anything with
3418 * mono_threads_abort_appdomain_threads:
3420 * Abort threads which has references to the given appdomain.
3423 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3425 #ifdef __native_client__
3429 abort_appdomain_data user_data;
3431 int orig_timeout = timeout;
3434 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3436 start_time = mono_msec_ticks ();
3438 mono_threads_lock ();
3440 user_data.domain = domain;
3441 user_data.wait.num = 0;
3442 /* This shouldn't take any locks */
3443 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3444 mono_threads_unlock ();
3446 if (user_data.wait.num > 0) {
3447 /* Abort the threads outside the threads lock */
3448 for (i = 0; i < user_data.wait.num; ++i)
3449 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3452 * We should wait for the threads either to abort, or to leave the
3453 * domain. We can't do the latter, so we wait with a timeout.
3455 wait_for_tids (&user_data.wait, 100);
3458 /* Update remaining time */
3459 timeout -= mono_msec_ticks () - start_time;
3460 start_time = mono_msec_ticks ();
3462 if (orig_timeout != -1 && timeout < 0)
3465 while (user_data.wait.num > 0);
3467 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3473 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3475 MonoInternalThread *thread = (MonoInternalThread*)value;
3476 MonoDomain *domain = (MonoDomain*)user_data;
3479 /* No locking needed here */
3480 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3482 if (thread->cached_culture_info) {
3483 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3484 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3485 if (obj && obj->vtable->domain == domain)
3486 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3492 * mono_threads_clear_cached_culture:
3494 * Clear the cached_current_culture from all threads if it is in the
3498 mono_threads_clear_cached_culture (MonoDomain *domain)
3500 mono_threads_lock ();
3501 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3502 mono_threads_unlock ();
3506 * mono_thread_get_undeniable_exception:
3508 * Return an exception which needs to be raised when leaving a catch clause.
3509 * This is used for undeniable exception propagation.
3512 mono_thread_get_undeniable_exception (void)
3514 MonoInternalThread *thread = mono_thread_internal_current ();
3516 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3518 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3519 * exception if the thread no longer references a dying appdomain.
3521 thread->abort_exc->trace_ips = NULL;
3522 thread->abort_exc->stack_trace = NULL;
3523 return thread->abort_exc;
3529 #if MONO_SMALL_CONFIG
3530 #define NUM_STATIC_DATA_IDX 4
3531 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3535 #define NUM_STATIC_DATA_IDX 8
3536 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3537 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3541 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3544 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
3547 gpointer *static_data = addr;
3548 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3551 if (!static_data [i])
3553 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3554 ptr = static_data [i];
3555 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3556 uintptr_t bmap = static_reference_bitmaps [i][j];
3559 if ((bmap & 1) && *p) {
3570 * mono_alloc_static_data
3572 * Allocate memory blocks for storing threads or context static data
3575 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3577 guint idx = (offset >> 24) - 1;
3580 gpointer* static_data = *static_data_ptr;
3582 static void* tls_desc = NULL;
3583 if (mono_gc_user_markers_supported () && !tls_desc)
3584 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3585 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3586 *static_data_ptr = static_data;
3587 static_data [0] = static_data;
3590 for (i = 1; i <= idx; ++i) {
3591 if (static_data [i])
3593 if (mono_gc_user_markers_supported () && threadlocal)
3594 static_data [i] = g_malloc0 (static_data_size [i]);
3596 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3601 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3604 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3605 gpointer p = static_data [i];
3609 * At this point, the static data pointer array is still registered with the
3610 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3611 * data. Freeing the individual arrays without first nulling their slots
3612 * would make it possible for mark_tls_slots() to encounter a pointer to
3613 * such an already freed array. See bug #13813.
3615 static_data [i] = NULL;
3616 mono_memory_write_barrier ();
3617 if (mono_gc_user_markers_supported () && threadlocal)
3620 mono_gc_free_fixed (p);
3622 mono_gc_free_fixed (static_data);
3626 * mono_init_static_data_info
3628 * Initializes static data counters
3630 static void mono_init_static_data_info (StaticDataInfo *static_data)
3632 static_data->idx = 0;
3633 static_data->offset = 0;
3634 static_data->freelist = NULL;
3638 * mono_alloc_static_data_slot
3640 * Generates an offset for static data. static_data contains the counters
3641 * used to generate it.
3644 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3648 if (!static_data->idx && !static_data->offset) {
3650 * we use the first chunk of the first allocation also as
3651 * an array for the rest of the data
3653 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3655 static_data->offset += align - 1;
3656 static_data->offset &= ~(align - 1);
3657 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3658 static_data->idx ++;
3659 g_assert (size <= static_data_size [static_data->idx]);
3660 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3661 static_data->offset = 0;
3663 offset = static_data->offset | ((static_data->idx + 1) << 24);
3664 static_data->offset += size;
3669 * ensure thread static fields already allocated are valid for thread
3670 * This function is called when a thread is created or on thread attach.
3673 thread_adjust_static_data (MonoInternalThread *thread)
3677 mono_threads_lock ();
3678 if (thread_static_info.offset || thread_static_info.idx > 0) {
3679 /* get the current allocated size */
3680 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3681 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3683 mono_threads_unlock ();
3687 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3689 MonoInternalThread *thread = value;
3690 guint32 offset = GPOINTER_TO_UINT (user);
3692 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3695 static MonoThreadDomainTls*
3696 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3698 MonoThreadDomainTls* prev = NULL;
3699 MonoThreadDomainTls* tmp = static_data->freelist;
3701 if (tmp->size == size) {
3703 prev->next = tmp->next;
3705 static_data->freelist = tmp->next;
3715 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3718 int idx = (offset >> 24) - 1;
3720 if (!static_reference_bitmaps [idx])
3721 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3722 rb = static_reference_bitmaps [idx];
3724 offset /= sizeof (gpointer);
3725 /* offset is now the bitmap offset */
3726 for (i = 0; i < numbits; ++i) {
3727 if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
3728 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3733 clear_reference_bitmap (guint32 offset, guint32 size)
3735 int idx = (offset >> 24) - 1;
3737 rb = static_reference_bitmaps [idx];
3739 offset /= sizeof (gpointer);
3740 size /= sizeof (gpointer);
3742 /* offset is now the bitmap offset */
3743 for (; offset < size; ++offset)
3744 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3748 * The offset for a special static variable is composed of three parts:
3749 * a bit that indicates the type of static data (0:thread, 1:context),
3750 * an index in the array of chunks of memory for the thread (thread->static_data)
3751 * and an offset in that chunk of mem. This allows allocating less memory in the
3756 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3759 if (static_type == SPECIAL_STATIC_THREAD) {
3760 MonoThreadDomainTls *item;
3761 mono_threads_lock ();
3762 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3763 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3765 offset = item->offset;
3768 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3770 update_tls_reference_bitmap (offset, bitmap, numbits);
3771 /* This can be called during startup */
3772 if (threads != NULL)
3773 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3774 mono_threads_unlock ();
3776 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3777 mono_contexts_lock ();
3778 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3779 mono_contexts_unlock ();
3780 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3786 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3788 /* The high bit means either thread (0) or static (1) data. */
3790 guint32 static_type = (offset & 0x80000000);
3793 offset &= 0x7fffffff;
3794 idx = (offset >> 24) - 1;
3796 if (static_type == 0) {
3797 return get_thread_static_data (thread, offset);
3799 /* Allocate static data block under demand, since we don't have a list
3802 MonoAppContext *context = mono_context_get ();
3803 if (!context->static_data || !context->static_data [idx]) {
3804 mono_contexts_lock ();
3805 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3806 mono_contexts_unlock ();
3808 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3813 mono_get_special_static_data (guint32 offset)
3815 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3824 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3826 MonoInternalThread *thread = value;
3827 TlsOffsetSize *data = user;
3828 int idx = (data->offset >> 24) - 1;
3831 if (!thread->static_data || !thread->static_data [idx])
3833 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3834 mono_gc_bzero_atomic (ptr, data->size);
3838 do_free_special_slot (guint32 offset, guint32 size)
3840 guint32 static_type = (offset & 0x80000000);
3841 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3842 if (static_type == 0) {
3844 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3845 data.offset = offset & 0x7fffffff;
3847 clear_reference_bitmap (data.offset, data.size);
3848 if (threads != NULL)
3849 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3850 item->offset = offset;
3853 if (!mono_runtime_is_shutting_down ()) {
3854 item->next = thread_static_info.freelist;
3855 thread_static_info.freelist = item;
3857 /* We could be called during shutdown after mono_thread_cleanup () is called */
3861 /* FIXME: free context static data as well */
3866 do_free_special (gpointer key, gpointer value, gpointer data)
3868 MonoClassField *field = key;
3869 guint32 offset = GPOINTER_TO_UINT (value);
3872 size = mono_type_size (field->type, &align);
3873 do_free_special_slot (offset, size);
3877 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3879 mono_threads_lock ();
3880 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3881 mono_threads_unlock ();
3885 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3887 mono_threads_lock ();
3888 do_free_special_slot (offset, size);
3889 mono_threads_unlock ();
3893 * allocates room in the thread local area for storing an instance of the struct type
3894 * the allocation is kept track of in domain->tlsrec_list.
3897 mono_thread_alloc_tls (MonoReflectionType *type)
3899 MonoDomain *domain = mono_domain_get ();
3901 MonoTlsDataRecord *tlsrec;
3904 gsize default_bitmap [4] = {0};
3905 uint32_t tls_offset;
3909 klass = mono_class_from_mono_type (type->type);
3910 /* TlsDatum is a struct, so we subtract the object header size offset */
3911 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3912 size = mono_type_size (type->type, &align);
3913 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3914 if (bitmap != default_bitmap)
3916 tlsrec = g_new0 (MonoTlsDataRecord, 1);
3917 tlsrec->tls_offset = tls_offset;
3918 tlsrec->size = size;
3919 mono_domain_lock (domain);
3920 tlsrec->next = domain->tlsrec_list;
3921 domain->tlsrec_list = tlsrec;
3922 mono_domain_unlock (domain);
3927 mono_thread_destroy_tls (uint32_t tls_offset)
3929 MonoTlsDataRecord *prev = NULL;
3930 MonoTlsDataRecord *cur;
3932 MonoDomain *domain = mono_domain_get ();
3933 mono_domain_lock (domain);
3934 cur = domain->tlsrec_list;
3936 if (cur->tls_offset == tls_offset) {
3938 prev->next = cur->next;
3940 domain->tlsrec_list = cur->next;
3948 mono_domain_unlock (domain);
3950 mono_special_static_data_free_slot (tls_offset, size);
3954 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
3957 mono_thread_destroy_domain_tls (MonoDomain *domain)
3959 while (domain->tlsrec_list)
3960 mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
3963 static MonoClassField *local_slots = NULL;
3966 /* local tls data to get locals_slot from a thread */
3969 /* index in the locals_slot array */
3974 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
3976 LocalSlotID *sid = user_data;
3977 MonoInternalThread *thread = (MonoInternalThread*)value;
3978 MonoArray *slots_array;
3980 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
3981 * it is for the right domain, so we need to check if it is allocated an initialized
3982 * for the current thread.
3984 /*g_print ("handling thread %p\n", thread);*/
3985 if (!thread->static_data || !thread->static_data [sid->idx])
3987 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
3988 if (!slots_array || sid->slot >= mono_array_length (slots_array))
3990 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
3994 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4002 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4004 g_warning ("local_slots field not found in Thread class");
4008 domain = mono_domain_get ();
4009 mono_domain_lock (domain);
4010 if (domain->special_static_fields)
4011 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4012 mono_domain_unlock (domain);
4015 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4016 sid.offset = GPOINTER_TO_UINT (addr);
4017 sid.offset &= 0x7fffffff;
4018 sid.idx = (sid.offset >> 24) - 1;
4019 mono_threads_lock ();
4020 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4021 mono_threads_unlock ();
4023 /* FIXME: clear the slot for MonoAppContexts, too */
4028 static void CALLBACK dummy_apc (ULONG_PTR param)
4034 * mono_thread_execute_interruption
4036 * Performs the operation that the requested thread state requires (abort,
4039 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4041 LOCK_THREAD (thread);
4043 /* MonoThread::interruption_requested can only be changed with atomics */
4044 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4045 /* this will consume pending APC calls */
4047 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4049 InterlockedDecrement (&thread_interruption_requested);
4051 /* Clear the interrupted flag of the thread so it can wait again */
4052 wapi_clear_interruption ();
4056 if ((thread->state & ThreadState_AbortRequested) != 0) {
4057 UNLOCK_THREAD (thread);
4058 if (thread->abort_exc == NULL) {
4060 * This might be racy, but it has to be called outside the lock
4061 * since it calls managed code.
4063 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4065 return thread->abort_exc;
4067 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4068 self_suspend_internal (thread);
4071 else if ((thread->state & ThreadState_StopRequested) != 0) {
4072 /* FIXME: do this through the JIT? */
4074 UNLOCK_THREAD (thread);
4076 mono_thread_exit ();
4078 } else if (thread->pending_exception) {
4081 exc = thread->pending_exception;
4082 thread->pending_exception = NULL;
4084 UNLOCK_THREAD (thread);
4086 } else if (thread->thread_interrupt_requested) {
4088 thread->thread_interrupt_requested = FALSE;
4089 UNLOCK_THREAD (thread);
4091 return(mono_get_exception_thread_interrupted ());
4094 UNLOCK_THREAD (thread);
4100 * mono_thread_request_interruption
4102 * A signal handler can call this method to request the interruption of a
4103 * thread. The result of the interruption will depend on the current state of
4104 * the thread. If the result is an exception that needs to be throw, it is
4105 * provided as return value.
4108 mono_thread_request_interruption (gboolean running_managed)
4110 MonoInternalThread *thread = mono_thread_internal_current ();
4112 /* The thread may already be stopping */
4117 if (thread->interrupt_on_stop &&
4118 thread->state & ThreadState_StopRequested &&
4119 thread->state & ThreadState_Background)
4123 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4125 InterlockedIncrement (&thread_interruption_requested);
4127 if (!running_managed || is_running_protected_wrapper ()) {
4128 /* Can't stop while in unmanaged code. Increase the global interruption
4129 request count. When exiting the unmanaged method the count will be
4130 checked and the thread will be interrupted. */
4132 if (mono_thread_notify_pending_exc_fn && !running_managed)
4133 /* The JIT will notify the thread about the interruption */
4134 /* This shouldn't take any locks */
4135 mono_thread_notify_pending_exc_fn ();
4137 /* this will awake the thread if it is in WaitForSingleObject
4139 /* Our implementation of this function ignores the func argument */
4141 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
4146 return mono_thread_execute_interruption (thread);
4150 /*This function should be called by a thread after it has exited all of
4151 * its handle blocks at interruption time.*/
4153 mono_thread_resume_interruption (void)
4155 MonoInternalThread *thread = mono_thread_internal_current ();
4156 gboolean still_aborting;
4158 /* The thread may already be stopping */
4162 LOCK_THREAD (thread);
4163 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4164 UNLOCK_THREAD (thread);
4166 /*This can happen if the protected block called Thread::ResetAbort*/
4167 if (!still_aborting)
4170 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4172 InterlockedIncrement (&thread_interruption_requested);
4175 wapi_self_interrupt ();
4177 return mono_thread_execute_interruption (thread);
4180 gboolean mono_thread_interruption_requested ()
4182 if (thread_interruption_requested) {
4183 MonoInternalThread *thread = mono_thread_internal_current ();
4184 /* The thread may already be stopping */
4186 return (thread->interruption_requested);
4191 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4193 MonoInternalThread *thread = mono_thread_internal_current ();
4195 /* The thread may already be stopping */
4199 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4200 MonoException* exc = mono_thread_execute_interruption (thread);
4201 if (exc) mono_raise_exception (exc);
4206 * Performs the interruption of the current thread, if one has been requested,
4207 * and the thread is not running a protected wrapper.
4209 void mono_thread_interruption_checkpoint ()
4211 mono_thread_interruption_checkpoint_request (FALSE);
4215 * Performs the interruption of the current thread, if one has been requested.
4217 void mono_thread_force_interruption_checkpoint ()
4219 mono_thread_interruption_checkpoint_request (TRUE);
4223 * mono_thread_get_and_clear_pending_exception:
4225 * Return any pending exceptions for the current thread and clear it as a side effect.
4228 mono_thread_get_and_clear_pending_exception (void)
4230 MonoInternalThread *thread = mono_thread_internal_current ();
4232 /* The thread may already be stopping */
4236 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4237 return mono_thread_execute_interruption (thread);
4240 if (thread->pending_exception) {
4241 MonoException *exc = thread->pending_exception;
4243 thread->pending_exception = NULL;
4251 * mono_set_pending_exception:
4253 * Set the pending exception of the current thread to EXC.
4254 * The exception will be thrown when execution returns to managed code.
4257 mono_set_pending_exception (MonoException *exc)
4259 MonoInternalThread *thread = mono_thread_internal_current ();
4261 /* The thread may already be stopping */
4265 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4267 mono_thread_request_interruption (FALSE);
4271 * mono_thread_interruption_request_flag:
4273 * Returns the address of a flag that will be non-zero if an interruption has
4274 * been requested for a thread. The thread to interrupt may not be the current
4275 * thread, so an additional call to mono_thread_interruption_requested() or
4276 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4279 gint32* mono_thread_interruption_request_flag ()
4281 return &thread_interruption_requested;
4285 mono_thread_init_apartment_state (void)
4288 MonoInternalThread* thread = mono_thread_internal_current ();
4290 /* Positive return value indicates success, either
4291 * S_OK if this is first CoInitialize call, or
4292 * S_FALSE if CoInitialize already called, but with same
4293 * threading model. A negative value indicates failure,
4294 * probably due to trying to change the threading model.
4296 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4297 ? COINIT_APARTMENTTHREADED
4298 : COINIT_MULTITHREADED) < 0) {
4299 thread->apartment_state = ThreadApartmentState_Unknown;
4305 mono_thread_cleanup_apartment_state (void)
4308 MonoInternalThread* thread = mono_thread_internal_current ();
4310 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4317 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4319 LOCK_THREAD (thread);
4320 thread->state |= state;
4321 UNLOCK_THREAD (thread);
4325 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4327 LOCK_THREAD (thread);
4328 thread->state &= ~state;
4329 UNLOCK_THREAD (thread);
4333 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4335 gboolean ret = FALSE;
4337 LOCK_THREAD (thread);
4339 if ((thread->state & test) != 0) {
4343 UNLOCK_THREAD (thread);
4348 //static MonoClassField *execution_context_field;
4351 get_execution_context_addr (void)
4353 MonoDomain *domain = mono_domain_get ();
4354 guint32 offset = domain->execution_context_field_offset;
4357 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4360 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4362 mono_domain_lock (domain);
4363 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4364 mono_domain_unlock (domain);
4367 domain->execution_context_field_offset = offset;
4370 return (MonoObject**) mono_get_special_static_data (offset);
4374 mono_thread_get_execution_context (void)
4376 return *get_execution_context_addr ();
4380 mono_thread_set_execution_context (MonoObject *ec)
4382 *get_execution_context_addr () = ec;
4385 static gboolean has_tls_get = FALSE;
4388 mono_runtime_set_has_tls_get (gboolean val)
4394 mono_runtime_has_tls_get (void)
4400 mono_thread_kill (MonoInternalThread *thread, int signal)
4402 #ifdef __native_client__
4403 /* Workaround pthread_kill abort() in NaCl glibc. */
4407 /* Win32 uses QueueUserAPC and callers of this are guarded */
4408 g_assert_not_reached ();
4410 # ifdef PTHREAD_POINTER_ID
4411 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4413 # ifdef PLATFORM_ANDROID
4414 if (thread->android_tid != 0) {
4416 int old_errno = errno;
4418 ret = tkill ((pid_t) thread->android_tid, signal);
4427 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4429 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4436 self_interrupt_thread (void *_unused)
4438 MonoThreadInfo *info = mono_thread_info_current ();
4439 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4440 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4441 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4442 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4446 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4450 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4454 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4456 MonoJitInfo **dest = data;
4462 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4464 MonoJitInfo *ji = NULL;
4467 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4472 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4475 MonoThreadInfo *info = NULL;
4476 gboolean protected_wrapper;
4477 gboolean running_managed;
4479 if (!mono_thread_info_new_interrupt_enabled ()) {
4480 signal_thread_state_change (thread);
4485 FIXME this is insanely broken, it doesn't cause interruption to happen
4486 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4488 if (thread == mono_thread_internal_current ()) {
4489 /* Do it synchronously */
4490 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4492 mono_raise_exception (exc);
4494 wapi_interrupt_thread (thread->handle);
4499 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4500 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4504 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4505 mono_thread_info_resume (mono_thread_info_get_tid (info));
4509 /*someone is already interrupting it*/
4510 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4511 mono_thread_info_resume (mono_thread_info_get_tid (info));
4514 InterlockedIncrement (&thread_interruption_requested);
4516 ji = mono_thread_info_get_last_managed (info);
4517 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4518 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4520 if (!protected_wrapper && running_managed) {
4521 /*We are in managed code*/
4522 /*Set the thread to call */
4523 if (install_async_abort)
4524 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4525 mono_thread_info_resume (mono_thread_info_get_tid (info));
4527 gpointer interrupt_handle;
4529 * This will cause waits to be broken.
4530 * It will also prevent the thread from entering a wait, so if the thread returns
4531 * from the wait before it receives the abort signal, it will just spin in the wait
4532 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4536 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4538 mono_thread_info_resume (mono_thread_info_get_tid (info));
4540 wapi_finish_interrupt_thread (interrupt_handle);
4543 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4547 transition_to_suspended (MonoInternalThread *thread)
4549 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4550 g_assert (0); /*FIXME we should not reach this */
4551 /*Make sure we balance the suspend count.*/
4552 mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
4554 thread->state &= ~ThreadState_SuspendRequested;
4555 thread->state |= ThreadState_Suspended;
4556 mono_thread_info_finish_suspend ();
4558 UNLOCK_THREAD (thread);
4562 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4564 if (!mono_thread_info_new_interrupt_enabled ()) {
4565 signal_thread_state_change (thread);
4569 LOCK_THREAD (thread);
4570 if (thread == mono_thread_internal_current ()) {
4571 transition_to_suspended (thread);
4572 mono_thread_info_self_suspend ();
4574 MonoThreadInfo *info;
4576 gboolean protected_wrapper;
4577 gboolean running_managed;
4579 /*A null info usually means the thread is already dead. */
4580 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
4581 UNLOCK_THREAD (thread);
4585 ji = mono_thread_info_get_last_managed (info);
4586 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4587 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4589 if (running_managed && !protected_wrapper) {
4590 transition_to_suspended (thread);
4592 gpointer interrupt_handle;
4594 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4595 InterlockedIncrement (&thread_interruption_requested);
4598 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4600 mono_thread_info_resume (mono_thread_info_get_tid (info));
4603 wapi_finish_interrupt_thread (interrupt_handle);
4605 UNLOCK_THREAD (thread);
4610 /*This is called with @thread synch_cs held and it must release it*/
4612 self_suspend_internal (MonoInternalThread *thread)
4614 if (!mono_thread_info_new_interrupt_enabled ()) {
4615 thread->state &= ~ThreadState_SuspendRequested;
4616 thread->state |= ThreadState_Suspended;
4617 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4618 if (thread->suspend_event == NULL) {
4619 UNLOCK_THREAD (thread);
4622 if (thread->suspended_event)
4623 SetEvent (thread->suspended_event);
4625 UNLOCK_THREAD (thread);
4627 if (shutting_down) {
4628 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4633 WaitForSingleObject (thread->suspend_event, INFINITE);
4635 LOCK_THREAD (thread);
4637 CloseHandle (thread->suspend_event);
4638 thread->suspend_event = NULL;
4639 thread->state &= ~ThreadState_Suspended;
4641 /* The thread that requested the resume will have replaced this event
4642 * and will be waiting for it
4644 SetEvent (thread->resume_event);
4646 UNLOCK_THREAD (thread);
4650 transition_to_suspended (thread);
4651 mono_thread_info_self_suspend ();
4654 /*This is called with @thread synch_cs held and it must release it*/
4656 resume_thread_internal (MonoInternalThread *thread)
4658 if (!mono_thread_info_new_interrupt_enabled ()) {
4659 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4660 if (thread->resume_event == NULL) {
4661 UNLOCK_THREAD (thread);
4665 /* Awake the thread */
4666 SetEvent (thread->suspend_event);
4668 UNLOCK_THREAD (thread);
4670 /* Wait for the thread to awake */
4671 WaitForSingleObject (thread->resume_event, INFINITE);
4672 CloseHandle (thread->resume_event);
4673 thread->resume_event = NULL;
4677 UNLOCK_THREAD (thread);
4678 /* Awake the thread */
4679 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4681 LOCK_THREAD (thread);
4682 thread->state &= ~ThreadState_Suspended;
4683 UNLOCK_THREAD (thread);
4689 * mono_thread_is_foreign:
4690 * @thread: the thread to query
4692 * This function allows one to determine if a thread was created by the mono runtime and has
4693 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4695 * Returns: true if @thread was not created by the runtime.
4698 mono_thread_is_foreign (MonoThread *thread)
4700 MonoThreadInfo *info = thread->internal_thread->thread_info;
4701 return info->runtime_thread == FALSE;
4705 * mono_add_joinable_thread:
4707 * Add TID to the list of joinable threads.
4708 * LOCKING: Acquires the threads lock.
4711 mono_threads_add_joinable_thread (gpointer tid)
4715 * We cannot detach from threads because it causes problems like
4716 * 2fd16f60/r114307. So we collect them and join them when
4717 * we have time (in he finalizer thread).
4719 joinable_threads_lock ();
4720 if (!joinable_threads)
4721 joinable_threads = g_hash_table_new (NULL, NULL);
4722 g_hash_table_insert (joinable_threads, tid, tid);
4723 joinable_thread_count ++;
4724 joinable_threads_unlock ();
4726 mono_gc_finalize_notify ();
4731 * mono_threads_join_threads:
4733 * Join all joinable threads. This is called from the finalizer thread.
4734 * LOCKING: Acquires the threads lock.
4737 mono_threads_join_threads (void)
4740 GHashTableIter iter;
4747 if (!joinable_thread_count)
4751 joinable_threads_lock ();
4753 if (g_hash_table_size (joinable_threads)) {
4754 g_hash_table_iter_init (&iter, joinable_threads);
4755 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4756 thread = (pthread_t)tid;
4757 g_hash_table_remove (joinable_threads, key);
4758 joinable_thread_count --;
4761 joinable_threads_unlock ();
4763 if (thread != pthread_self ())
4764 /* This shouldn't block */
4765 pthread_join (thread, NULL);
4776 * Wait for thread TID to exit.
4777 * LOCKING: Acquires the threads lock.
4780 mono_thread_join (gpointer tid)
4784 gboolean found = FALSE;
4786 joinable_threads_lock ();
4787 if (!joinable_threads)
4788 joinable_threads = g_hash_table_new (NULL, NULL);
4789 if (g_hash_table_lookup (joinable_threads, tid)) {
4790 g_hash_table_remove (joinable_threads, tid);
4791 joinable_thread_count --;
4794 joinable_threads_unlock ();
4797 thread = (pthread_t)tid;
4798 pthread_join (thread, NULL);