2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threadpool.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internal.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internal.h>
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
51 #define USE_TKILL_ON_ANDROID 1
54 #ifdef PLATFORM_ANDROID
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid, int signal);
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func)(void *);
107 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
108 struct _MonoThreadDomainTls {
109 MonoThreadDomainTls *next;
117 MonoThreadDomainTls *freelist;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 static void mono_threads_lock (void);
130 static void mono_threads_unlock (void);
131 static mono_mutex_t threads_mutex;
133 /* Controls access to context static data */
134 #define mono_contexts_lock() mono_mutex_lock (&contexts_mutex)
135 #define mono_contexts_unlock() mono_mutex_unlock (&contexts_mutex)
136 static mono_mutex_t contexts_mutex;
138 /* Controls access to the 'joinable_threads' hash table */
139 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
140 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
141 static mono_mutex_t joinable_threads_mutex;
143 /* Holds current status of static data heap */
144 static StaticDataInfo thread_static_info;
145 static StaticDataInfo context_static_info;
147 /* The hash of existing threads (key is thread ID, value is
148 * MonoInternalThread*) that need joining before exit
150 static MonoGHashTable *threads=NULL;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable *threads_starting_up = NULL;
159 /* Maps a MonoThread to its start argument */
160 /* Protected by mono_threads_lock () */
161 static MonoGHashTable *thread_start_args = NULL;
163 /* The TLS key that holds the MonoObject assigned to each thread */
164 static MonoNativeTlsKey current_object_key;
167 /* Protected by the threads lock */
168 static GHashTable *joinable_threads;
169 static int joinable_thread_count;
171 #ifdef MONO_HAVE_FAST_TLS
172 /* we need to use both the Tls* functions and __thread because
173 * the gc needs to see all the threads
175 MONO_FAST_TLS_DECLARE(tls_current_object);
176 #define SET_CURRENT_OBJECT(x) do { \
177 MONO_FAST_TLS_SET (tls_current_object, x); \
178 mono_native_tls_set_value (current_object_key, x); \
180 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
182 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
183 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
186 /* function called at thread start */
187 static MonoThreadStartCB mono_thread_start_cb = NULL;
189 /* function called at thread attach */
190 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
192 /* function called at thread cleanup */
193 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
195 /* function called to notify the runtime about a pending exception on the current thread */
196 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
198 /* The default stack size for each thread */
199 static guint32 default_stacksize = 0;
200 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
202 static void thread_adjust_static_data (MonoInternalThread *thread);
203 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
204 static void mono_init_static_data_info (StaticDataInfo *static_data);
205 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
206 static gboolean mono_thread_resume (MonoInternalThread* thread);
207 static void signal_thread_state_change (MonoInternalThread *thread);
208 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
209 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
210 static void self_suspend_internal (MonoInternalThread *thread);
211 static gboolean resume_thread_internal (MonoInternalThread *thread);
213 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
214 static void ref_stack_destroy (gpointer rs);
216 /* Spin lock for InterlockedXXX 64 bit functions */
217 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
218 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
219 static mono_mutex_t interlocked_mutex;
221 /* global count of thread interruptions requested */
222 static gint32 thread_interruption_requested = 0;
224 /* Event signaled when a thread changes its background mode */
225 static HANDLE background_change_event;
227 static gboolean shutting_down = FALSE;
229 static gint32 managed_thread_id_counter = 0;
233 mono_threads_lock (void)
236 mono_locks_acquire (&threads_mutex, ThreadsLock);
237 MONO_FINISH_TRY_BLOCKING
241 mono_threads_unlock (void)
243 mono_locks_release (&threads_mutex, ThreadsLock);
248 get_next_managed_thread_id (void)
250 return InterlockedIncrement (&managed_thread_id_counter);
254 mono_thread_get_tls_key (void)
256 return current_object_key;
260 mono_thread_get_tls_offset (void)
263 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
267 static inline MonoNativeThreadId
268 thread_get_tid (MonoInternalThread *thread)
270 /* We store the tid as a guint64 to keep the object layout constant between platforms */
271 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
274 /* handle_store() and handle_remove() manage the array of threads that
275 * still need to be waited for when the main thread exits.
277 * If handle_store() returns FALSE the thread must not be started
278 * because Mono is shutting down.
280 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
282 mono_threads_lock ();
284 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
286 if (threads_starting_up)
287 mono_g_hash_table_remove (threads_starting_up, thread);
289 if (shutting_down && !force_attach) {
290 mono_threads_unlock ();
295 MONO_GC_REGISTER_ROOT_FIXED (threads);
296 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
299 /* We don't need to duplicate thread->handle, because it is
300 * only closed when the thread object is finalized by the GC.
302 g_assert (thread->internal_thread);
303 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
304 thread->internal_thread);
306 mono_threads_unlock ();
311 static gboolean handle_remove(MonoInternalThread *thread)
314 gsize tid = thread->tid;
316 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
318 mono_threads_lock ();
321 /* We have to check whether the thread object for the
322 * tid is still the same in the table because the
323 * thread might have been destroyed and the tid reused
324 * in the meantime, in which case the tid would be in
325 * the table, but with another thread object.
327 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
328 mono_g_hash_table_remove (threads, (gpointer)tid);
337 mono_threads_unlock ();
339 /* Don't close the handle here, wait for the object finalizer
340 * to do it. Otherwise, the following race condition applies:
342 * 1) Thread exits (and handle_remove() closes the handle)
344 * 2) Some other handle is reassigned the same slot
346 * 3) Another thread tries to join the first thread, and
347 * blocks waiting for the reassigned handle to be signalled
348 * (which might never happen). This is possible, because the
349 * thread calling Join() still has a reference to the first
355 static void ensure_synch_cs_set (MonoInternalThread *thread)
357 mono_mutex_t *synch_cs;
359 if (thread->synch_cs != NULL) {
363 synch_cs = g_new0 (mono_mutex_t, 1);
364 mono_mutex_init_recursive (synch_cs);
366 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
367 synch_cs, NULL) != NULL) {
368 /* Another thread must have installed this CS */
369 mono_mutex_destroy (synch_cs);
375 lock_thread (MonoInternalThread *thread)
377 if (!thread->synch_cs)
378 ensure_synch_cs_set (thread);
380 g_assert (thread->synch_cs);
383 mono_mutex_lock (thread->synch_cs);
384 MONO_FINISH_TRY_BLOCKING
388 unlock_thread (MonoInternalThread *thread)
390 mono_mutex_unlock (thread->synch_cs);
394 * NOTE: this function can be called also for threads different from the current one:
395 * make sure no code called from it will ever assume it is run on the thread that is
396 * getting cleaned up.
398 static void thread_cleanup (MonoInternalThread *thread)
400 g_assert (thread != NULL);
402 if (thread->abort_state_handle) {
403 mono_gchandle_free (thread->abort_state_handle);
404 thread->abort_state_handle = 0;
406 thread->abort_exc = NULL;
407 thread->current_appcontext = NULL;
410 * This is necessary because otherwise we might have
411 * cross-domain references which will not get cleaned up when
412 * the target domain is unloaded.
414 if (thread->cached_culture_info) {
416 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
417 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
421 * thread->synch_cs can be NULL if this was called after
422 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
423 * This can happen only during shutdown.
424 * The shutting_down flag is not always set, so we can't assert on it.
426 if (thread->synch_cs)
427 LOCK_THREAD (thread);
429 thread->state |= ThreadState_Stopped;
430 thread->state &= ~ThreadState_Background;
432 if (thread->synch_cs)
433 UNLOCK_THREAD (thread);
436 An interruption request has leaked to cleanup. Adjust the global counter.
438 This can happen is the abort source thread finds the abortee (this) thread
439 in unmanaged code. If this thread never trips back to managed code or check
440 the local flag it will be left set and positively unbalance the global counter.
442 Leaving the counter unbalanced will cause a performance degradation since all threads
443 will now keep checking their local flags all the time.
445 if (InterlockedExchange (&thread->interruption_requested, 0))
446 InterlockedDecrement (&thread_interruption_requested);
448 /* if the thread is not in the hash it has been removed already */
449 if (!handle_remove (thread)) {
450 if (thread == mono_thread_internal_current ()) {
451 mono_domain_unset ();
452 mono_memory_barrier ();
454 /* This needs to be called even if handle_remove () fails */
455 if (mono_thread_cleanup_fn)
456 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
459 mono_release_type_locks (thread);
461 mono_profiler_thread_end (thread->tid);
463 if (thread == mono_thread_internal_current ()) {
465 * This will signal async signal handlers that the thread has exited.
466 * The profiler callback needs this to be set, so it cannot be done earlier.
468 mono_domain_unset ();
469 mono_memory_barrier ();
472 if (thread == mono_thread_internal_current ())
473 mono_thread_pop_appdomain_ref ();
475 thread->cached_culture_info = NULL;
477 mono_free_static_data (thread->static_data, TRUE);
478 thread->static_data = NULL;
479 ref_stack_destroy (thread->appdomain_refs);
480 thread->appdomain_refs = NULL;
482 if (mono_thread_cleanup_fn)
483 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
485 if (mono_gc_is_moving ()) {
486 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
487 thread->thread_pinning_ref = NULL;
492 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
495 g_assert ((offset & 0x80000000) == 0);
496 offset &= 0x7fffffff;
497 idx = (offset >> 24) - 1;
498 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
502 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
504 static MonoClassField *current_thread_field = NULL;
508 if (!current_thread_field) {
509 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
510 g_assert (current_thread_field);
513 mono_class_vtable (domain, mono_defaults.thread_class);
514 mono_domain_lock (domain);
515 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
516 mono_domain_unlock (domain);
519 return get_thread_static_data (thread, offset);
523 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
525 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
527 g_assert (current->obj.vtable->domain == domain);
529 g_assert (!*current_thread_ptr);
530 *current_thread_ptr = current;
534 create_thread_object (MonoDomain *domain)
536 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
537 return (MonoThread*)mono_gc_alloc_mature (vt);
541 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
543 MonoThread *thread = create_thread_object (domain);
544 MONO_OBJECT_SETREF (thread, internal_thread, internal);
548 static MonoInternalThread*
549 create_internal_thread (void)
551 MonoInternalThread *thread;
554 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
555 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
557 thread->synch_cs = g_new0 (mono_mutex_t, 1);
558 mono_mutex_init_recursive (thread->synch_cs);
560 thread->apartment_state = ThreadApartmentState_Unknown;
561 thread->managed_id = get_next_managed_thread_id ();
562 if (mono_gc_is_moving ()) {
563 thread->thread_pinning_ref = thread;
564 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
571 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
573 MonoDomain *domain = mono_get_root_domain ();
575 if (!candidate || candidate->obj.vtable->domain != domain)
576 candidate = new_thread_with_internal (domain, thread);
577 set_current_thread_for_domain (domain, thread, candidate);
578 g_assert (!thread->root_domain_thread);
579 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
582 static guint32 WINAPI start_wrapper_internal(void *data)
584 MonoThreadInfo *info;
585 StartInfo *start_info = (StartInfo *)data;
586 guint32 (*start_func)(void *);
590 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
593 MonoInternalThread *internal = start_info->obj->internal_thread;
594 MonoObject *start_delegate = start_info->delegate;
595 MonoDomain *domain = start_info->obj->obj.vtable->domain;
597 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
599 /* We can be sure start_info->obj->tid and
600 * start_info->obj->handle have been set, because the thread
601 * was created suspended, and these values were set before the
605 info = mono_thread_info_current ();
607 internal->thread_info = info;
608 internal->small_id = info->small_id;
612 SET_CURRENT_OBJECT (internal);
614 /* Every thread references the appdomain which created it */
615 mono_thread_push_appdomain_ref (domain);
617 if (!mono_domain_set (domain, FALSE)) {
618 /* No point in raising an appdomain_unloaded exception here */
619 /* FIXME: Cleanup here */
620 mono_thread_pop_appdomain_ref ();
624 start_func = start_info->func;
625 start_arg = start_info->start_arg;
627 /* We have to do this here because mono_thread_new_init()
628 requires that root_domain_thread is set up. */
629 thread_adjust_static_data (internal);
630 init_root_domain_thread (internal, start_info->obj);
632 /* This MUST be called before any managed code can be
633 * executed, as it calls the callback function that (for the
634 * jit) sets the lmf marker.
636 mono_thread_new_init (tid, &tid, start_func);
637 internal->stack_ptr = &tid;
639 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
641 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
643 /* On 2.0 profile (and higher), set explicitly since state might have been
645 if (internal->apartment_state == ThreadApartmentState_Unknown)
646 internal->apartment_state = ThreadApartmentState_MTA;
648 mono_thread_init_apartment_state ();
650 if(internal->start_notify!=NULL) {
651 /* Let the thread that called Start() know we're
654 ReleaseSemaphore (internal->start_notify, 1, NULL);
657 mono_threads_lock ();
658 mono_g_hash_table_remove (thread_start_args, start_info->obj);
659 mono_threads_unlock ();
661 mono_thread_set_execution_context (start_info->obj->ec_to_set);
662 start_info->obj->ec_to_set = NULL;
665 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
669 * Call this after calling start_notify, since the profiler callback might want
670 * to lock the thread, and the lock is held by thread_start () which waits for
673 mono_profiler_thread_start (tid);
675 /* if the name was set before starting, we didn't invoke the profiler callback */
676 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
677 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
678 mono_profiler_thread_name (internal->tid, tname);
681 /* start_func is set only for unmanaged start functions */
683 start_func (start_arg);
686 g_assert (start_delegate != NULL);
687 args [0] = start_arg;
688 /* we may want to handle the exception here. See comment below on unhandled exceptions */
689 mono_runtime_delegate_invoke (start_delegate, args, NULL);
692 /* If the thread calls ExitThread at all, this remaining code
693 * will not be executed, but the main thread will eventually
694 * call thread_cleanup() on this thread's behalf.
697 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
699 /* Do any cleanup needed for apartment state. This
700 * cannot be done in thread_cleanup since thread_cleanup could be
701 * called for a thread other than the current thread.
702 * mono_thread_cleanup_apartment_state cleans up apartment
703 * for the current thead */
704 mono_thread_cleanup_apartment_state ();
706 thread_cleanup (internal);
710 /* Remove the reference to the thread object in the TLS data,
711 * so the thread object can be finalized. This won't be
712 * reached if the thread threw an uncaught exception, so those
713 * thread handles will stay referenced :-( (This is due to
714 * missing support for scanning thread-specific data in the
715 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
718 SET_CURRENT_OBJECT (NULL);
723 static guint32 WINAPI start_wrapper(void *data)
727 /* Avoid scanning the frames above this frame during a GC */
728 mono_gc_set_stack_end ((void*)&dummy);
730 return start_wrapper_internal (data);
736 * Common thread creation code.
737 * LOCKING: Acquires the threads lock.
740 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
741 gboolean throw_on_failure)
743 HANDLE thread_handle;
744 MonoNativeThreadId tid;
745 guint32 create_flags;
748 * Join joinable threads to prevent running out of threads since the finalizer
749 * thread might be blocked/backlogged.
751 mono_threads_join_threads ();
753 mono_threads_lock ();
756 mono_threads_unlock ();
760 * The thread start argument may be an object reference, and there is
761 * no ref to keep it alive when the new thread is started but not yet
762 * registered with the collector. So we store it in a GC tracked hash
765 if (thread_start_args == NULL) {
766 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
767 thread_start_args = mono_g_hash_table_new (NULL, NULL);
769 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
770 if (threads_starting_up == NULL) {
771 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
772 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
774 mono_g_hash_table_insert (threads_starting_up, thread, thread);
775 mono_threads_unlock ();
777 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
778 if (!internal->start_notify) {
779 mono_threads_lock ();
780 mono_g_hash_table_remove (threads_starting_up, thread);
781 mono_threads_unlock ();
782 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
788 stack_size = default_stacksize_for_thread (internal);
790 /* Create suspended, so we can do some housekeeping before the thread
793 create_flags = CREATE_SUSPENDED;
795 MONO_PREPARE_BLOCKING
796 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
797 stack_size, create_flags, &tid);
800 if (thread_handle == NULL) {
801 /* The thread couldn't be created, so throw an exception */
802 mono_threads_lock ();
803 mono_g_hash_table_remove (threads_starting_up, thread);
804 mono_threads_unlock ();
806 if (throw_on_failure)
807 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
809 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
812 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
814 internal->handle = thread_handle;
815 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
817 internal->threadpool_thread = threadpool_thread;
818 if (threadpool_thread)
819 mono_thread_set_state (internal, ThreadState_Background);
821 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
823 /* Only store the handle when the thread is about to be
824 * launched, to avoid the main thread deadlocking while trying
825 * to clean up a thread that will never be signalled.
827 if (!handle_store (thread, FALSE))
830 MONO_PREPARE_BLOCKING
831 mono_thread_info_resume (tid);
834 if (internal->start_notify) {
836 * Wait for the thread to set up its TLS data etc, so
837 * theres no potential race condition if someone tries
838 * to look up the data believing the thread has
841 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
843 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
845 CloseHandle (internal->start_notify);
846 internal->start_notify = NULL;
849 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
854 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
856 if (mono_thread_start_cb) {
857 mono_thread_start_cb (tid, stack_start, func);
861 void mono_threads_set_default_stacksize (guint32 stacksize)
863 default_stacksize = stacksize;
866 guint32 mono_threads_get_default_stacksize (void)
868 return default_stacksize;
872 * mono_thread_create_internal:
876 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
879 MonoInternalThread *internal;
880 StartInfo *start_info;
883 thread = create_thread_object (domain);
884 internal = create_internal_thread ();
885 MONO_OBJECT_SETREF (thread, internal_thread, internal);
887 start_info = g_new0 (StartInfo, 1);
888 start_info->func = func;
889 start_info->obj = thread;
890 start_info->start_arg = arg;
892 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
896 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
897 if (mono_check_corlib_version () == NULL)
898 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
904 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
906 mono_thread_create_internal (domain, func, arg, FALSE, 0);
910 mono_thread_attach (MonoDomain *domain)
912 return mono_thread_attach_full (domain, FALSE);
916 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
918 MonoThreadInfo *info;
919 MonoInternalThread *thread;
920 MonoThread *current_thread;
921 HANDLE thread_handle;
924 if ((thread = mono_thread_internal_current ())) {
925 if (domain != mono_domain_get ())
926 mono_domain_set (domain, TRUE);
927 /* Already attached */
928 return mono_thread_current ();
931 if (!mono_gc_register_thread (&domain)) {
932 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 ());
935 thread = create_internal_thread ();
937 thread_handle = mono_thread_info_open_handle ();
938 g_assert (thread_handle);
940 tid=GetCurrentThreadId ();
942 thread->handle=thread_handle;
944 #ifdef PLATFORM_ANDROID
945 thread->android_tid = (gpointer) gettid ();
947 thread->stack_ptr = &tid;
949 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
951 info = mono_thread_info_current ();
953 thread->thread_info = info;
954 thread->small_id = info->small_id;
956 current_thread = new_thread_with_internal (domain, thread);
958 if (!handle_store (current_thread, force_attach)) {
959 /* Mono is shutting down, so just wait for the end */
964 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
966 SET_CURRENT_OBJECT (thread);
967 mono_domain_set (domain, TRUE);
969 thread_adjust_static_data (thread);
971 init_root_domain_thread (thread, current_thread);
972 if (domain != mono_get_root_domain ())
973 set_current_thread_for_domain (domain, thread, current_thread);
976 if (mono_thread_attach_cb) {
980 mono_thread_info_get_stack_bounds (&staddr, &stsize);
983 mono_thread_attach_cb (tid, &tid);
985 mono_thread_attach_cb (tid, staddr + stsize);
988 // FIXME: Need a separate callback
989 mono_profiler_thread_start (tid);
991 return current_thread;
995 mono_thread_detach_internal (MonoInternalThread *thread)
997 g_return_if_fail (thread != NULL);
999 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1001 thread_cleanup (thread);
1003 SET_CURRENT_OBJECT (NULL);
1004 mono_domain_unset ();
1006 /* Don't need to CloseHandle this thread, even though we took a
1007 * reference in mono_thread_attach (), because the GC will do it
1008 * when the Thread object is finalised.
1013 mono_thread_detach (MonoThread *thread)
1016 mono_thread_detach_internal (thread->internal_thread);
1020 * mono_thread_detach_if_exiting:
1022 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1023 * This should be used at the end of embedding code which calls into managed code, and which
1024 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1027 mono_thread_detach_if_exiting (void)
1029 if (mono_thread_info_is_exiting ()) {
1030 MonoInternalThread *thread;
1032 thread = mono_thread_internal_current ();
1034 mono_thread_detach_internal (thread);
1035 mono_thread_info_detach ();
1043 MonoInternalThread *thread = mono_thread_internal_current ();
1045 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1047 thread_cleanup (thread);
1048 SET_CURRENT_OBJECT (NULL);
1049 mono_domain_unset ();
1051 /* we could add a callback here for embedders to use. */
1052 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1053 exit (mono_environment_exitcode_get ());
1054 mono_thread_info_exit ();
1058 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1060 MonoInternalThread *internal = create_internal_thread ();
1062 internal->state = ThreadState_Unstarted;
1064 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1068 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
1071 StartInfo *start_info;
1072 MonoInternalThread *internal;
1075 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1077 if (!this->internal_thread)
1078 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1079 internal = this->internal_thread;
1081 LOCK_THREAD (internal);
1083 if ((internal->state & ThreadState_Unstarted) == 0) {
1084 UNLOCK_THREAD (internal);
1085 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1089 if ((internal->state & ThreadState_Aborted) != 0) {
1090 UNLOCK_THREAD (internal);
1093 /* This is freed in start_wrapper */
1094 start_info = g_new0 (StartInfo, 1);
1095 start_info->func = NULL;
1096 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1097 start_info->delegate = start;
1098 start_info->obj = this;
1099 g_assert (this->obj.vtable->domain == mono_domain_get ());
1101 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1103 UNLOCK_THREAD (internal);
1107 internal->state &= ~ThreadState_Unstarted;
1109 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1111 UNLOCK_THREAD (internal);
1112 return internal->handle;
1116 * This is called from the finalizer of the internal thread object.
1119 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1121 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1124 * Since threads keep a reference to their thread object while running, by the time this function is called,
1125 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1126 * when thread_cleanup () can be called after this.
1129 CloseHandle (thread);
1131 if (this->synch_cs) {
1132 mono_mutex_t *synch_cs = this->synch_cs;
1133 this->synch_cs = NULL;
1134 mono_mutex_destroy (synch_cs);
1139 void *name = this->name;
1146 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1149 MonoInternalThread *thread = mono_thread_internal_current ();
1151 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1153 mono_thread_current_check_pending_interrupt ();
1156 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1158 MONO_PREPARE_BLOCKING
1159 res = SleepEx(ms,TRUE);
1160 MONO_FINISH_BLOCKING
1162 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1164 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1165 MonoException* exc = mono_thread_execute_interruption (thread);
1167 mono_raise_exception (exc);
1179 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1184 ves_icall_System_Threading_Thread_GetDomainID (void)
1186 return mono_domain_get()->domain_id;
1190 ves_icall_System_Threading_Thread_Yield (void)
1192 return mono_thread_info_yield ();
1196 * mono_thread_get_name:
1198 * Return the name of the thread. NAME_LEN is set to the length of the name.
1199 * Return NULL if the thread has no name. The returned memory is owned by the
1203 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1207 LOCK_THREAD (this_obj);
1209 if (!this_obj->name) {
1213 *name_len = this_obj->name_len;
1214 res = g_new (gunichar2, this_obj->name_len);
1215 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1218 UNLOCK_THREAD (this_obj);
1224 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1228 LOCK_THREAD (this_obj);
1230 if (!this_obj->name)
1233 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1235 UNLOCK_THREAD (this_obj);
1241 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1243 LOCK_THREAD (this_obj);
1245 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1246 UNLOCK_THREAD (this_obj);
1248 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1251 if (this_obj->name) {
1252 g_free (this_obj->name);
1253 this_obj->name_len = 0;
1256 this_obj->name = g_new (gunichar2, mono_string_length (name));
1257 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1258 this_obj->name_len = mono_string_length (name);
1261 this_obj->name = NULL;
1264 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1266 UNLOCK_THREAD (this_obj);
1268 if (this_obj->name && this_obj->tid) {
1269 char *tname = mono_string_to_utf8 (name);
1270 mono_profiler_thread_name (this_obj->tid, tname);
1271 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1277 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1279 mono_thread_set_name_internal (this_obj, name, TRUE);
1283 ves_icall_System_Threading_Thread_GetPriority (MonoInternalThread *thread)
1285 return ThreadPriority_Lowest;
1289 ves_icall_System_Threading_Thread_SetPriority (MonoInternalThread *thread, int priority)
1293 /* If the array is already in the requested domain, we just return it,
1294 otherwise we return a copy in that domain. */
1296 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1303 if (mono_object_domain (arr) == domain)
1306 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1307 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1312 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1314 return byte_array_to_domain (arr, mono_get_root_domain ());
1318 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1320 return byte_array_to_domain (arr, mono_domain_get ());
1324 mono_thread_current (void)
1326 MonoDomain *domain = mono_domain_get ();
1327 MonoInternalThread *internal = mono_thread_internal_current ();
1328 MonoThread **current_thread_ptr;
1330 g_assert (internal);
1331 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1333 if (!*current_thread_ptr) {
1334 g_assert (domain != mono_get_root_domain ());
1335 *current_thread_ptr = new_thread_with_internal (domain, internal);
1337 return *current_thread_ptr;
1341 mono_thread_internal_current (void)
1343 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1344 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1349 ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1350 int ms, HANDLE thread)
1352 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1355 mono_thread_current_check_pending_interrupt ();
1359 if ((this->state & ThreadState_Unstarted) != 0) {
1360 UNLOCK_THREAD (this);
1362 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1366 UNLOCK_THREAD (this);
1371 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1373 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1375 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1377 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1379 if(ret==WAIT_OBJECT_0) {
1380 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1385 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1391 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1399 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1402 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1404 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1406 if (ret != WAIT_IO_COMPLETION)
1409 exc = mono_thread_execute_interruption (thread);
1411 mono_raise_exception (exc);
1416 /* Re-calculate ms according to the time passed */
1417 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1418 if (diff_ms >= ms) {
1422 wait = ms - diff_ms;
1428 /* FIXME: exitContext isnt documented */
1429 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1435 MonoObject *waitHandle;
1436 MonoInternalThread *thread = mono_thread_internal_current ();
1438 /* Do this WaitSleepJoin check before creating objects */
1439 mono_thread_current_check_pending_interrupt ();
1441 /* We fail in managed if the array has more than 64 elements */
1442 numhandles = (guint32)mono_array_length(mono_handles);
1443 handles = g_new0(HANDLE, numhandles);
1445 for(i = 0; i < numhandles; i++) {
1446 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1447 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1454 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1456 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1458 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1462 if(ret==WAIT_FAILED) {
1463 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1465 } else if(ret==WAIT_TIMEOUT) {
1466 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1473 /* FIXME: exitContext isnt documented */
1474 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1476 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1477 uintptr_t numhandles;
1480 MonoObject *waitHandle;
1481 MonoInternalThread *thread = mono_thread_internal_current ();
1483 /* Do this WaitSleepJoin check before creating objects */
1484 mono_thread_current_check_pending_interrupt ();
1486 numhandles = mono_array_length(mono_handles);
1487 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1490 for(i = 0; i < numhandles; i++) {
1491 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1492 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1499 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1501 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1503 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1505 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1508 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1510 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1511 return ret - WAIT_OBJECT_0;
1513 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1514 return ret - WAIT_ABANDONED_0;
1521 /* FIXME: exitContext isnt documented */
1522 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1525 MonoInternalThread *thread = mono_thread_internal_current ();
1527 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1533 mono_thread_current_check_pending_interrupt ();
1535 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1537 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1539 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1541 if(ret==WAIT_FAILED) {
1542 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1544 } else if(ret==WAIT_TIMEOUT) {
1545 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1553 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1556 MonoInternalThread *thread = mono_thread_internal_current ();
1561 mono_thread_current_check_pending_interrupt ();
1563 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1565 MONO_PREPARE_BLOCKING
1566 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1567 MONO_FINISH_BLOCKING
1569 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1571 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1574 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1581 mutex = CreateMutex (NULL, owned, NULL);
1583 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1585 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1593 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1594 return(ReleaseMutex (handle));
1597 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1603 *error = ERROR_SUCCESS;
1605 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1607 *error = GetLastError ();
1614 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1621 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1623 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1624 mono_string_chars (name));
1626 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1634 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1638 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1643 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1647 *error = ERROR_SUCCESS;
1649 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1651 *error = GetLastError ();
1657 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1664 event = CreateEvent (NULL, manual, initial, NULL);
1666 event = CreateEvent (NULL, manual, initial,
1667 mono_string_chars (name));
1669 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1677 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1678 return (SetEvent(handle));
1681 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1682 return (ResetEvent(handle));
1686 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1687 CloseHandle (handle);
1690 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1696 *error = ERROR_SUCCESS;
1698 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1700 *error = GetLastError ();
1706 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1708 return InterlockedIncrement (location);
1711 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1713 #if SIZEOF_VOID_P == 4
1714 if (G_UNLIKELY ((size_t)location & 0x7)) {
1716 mono_interlocked_lock ();
1719 mono_interlocked_unlock ();
1723 return InterlockedIncrement64 (location);
1726 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1728 return InterlockedDecrement(location);
1731 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1733 #if SIZEOF_VOID_P == 4
1734 if (G_UNLIKELY ((size_t)location & 0x7)) {
1736 mono_interlocked_lock ();
1739 mono_interlocked_unlock ();
1743 return InterlockedDecrement64 (location);
1746 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1748 return InterlockedExchange(location, value);
1751 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1754 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1755 mono_gc_wbarrier_generic_nostore (location);
1759 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1761 return InterlockedExchangePointer(location, value);
1764 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1766 IntFloatUnion val, ret;
1769 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1775 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1777 #if SIZEOF_VOID_P == 4
1778 if (G_UNLIKELY ((size_t)location & 0x7)) {
1780 mono_interlocked_lock ();
1783 mono_interlocked_unlock ();
1787 return InterlockedExchange64 (location, value);
1791 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1793 LongDoubleUnion val, ret;
1796 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1801 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1803 return InterlockedCompareExchange(location, value, comparand);
1806 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1808 gint32 r = InterlockedCompareExchange(location, value, comparand);
1809 *success = r == comparand;
1813 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1816 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1817 mono_gc_wbarrier_generic_nostore (location);
1821 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1823 return InterlockedCompareExchangePointer(location, value, comparand);
1826 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1828 IntFloatUnion val, ret, cmp;
1831 cmp.fval = comparand;
1832 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1838 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1840 #if SIZEOF_VOID_P == 8
1841 LongDoubleUnion val, comp, ret;
1844 comp.fval = comparand;
1845 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1851 mono_interlocked_lock ();
1853 if (old == comparand)
1855 mono_interlocked_unlock ();
1862 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1864 #if SIZEOF_VOID_P == 4
1865 if (G_UNLIKELY ((size_t)location & 0x7)) {
1867 mono_interlocked_lock ();
1869 if (old == comparand)
1871 mono_interlocked_unlock ();
1875 return InterlockedCompareExchange64 (location, value, comparand);
1879 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1882 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1883 mono_gc_wbarrier_generic_nostore (location);
1888 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1891 res = InterlockedExchangePointer ((gpointer *)location, value);
1892 mono_gc_wbarrier_generic_nostore (location);
1897 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1899 return InterlockedAdd (location, value);
1903 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1905 #if SIZEOF_VOID_P == 4
1906 if (G_UNLIKELY ((size_t)location & 0x7)) {
1908 mono_interlocked_lock ();
1911 mono_interlocked_unlock ();
1915 return InterlockedAdd64 (location, value);
1919 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1921 #if SIZEOF_VOID_P == 4
1922 if (G_UNLIKELY ((size_t)location & 0x7)) {
1924 mono_interlocked_lock ();
1926 mono_interlocked_unlock ();
1930 return InterlockedRead64 (location);
1934 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1936 mono_memory_barrier ();
1940 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1942 mono_thread_clr_state (this, state);
1944 if (state & ThreadState_Background) {
1945 /* If the thread changes the background mode, the main thread has to
1946 * be notified, since it has to rebuild the list of threads to
1949 SetEvent (background_change_event);
1954 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1956 mono_thread_set_state (this, state);
1958 if (state & ThreadState_Background) {
1959 /* If the thread changes the background mode, the main thread has to
1960 * be notified, since it has to rebuild the list of threads to
1963 SetEvent (background_change_event);
1968 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1974 state = this->state;
1976 UNLOCK_THREAD (this);
1981 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
1983 MonoInternalThread *current;
1988 current = mono_thread_internal_current ();
1990 this->thread_interrupt_requested = TRUE;
1991 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
1993 UNLOCK_THREAD (this);
1996 abort_thread_internal (this, TRUE, FALSE);
2000 void mono_thread_current_check_pending_interrupt ()
2002 MonoInternalThread *thread = mono_thread_internal_current ();
2003 gboolean throw = FALSE;
2005 LOCK_THREAD (thread);
2007 if (thread->thread_interrupt_requested) {
2009 thread->thread_interrupt_requested = FALSE;
2012 UNLOCK_THREAD (thread);
2015 mono_raise_exception (mono_get_exception_thread_interrupted ());
2020 mono_thread_get_abort_signal (void)
2022 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
2024 #elif defined(PLATFORM_ANDROID)
2026 #elif !defined (SIGRTMIN)
2031 #endif /* SIGUSR1 */
2033 static int abort_signum = -1;
2035 if (abort_signum != -1)
2036 return abort_signum;
2037 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2038 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2039 struct sigaction sinfo;
2040 sigaction (i, NULL, &sinfo);
2041 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2046 /* fallback to the old way */
2048 #endif /* HOST_WIN32 */
2052 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2054 MonoException* exc = mono_thread_request_interruption (FALSE);
2055 if (exc) mono_raise_exception (exc);
2057 #endif /* HOST_WIN32 */
2060 * signal_thread_state_change
2062 * Tells the thread that his state has changed and it has to enter the new
2063 * state as soon as possible.
2065 static void signal_thread_state_change (MonoInternalThread *thread)
2068 gpointer wait_handle;
2071 if (thread == mono_thread_internal_current ()) {
2072 /* Do it synchronously */
2073 MonoException *exc = mono_thread_request_interruption (FALSE);
2075 mono_raise_exception (exc);
2079 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, (ULONG_PTR)NULL);
2082 * This will cause waits to be broken.
2083 * It will also prevent the thread from entering a wait, so if the thread returns
2084 * from the wait before it receives the abort signal, it will just spin in the wait
2085 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2088 wait_handle = mono_thread_info_prepare_interrupt (thread->handle);
2090 /* fixme: store the state somewhere */
2091 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2093 mono_thread_info_finish_interrupt (wait_handle);
2094 #endif /* HOST_WIN32 */
2098 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2100 LOCK_THREAD (thread);
2102 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2103 (thread->state & ThreadState_StopRequested) != 0 ||
2104 (thread->state & ThreadState_Stopped) != 0)
2106 UNLOCK_THREAD (thread);
2110 if ((thread->state & ThreadState_Unstarted) != 0) {
2111 thread->state |= ThreadState_Aborted;
2112 UNLOCK_THREAD (thread);
2116 thread->state |= ThreadState_AbortRequested;
2117 if (thread->abort_state_handle)
2118 mono_gchandle_free (thread->abort_state_handle);
2120 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2121 g_assert (thread->abort_state_handle);
2123 thread->abort_state_handle = 0;
2125 thread->abort_exc = NULL;
2128 * abort_exc is set in mono_thread_execute_interruption(),
2129 * triggered by the call to signal_thread_state_change(),
2130 * below. There's a point between where we have
2131 * abort_state_handle set, but abort_exc NULL, but that's not
2135 UNLOCK_THREAD (thread);
2137 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2139 /* During shutdown, we can't wait for other threads */
2141 /* Make sure the thread is awake */
2142 mono_thread_resume (thread);
2144 abort_thread_internal (thread, TRUE, TRUE);
2148 ves_icall_System_Threading_Thread_ResetAbort (void)
2150 MonoInternalThread *thread = mono_thread_internal_current ();
2151 gboolean was_aborting;
2153 LOCK_THREAD (thread);
2154 was_aborting = thread->state & ThreadState_AbortRequested;
2155 thread->state &= ~ThreadState_AbortRequested;
2156 UNLOCK_THREAD (thread);
2158 if (!was_aborting) {
2159 const char *msg = "Unable to reset abort because no abort was requested";
2160 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2163 thread->abort_exc = NULL;
2164 if (thread->abort_state_handle) {
2165 mono_gchandle_free (thread->abort_state_handle);
2166 /* This is actually not necessary - the handle
2167 only counts if the exception is set */
2168 thread->abort_state_handle = 0;
2173 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2175 LOCK_THREAD (thread);
2177 thread->state &= ~ThreadState_AbortRequested;
2179 if (thread->abort_exc) {
2180 thread->abort_exc = NULL;
2181 if (thread->abort_state_handle) {
2182 mono_gchandle_free (thread->abort_state_handle);
2183 /* This is actually not necessary - the handle
2184 only counts if the exception is set */
2185 thread->abort_state_handle = 0;
2189 UNLOCK_THREAD (thread);
2193 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2195 MonoInternalThread *thread = this->internal_thread;
2196 MonoObject *state, *deserialized = NULL, *exc;
2199 if (!thread->abort_state_handle)
2202 state = mono_gchandle_get_target (thread->abort_state_handle);
2205 domain = mono_domain_get ();
2206 if (mono_object_domain (state) == domain)
2209 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2211 if (!deserialized) {
2212 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2214 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2215 mono_set_pending_exception (invalid_op_exc);
2219 return deserialized;
2223 mono_thread_suspend (MonoInternalThread *thread)
2225 LOCK_THREAD (thread);
2227 if ((thread->state & ThreadState_Unstarted) != 0 ||
2228 (thread->state & ThreadState_Aborted) != 0 ||
2229 (thread->state & ThreadState_Stopped) != 0)
2231 UNLOCK_THREAD (thread);
2235 if ((thread->state & ThreadState_Suspended) != 0 ||
2236 (thread->state & ThreadState_SuspendRequested) != 0 ||
2237 (thread->state & ThreadState_StopRequested) != 0)
2239 UNLOCK_THREAD (thread);
2243 thread->state |= ThreadState_SuspendRequested;
2245 UNLOCK_THREAD (thread);
2247 suspend_thread_internal (thread, FALSE);
2252 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2254 if (!mono_thread_suspend (thread)) {
2255 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2261 mono_thread_resume (MonoInternalThread *thread)
2263 LOCK_THREAD (thread);
2265 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2266 thread->state &= ~ThreadState_SuspendRequested;
2267 UNLOCK_THREAD (thread);
2271 if ((thread->state & ThreadState_Suspended) == 0 ||
2272 (thread->state & ThreadState_Unstarted) != 0 ||
2273 (thread->state & ThreadState_Aborted) != 0 ||
2274 (thread->state & ThreadState_Stopped) != 0)
2276 UNLOCK_THREAD (thread);
2280 return resume_thread_internal (thread);
2284 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2286 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2287 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2293 mono_threads_is_critical_method (MonoMethod *method)
2295 switch (method->wrapper_type) {
2296 case MONO_WRAPPER_RUNTIME_INVOKE:
2297 case MONO_WRAPPER_XDOMAIN_INVOKE:
2298 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2305 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2310 if (mono_threads_is_critical_method (m)) {
2311 *((gboolean*)data) = TRUE;
2318 is_running_protected_wrapper (void)
2320 gboolean found = FALSE;
2321 mono_stack_walk (find_wrapper, &found);
2325 void mono_thread_internal_stop (MonoInternalThread *thread)
2327 LOCK_THREAD (thread);
2329 if ((thread->state & ThreadState_StopRequested) != 0 ||
2330 (thread->state & ThreadState_Stopped) != 0)
2332 UNLOCK_THREAD (thread);
2336 /* Make sure the thread is awake */
2337 mono_thread_resume (thread);
2339 thread->state |= ThreadState_StopRequested;
2340 thread->state &= ~ThreadState_AbortRequested;
2342 UNLOCK_THREAD (thread);
2344 abort_thread_internal (thread, TRUE, TRUE);
2347 void mono_thread_stop (MonoThread *thread)
2349 mono_thread_internal_stop (thread->internal_thread);
2353 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2356 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2361 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2364 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2369 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2372 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2377 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2380 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2385 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2388 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2389 return (void *) tmp;
2393 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2395 volatile MonoObject *tmp;
2396 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2397 return (MonoObject *) tmp;
2401 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2404 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2409 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2412 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2417 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2419 return InterlockedRead8 (ptr);
2423 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2425 return InterlockedRead16 (ptr);
2429 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2431 return InterlockedRead (ptr);
2435 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2437 #if SIZEOF_VOID_P == 4
2438 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2440 mono_interlocked_lock ();
2441 val = *(gint64*)ptr;
2442 mono_interlocked_unlock ();
2446 return InterlockedRead64 (ptr);
2450 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2452 return InterlockedReadPointer (ptr);
2456 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2460 #if SIZEOF_VOID_P == 4
2461 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2463 mono_interlocked_lock ();
2464 val = *(double*)ptr;
2465 mono_interlocked_unlock ();
2470 u.ival = InterlockedRead64 (ptr);
2476 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2480 u.ival = InterlockedRead (ptr);
2486 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2488 return InterlockedReadPointer (ptr);
2492 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2494 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2498 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2500 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2504 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2506 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2510 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2512 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2516 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2518 mono_atomic_store_release ((volatile void **) ptr, value);
2522 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2524 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2528 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2530 mono_atomic_store_release ((volatile double *) ptr, value);
2534 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2536 mono_atomic_store_release ((volatile float *) ptr, value);
2540 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2542 InterlockedWrite8 (ptr, value);
2546 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2548 InterlockedWrite16 (ptr, value);
2552 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2554 InterlockedWrite (ptr, value);
2558 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2560 #if SIZEOF_VOID_P == 4
2561 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2562 mono_interlocked_lock ();
2563 *(gint64*)ptr = value;
2564 mono_interlocked_unlock ();
2569 InterlockedWrite64 (ptr, value);
2573 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2575 InterlockedWritePointer (ptr, value);
2579 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2583 #if SIZEOF_VOID_P == 4
2584 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2585 mono_interlocked_lock ();
2586 *(double*)ptr = value;
2587 mono_interlocked_unlock ();
2594 InterlockedWrite64 (ptr, u.ival);
2598 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2604 InterlockedWrite (ptr, u.ival);
2608 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2610 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2614 mono_thread_init_tls (void)
2616 MONO_FAST_TLS_INIT (tls_current_object);
2617 mono_native_tls_alloc (¤t_object_key, NULL);
2620 void mono_thread_init (MonoThreadStartCB start_cb,
2621 MonoThreadAttachCB attach_cb)
2623 mono_mutex_init_recursive(&threads_mutex);
2624 mono_mutex_init_recursive(&interlocked_mutex);
2625 mono_mutex_init_recursive(&contexts_mutex);
2626 mono_mutex_init_recursive(&joinable_threads_mutex);
2628 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2629 g_assert(background_change_event != NULL);
2631 mono_init_static_data_info (&thread_static_info);
2632 mono_init_static_data_info (&context_static_info);
2634 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2636 mono_thread_start_cb = start_cb;
2637 mono_thread_attach_cb = attach_cb;
2639 /* Get a pseudo handle to the current process. This is just a
2640 * kludge so that wapi can build a process handle if needed.
2641 * As a pseudo handle is returned, we don't need to clean
2644 GetCurrentProcess ();
2647 void mono_thread_cleanup (void)
2649 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2650 MonoThreadInfo *info;
2652 /* The main thread must abandon any held mutexes (particularly
2653 * important for named mutexes as they are shared across
2654 * processes, see bug 74680.) This will happen when the
2655 * thread exits, but if it's not running in a subthread it
2656 * won't exit in time.
2658 info = mono_thread_info_current ();
2659 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2663 /* This stuff needs more testing, it seems one of these
2664 * critical sections can be locked when mono_thread_cleanup is
2667 mono_mutex_destroy (&threads_mutex);
2668 mono_mutex_destroy (&interlocked_mutex);
2669 mono_mutex_destroy (&contexts_mutex);
2670 mono_mutex_destroy (&delayed_free_table_mutex);
2671 mono_mutex_destroy (&small_id_mutex);
2672 CloseHandle (background_change_event);
2675 mono_native_tls_free (current_object_key);
2679 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2681 mono_thread_cleanup_fn = func;
2685 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2687 thread->internal_thread->manage_callback = func;
2690 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2692 mono_thread_notify_pending_exc_fn = func;
2696 static void print_tids (gpointer key, gpointer value, gpointer user)
2698 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2699 * sizeof(uint) and a cast to uint would overflow
2701 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2702 * print this as a pointer.
2704 g_message ("Waiting for: %p", key);
2709 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2710 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2714 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2718 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2720 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2722 if(ret==WAIT_FAILED) {
2723 /* See the comment in build_wait_tids() */
2724 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2728 for(i=0; i<wait->num; i++)
2729 CloseHandle (wait->handles[i]);
2731 if (ret == WAIT_TIMEOUT)
2734 for(i=0; i<wait->num; i++) {
2735 gsize tid = wait->threads[i]->tid;
2738 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2739 * it can still run io-layer etc. code. So wait for it to really exit.
2740 * FIXME: This won't join threads which are not in the joinable_hash yet.
2742 mono_thread_join ((gpointer)tid);
2744 mono_threads_lock ();
2745 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2746 /* This thread must have been killed, because
2747 * it hasn't cleaned itself up. (It's just
2748 * possible that the thread exited before the
2749 * parent thread had a chance to store the
2750 * handle, and now there is another pointer to
2751 * the already-exited thread stored. In this
2752 * case, we'll just get two
2753 * mono_profiler_thread_end() calls for the
2757 mono_threads_unlock ();
2758 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2759 thread_cleanup (wait->threads[i]);
2761 mono_threads_unlock ();
2766 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2768 guint32 i, ret, count;
2770 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2772 /* Add the thread state change event, so it wakes up if a thread changes
2773 * to background mode.
2776 if (count < MAXIMUM_WAIT_OBJECTS) {
2777 wait->handles [count] = background_change_event;
2781 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2783 if(ret==WAIT_FAILED) {
2784 /* See the comment in build_wait_tids() */
2785 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2789 for(i=0; i<wait->num; i++)
2790 CloseHandle (wait->handles[i]);
2792 if (ret == WAIT_TIMEOUT)
2795 if (ret < wait->num) {
2796 gsize tid = wait->threads[ret]->tid;
2797 mono_threads_lock ();
2798 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2799 /* See comment in wait_for_tids about thread cleanup */
2800 mono_threads_unlock ();
2801 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2802 thread_cleanup (wait->threads [ret]);
2804 mono_threads_unlock ();
2808 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2810 struct wait_data *wait=(struct wait_data *)user;
2812 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2814 MonoInternalThread *thread=(MonoInternalThread *)value;
2816 /* Ignore background threads, we abort them later */
2817 /* Do not lock here since it is not needed and the caller holds threads_lock */
2818 if (thread->state & ThreadState_Background) {
2819 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2820 return; /* just leave, ignore */
2823 if (mono_gc_is_finalizer_internal_thread (thread)) {
2824 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2828 if (thread == mono_thread_internal_current ()) {
2829 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2833 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2834 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2838 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2839 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2843 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2844 if (handle == NULL) {
2845 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2849 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2850 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2851 wait->handles[wait->num]=handle;
2852 wait->threads[wait->num]=thread;
2855 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2857 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2862 /* Just ignore the rest, we can't do anything with
2869 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2871 struct wait_data *wait=(struct wait_data *)user;
2872 gsize self = GetCurrentThreadId ();
2873 MonoInternalThread *thread = value;
2876 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2879 /* The finalizer thread is not a background thread */
2880 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2881 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2883 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2887 /* printf ("A: %d\n", wait->num); */
2888 wait->handles[wait->num]=thread->handle;
2889 wait->threads[wait->num]=thread;
2892 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2893 mono_thread_internal_stop (thread);
2897 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2901 * mono_threads_set_shutting_down:
2903 * Is called by a thread that wants to shut down Mono. If the runtime is already
2904 * shutting down, the calling thread is suspended/stopped, and this function never
2908 mono_threads_set_shutting_down (void)
2910 MonoInternalThread *current_thread = mono_thread_internal_current ();
2912 mono_threads_lock ();
2914 if (shutting_down) {
2915 mono_threads_unlock ();
2917 /* Make sure we're properly suspended/stopped */
2919 LOCK_THREAD (current_thread);
2921 if ((current_thread->state & ThreadState_SuspendRequested) ||
2922 (current_thread->state & ThreadState_AbortRequested) ||
2923 (current_thread->state & ThreadState_StopRequested)) {
2924 UNLOCK_THREAD (current_thread);
2925 mono_thread_execute_interruption (current_thread);
2927 current_thread->state |= ThreadState_Stopped;
2928 UNLOCK_THREAD (current_thread);
2931 /*since we're killing the thread, unset the current domain.*/
2932 mono_domain_unset ();
2934 /* Wake up other threads potentially waiting for us */
2935 mono_thread_info_exit ();
2937 shutting_down = TRUE;
2939 /* Not really a background state change, but this will
2940 * interrupt the main thread if it is waiting for all
2941 * the other threads.
2943 SetEvent (background_change_event);
2945 mono_threads_unlock ();
2949 void mono_thread_manage (void)
2951 struct wait_data wait_data;
2952 struct wait_data *wait = &wait_data;
2954 memset (wait, 0, sizeof (struct wait_data));
2955 /* join each thread that's still running */
2956 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2958 mono_threads_lock ();
2960 THREAD_DEBUG (g_message("%s: No threads", __func__));
2961 mono_threads_unlock ();
2964 mono_threads_unlock ();
2967 mono_threads_lock ();
2968 if (shutting_down) {
2969 /* somebody else is shutting down */
2970 mono_threads_unlock ();
2973 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2974 mono_g_hash_table_foreach (threads, print_tids, NULL));
2976 ResetEvent (background_change_event);
2978 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2979 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2980 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2981 mono_threads_unlock ();
2983 /* Something to wait for */
2984 wait_for_tids_or_state_change (wait, INFINITE);
2986 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2987 } while(wait->num>0);
2989 /* Mono is shutting down, so just wait for the end */
2990 if (!mono_runtime_try_shutdown ()) {
2991 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2992 mono_thread_suspend (mono_thread_internal_current ());
2993 mono_thread_execute_interruption (mono_thread_internal_current ());
2997 * Remove everything but the finalizer thread and self.
2998 * Also abort all the background threads
3001 mono_threads_lock ();
3004 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3005 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3006 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3008 mono_threads_unlock ();
3010 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3012 /* Something to wait for */
3013 wait_for_tids (wait, INFINITE);
3015 } while (wait->num > 0);
3018 * give the subthreads a chance to really quit (this is mainly needed
3019 * to get correct user and system times from getrusage/wait/time(1)).
3020 * This could be removed if we avoid pthread_detach() and use pthread_join().
3022 mono_thread_info_yield ();
3025 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3027 MonoInternalThread *thread=(MonoInternalThread *)value;
3029 if(thread->tid != (gsize)user) {
3030 /*TerminateThread (thread->handle, -1);*/
3034 void mono_thread_abort_all_other_threads (void)
3036 gsize self = GetCurrentThreadId ();
3038 mono_threads_lock ();
3039 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3040 mono_g_hash_table_size (threads));
3041 mono_g_hash_table_foreach (threads, print_tids, NULL));
3043 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3045 mono_threads_unlock ();
3049 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3051 MonoInternalThread *thread = (MonoInternalThread*)value;
3052 struct wait_data *wait = (struct wait_data*)user_data;
3056 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3058 * This needs no locking.
3060 if ((thread->state & ThreadState_Suspended) != 0 ||
3061 (thread->state & ThreadState_Stopped) != 0)
3064 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3065 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3069 wait->handles [wait->num] = handle;
3070 wait->threads [wait->num] = thread;
3076 * mono_thread_suspend_all_other_threads:
3078 * Suspend all managed threads except the finalizer thread and this thread. It is
3079 * not possible to resume them later.
3081 void mono_thread_suspend_all_other_threads (void)
3083 struct wait_data wait_data;
3084 struct wait_data *wait = &wait_data;
3086 gsize self = GetCurrentThreadId ();
3088 guint32 eventidx = 0;
3089 gboolean starting, finished;
3091 memset (wait, 0, sizeof (struct wait_data));
3093 * The other threads could be in an arbitrary state at this point, i.e.
3094 * they could be starting up, shutting down etc. This means that there could be
3095 * threads which are not even in the threads hash table yet.
3099 * First we set a barrier which will be checked by all threads before they
3100 * are added to the threads hash table, and they will exit if the flag is set.
3101 * This ensures that no threads could be added to the hash later.
3102 * We will use shutting_down as the barrier for now.
3104 g_assert (shutting_down);
3107 * We make multiple calls to WaitForMultipleObjects since:
3108 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3109 * - some threads could exit without becoming suspended
3114 * Make a copy of the hashtable since we can't do anything with
3115 * threads while threads_mutex is held.
3118 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3119 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3120 mono_threads_lock ();
3121 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3122 mono_threads_unlock ();
3124 events = g_new0 (gpointer, wait->num);
3126 /* Get the suspended events that we'll be waiting for */
3127 for (i = 0; i < wait->num; ++i) {
3128 MonoInternalThread *thread = wait->threads [i];
3129 gboolean signal_suspend = FALSE;
3131 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3132 //CloseHandle (wait->handles [i]);
3133 wait->threads [i] = NULL; /* ignore this thread in next loop */
3137 LOCK_THREAD (thread);
3139 if (thread->suspended_event == NULL) {
3140 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3141 if (thread->suspended_event == NULL) {
3142 /* Forget this one and go on to the next */
3143 UNLOCK_THREAD (thread);
3148 if ((thread->state & ThreadState_Suspended) != 0 ||
3149 (thread->state & ThreadState_StopRequested) != 0 ||
3150 (thread->state & ThreadState_Stopped) != 0) {
3151 UNLOCK_THREAD (thread);
3152 CloseHandle (wait->handles [i]);
3153 wait->threads [i] = NULL; /* ignore this thread in next loop */
3157 if ((thread->state & ThreadState_SuspendRequested) == 0)
3158 signal_suspend = TRUE;
3160 events [eventidx++] = thread->suspended_event;
3162 /* Convert abort requests into suspend requests */
3163 if ((thread->state & ThreadState_AbortRequested) != 0)
3164 thread->state &= ~ThreadState_AbortRequested;
3166 thread->state |= ThreadState_SuspendRequested;
3168 UNLOCK_THREAD (thread);
3170 /* Signal the thread to suspend */
3171 if (mono_thread_info_new_interrupt_enabled ())
3172 suspend_thread_internal (thread, TRUE);
3173 else if (signal_suspend)
3174 signal_thread_state_change (thread);
3177 /*Only wait on the suspend event if we are using the old path */
3178 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3179 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3180 for (i = 0; i < wait->num; ++i) {
3181 MonoInternalThread *thread = wait->threads [i];
3186 LOCK_THREAD (thread);
3187 if ((thread->state & ThreadState_Suspended) != 0) {
3188 CloseHandle (thread->suspended_event);
3189 thread->suspended_event = NULL;
3191 UNLOCK_THREAD (thread);
3195 if (eventidx <= 0) {
3197 * If there are threads which are starting up, we wait until they
3198 * are suspended when they try to register in the threads hash.
3199 * This is guaranteed to finish, since the threads which can create new
3200 * threads get suspended after a while.
3201 * FIXME: The finalizer thread can still create new threads.
3203 mono_threads_lock ();
3204 if (threads_starting_up)
3205 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3208 mono_threads_unlock ();
3220 collect_threads (gpointer key, gpointer value, gpointer user_data)
3222 MonoInternalThread *thread = (MonoInternalThread*)value;
3223 struct wait_data *wait = (struct wait_data*)user_data;
3226 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3227 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3231 wait->handles [wait->num] = handle;
3232 wait->threads [wait->num] = thread;
3237 static gboolean thread_dump_requested;
3239 static G_GNUC_UNUSED gboolean
3240 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3242 GString *p = (GString*)data;
3243 MonoMethod *method = NULL;
3245 method = mono_jit_info_get_method (frame->ji);
3248 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3249 g_string_append_printf (p, " %s\n", location);
3252 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3257 static SuspendThreadResult
3258 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3260 MonoInternalThread *thread = ud;
3261 GString* text = g_string_new (0);
3263 GError *error = NULL;
3266 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3268 g_string_append_printf (text, "\n\"%s\"", name);
3271 else if (thread->threadpool_thread)
3272 g_string_append (text, "\n\"<threadpool thread>\"");
3274 g_string_append (text, "\n\"<unnamed thread>\"");
3277 /* This no longer works with remote unwinding */
3279 wapi_desc = wapi_current_thread_desc ();
3280 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3285 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, text);
3287 fprintf (stdout, "%s", text->str);
3289 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3290 OutputDebugStringA(text->str);
3293 g_string_free (text, TRUE);
3295 return MonoResumeThread;
3299 dump_thread (gpointer key, gpointer value, gpointer user)
3301 MonoInternalThread *thread = (MonoInternalThread *)value;
3303 if (thread == mono_thread_internal_current ())
3307 FIXME This still can hang if we stop a thread during malloc.
3308 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3309 that takes a callback and runs it with the target suspended.
3310 We probably should loop a bit around trying to get it to either managed code
3313 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
3317 mono_threads_perform_thread_dump (void)
3319 if (!thread_dump_requested)
3322 printf ("Full thread dump:\n");
3324 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3325 something needs then in the process.
3327 mono_loader_lock ();
3328 mono_domain_lock (mono_get_root_domain ());
3330 mono_threads_lock ();
3331 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3332 mono_threads_unlock ();
3334 mono_domain_unlock (mono_get_root_domain ());
3335 mono_loader_unlock ();
3337 thread_dump_requested = FALSE;
3341 * mono_threads_request_thread_dump:
3343 * Ask all threads except the current to print their stacktrace to stdout.
3346 mono_threads_request_thread_dump (void)
3348 struct wait_data wait_data;
3349 struct wait_data *wait = &wait_data;
3352 /*The new thread dump code runs out of the finalizer thread. */
3353 if (mono_thread_info_new_interrupt_enabled ()) {
3354 thread_dump_requested = TRUE;
3355 mono_gc_finalize_notify ();
3360 memset (wait, 0, sizeof (struct wait_data));
3363 * Make a copy of the hashtable since we can't do anything with
3364 * threads while threads_mutex is held.
3366 mono_threads_lock ();
3367 mono_g_hash_table_foreach (threads, collect_threads, wait);
3368 mono_threads_unlock ();
3370 for (i = 0; i < wait->num; ++i) {
3371 MonoInternalThread *thread = wait->threads [i];
3373 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3374 (thread != mono_thread_internal_current ()) &&
3375 !thread->thread_dump_requested) {
3376 thread->thread_dump_requested = TRUE;
3378 signal_thread_state_change (thread);
3381 CloseHandle (wait->handles [i]);
3387 gint allocated; /* +1 so that refs [allocated] == NULL */
3391 typedef struct ref_stack RefStack;
3394 ref_stack_new (gint initial_size)
3398 initial_size = MAX (initial_size, 16) + 1;
3399 rs = g_new0 (RefStack, 1);
3400 rs->refs = g_new0 (gpointer, initial_size);
3401 rs->allocated = initial_size;
3406 ref_stack_destroy (gpointer ptr)
3417 ref_stack_push (RefStack *rs, gpointer ptr)
3419 g_assert (rs != NULL);
3421 if (rs->bottom >= rs->allocated) {
3422 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3423 rs->allocated <<= 1;
3424 rs->refs [rs->allocated] = NULL;
3426 rs->refs [rs->bottom++] = ptr;
3430 ref_stack_pop (RefStack *rs)
3432 if (rs == NULL || rs->bottom == 0)
3436 rs->refs [rs->bottom] = NULL;
3440 ref_stack_find (RefStack *rs, gpointer ptr)
3447 for (refs = rs->refs; refs && *refs; refs++) {
3455 * mono_thread_push_appdomain_ref:
3457 * Register that the current thread may have references to objects in domain
3458 * @domain on its stack. Each call to this function should be paired with a
3459 * call to pop_appdomain_ref.
3462 mono_thread_push_appdomain_ref (MonoDomain *domain)
3464 MonoInternalThread *thread = mono_thread_internal_current ();
3467 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3468 SPIN_LOCK (thread->lock_thread_id);
3469 if (thread->appdomain_refs == NULL)
3470 thread->appdomain_refs = ref_stack_new (16);
3471 ref_stack_push (thread->appdomain_refs, domain);
3472 SPIN_UNLOCK (thread->lock_thread_id);
3477 mono_thread_pop_appdomain_ref (void)
3479 MonoInternalThread *thread = mono_thread_internal_current ();
3482 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3483 SPIN_LOCK (thread->lock_thread_id);
3484 ref_stack_pop (thread->appdomain_refs);
3485 SPIN_UNLOCK (thread->lock_thread_id);
3490 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3493 SPIN_LOCK (thread->lock_thread_id);
3494 res = ref_stack_find (thread->appdomain_refs, domain);
3495 SPIN_UNLOCK (thread->lock_thread_id);
3500 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3502 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3505 typedef struct abort_appdomain_data {
3506 struct wait_data wait;
3508 } abort_appdomain_data;
3511 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3513 MonoInternalThread *thread = (MonoInternalThread*)value;
3514 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3515 MonoDomain *domain = data->domain;
3517 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3518 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3520 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3521 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3524 data->wait.handles [data->wait.num] = handle;
3525 data->wait.threads [data->wait.num] = thread;
3528 /* Just ignore the rest, we can't do anything with
3536 * mono_threads_abort_appdomain_threads:
3538 * Abort threads which has references to the given appdomain.
3541 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3543 #ifdef __native_client__
3547 abort_appdomain_data user_data;
3549 int orig_timeout = timeout;
3552 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3554 start_time = mono_msec_ticks ();
3556 mono_threads_lock ();
3558 user_data.domain = domain;
3559 user_data.wait.num = 0;
3560 /* This shouldn't take any locks */
3561 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3562 mono_threads_unlock ();
3564 if (user_data.wait.num > 0) {
3565 /* Abort the threads outside the threads lock */
3566 for (i = 0; i < user_data.wait.num; ++i)
3567 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3570 * We should wait for the threads either to abort, or to leave the
3571 * domain. We can't do the latter, so we wait with a timeout.
3573 wait_for_tids (&user_data.wait, 100);
3576 /* Update remaining time */
3577 timeout -= mono_msec_ticks () - start_time;
3578 start_time = mono_msec_ticks ();
3580 if (orig_timeout != -1 && timeout < 0)
3583 while (user_data.wait.num > 0);
3585 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3591 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3593 MonoInternalThread *thread = (MonoInternalThread*)value;
3594 MonoDomain *domain = (MonoDomain*)user_data;
3597 /* No locking needed here */
3598 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3600 if (thread->cached_culture_info) {
3601 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3602 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3603 if (obj && obj->vtable->domain == domain)
3604 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3610 * mono_threads_clear_cached_culture:
3612 * Clear the cached_current_culture from all threads if it is in the
3616 mono_threads_clear_cached_culture (MonoDomain *domain)
3618 mono_threads_lock ();
3619 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3620 mono_threads_unlock ();
3624 * mono_thread_get_undeniable_exception:
3626 * Return an exception which needs to be raised when leaving a catch clause.
3627 * This is used for undeniable exception propagation.
3630 mono_thread_get_undeniable_exception (void)
3632 MonoInternalThread *thread = mono_thread_internal_current ();
3634 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3636 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3637 * exception if the thread no longer references a dying appdomain.
3639 thread->abort_exc->trace_ips = NULL;
3640 thread->abort_exc->stack_trace = NULL;
3641 return thread->abort_exc;
3647 #if MONO_SMALL_CONFIG
3648 #define NUM_STATIC_DATA_IDX 4
3649 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3653 #define NUM_STATIC_DATA_IDX 8
3654 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3655 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3659 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3662 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3665 gpointer *static_data = addr;
3666 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3669 if (!static_data [i])
3671 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3672 ptr = static_data [i];
3673 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3674 uintptr_t bmap = static_reference_bitmaps [i][j];
3677 if ((bmap & 1) && *p) {
3678 mark_func (p, gc_data);
3688 * mono_alloc_static_data
3690 * Allocate memory blocks for storing threads or context static data
3693 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3695 guint idx = (offset >> 24) - 1;
3698 gpointer* static_data = *static_data_ptr;
3700 static void* tls_desc = NULL;
3701 if (mono_gc_user_markers_supported () && !tls_desc)
3702 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3703 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3704 *static_data_ptr = static_data;
3705 static_data [0] = static_data;
3708 for (i = 1; i <= idx; ++i) {
3709 if (static_data [i])
3711 if (mono_gc_user_markers_supported () && threadlocal)
3712 static_data [i] = g_malloc0 (static_data_size [i]);
3714 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3719 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3722 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3723 gpointer p = static_data [i];
3727 * At this point, the static data pointer array is still registered with the
3728 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3729 * data. Freeing the individual arrays without first nulling their slots
3730 * would make it possible for mark_tls_slots() to encounter a pointer to
3731 * such an already freed array. See bug #13813.
3733 static_data [i] = NULL;
3734 mono_memory_write_barrier ();
3735 if (mono_gc_user_markers_supported () && threadlocal)
3738 mono_gc_free_fixed (p);
3740 mono_gc_free_fixed (static_data);
3744 * mono_init_static_data_info
3746 * Initializes static data counters
3748 static void mono_init_static_data_info (StaticDataInfo *static_data)
3750 static_data->idx = 0;
3751 static_data->offset = 0;
3752 static_data->freelist = NULL;
3756 * mono_alloc_static_data_slot
3758 * Generates an offset for static data. static_data contains the counters
3759 * used to generate it.
3762 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3766 if (!static_data->idx && !static_data->offset) {
3768 * we use the first chunk of the first allocation also as
3769 * an array for the rest of the data
3771 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3773 static_data->offset += align - 1;
3774 static_data->offset &= ~(align - 1);
3775 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3776 static_data->idx ++;
3777 g_assert (size <= static_data_size [static_data->idx]);
3778 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3779 static_data->offset = 0;
3781 offset = static_data->offset | ((static_data->idx + 1) << 24);
3782 static_data->offset += size;
3787 * ensure thread static fields already allocated are valid for thread
3788 * This function is called when a thread is created or on thread attach.
3791 thread_adjust_static_data (MonoInternalThread *thread)
3795 mono_threads_lock ();
3796 if (thread_static_info.offset || thread_static_info.idx > 0) {
3797 /* get the current allocated size */
3798 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3799 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3801 mono_threads_unlock ();
3805 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3807 MonoInternalThread *thread = value;
3808 guint32 offset = GPOINTER_TO_UINT (user);
3810 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3813 static MonoThreadDomainTls*
3814 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3816 MonoThreadDomainTls* prev = NULL;
3817 MonoThreadDomainTls* tmp = static_data->freelist;
3819 if (tmp->size == size) {
3821 prev->next = tmp->next;
3823 static_data->freelist = tmp->next;
3832 #if SIZEOF_VOID_P == 4
3839 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3842 int idx = (offset >> 24) - 1;
3844 if (!static_reference_bitmaps [idx])
3845 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3846 rb = static_reference_bitmaps [idx];
3848 offset /= sizeof (gpointer);
3849 /* offset is now the bitmap offset */
3850 for (i = 0; i < numbits; ++i) {
3851 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3852 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (ONE_P << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3857 clear_reference_bitmap (guint32 offset, guint32 size)
3859 int idx = (offset >> 24) - 1;
3861 rb = static_reference_bitmaps [idx];
3863 offset /= sizeof (gpointer);
3864 size /= sizeof (gpointer);
3866 /* offset is now the bitmap offset */
3867 for (; offset < size; ++offset)
3868 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3872 * The offset for a special static variable is composed of three parts:
3873 * a bit that indicates the type of static data (0:thread, 1:context),
3874 * an index in the array of chunks of memory for the thread (thread->static_data)
3875 * and an offset in that chunk of mem. This allows allocating less memory in the
3880 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3883 if (static_type == SPECIAL_STATIC_THREAD) {
3884 MonoThreadDomainTls *item;
3885 mono_threads_lock ();
3886 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3887 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3889 offset = item->offset;
3892 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3894 update_tls_reference_bitmap (offset, bitmap, numbits);
3895 /* This can be called during startup */
3896 if (threads != NULL)
3897 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3898 mono_threads_unlock ();
3900 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3901 mono_contexts_lock ();
3902 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3903 mono_contexts_unlock ();
3904 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3910 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3912 /* The high bit means either thread (0) or static (1) data. */
3914 guint32 static_type = (offset & 0x80000000);
3917 offset &= 0x7fffffff;
3918 idx = (offset >> 24) - 1;
3920 if (static_type == 0) {
3921 return get_thread_static_data (thread, offset);
3923 /* Allocate static data block under demand, since we don't have a list
3926 MonoAppContext *context = mono_context_get ();
3927 if (!context->static_data || !context->static_data [idx]) {
3928 mono_contexts_lock ();
3929 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3930 mono_contexts_unlock ();
3932 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3937 mono_get_special_static_data (guint32 offset)
3939 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3948 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3950 MonoInternalThread *thread = value;
3951 TlsOffsetSize *data = user;
3952 int idx = (data->offset >> 24) - 1;
3955 if (!thread->static_data || !thread->static_data [idx])
3957 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3958 mono_gc_bzero_atomic (ptr, data->size);
3962 do_free_special_slot (guint32 offset, guint32 size)
3964 guint32 static_type = (offset & 0x80000000);
3965 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3966 if (static_type == 0) {
3968 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3969 data.offset = offset & 0x7fffffff;
3971 clear_reference_bitmap (data.offset, data.size);
3972 if (threads != NULL)
3973 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3974 item->offset = offset;
3977 if (!mono_runtime_is_shutting_down ()) {
3978 item->next = thread_static_info.freelist;
3979 thread_static_info.freelist = item;
3981 /* We could be called during shutdown after mono_thread_cleanup () is called */
3985 /* FIXME: free context static data as well */
3990 do_free_special (gpointer key, gpointer value, gpointer data)
3992 MonoClassField *field = key;
3993 guint32 offset = GPOINTER_TO_UINT (value);
3996 size = mono_type_size (field->type, &align);
3997 do_free_special_slot (offset, size);
4001 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4003 mono_threads_lock ();
4004 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4005 mono_threads_unlock ();
4009 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4011 mono_threads_lock ();
4012 do_free_special_slot (offset, size);
4013 mono_threads_unlock ();
4017 * allocates room in the thread local area for storing an instance of the struct type
4018 * the allocation is kept track of in domain->tlsrec_list.
4021 mono_thread_alloc_tls (MonoReflectionType *type)
4023 MonoDomain *domain = mono_domain_get ();
4025 MonoTlsDataRecord *tlsrec;
4028 gsize default_bitmap [4] = {0};
4029 uint32_t tls_offset;
4033 klass = mono_class_from_mono_type (type->type);
4034 /* TlsDatum is a struct, so we subtract the object header size offset */
4035 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
4036 size = mono_type_size (type->type, &align);
4037 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
4038 if (bitmap != default_bitmap)
4040 tlsrec = g_new0 (MonoTlsDataRecord, 1);
4041 tlsrec->tls_offset = tls_offset;
4042 tlsrec->size = size;
4043 mono_domain_lock (domain);
4044 tlsrec->next = domain->tlsrec_list;
4045 domain->tlsrec_list = tlsrec;
4046 mono_domain_unlock (domain);
4051 destroy_tls (MonoDomain *domain, uint32_t tls_offset)
4053 MonoTlsDataRecord *prev = NULL;
4054 MonoTlsDataRecord *cur;
4057 mono_domain_lock (domain);
4058 cur = domain->tlsrec_list;
4060 if (cur->tls_offset == tls_offset) {
4062 prev->next = cur->next;
4064 domain->tlsrec_list = cur->next;
4072 mono_domain_unlock (domain);
4074 mono_special_static_data_free_slot (tls_offset, size);
4078 mono_thread_destroy_tls (uint32_t tls_offset)
4080 destroy_tls (mono_domain_get (), tls_offset);
4084 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
4087 mono_thread_destroy_domain_tls (MonoDomain *domain)
4089 while (domain->tlsrec_list)
4090 destroy_tls (domain, domain->tlsrec_list->tls_offset);
4093 static MonoClassField *local_slots = NULL;
4096 /* local tls data to get locals_slot from a thread */
4099 /* index in the locals_slot array */
4104 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4106 LocalSlotID *sid = user_data;
4107 MonoInternalThread *thread = (MonoInternalThread*)value;
4108 MonoArray *slots_array;
4110 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4111 * it is for the right domain, so we need to check if it is allocated an initialized
4112 * for the current thread.
4114 /*g_print ("handling thread %p\n", thread);*/
4115 if (!thread->static_data || !thread->static_data [sid->idx])
4117 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4118 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4120 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4124 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4132 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4134 g_warning ("local_slots field not found in Thread class");
4138 domain = mono_domain_get ();
4139 mono_domain_lock (domain);
4140 if (domain->special_static_fields)
4141 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4142 mono_domain_unlock (domain);
4145 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4146 sid.offset = GPOINTER_TO_UINT (addr);
4147 sid.offset &= 0x7fffffff;
4148 sid.idx = (sid.offset >> 24) - 1;
4149 mono_threads_lock ();
4150 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4151 mono_threads_unlock ();
4153 /* FIXME: clear the slot for MonoAppContexts, too */
4158 static void CALLBACK dummy_apc (ULONG_PTR param)
4164 * mono_thread_execute_interruption
4166 * Performs the operation that the requested thread state requires (abort,
4169 static MonoException*
4170 mono_thread_execute_interruption (MonoInternalThread *thread)
4172 LOCK_THREAD (thread);
4174 /* MonoThread::interruption_requested can only be changed with atomics */
4175 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4176 /* this will consume pending APC calls */
4178 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4180 InterlockedDecrement (&thread_interruption_requested);
4181 /* Clear the interrupted flag of the thread so it can wait again */
4182 mono_thread_info_clear_interruption ();
4185 if ((thread->state & ThreadState_AbortRequested) != 0) {
4186 UNLOCK_THREAD (thread);
4187 if (thread->abort_exc == NULL) {
4189 * This might be racy, but it has to be called outside the lock
4190 * since it calls managed code.
4192 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4194 return thread->abort_exc;
4196 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4197 self_suspend_internal (thread);
4200 else if ((thread->state & ThreadState_StopRequested) != 0) {
4201 /* FIXME: do this through the JIT? */
4203 UNLOCK_THREAD (thread);
4205 mono_thread_exit ();
4207 } else if (thread->pending_exception) {
4210 exc = thread->pending_exception;
4211 thread->pending_exception = NULL;
4213 UNLOCK_THREAD (thread);
4215 } else if (thread->thread_interrupt_requested) {
4217 thread->thread_interrupt_requested = FALSE;
4218 UNLOCK_THREAD (thread);
4220 return(mono_get_exception_thread_interrupted ());
4223 UNLOCK_THREAD (thread);
4229 * mono_thread_request_interruption
4231 * A signal handler can call this method to request the interruption of a
4232 * thread. The result of the interruption will depend on the current state of
4233 * the thread. If the result is an exception that needs to be throw, it is
4234 * provided as return value.
4237 mono_thread_request_interruption (gboolean running_managed)
4239 MonoInternalThread *thread = mono_thread_internal_current ();
4241 /* The thread may already be stopping */
4246 if (thread->interrupt_on_stop &&
4247 thread->state & ThreadState_StopRequested &&
4248 thread->state & ThreadState_Background)
4252 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4254 InterlockedIncrement (&thread_interruption_requested);
4256 if (!running_managed || is_running_protected_wrapper ()) {
4257 /* Can't stop while in unmanaged code. Increase the global interruption
4258 request count. When exiting the unmanaged method the count will be
4259 checked and the thread will be interrupted. */
4261 if (mono_thread_notify_pending_exc_fn && !running_managed)
4262 /* The JIT will notify the thread about the interruption */
4263 /* This shouldn't take any locks */
4264 mono_thread_notify_pending_exc_fn (NULL);
4266 /* this will awake the thread if it is in WaitForSingleObject
4268 /* Our implementation of this function ignores the func argument */
4270 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4272 mono_thread_info_self_interrupt ();
4277 return mono_thread_execute_interruption (thread);
4281 /*This function should be called by a thread after it has exited all of
4282 * its handle blocks at interruption time.*/
4284 mono_thread_resume_interruption (void)
4286 MonoInternalThread *thread = mono_thread_internal_current ();
4287 gboolean still_aborting;
4289 /* The thread may already be stopping */
4293 LOCK_THREAD (thread);
4294 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4295 UNLOCK_THREAD (thread);
4297 /*This can happen if the protected block called Thread::ResetAbort*/
4298 if (!still_aborting)
4301 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4303 InterlockedIncrement (&thread_interruption_requested);
4305 mono_thread_info_self_interrupt ();
4307 return mono_thread_execute_interruption (thread);
4310 gboolean mono_thread_interruption_requested ()
4312 if (thread_interruption_requested) {
4313 MonoInternalThread *thread = mono_thread_internal_current ();
4314 /* The thread may already be stopping */
4316 return (thread->interruption_requested);
4321 static MonoException*
4322 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4324 MonoInternalThread *thread = mono_thread_internal_current ();
4326 /* The thread may already be stopping */
4330 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4331 MonoException* exc = mono_thread_execute_interruption (thread);
4339 * Performs the interruption of the current thread, if one has been requested,
4340 * and the thread is not running a protected wrapper.
4341 * Return the exception which needs to be thrown, if any.
4344 mono_thread_interruption_checkpoint (void)
4346 return mono_thread_interruption_checkpoint_request (FALSE);
4350 * Performs the interruption of the current thread, if one has been requested.
4351 * Return the exception which needs to be thrown, if any.
4354 mono_thread_force_interruption_checkpoint_noraise (void)
4356 return mono_thread_interruption_checkpoint_request (TRUE);
4360 * Performs the interruption of the current thread, if one has been requested.
4361 * Throw the exception which needs to be thrown, if any.
4364 mono_thread_force_interruption_checkpoint (void)
4368 ex = mono_thread_interruption_checkpoint_request (TRUE);
4370 mono_raise_exception (ex);
4374 * mono_thread_get_and_clear_pending_exception:
4376 * Return any pending exceptions for the current thread and clear it as a side effect.
4379 mono_thread_get_and_clear_pending_exception (void)
4381 MonoInternalThread *thread = mono_thread_internal_current ();
4383 /* The thread may already be stopping */
4387 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4388 return mono_thread_execute_interruption (thread);
4391 if (thread->pending_exception) {
4392 MonoException *exc = thread->pending_exception;
4394 thread->pending_exception = NULL;
4402 * mono_set_pending_exception:
4404 * Set the pending exception of the current thread to EXC.
4405 * The exception will be thrown when execution returns to managed code.
4408 mono_set_pending_exception (MonoException *exc)
4410 MonoInternalThread *thread = mono_thread_internal_current ();
4412 /* The thread may already be stopping */
4416 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4418 mono_thread_request_interruption (FALSE);
4422 * mono_thread_interruption_request_flag:
4424 * Returns the address of a flag that will be non-zero if an interruption has
4425 * been requested for a thread. The thread to interrupt may not be the current
4426 * thread, so an additional call to mono_thread_interruption_requested() or
4427 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4430 gint32* mono_thread_interruption_request_flag ()
4432 return &thread_interruption_requested;
4436 mono_thread_init_apartment_state (void)
4439 MonoInternalThread* thread = mono_thread_internal_current ();
4441 /* Positive return value indicates success, either
4442 * S_OK if this is first CoInitialize call, or
4443 * S_FALSE if CoInitialize already called, but with same
4444 * threading model. A negative value indicates failure,
4445 * probably due to trying to change the threading model.
4447 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4448 ? COINIT_APARTMENTTHREADED
4449 : COINIT_MULTITHREADED) < 0) {
4450 thread->apartment_state = ThreadApartmentState_Unknown;
4456 mono_thread_cleanup_apartment_state (void)
4459 MonoInternalThread* thread = mono_thread_internal_current ();
4461 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4468 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4470 LOCK_THREAD (thread);
4471 thread->state |= state;
4472 UNLOCK_THREAD (thread);
4476 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4478 LOCK_THREAD (thread);
4479 thread->state &= ~state;
4480 UNLOCK_THREAD (thread);
4484 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4486 gboolean ret = FALSE;
4488 LOCK_THREAD (thread);
4490 if ((thread->state & test) != 0) {
4494 UNLOCK_THREAD (thread);
4499 //static MonoClassField *execution_context_field;
4502 get_execution_context_addr (void)
4504 MonoDomain *domain = mono_domain_get ();
4505 guint32 offset = domain->execution_context_field_offset;
4508 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4511 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4513 mono_domain_lock (domain);
4514 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4515 mono_domain_unlock (domain);
4518 domain->execution_context_field_offset = offset;
4521 return (MonoObject**) mono_get_special_static_data (offset);
4525 mono_thread_get_execution_context (void)
4527 return *get_execution_context_addr ();
4531 mono_thread_set_execution_context (MonoObject *ec)
4533 *get_execution_context_addr () = ec;
4536 static gboolean has_tls_get = FALSE;
4539 mono_runtime_set_has_tls_get (gboolean val)
4545 mono_runtime_has_tls_get (void)
4551 mono_thread_kill (MonoInternalThread *thread, int signal)
4553 #ifdef __native_client__
4554 /* Workaround pthread_kill abort() in NaCl glibc. */
4557 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
4558 /* Win32 uses QueueUserAPC and callers of this are guarded */
4559 g_assert_not_reached ();
4561 # ifdef PTHREAD_POINTER_ID
4562 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4564 # ifdef USE_TKILL_ON_ANDROID
4565 if (thread->android_tid != 0) {
4567 int old_errno = errno;
4569 ret = tkill ((pid_t) thread->android_tid, signal);
4578 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4580 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4587 self_interrupt_thread (void *_unused)
4589 MonoThreadInfo *info = mono_thread_info_current ();
4590 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4591 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4592 mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
4593 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4597 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4601 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4605 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4607 MonoJitInfo **dest = data;
4613 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4615 MonoJitInfo *ji = NULL;
4618 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4623 MonoInternalThread *thread;
4624 gboolean install_async_abort;
4625 gpointer interrupt_handle;
4628 static SuspendThreadResult
4629 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4631 AbortThreadData *data = ud;
4632 MonoInternalThread *thread = data->thread;
4633 MonoJitInfo *ji = NULL;
4634 gboolean protected_wrapper;
4635 gboolean running_managed;
4637 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4638 return MonoResumeThread;
4640 /*someone is already interrupting it*/
4641 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4642 return MonoResumeThread;
4644 InterlockedIncrement (&thread_interruption_requested);
4646 ji = mono_thread_info_get_last_managed (info);
4647 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4648 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4650 if (!protected_wrapper && running_managed) {
4651 /*We are in managed code*/
4652 /*Set the thread to call */
4653 if (data->install_async_abort)
4654 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4655 return MonoResumeThread;
4657 if (mono_thread_notify_pending_exc_fn)
4658 /* The JIT will notify the thread about the interruption */
4659 mono_thread_notify_pending_exc_fn (info);
4662 * This will cause waits to be broken.
4663 * It will also prevent the thread from entering a wait, so if the thread returns
4664 * from the wait before it receives the abort signal, it will just spin in the wait
4665 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4668 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4669 return MonoResumeThread;
4674 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4676 AbortThreadData data = { 0 };
4677 data.thread = thread;
4678 data.install_async_abort = install_async_abort;
4680 if (!mono_thread_info_new_interrupt_enabled ()) {
4681 signal_thread_state_change (thread);
4686 FIXME this is insanely broken, it doesn't cause interruption to happen
4687 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4689 if (thread == mono_thread_internal_current ()) {
4690 /* Do it synchronously */
4691 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4693 mono_raise_exception (exc);
4694 mono_thread_info_interrupt (thread->handle);
4698 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
4699 if (data.interrupt_handle)
4700 mono_thread_info_finish_interrupt (data.interrupt_handle);
4701 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4705 MonoInternalThread *thread;
4707 gpointer interrupt_handle;
4708 } SuspendThreadData;
4710 static SuspendThreadResult
4711 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4713 SuspendThreadData *data = ud;
4714 MonoInternalThread *thread = data->thread;
4715 MonoJitInfo *ji = NULL;
4716 gboolean protected_wrapper;
4717 gboolean running_managed;
4719 ji = mono_thread_info_get_last_managed (info);
4720 protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4721 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4723 if (running_managed && !protected_wrapper) {
4724 thread->state &= ~ThreadState_SuspendRequested;
4725 thread->state |= ThreadState_Suspended;
4726 return KeepSuspended;
4728 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4729 InterlockedIncrement (&thread_interruption_requested);
4730 if (data->interrupt)
4731 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4733 if (mono_thread_notify_pending_exc_fn && !running_managed)
4734 /* The JIT will notify the thread about the interruption */
4735 mono_thread_notify_pending_exc_fn (info);
4736 return MonoResumeThread;
4741 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4743 if (!mono_thread_info_new_interrupt_enabled ()) {
4744 signal_thread_state_change (thread);
4748 LOCK_THREAD (thread);
4749 if (thread == mono_thread_internal_current ()) {
4750 mono_thread_info_begin_self_suspend ();
4751 //XXX replace this with better named functions
4752 thread->state &= ~ThreadState_SuspendRequested;
4753 thread->state |= ThreadState_Suspended;
4754 UNLOCK_THREAD (thread);
4755 mono_thread_info_end_self_suspend ();
4757 SuspendThreadData data = { 0 };
4758 data.thread = thread;
4759 data.interrupt = interrupt;
4761 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
4762 if (data.interrupt_handle)
4763 mono_thread_info_finish_interrupt (data.interrupt_handle);
4764 UNLOCK_THREAD (thread);
4768 /*This is called with @thread synch_cs held and it must release it*/
4770 self_suspend_internal (MonoInternalThread *thread)
4772 if (!mono_thread_info_new_interrupt_enabled ()) {
4773 thread->state &= ~ThreadState_SuspendRequested;
4774 thread->state |= ThreadState_Suspended;
4775 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4776 if (thread->suspend_event == NULL) {
4777 UNLOCK_THREAD (thread);
4780 if (thread->suspended_event)
4781 SetEvent (thread->suspended_event);
4783 UNLOCK_THREAD (thread);
4785 if (shutting_down) {
4786 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4791 WaitForSingleObject (thread->suspend_event, INFINITE);
4793 LOCK_THREAD (thread);
4795 CloseHandle (thread->suspend_event);
4796 thread->suspend_event = NULL;
4797 thread->state &= ~ThreadState_Suspended;
4799 /* The thread that requested the resume will have replaced this event
4800 * and will be waiting for it
4802 SetEvent (thread->resume_event);
4804 UNLOCK_THREAD (thread);
4808 mono_thread_info_begin_self_suspend ();
4809 thread->state &= ~ThreadState_SuspendRequested;
4810 thread->state |= ThreadState_Suspended;
4811 UNLOCK_THREAD (thread);
4812 mono_thread_info_end_self_suspend ();
4815 /*This is called with @thread synch_cs held and it must release it*/
4817 resume_thread_internal (MonoInternalThread *thread)
4819 if (!mono_thread_info_new_interrupt_enabled ()) {
4820 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4821 if (thread->resume_event == NULL) {
4822 UNLOCK_THREAD (thread);
4826 /* Awake the thread */
4827 SetEvent (thread->suspend_event);
4829 UNLOCK_THREAD (thread);
4831 /* Wait for the thread to awake */
4832 WaitForSingleObject (thread->resume_event, INFINITE);
4833 CloseHandle (thread->resume_event);
4834 thread->resume_event = NULL;
4838 UNLOCK_THREAD (thread);
4839 /* Awake the thread */
4840 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4842 LOCK_THREAD (thread);
4843 thread->state &= ~ThreadState_Suspended;
4844 UNLOCK_THREAD (thread);
4850 * mono_thread_is_foreign:
4851 * @thread: the thread to query
4853 * This function allows one to determine if a thread was created by the mono runtime and has
4854 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4856 * Returns: true if @thread was not created by the runtime.
4859 mono_thread_is_foreign (MonoThread *thread)
4861 MonoThreadInfo *info = thread->internal_thread->thread_info;
4862 return info->runtime_thread == FALSE;
4866 * mono_add_joinable_thread:
4868 * Add TID to the list of joinable threads.
4869 * LOCKING: Acquires the threads lock.
4872 mono_threads_add_joinable_thread (gpointer tid)
4876 * We cannot detach from threads because it causes problems like
4877 * 2fd16f60/r114307. So we collect them and join them when
4878 * we have time (in he finalizer thread).
4880 joinable_threads_lock ();
4881 if (!joinable_threads)
4882 joinable_threads = g_hash_table_new (NULL, NULL);
4883 g_hash_table_insert (joinable_threads, tid, tid);
4884 joinable_thread_count ++;
4885 joinable_threads_unlock ();
4887 mono_gc_finalize_notify ();
4892 * mono_threads_join_threads:
4894 * Join all joinable threads. This is called from the finalizer thread.
4895 * LOCKING: Acquires the threads lock.
4898 mono_threads_join_threads (void)
4901 GHashTableIter iter;
4908 if (!joinable_thread_count)
4912 joinable_threads_lock ();
4914 if (g_hash_table_size (joinable_threads)) {
4915 g_hash_table_iter_init (&iter, joinable_threads);
4916 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4917 thread = (pthread_t)tid;
4918 g_hash_table_remove (joinable_threads, key);
4919 joinable_thread_count --;
4922 joinable_threads_unlock ();
4924 if (thread != pthread_self ())
4925 /* This shouldn't block */
4926 pthread_join (thread, NULL);
4937 * Wait for thread TID to exit.
4938 * LOCKING: Acquires the threads lock.
4941 mono_thread_join (gpointer tid)
4945 gboolean found = FALSE;
4947 joinable_threads_lock ();
4948 if (!joinable_threads)
4949 joinable_threads = g_hash_table_new (NULL, NULL);
4950 if (g_hash_table_lookup (joinable_threads, tid)) {
4951 g_hash_table_remove (joinable_threads, tid);
4952 joinable_thread_count --;
4955 joinable_threads_unlock ();
4958 thread = (pthread_t)tid;
4959 pthread_join (thread, NULL);