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 MONO_PREPARE_BLOCKING
844 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
847 CloseHandle (internal->start_notify);
848 internal->start_notify = NULL;
851 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
856 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
858 if (mono_thread_start_cb) {
859 mono_thread_start_cb (tid, stack_start, func);
863 void mono_threads_set_default_stacksize (guint32 stacksize)
865 default_stacksize = stacksize;
868 guint32 mono_threads_get_default_stacksize (void)
870 return default_stacksize;
874 * mono_thread_create_internal:
878 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
881 MonoInternalThread *internal;
882 StartInfo *start_info;
885 thread = create_thread_object (domain);
886 internal = create_internal_thread ();
887 MONO_OBJECT_SETREF (thread, internal_thread, internal);
889 start_info = g_new0 (StartInfo, 1);
890 start_info->func = func;
891 start_info->obj = thread;
892 start_info->start_arg = arg;
894 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
898 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
899 if (mono_check_corlib_version () == NULL)
900 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
906 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
908 mono_thread_create_internal (domain, func, arg, FALSE, 0);
912 mono_thread_attach (MonoDomain *domain)
914 return mono_thread_attach_full (domain, FALSE);
918 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
920 MonoThreadInfo *info;
921 MonoInternalThread *thread;
922 MonoThread *current_thread;
923 HANDLE thread_handle;
926 if ((thread = mono_thread_internal_current ())) {
927 if (domain != mono_domain_get ())
928 mono_domain_set (domain, TRUE);
929 /* Already attached */
930 return mono_thread_current ();
933 if (!mono_gc_register_thread (&domain)) {
934 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 ());
937 thread = create_internal_thread ();
939 thread_handle = mono_thread_info_open_handle ();
940 g_assert (thread_handle);
942 tid=GetCurrentThreadId ();
944 thread->handle=thread_handle;
946 #ifdef PLATFORM_ANDROID
947 thread->android_tid = (gpointer) gettid ();
949 thread->stack_ptr = &tid;
951 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
953 info = mono_thread_info_current ();
955 thread->thread_info = info;
956 thread->small_id = info->small_id;
958 current_thread = new_thread_with_internal (domain, thread);
960 if (!handle_store (current_thread, force_attach)) {
961 /* Mono is shutting down, so just wait for the end */
966 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
968 SET_CURRENT_OBJECT (thread);
969 mono_domain_set (domain, TRUE);
971 thread_adjust_static_data (thread);
973 init_root_domain_thread (thread, current_thread);
974 if (domain != mono_get_root_domain ())
975 set_current_thread_for_domain (domain, thread, current_thread);
978 if (mono_thread_attach_cb) {
982 mono_thread_info_get_stack_bounds (&staddr, &stsize);
985 mono_thread_attach_cb (tid, &tid);
987 mono_thread_attach_cb (tid, staddr + stsize);
990 // FIXME: Need a separate callback
991 mono_profiler_thread_start (tid);
993 return current_thread;
997 mono_thread_detach_internal (MonoInternalThread *thread)
999 g_return_if_fail (thread != NULL);
1001 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1003 thread_cleanup (thread);
1005 SET_CURRENT_OBJECT (NULL);
1006 mono_domain_unset ();
1008 /* Don't need to CloseHandle this thread, even though we took a
1009 * reference in mono_thread_attach (), because the GC will do it
1010 * when the Thread object is finalised.
1015 mono_thread_detach (MonoThread *thread)
1018 mono_thread_detach_internal (thread->internal_thread);
1022 * mono_thread_detach_if_exiting:
1024 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1025 * This should be used at the end of embedding code which calls into managed code, and which
1026 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1029 mono_thread_detach_if_exiting (void)
1031 if (mono_thread_info_is_exiting ()) {
1032 MonoInternalThread *thread;
1034 thread = mono_thread_internal_current ();
1036 mono_thread_detach_internal (thread);
1037 mono_thread_info_detach ();
1045 MonoInternalThread *thread = mono_thread_internal_current ();
1047 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1049 thread_cleanup (thread);
1050 SET_CURRENT_OBJECT (NULL);
1051 mono_domain_unset ();
1053 /* we could add a callback here for embedders to use. */
1054 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1055 exit (mono_environment_exitcode_get ());
1056 mono_thread_info_exit ();
1060 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1062 MonoInternalThread *internal = create_internal_thread ();
1064 internal->state = ThreadState_Unstarted;
1066 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1070 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
1073 StartInfo *start_info;
1074 MonoInternalThread *internal;
1077 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1079 if (!this->internal_thread)
1080 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1081 internal = this->internal_thread;
1083 LOCK_THREAD (internal);
1085 if ((internal->state & ThreadState_Unstarted) == 0) {
1086 UNLOCK_THREAD (internal);
1087 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1091 if ((internal->state & ThreadState_Aborted) != 0) {
1092 UNLOCK_THREAD (internal);
1095 /* This is freed in start_wrapper */
1096 start_info = g_new0 (StartInfo, 1);
1097 start_info->func = NULL;
1098 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1099 start_info->delegate = start;
1100 start_info->obj = this;
1101 g_assert (this->obj.vtable->domain == mono_domain_get ());
1103 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1105 UNLOCK_THREAD (internal);
1109 internal->state &= ~ThreadState_Unstarted;
1111 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1113 UNLOCK_THREAD (internal);
1114 return internal->handle;
1118 * This is called from the finalizer of the internal thread object.
1121 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1123 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1126 * Since threads keep a reference to their thread object while running, by the time this function is called,
1127 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1128 * when thread_cleanup () can be called after this.
1131 CloseHandle (thread);
1133 if (this->synch_cs) {
1134 mono_mutex_t *synch_cs = this->synch_cs;
1135 this->synch_cs = NULL;
1136 mono_mutex_destroy (synch_cs);
1141 void *name = this->name;
1148 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1151 MonoInternalThread *thread = mono_thread_internal_current ();
1153 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1155 mono_thread_current_check_pending_interrupt ();
1158 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1160 MONO_PREPARE_BLOCKING
1161 res = SleepEx(ms,TRUE);
1162 MONO_FINISH_BLOCKING
1164 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1166 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1167 MonoException* exc = mono_thread_execute_interruption (thread);
1169 mono_raise_exception (exc);
1181 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1186 ves_icall_System_Threading_Thread_GetDomainID (void)
1188 return mono_domain_get()->domain_id;
1192 ves_icall_System_Threading_Thread_Yield (void)
1194 return mono_thread_info_yield ();
1198 * mono_thread_get_name:
1200 * Return the name of the thread. NAME_LEN is set to the length of the name.
1201 * Return NULL if the thread has no name. The returned memory is owned by the
1205 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1209 LOCK_THREAD (this_obj);
1211 if (!this_obj->name) {
1215 *name_len = this_obj->name_len;
1216 res = g_new (gunichar2, this_obj->name_len);
1217 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1220 UNLOCK_THREAD (this_obj);
1226 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1230 LOCK_THREAD (this_obj);
1232 if (!this_obj->name)
1235 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1237 UNLOCK_THREAD (this_obj);
1243 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1245 LOCK_THREAD (this_obj);
1247 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1248 UNLOCK_THREAD (this_obj);
1250 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1253 if (this_obj->name) {
1254 g_free (this_obj->name);
1255 this_obj->name_len = 0;
1258 this_obj->name = g_new (gunichar2, mono_string_length (name));
1259 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1260 this_obj->name_len = mono_string_length (name);
1263 this_obj->name = NULL;
1266 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1268 UNLOCK_THREAD (this_obj);
1270 if (this_obj->name && this_obj->tid) {
1271 char *tname = mono_string_to_utf8 (name);
1272 mono_profiler_thread_name (this_obj->tid, tname);
1273 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1279 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1281 mono_thread_set_name_internal (this_obj, name, TRUE);
1285 ves_icall_System_Threading_Thread_GetPriority (MonoInternalThread *thread)
1287 return ThreadPriority_Lowest;
1291 ves_icall_System_Threading_Thread_SetPriority (MonoInternalThread *thread, int priority)
1295 /* If the array is already in the requested domain, we just return it,
1296 otherwise we return a copy in that domain. */
1298 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1305 if (mono_object_domain (arr) == domain)
1308 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1309 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1314 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1316 return byte_array_to_domain (arr, mono_get_root_domain ());
1320 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1322 return byte_array_to_domain (arr, mono_domain_get ());
1326 mono_thread_current (void)
1328 MonoDomain *domain = mono_domain_get ();
1329 MonoInternalThread *internal = mono_thread_internal_current ();
1330 MonoThread **current_thread_ptr;
1332 g_assert (internal);
1333 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1335 if (!*current_thread_ptr) {
1336 g_assert (domain != mono_get_root_domain ());
1337 *current_thread_ptr = new_thread_with_internal (domain, internal);
1339 return *current_thread_ptr;
1343 mono_thread_internal_current (void)
1345 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1346 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1351 ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1352 int ms, HANDLE thread)
1354 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1357 mono_thread_current_check_pending_interrupt ();
1361 if ((this->state & ThreadState_Unstarted) != 0) {
1362 UNLOCK_THREAD (this);
1364 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1368 UNLOCK_THREAD (this);
1373 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1375 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1377 MONO_PREPARE_BLOCKING
1378 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1379 MONO_FINISH_BLOCKING
1381 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1383 if(ret==WAIT_OBJECT_0) {
1384 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1389 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1395 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1403 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1405 MONO_PREPARE_BLOCKING
1407 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1409 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1410 MONO_FINISH_BLOCKING
1412 if (ret != WAIT_IO_COMPLETION)
1415 exc = mono_thread_execute_interruption (thread);
1417 mono_raise_exception (exc);
1422 /* Re-calculate ms according to the time passed */
1423 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1424 if (diff_ms >= ms) {
1428 wait = ms - diff_ms;
1434 /* FIXME: exitContext isnt documented */
1435 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1441 MonoObject *waitHandle;
1442 MonoInternalThread *thread = mono_thread_internal_current ();
1444 /* Do this WaitSleepJoin check before creating objects */
1445 mono_thread_current_check_pending_interrupt ();
1447 /* We fail in managed if the array has more than 64 elements */
1448 numhandles = (guint32)mono_array_length(mono_handles);
1449 handles = g_new0(HANDLE, numhandles);
1451 for(i = 0; i < numhandles; i++) {
1452 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1453 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1460 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1462 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1464 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1468 if(ret==WAIT_FAILED) {
1469 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1471 } else if(ret==WAIT_TIMEOUT) {
1472 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1479 /* FIXME: exitContext isnt documented */
1480 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1482 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1483 uintptr_t numhandles;
1486 MonoObject *waitHandle;
1487 MonoInternalThread *thread = mono_thread_internal_current ();
1489 /* Do this WaitSleepJoin check before creating objects */
1490 mono_thread_current_check_pending_interrupt ();
1492 numhandles = mono_array_length(mono_handles);
1493 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1496 for(i = 0; i < numhandles; i++) {
1497 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1498 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1505 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1507 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1509 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1511 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1514 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1516 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1517 return ret - WAIT_OBJECT_0;
1519 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1520 return ret - WAIT_ABANDONED_0;
1527 /* FIXME: exitContext isnt documented */
1528 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1531 MonoInternalThread *thread = mono_thread_internal_current ();
1533 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1539 mono_thread_current_check_pending_interrupt ();
1541 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1543 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1545 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1547 if(ret==WAIT_FAILED) {
1548 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1550 } else if(ret==WAIT_TIMEOUT) {
1551 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1559 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1562 MonoInternalThread *thread = mono_thread_internal_current ();
1567 mono_thread_current_check_pending_interrupt ();
1569 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1571 MONO_PREPARE_BLOCKING
1572 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1573 MONO_FINISH_BLOCKING
1575 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1577 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1580 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1587 mutex = CreateMutex (NULL, owned, NULL);
1589 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1591 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1599 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1600 return(ReleaseMutex (handle));
1603 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1609 *error = ERROR_SUCCESS;
1611 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1613 *error = GetLastError ();
1620 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1627 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1629 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1630 mono_string_chars (name));
1632 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1640 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1644 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1649 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1653 *error = ERROR_SUCCESS;
1655 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1657 *error = GetLastError ();
1663 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1670 event = CreateEvent (NULL, manual, initial, NULL);
1672 event = CreateEvent (NULL, manual, initial,
1673 mono_string_chars (name));
1675 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1683 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1684 return (SetEvent(handle));
1687 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1688 return (ResetEvent(handle));
1692 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1693 CloseHandle (handle);
1696 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1702 *error = ERROR_SUCCESS;
1704 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1706 *error = GetLastError ();
1712 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1714 return InterlockedIncrement (location);
1717 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1719 #if SIZEOF_VOID_P == 4
1720 if (G_UNLIKELY ((size_t)location & 0x7)) {
1722 mono_interlocked_lock ();
1725 mono_interlocked_unlock ();
1729 return InterlockedIncrement64 (location);
1732 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1734 return InterlockedDecrement(location);
1737 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1739 #if SIZEOF_VOID_P == 4
1740 if (G_UNLIKELY ((size_t)location & 0x7)) {
1742 mono_interlocked_lock ();
1745 mono_interlocked_unlock ();
1749 return InterlockedDecrement64 (location);
1752 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1754 return InterlockedExchange(location, value);
1757 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1760 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1761 mono_gc_wbarrier_generic_nostore (location);
1765 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1767 return InterlockedExchangePointer(location, value);
1770 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1772 IntFloatUnion val, ret;
1775 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1781 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1783 #if SIZEOF_VOID_P == 4
1784 if (G_UNLIKELY ((size_t)location & 0x7)) {
1786 mono_interlocked_lock ();
1789 mono_interlocked_unlock ();
1793 return InterlockedExchange64 (location, value);
1797 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1799 LongDoubleUnion val, ret;
1802 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1807 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1809 return InterlockedCompareExchange(location, value, comparand);
1812 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1814 gint32 r = InterlockedCompareExchange(location, value, comparand);
1815 *success = r == comparand;
1819 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1822 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1823 mono_gc_wbarrier_generic_nostore (location);
1827 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1829 return InterlockedCompareExchangePointer(location, value, comparand);
1832 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1834 IntFloatUnion val, ret, cmp;
1837 cmp.fval = comparand;
1838 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1844 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1846 #if SIZEOF_VOID_P == 8
1847 LongDoubleUnion val, comp, ret;
1850 comp.fval = comparand;
1851 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1857 mono_interlocked_lock ();
1859 if (old == comparand)
1861 mono_interlocked_unlock ();
1868 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1870 #if SIZEOF_VOID_P == 4
1871 if (G_UNLIKELY ((size_t)location & 0x7)) {
1873 mono_interlocked_lock ();
1875 if (old == comparand)
1877 mono_interlocked_unlock ();
1881 return InterlockedCompareExchange64 (location, value, comparand);
1885 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1888 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1889 mono_gc_wbarrier_generic_nostore (location);
1894 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1897 res = InterlockedExchangePointer ((gpointer *)location, value);
1898 mono_gc_wbarrier_generic_nostore (location);
1903 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1905 return InterlockedAdd (location, value);
1909 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1911 #if SIZEOF_VOID_P == 4
1912 if (G_UNLIKELY ((size_t)location & 0x7)) {
1914 mono_interlocked_lock ();
1917 mono_interlocked_unlock ();
1921 return InterlockedAdd64 (location, value);
1925 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1927 #if SIZEOF_VOID_P == 4
1928 if (G_UNLIKELY ((size_t)location & 0x7)) {
1930 mono_interlocked_lock ();
1932 mono_interlocked_unlock ();
1936 return InterlockedRead64 (location);
1940 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1942 mono_memory_barrier ();
1946 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1948 mono_thread_clr_state (this, state);
1950 if (state & ThreadState_Background) {
1951 /* If the thread changes the background mode, the main thread has to
1952 * be notified, since it has to rebuild the list of threads to
1955 SetEvent (background_change_event);
1960 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1962 mono_thread_set_state (this, state);
1964 if (state & ThreadState_Background) {
1965 /* If the thread changes the background mode, the main thread has to
1966 * be notified, since it has to rebuild the list of threads to
1969 SetEvent (background_change_event);
1974 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1980 state = this->state;
1982 UNLOCK_THREAD (this);
1987 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
1989 MonoInternalThread *current;
1994 current = mono_thread_internal_current ();
1996 this->thread_interrupt_requested = TRUE;
1997 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
1999 UNLOCK_THREAD (this);
2002 abort_thread_internal (this, TRUE, FALSE);
2006 void mono_thread_current_check_pending_interrupt ()
2008 MonoInternalThread *thread = mono_thread_internal_current ();
2009 gboolean throw = FALSE;
2011 LOCK_THREAD (thread);
2013 if (thread->thread_interrupt_requested) {
2015 thread->thread_interrupt_requested = FALSE;
2018 UNLOCK_THREAD (thread);
2021 mono_raise_exception (mono_get_exception_thread_interrupted ());
2026 mono_thread_get_abort_signal (void)
2028 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
2030 #elif defined(PLATFORM_ANDROID)
2032 #elif !defined (SIGRTMIN)
2037 #endif /* SIGUSR1 */
2039 static int abort_signum = -1;
2041 if (abort_signum != -1)
2042 return abort_signum;
2043 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2044 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2045 struct sigaction sinfo;
2046 sigaction (i, NULL, &sinfo);
2047 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2052 /* fallback to the old way */
2054 #endif /* HOST_WIN32 */
2058 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2060 MonoException* exc = mono_thread_request_interruption (FALSE);
2061 if (exc) mono_raise_exception (exc);
2063 #endif /* HOST_WIN32 */
2066 * signal_thread_state_change
2068 * Tells the thread that his state has changed and it has to enter the new
2069 * state as soon as possible.
2071 static void signal_thread_state_change (MonoInternalThread *thread)
2074 gpointer wait_handle;
2077 if (thread == mono_thread_internal_current ()) {
2078 /* Do it synchronously */
2079 MonoException *exc = mono_thread_request_interruption (FALSE);
2081 mono_raise_exception (exc);
2085 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, (ULONG_PTR)NULL);
2088 * This will cause waits to be broken.
2089 * It will also prevent the thread from entering a wait, so if the thread returns
2090 * from the wait before it receives the abort signal, it will just spin in the wait
2091 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2094 wait_handle = mono_thread_info_prepare_interrupt (thread->handle);
2096 /* fixme: store the state somewhere */
2097 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2099 mono_thread_info_finish_interrupt (wait_handle);
2100 #endif /* HOST_WIN32 */
2104 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2106 LOCK_THREAD (thread);
2108 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2109 (thread->state & ThreadState_StopRequested) != 0 ||
2110 (thread->state & ThreadState_Stopped) != 0)
2112 UNLOCK_THREAD (thread);
2116 if ((thread->state & ThreadState_Unstarted) != 0) {
2117 thread->state |= ThreadState_Aborted;
2118 UNLOCK_THREAD (thread);
2122 thread->state |= ThreadState_AbortRequested;
2123 if (thread->abort_state_handle)
2124 mono_gchandle_free (thread->abort_state_handle);
2126 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2127 g_assert (thread->abort_state_handle);
2129 thread->abort_state_handle = 0;
2131 thread->abort_exc = NULL;
2134 * abort_exc is set in mono_thread_execute_interruption(),
2135 * triggered by the call to signal_thread_state_change(),
2136 * below. There's a point between where we have
2137 * abort_state_handle set, but abort_exc NULL, but that's not
2141 UNLOCK_THREAD (thread);
2143 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2145 /* During shutdown, we can't wait for other threads */
2147 /* Make sure the thread is awake */
2148 mono_thread_resume (thread);
2150 abort_thread_internal (thread, TRUE, TRUE);
2154 ves_icall_System_Threading_Thread_ResetAbort (void)
2156 MonoInternalThread *thread = mono_thread_internal_current ();
2157 gboolean was_aborting;
2159 LOCK_THREAD (thread);
2160 was_aborting = thread->state & ThreadState_AbortRequested;
2161 thread->state &= ~ThreadState_AbortRequested;
2162 UNLOCK_THREAD (thread);
2164 if (!was_aborting) {
2165 const char *msg = "Unable to reset abort because no abort was requested";
2166 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2169 thread->abort_exc = NULL;
2170 if (thread->abort_state_handle) {
2171 mono_gchandle_free (thread->abort_state_handle);
2172 /* This is actually not necessary - the handle
2173 only counts if the exception is set */
2174 thread->abort_state_handle = 0;
2179 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2181 LOCK_THREAD (thread);
2183 thread->state &= ~ThreadState_AbortRequested;
2185 if (thread->abort_exc) {
2186 thread->abort_exc = NULL;
2187 if (thread->abort_state_handle) {
2188 mono_gchandle_free (thread->abort_state_handle);
2189 /* This is actually not necessary - the handle
2190 only counts if the exception is set */
2191 thread->abort_state_handle = 0;
2195 UNLOCK_THREAD (thread);
2199 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2201 MonoInternalThread *thread = this->internal_thread;
2202 MonoObject *state, *deserialized = NULL, *exc;
2205 if (!thread->abort_state_handle)
2208 state = mono_gchandle_get_target (thread->abort_state_handle);
2211 domain = mono_domain_get ();
2212 if (mono_object_domain (state) == domain)
2215 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2217 if (!deserialized) {
2218 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2220 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2221 mono_set_pending_exception (invalid_op_exc);
2225 return deserialized;
2229 mono_thread_suspend (MonoInternalThread *thread)
2231 LOCK_THREAD (thread);
2233 if ((thread->state & ThreadState_Unstarted) != 0 ||
2234 (thread->state & ThreadState_Aborted) != 0 ||
2235 (thread->state & ThreadState_Stopped) != 0)
2237 UNLOCK_THREAD (thread);
2241 if ((thread->state & ThreadState_Suspended) != 0 ||
2242 (thread->state & ThreadState_SuspendRequested) != 0 ||
2243 (thread->state & ThreadState_StopRequested) != 0)
2245 UNLOCK_THREAD (thread);
2249 thread->state |= ThreadState_SuspendRequested;
2251 UNLOCK_THREAD (thread);
2253 suspend_thread_internal (thread, FALSE);
2258 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2260 if (!mono_thread_suspend (thread)) {
2261 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2267 mono_thread_resume (MonoInternalThread *thread)
2269 LOCK_THREAD (thread);
2271 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2272 thread->state &= ~ThreadState_SuspendRequested;
2273 UNLOCK_THREAD (thread);
2277 if ((thread->state & ThreadState_Suspended) == 0 ||
2278 (thread->state & ThreadState_Unstarted) != 0 ||
2279 (thread->state & ThreadState_Aborted) != 0 ||
2280 (thread->state & ThreadState_Stopped) != 0)
2282 UNLOCK_THREAD (thread);
2286 return resume_thread_internal (thread);
2290 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2292 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2293 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2299 mono_threads_is_critical_method (MonoMethod *method)
2301 switch (method->wrapper_type) {
2302 case MONO_WRAPPER_RUNTIME_INVOKE:
2303 case MONO_WRAPPER_XDOMAIN_INVOKE:
2304 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2311 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2316 if (mono_threads_is_critical_method (m)) {
2317 *((gboolean*)data) = TRUE;
2324 is_running_protected_wrapper (void)
2326 gboolean found = FALSE;
2327 mono_stack_walk (find_wrapper, &found);
2331 void mono_thread_internal_stop (MonoInternalThread *thread)
2333 LOCK_THREAD (thread);
2335 if ((thread->state & ThreadState_StopRequested) != 0 ||
2336 (thread->state & ThreadState_Stopped) != 0)
2338 UNLOCK_THREAD (thread);
2342 /* Make sure the thread is awake */
2343 mono_thread_resume (thread);
2345 thread->state |= ThreadState_StopRequested;
2346 thread->state &= ~ThreadState_AbortRequested;
2348 UNLOCK_THREAD (thread);
2350 abort_thread_internal (thread, TRUE, TRUE);
2353 void mono_thread_stop (MonoThread *thread)
2355 mono_thread_internal_stop (thread->internal_thread);
2359 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2362 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2367 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2370 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2375 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2378 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2383 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2386 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2391 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2394 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2395 return (void *) tmp;
2399 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2401 volatile MonoObject *tmp;
2402 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2403 return (MonoObject *) tmp;
2407 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2410 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2415 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2418 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2423 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2425 return InterlockedRead8 (ptr);
2429 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2431 return InterlockedRead16 (ptr);
2435 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2437 return InterlockedRead (ptr);
2441 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2443 #if SIZEOF_VOID_P == 4
2444 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2446 mono_interlocked_lock ();
2447 val = *(gint64*)ptr;
2448 mono_interlocked_unlock ();
2452 return InterlockedRead64 (ptr);
2456 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2458 return InterlockedReadPointer (ptr);
2462 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2466 #if SIZEOF_VOID_P == 4
2467 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2469 mono_interlocked_lock ();
2470 val = *(double*)ptr;
2471 mono_interlocked_unlock ();
2476 u.ival = InterlockedRead64 (ptr);
2482 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2486 u.ival = InterlockedRead (ptr);
2492 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2494 return InterlockedReadPointer (ptr);
2498 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2500 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2504 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2506 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2510 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2512 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2516 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2518 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2522 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2524 mono_atomic_store_release ((volatile void **) ptr, value);
2528 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2530 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2534 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2536 mono_atomic_store_release ((volatile double *) ptr, value);
2540 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2542 mono_atomic_store_release ((volatile float *) ptr, value);
2546 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2548 InterlockedWrite8 (ptr, value);
2552 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2554 InterlockedWrite16 (ptr, value);
2558 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2560 InterlockedWrite (ptr, value);
2564 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2566 #if SIZEOF_VOID_P == 4
2567 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2568 mono_interlocked_lock ();
2569 *(gint64*)ptr = value;
2570 mono_interlocked_unlock ();
2575 InterlockedWrite64 (ptr, value);
2579 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2581 InterlockedWritePointer (ptr, value);
2585 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2589 #if SIZEOF_VOID_P == 4
2590 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2591 mono_interlocked_lock ();
2592 *(double*)ptr = value;
2593 mono_interlocked_unlock ();
2600 InterlockedWrite64 (ptr, u.ival);
2604 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2610 InterlockedWrite (ptr, u.ival);
2614 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2616 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2620 mono_thread_init_tls (void)
2622 MONO_FAST_TLS_INIT (tls_current_object);
2623 mono_native_tls_alloc (¤t_object_key, NULL);
2626 void mono_thread_init (MonoThreadStartCB start_cb,
2627 MonoThreadAttachCB attach_cb)
2629 mono_mutex_init_recursive(&threads_mutex);
2630 mono_mutex_init_recursive(&interlocked_mutex);
2631 mono_mutex_init_recursive(&contexts_mutex);
2632 mono_mutex_init_recursive(&joinable_threads_mutex);
2634 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2635 g_assert(background_change_event != NULL);
2637 mono_init_static_data_info (&thread_static_info);
2638 mono_init_static_data_info (&context_static_info);
2640 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2642 mono_thread_start_cb = start_cb;
2643 mono_thread_attach_cb = attach_cb;
2645 /* Get a pseudo handle to the current process. This is just a
2646 * kludge so that wapi can build a process handle if needed.
2647 * As a pseudo handle is returned, we don't need to clean
2650 GetCurrentProcess ();
2653 void mono_thread_cleanup (void)
2655 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2656 MonoThreadInfo *info;
2658 /* The main thread must abandon any held mutexes (particularly
2659 * important for named mutexes as they are shared across
2660 * processes, see bug 74680.) This will happen when the
2661 * thread exits, but if it's not running in a subthread it
2662 * won't exit in time.
2664 info = mono_thread_info_current ();
2665 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2669 /* This stuff needs more testing, it seems one of these
2670 * critical sections can be locked when mono_thread_cleanup is
2673 mono_mutex_destroy (&threads_mutex);
2674 mono_mutex_destroy (&interlocked_mutex);
2675 mono_mutex_destroy (&contexts_mutex);
2676 mono_mutex_destroy (&delayed_free_table_mutex);
2677 mono_mutex_destroy (&small_id_mutex);
2678 CloseHandle (background_change_event);
2681 mono_native_tls_free (current_object_key);
2685 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2687 mono_thread_cleanup_fn = func;
2691 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2693 thread->internal_thread->manage_callback = func;
2696 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2698 mono_thread_notify_pending_exc_fn = func;
2702 static void print_tids (gpointer key, gpointer value, gpointer user)
2704 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2705 * sizeof(uint) and a cast to uint would overflow
2707 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2708 * print this as a pointer.
2710 g_message ("Waiting for: %p", key);
2715 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2716 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2720 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2724 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2726 MONO_PREPARE_BLOCKING
2727 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2728 MONO_FINISH_BLOCKING
2730 if(ret==WAIT_FAILED) {
2731 /* See the comment in build_wait_tids() */
2732 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2736 for(i=0; i<wait->num; i++)
2737 CloseHandle (wait->handles[i]);
2739 if (ret == WAIT_TIMEOUT)
2742 for(i=0; i<wait->num; i++) {
2743 gsize tid = wait->threads[i]->tid;
2746 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2747 * it can still run io-layer etc. code. So wait for it to really exit.
2748 * FIXME: This won't join threads which are not in the joinable_hash yet.
2750 mono_thread_join ((gpointer)tid);
2752 mono_threads_lock ();
2753 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2754 /* This thread must have been killed, because
2755 * it hasn't cleaned itself up. (It's just
2756 * possible that the thread exited before the
2757 * parent thread had a chance to store the
2758 * handle, and now there is another pointer to
2759 * the already-exited thread stored. In this
2760 * case, we'll just get two
2761 * mono_profiler_thread_end() calls for the
2765 mono_threads_unlock ();
2766 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2767 thread_cleanup (wait->threads[i]);
2769 mono_threads_unlock ();
2774 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2776 guint32 i, ret, count;
2778 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2780 /* Add the thread state change event, so it wakes up if a thread changes
2781 * to background mode.
2784 if (count < MAXIMUM_WAIT_OBJECTS) {
2785 wait->handles [count] = background_change_event;
2789 MONO_PREPARE_BLOCKING
2790 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2791 MONO_FINISH_BLOCKING
2793 if(ret==WAIT_FAILED) {
2794 /* See the comment in build_wait_tids() */
2795 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2799 for(i=0; i<wait->num; i++)
2800 CloseHandle (wait->handles[i]);
2802 if (ret == WAIT_TIMEOUT)
2805 if (ret < wait->num) {
2806 gsize tid = wait->threads[ret]->tid;
2807 mono_threads_lock ();
2808 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2809 /* See comment in wait_for_tids about thread cleanup */
2810 mono_threads_unlock ();
2811 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2812 thread_cleanup (wait->threads [ret]);
2814 mono_threads_unlock ();
2818 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2820 struct wait_data *wait=(struct wait_data *)user;
2822 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2824 MonoInternalThread *thread=(MonoInternalThread *)value;
2826 /* Ignore background threads, we abort them later */
2827 /* Do not lock here since it is not needed and the caller holds threads_lock */
2828 if (thread->state & ThreadState_Background) {
2829 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2830 return; /* just leave, ignore */
2833 if (mono_gc_is_finalizer_internal_thread (thread)) {
2834 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2838 if (thread == mono_thread_internal_current ()) {
2839 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2843 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2844 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2848 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2849 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2853 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2854 if (handle == NULL) {
2855 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2859 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2860 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2861 wait->handles[wait->num]=handle;
2862 wait->threads[wait->num]=thread;
2865 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2867 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2872 /* Just ignore the rest, we can't do anything with
2879 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2881 struct wait_data *wait=(struct wait_data *)user;
2882 gsize self = GetCurrentThreadId ();
2883 MonoInternalThread *thread = value;
2886 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2889 /* The finalizer thread is not a background thread */
2890 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2891 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2893 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2897 /* printf ("A: %d\n", wait->num); */
2898 wait->handles[wait->num]=thread->handle;
2899 wait->threads[wait->num]=thread;
2902 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2903 mono_thread_internal_stop (thread);
2907 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2911 * mono_threads_set_shutting_down:
2913 * Is called by a thread that wants to shut down Mono. If the runtime is already
2914 * shutting down, the calling thread is suspended/stopped, and this function never
2918 mono_threads_set_shutting_down (void)
2920 MonoInternalThread *current_thread = mono_thread_internal_current ();
2922 mono_threads_lock ();
2924 if (shutting_down) {
2925 mono_threads_unlock ();
2927 /* Make sure we're properly suspended/stopped */
2929 LOCK_THREAD (current_thread);
2931 if ((current_thread->state & ThreadState_SuspendRequested) ||
2932 (current_thread->state & ThreadState_AbortRequested) ||
2933 (current_thread->state & ThreadState_StopRequested)) {
2934 UNLOCK_THREAD (current_thread);
2935 mono_thread_execute_interruption (current_thread);
2937 current_thread->state |= ThreadState_Stopped;
2938 UNLOCK_THREAD (current_thread);
2941 /*since we're killing the thread, unset the current domain.*/
2942 mono_domain_unset ();
2944 /* Wake up other threads potentially waiting for us */
2945 mono_thread_info_exit ();
2947 shutting_down = TRUE;
2949 /* Not really a background state change, but this will
2950 * interrupt the main thread if it is waiting for all
2951 * the other threads.
2953 SetEvent (background_change_event);
2955 mono_threads_unlock ();
2959 void mono_thread_manage (void)
2961 struct wait_data wait_data;
2962 struct wait_data *wait = &wait_data;
2964 memset (wait, 0, sizeof (struct wait_data));
2965 /* join each thread that's still running */
2966 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2968 mono_threads_lock ();
2970 THREAD_DEBUG (g_message("%s: No threads", __func__));
2971 mono_threads_unlock ();
2974 mono_threads_unlock ();
2977 mono_threads_lock ();
2978 if (shutting_down) {
2979 /* somebody else is shutting down */
2980 mono_threads_unlock ();
2983 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2984 mono_g_hash_table_foreach (threads, print_tids, NULL));
2986 ResetEvent (background_change_event);
2988 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2989 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2990 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2991 mono_threads_unlock ();
2993 /* Something to wait for */
2994 wait_for_tids_or_state_change (wait, INFINITE);
2996 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2997 } while(wait->num>0);
2999 /* Mono is shutting down, so just wait for the end */
3000 if (!mono_runtime_try_shutdown ()) {
3001 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3002 mono_thread_suspend (mono_thread_internal_current ());
3003 mono_thread_execute_interruption (mono_thread_internal_current ());
3007 * Remove everything but the finalizer thread and self.
3008 * Also abort all the background threads
3011 mono_threads_lock ();
3014 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3015 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3016 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3018 mono_threads_unlock ();
3020 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3022 /* Something to wait for */
3023 wait_for_tids (wait, INFINITE);
3025 } while (wait->num > 0);
3028 * give the subthreads a chance to really quit (this is mainly needed
3029 * to get correct user and system times from getrusage/wait/time(1)).
3030 * This could be removed if we avoid pthread_detach() and use pthread_join().
3032 mono_thread_info_yield ();
3035 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3037 MonoInternalThread *thread=(MonoInternalThread *)value;
3039 if(thread->tid != (gsize)user) {
3040 /*TerminateThread (thread->handle, -1);*/
3044 void mono_thread_abort_all_other_threads (void)
3046 gsize self = GetCurrentThreadId ();
3048 mono_threads_lock ();
3049 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3050 mono_g_hash_table_size (threads));
3051 mono_g_hash_table_foreach (threads, print_tids, NULL));
3053 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3055 mono_threads_unlock ();
3059 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3061 MonoInternalThread *thread = (MonoInternalThread*)value;
3062 struct wait_data *wait = (struct wait_data*)user_data;
3066 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3068 * This needs no locking.
3070 if ((thread->state & ThreadState_Suspended) != 0 ||
3071 (thread->state & ThreadState_Stopped) != 0)
3074 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3075 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3079 wait->handles [wait->num] = handle;
3080 wait->threads [wait->num] = thread;
3086 * mono_thread_suspend_all_other_threads:
3088 * Suspend all managed threads except the finalizer thread and this thread. It is
3089 * not possible to resume them later.
3091 void mono_thread_suspend_all_other_threads (void)
3093 struct wait_data wait_data;
3094 struct wait_data *wait = &wait_data;
3096 gsize self = GetCurrentThreadId ();
3098 guint32 eventidx = 0;
3099 gboolean starting, finished;
3101 memset (wait, 0, sizeof (struct wait_data));
3103 * The other threads could be in an arbitrary state at this point, i.e.
3104 * they could be starting up, shutting down etc. This means that there could be
3105 * threads which are not even in the threads hash table yet.
3109 * First we set a barrier which will be checked by all threads before they
3110 * are added to the threads hash table, and they will exit if the flag is set.
3111 * This ensures that no threads could be added to the hash later.
3112 * We will use shutting_down as the barrier for now.
3114 g_assert (shutting_down);
3117 * We make multiple calls to WaitForMultipleObjects since:
3118 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3119 * - some threads could exit without becoming suspended
3124 * Make a copy of the hashtable since we can't do anything with
3125 * threads while threads_mutex is held.
3128 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3129 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3130 mono_threads_lock ();
3131 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3132 mono_threads_unlock ();
3134 events = g_new0 (gpointer, wait->num);
3136 /* Get the suspended events that we'll be waiting for */
3137 for (i = 0; i < wait->num; ++i) {
3138 MonoInternalThread *thread = wait->threads [i];
3139 gboolean signal_suspend = FALSE;
3141 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3142 //CloseHandle (wait->handles [i]);
3143 wait->threads [i] = NULL; /* ignore this thread in next loop */
3147 LOCK_THREAD (thread);
3149 if (thread->suspended_event == NULL) {
3150 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3151 if (thread->suspended_event == NULL) {
3152 /* Forget this one and go on to the next */
3153 UNLOCK_THREAD (thread);
3158 if ((thread->state & ThreadState_Suspended) != 0 ||
3159 (thread->state & ThreadState_StopRequested) != 0 ||
3160 (thread->state & ThreadState_Stopped) != 0) {
3161 UNLOCK_THREAD (thread);
3162 CloseHandle (wait->handles [i]);
3163 wait->threads [i] = NULL; /* ignore this thread in next loop */
3167 if ((thread->state & ThreadState_SuspendRequested) == 0)
3168 signal_suspend = TRUE;
3170 events [eventidx++] = thread->suspended_event;
3172 /* Convert abort requests into suspend requests */
3173 if ((thread->state & ThreadState_AbortRequested) != 0)
3174 thread->state &= ~ThreadState_AbortRequested;
3176 thread->state |= ThreadState_SuspendRequested;
3178 UNLOCK_THREAD (thread);
3180 /* Signal the thread to suspend */
3181 if (mono_thread_info_new_interrupt_enabled ())
3182 suspend_thread_internal (thread, TRUE);
3183 else if (signal_suspend)
3184 signal_thread_state_change (thread);
3187 /*Only wait on the suspend event if we are using the old path */
3188 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3189 MONO_PREPARE_BLOCKING
3190 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3191 MONO_FINISH_BLOCKING
3193 for (i = 0; i < wait->num; ++i) {
3194 MonoInternalThread *thread = wait->threads [i];
3199 LOCK_THREAD (thread);
3200 if ((thread->state & ThreadState_Suspended) != 0) {
3201 CloseHandle (thread->suspended_event);
3202 thread->suspended_event = NULL;
3204 UNLOCK_THREAD (thread);
3208 if (eventidx <= 0) {
3210 * If there are threads which are starting up, we wait until they
3211 * are suspended when they try to register in the threads hash.
3212 * This is guaranteed to finish, since the threads which can create new
3213 * threads get suspended after a while.
3214 * FIXME: The finalizer thread can still create new threads.
3216 mono_threads_lock ();
3217 if (threads_starting_up)
3218 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3221 mono_threads_unlock ();
3233 collect_threads (gpointer key, gpointer value, gpointer user_data)
3235 MonoInternalThread *thread = (MonoInternalThread*)value;
3236 struct wait_data *wait = (struct wait_data*)user_data;
3239 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3240 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3244 wait->handles [wait->num] = handle;
3245 wait->threads [wait->num] = thread;
3250 static gboolean thread_dump_requested;
3252 static G_GNUC_UNUSED gboolean
3253 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3255 GString *p = (GString*)data;
3256 MonoMethod *method = NULL;
3258 method = mono_jit_info_get_method (frame->ji);
3261 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3262 g_string_append_printf (p, " %s\n", location);
3265 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3270 static SuspendThreadResult
3271 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3273 MonoInternalThread *thread = ud;
3274 GString* text = g_string_new (0);
3276 GError *error = NULL;
3279 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3281 g_string_append_printf (text, "\n\"%s\"", name);
3284 else if (thread->threadpool_thread)
3285 g_string_append (text, "\n\"<threadpool thread>\"");
3287 g_string_append (text, "\n\"<unnamed thread>\"");
3290 /* This no longer works with remote unwinding */
3292 wapi_desc = wapi_current_thread_desc ();
3293 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3298 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);
3300 fprintf (stdout, "%s", text->str);
3302 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3303 OutputDebugStringA(text->str);
3306 g_string_free (text, TRUE);
3308 return MonoResumeThread;
3312 dump_thread (gpointer key, gpointer value, gpointer user)
3314 MonoInternalThread *thread = (MonoInternalThread *)value;
3316 if (thread == mono_thread_internal_current ())
3320 FIXME This still can hang if we stop a thread during malloc.
3321 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3322 that takes a callback and runs it with the target suspended.
3323 We probably should loop a bit around trying to get it to either managed code
3326 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
3330 mono_threads_perform_thread_dump (void)
3332 if (!thread_dump_requested)
3335 printf ("Full thread dump:\n");
3337 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3338 something needs then in the process.
3340 mono_loader_lock ();
3341 mono_domain_lock (mono_get_root_domain ());
3343 mono_threads_lock ();
3344 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3345 mono_threads_unlock ();
3347 mono_domain_unlock (mono_get_root_domain ());
3348 mono_loader_unlock ();
3350 thread_dump_requested = FALSE;
3354 * mono_threads_request_thread_dump:
3356 * Ask all threads except the current to print their stacktrace to stdout.
3359 mono_threads_request_thread_dump (void)
3361 struct wait_data wait_data;
3362 struct wait_data *wait = &wait_data;
3365 /*The new thread dump code runs out of the finalizer thread. */
3366 if (mono_thread_info_new_interrupt_enabled ()) {
3367 thread_dump_requested = TRUE;
3368 mono_gc_finalize_notify ();
3373 memset (wait, 0, sizeof (struct wait_data));
3376 * Make a copy of the hashtable since we can't do anything with
3377 * threads while threads_mutex is held.
3379 mono_threads_lock ();
3380 mono_g_hash_table_foreach (threads, collect_threads, wait);
3381 mono_threads_unlock ();
3383 for (i = 0; i < wait->num; ++i) {
3384 MonoInternalThread *thread = wait->threads [i];
3386 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3387 (thread != mono_thread_internal_current ()) &&
3388 !thread->thread_dump_requested) {
3389 thread->thread_dump_requested = TRUE;
3391 signal_thread_state_change (thread);
3394 CloseHandle (wait->handles [i]);
3400 gint allocated; /* +1 so that refs [allocated] == NULL */
3404 typedef struct ref_stack RefStack;
3407 ref_stack_new (gint initial_size)
3411 initial_size = MAX (initial_size, 16) + 1;
3412 rs = g_new0 (RefStack, 1);
3413 rs->refs = g_new0 (gpointer, initial_size);
3414 rs->allocated = initial_size;
3419 ref_stack_destroy (gpointer ptr)
3430 ref_stack_push (RefStack *rs, gpointer ptr)
3432 g_assert (rs != NULL);
3434 if (rs->bottom >= rs->allocated) {
3435 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3436 rs->allocated <<= 1;
3437 rs->refs [rs->allocated] = NULL;
3439 rs->refs [rs->bottom++] = ptr;
3443 ref_stack_pop (RefStack *rs)
3445 if (rs == NULL || rs->bottom == 0)
3449 rs->refs [rs->bottom] = NULL;
3453 ref_stack_find (RefStack *rs, gpointer ptr)
3460 for (refs = rs->refs; refs && *refs; refs++) {
3468 * mono_thread_push_appdomain_ref:
3470 * Register that the current thread may have references to objects in domain
3471 * @domain on its stack. Each call to this function should be paired with a
3472 * call to pop_appdomain_ref.
3475 mono_thread_push_appdomain_ref (MonoDomain *domain)
3477 MonoInternalThread *thread = mono_thread_internal_current ();
3480 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3481 SPIN_LOCK (thread->lock_thread_id);
3482 if (thread->appdomain_refs == NULL)
3483 thread->appdomain_refs = ref_stack_new (16);
3484 ref_stack_push (thread->appdomain_refs, domain);
3485 SPIN_UNLOCK (thread->lock_thread_id);
3490 mono_thread_pop_appdomain_ref (void)
3492 MonoInternalThread *thread = mono_thread_internal_current ();
3495 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3496 SPIN_LOCK (thread->lock_thread_id);
3497 ref_stack_pop (thread->appdomain_refs);
3498 SPIN_UNLOCK (thread->lock_thread_id);
3503 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3506 SPIN_LOCK (thread->lock_thread_id);
3507 res = ref_stack_find (thread->appdomain_refs, domain);
3508 SPIN_UNLOCK (thread->lock_thread_id);
3513 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3515 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3518 typedef struct abort_appdomain_data {
3519 struct wait_data wait;
3521 } abort_appdomain_data;
3524 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3526 MonoInternalThread *thread = (MonoInternalThread*)value;
3527 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3528 MonoDomain *domain = data->domain;
3530 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3531 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3533 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3534 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3537 data->wait.handles [data->wait.num] = handle;
3538 data->wait.threads [data->wait.num] = thread;
3541 /* Just ignore the rest, we can't do anything with
3549 * mono_threads_abort_appdomain_threads:
3551 * Abort threads which has references to the given appdomain.
3554 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3556 #ifdef __native_client__
3560 abort_appdomain_data user_data;
3562 int orig_timeout = timeout;
3565 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3567 start_time = mono_msec_ticks ();
3569 mono_threads_lock ();
3571 user_data.domain = domain;
3572 user_data.wait.num = 0;
3573 /* This shouldn't take any locks */
3574 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3575 mono_threads_unlock ();
3577 if (user_data.wait.num > 0) {
3578 /* Abort the threads outside the threads lock */
3579 for (i = 0; i < user_data.wait.num; ++i)
3580 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3583 * We should wait for the threads either to abort, or to leave the
3584 * domain. We can't do the latter, so we wait with a timeout.
3586 wait_for_tids (&user_data.wait, 100);
3589 /* Update remaining time */
3590 timeout -= mono_msec_ticks () - start_time;
3591 start_time = mono_msec_ticks ();
3593 if (orig_timeout != -1 && timeout < 0)
3596 while (user_data.wait.num > 0);
3598 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3604 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3606 MonoInternalThread *thread = (MonoInternalThread*)value;
3607 MonoDomain *domain = (MonoDomain*)user_data;
3610 /* No locking needed here */
3611 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3613 if (thread->cached_culture_info) {
3614 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3615 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3616 if (obj && obj->vtable->domain == domain)
3617 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3623 * mono_threads_clear_cached_culture:
3625 * Clear the cached_current_culture from all threads if it is in the
3629 mono_threads_clear_cached_culture (MonoDomain *domain)
3631 mono_threads_lock ();
3632 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3633 mono_threads_unlock ();
3637 * mono_thread_get_undeniable_exception:
3639 * Return an exception which needs to be raised when leaving a catch clause.
3640 * This is used for undeniable exception propagation.
3643 mono_thread_get_undeniable_exception (void)
3645 MonoInternalThread *thread = mono_thread_internal_current ();
3647 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3649 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3650 * exception if the thread no longer references a dying appdomain.
3652 thread->abort_exc->trace_ips = NULL;
3653 thread->abort_exc->stack_trace = NULL;
3654 return thread->abort_exc;
3660 #if MONO_SMALL_CONFIG
3661 #define NUM_STATIC_DATA_IDX 4
3662 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3666 #define NUM_STATIC_DATA_IDX 8
3667 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3668 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3672 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3675 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3678 gpointer *static_data = addr;
3679 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3682 if (!static_data [i])
3684 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3685 ptr = static_data [i];
3686 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3687 uintptr_t bmap = static_reference_bitmaps [i][j];
3690 if ((bmap & 1) && *p) {
3691 mark_func (p, gc_data);
3701 * mono_alloc_static_data
3703 * Allocate memory blocks for storing threads or context static data
3706 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3708 guint idx = (offset >> 24) - 1;
3711 gpointer* static_data = *static_data_ptr;
3713 static void* tls_desc = NULL;
3714 if (mono_gc_user_markers_supported () && !tls_desc)
3715 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3716 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3717 *static_data_ptr = static_data;
3718 static_data [0] = static_data;
3721 for (i = 1; i <= idx; ++i) {
3722 if (static_data [i])
3724 if (mono_gc_user_markers_supported () && threadlocal)
3725 static_data [i] = g_malloc0 (static_data_size [i]);
3727 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3732 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3735 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3736 gpointer p = static_data [i];
3740 * At this point, the static data pointer array is still registered with the
3741 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3742 * data. Freeing the individual arrays without first nulling their slots
3743 * would make it possible for mark_tls_slots() to encounter a pointer to
3744 * such an already freed array. See bug #13813.
3746 static_data [i] = NULL;
3747 mono_memory_write_barrier ();
3748 if (mono_gc_user_markers_supported () && threadlocal)
3751 mono_gc_free_fixed (p);
3753 mono_gc_free_fixed (static_data);
3757 * mono_init_static_data_info
3759 * Initializes static data counters
3761 static void mono_init_static_data_info (StaticDataInfo *static_data)
3763 static_data->idx = 0;
3764 static_data->offset = 0;
3765 static_data->freelist = NULL;
3769 * mono_alloc_static_data_slot
3771 * Generates an offset for static data. static_data contains the counters
3772 * used to generate it.
3775 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3779 if (!static_data->idx && !static_data->offset) {
3781 * we use the first chunk of the first allocation also as
3782 * an array for the rest of the data
3784 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3786 static_data->offset += align - 1;
3787 static_data->offset &= ~(align - 1);
3788 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3789 static_data->idx ++;
3790 g_assert (size <= static_data_size [static_data->idx]);
3791 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3792 static_data->offset = 0;
3794 offset = static_data->offset | ((static_data->idx + 1) << 24);
3795 static_data->offset += size;
3800 * ensure thread static fields already allocated are valid for thread
3801 * This function is called when a thread is created or on thread attach.
3804 thread_adjust_static_data (MonoInternalThread *thread)
3808 mono_threads_lock ();
3809 if (thread_static_info.offset || thread_static_info.idx > 0) {
3810 /* get the current allocated size */
3811 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3812 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3814 mono_threads_unlock ();
3818 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3820 MonoInternalThread *thread = value;
3821 guint32 offset = GPOINTER_TO_UINT (user);
3823 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3826 static MonoThreadDomainTls*
3827 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3829 MonoThreadDomainTls* prev = NULL;
3830 MonoThreadDomainTls* tmp = static_data->freelist;
3832 if (tmp->size == size) {
3834 prev->next = tmp->next;
3836 static_data->freelist = tmp->next;
3845 #if SIZEOF_VOID_P == 4
3852 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3855 int idx = (offset >> 24) - 1;
3857 if (!static_reference_bitmaps [idx])
3858 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3859 rb = static_reference_bitmaps [idx];
3861 offset /= sizeof (gpointer);
3862 /* offset is now the bitmap offset */
3863 for (i = 0; i < numbits; ++i) {
3864 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3865 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (ONE_P << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3870 clear_reference_bitmap (guint32 offset, guint32 size)
3872 int idx = (offset >> 24) - 1;
3874 rb = static_reference_bitmaps [idx];
3876 offset /= sizeof (gpointer);
3877 size /= sizeof (gpointer);
3879 /* offset is now the bitmap offset */
3880 for (; offset < size; ++offset)
3881 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3885 * The offset for a special static variable is composed of three parts:
3886 * a bit that indicates the type of static data (0:thread, 1:context),
3887 * an index in the array of chunks of memory for the thread (thread->static_data)
3888 * and an offset in that chunk of mem. This allows allocating less memory in the
3893 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3896 if (static_type == SPECIAL_STATIC_THREAD) {
3897 MonoThreadDomainTls *item;
3898 mono_threads_lock ();
3899 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3900 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3902 offset = item->offset;
3905 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3907 update_tls_reference_bitmap (offset, bitmap, numbits);
3908 /* This can be called during startup */
3909 if (threads != NULL)
3910 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3911 mono_threads_unlock ();
3913 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3914 mono_contexts_lock ();
3915 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3916 mono_contexts_unlock ();
3917 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3923 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3925 /* The high bit means either thread (0) or static (1) data. */
3927 guint32 static_type = (offset & 0x80000000);
3930 offset &= 0x7fffffff;
3931 idx = (offset >> 24) - 1;
3933 if (static_type == 0) {
3934 return get_thread_static_data (thread, offset);
3936 /* Allocate static data block under demand, since we don't have a list
3939 MonoAppContext *context = mono_context_get ();
3940 if (!context->static_data || !context->static_data [idx]) {
3941 mono_contexts_lock ();
3942 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3943 mono_contexts_unlock ();
3945 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3950 mono_get_special_static_data (guint32 offset)
3952 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3961 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3963 MonoInternalThread *thread = value;
3964 TlsOffsetSize *data = user;
3965 int idx = (data->offset >> 24) - 1;
3968 if (!thread->static_data || !thread->static_data [idx])
3970 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3971 mono_gc_bzero_atomic (ptr, data->size);
3975 do_free_special_slot (guint32 offset, guint32 size)
3977 guint32 static_type = (offset & 0x80000000);
3978 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3979 if (static_type == 0) {
3981 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3982 data.offset = offset & 0x7fffffff;
3984 clear_reference_bitmap (data.offset, data.size);
3985 if (threads != NULL)
3986 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3987 item->offset = offset;
3990 if (!mono_runtime_is_shutting_down ()) {
3991 item->next = thread_static_info.freelist;
3992 thread_static_info.freelist = item;
3994 /* We could be called during shutdown after mono_thread_cleanup () is called */
3998 /* FIXME: free context static data as well */
4003 do_free_special (gpointer key, gpointer value, gpointer data)
4005 MonoClassField *field = key;
4006 guint32 offset = GPOINTER_TO_UINT (value);
4009 size = mono_type_size (field->type, &align);
4010 do_free_special_slot (offset, size);
4014 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4016 mono_threads_lock ();
4017 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4018 mono_threads_unlock ();
4022 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4024 mono_threads_lock ();
4025 do_free_special_slot (offset, size);
4026 mono_threads_unlock ();
4030 * allocates room in the thread local area for storing an instance of the struct type
4031 * the allocation is kept track of in domain->tlsrec_list.
4034 mono_thread_alloc_tls (MonoReflectionType *type)
4036 MonoDomain *domain = mono_domain_get ();
4038 MonoTlsDataRecord *tlsrec;
4041 gsize default_bitmap [4] = {0};
4042 uint32_t tls_offset;
4046 klass = mono_class_from_mono_type (type->type);
4047 /* TlsDatum is a struct, so we subtract the object header size offset */
4048 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
4049 size = mono_type_size (type->type, &align);
4050 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
4051 if (bitmap != default_bitmap)
4053 tlsrec = g_new0 (MonoTlsDataRecord, 1);
4054 tlsrec->tls_offset = tls_offset;
4055 tlsrec->size = size;
4056 mono_domain_lock (domain);
4057 tlsrec->next = domain->tlsrec_list;
4058 domain->tlsrec_list = tlsrec;
4059 mono_domain_unlock (domain);
4064 destroy_tls (MonoDomain *domain, uint32_t tls_offset)
4066 MonoTlsDataRecord *prev = NULL;
4067 MonoTlsDataRecord *cur;
4070 mono_domain_lock (domain);
4071 cur = domain->tlsrec_list;
4073 if (cur->tls_offset == tls_offset) {
4075 prev->next = cur->next;
4077 domain->tlsrec_list = cur->next;
4085 mono_domain_unlock (domain);
4087 mono_special_static_data_free_slot (tls_offset, size);
4091 mono_thread_destroy_tls (uint32_t tls_offset)
4093 destroy_tls (mono_domain_get (), tls_offset);
4097 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
4100 mono_thread_destroy_domain_tls (MonoDomain *domain)
4102 while (domain->tlsrec_list)
4103 destroy_tls (domain, domain->tlsrec_list->tls_offset);
4106 static MonoClassField *local_slots = NULL;
4109 /* local tls data to get locals_slot from a thread */
4112 /* index in the locals_slot array */
4117 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4119 LocalSlotID *sid = user_data;
4120 MonoInternalThread *thread = (MonoInternalThread*)value;
4121 MonoArray *slots_array;
4123 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4124 * it is for the right domain, so we need to check if it is allocated an initialized
4125 * for the current thread.
4127 /*g_print ("handling thread %p\n", thread);*/
4128 if (!thread->static_data || !thread->static_data [sid->idx])
4130 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4131 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4133 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4137 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4145 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4147 g_warning ("local_slots field not found in Thread class");
4151 domain = mono_domain_get ();
4152 mono_domain_lock (domain);
4153 if (domain->special_static_fields)
4154 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4155 mono_domain_unlock (domain);
4158 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4159 sid.offset = GPOINTER_TO_UINT (addr);
4160 sid.offset &= 0x7fffffff;
4161 sid.idx = (sid.offset >> 24) - 1;
4162 mono_threads_lock ();
4163 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4164 mono_threads_unlock ();
4166 /* FIXME: clear the slot for MonoAppContexts, too */
4171 static void CALLBACK dummy_apc (ULONG_PTR param)
4177 * mono_thread_execute_interruption
4179 * Performs the operation that the requested thread state requires (abort,
4182 static MonoException*
4183 mono_thread_execute_interruption (MonoInternalThread *thread)
4185 LOCK_THREAD (thread);
4187 /* MonoThread::interruption_requested can only be changed with atomics */
4188 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4189 /* this will consume pending APC calls */
4191 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4193 InterlockedDecrement (&thread_interruption_requested);
4194 /* Clear the interrupted flag of the thread so it can wait again */
4195 mono_thread_info_clear_interruption ();
4198 if ((thread->state & ThreadState_AbortRequested) != 0) {
4199 UNLOCK_THREAD (thread);
4200 if (thread->abort_exc == NULL) {
4202 * This might be racy, but it has to be called outside the lock
4203 * since it calls managed code.
4205 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4207 return thread->abort_exc;
4209 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4210 self_suspend_internal (thread);
4213 else if ((thread->state & ThreadState_StopRequested) != 0) {
4214 /* FIXME: do this through the JIT? */
4216 UNLOCK_THREAD (thread);
4218 mono_thread_exit ();
4220 } else if (thread->pending_exception) {
4223 exc = thread->pending_exception;
4224 thread->pending_exception = NULL;
4226 UNLOCK_THREAD (thread);
4228 } else if (thread->thread_interrupt_requested) {
4230 thread->thread_interrupt_requested = FALSE;
4231 UNLOCK_THREAD (thread);
4233 return(mono_get_exception_thread_interrupted ());
4236 UNLOCK_THREAD (thread);
4242 * mono_thread_request_interruption
4244 * A signal handler can call this method to request the interruption of a
4245 * thread. The result of the interruption will depend on the current state of
4246 * the thread. If the result is an exception that needs to be throw, it is
4247 * provided as return value.
4250 mono_thread_request_interruption (gboolean running_managed)
4252 MonoInternalThread *thread = mono_thread_internal_current ();
4254 /* The thread may already be stopping */
4259 if (thread->interrupt_on_stop &&
4260 thread->state & ThreadState_StopRequested &&
4261 thread->state & ThreadState_Background)
4265 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4267 InterlockedIncrement (&thread_interruption_requested);
4269 if (!running_managed || is_running_protected_wrapper ()) {
4270 /* Can't stop while in unmanaged code. Increase the global interruption
4271 request count. When exiting the unmanaged method the count will be
4272 checked and the thread will be interrupted. */
4274 if (mono_thread_notify_pending_exc_fn && !running_managed)
4275 /* The JIT will notify the thread about the interruption */
4276 /* This shouldn't take any locks */
4277 mono_thread_notify_pending_exc_fn (NULL);
4279 /* this will awake the thread if it is in WaitForSingleObject
4281 /* Our implementation of this function ignores the func argument */
4283 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4285 mono_thread_info_self_interrupt ();
4290 return mono_thread_execute_interruption (thread);
4294 /*This function should be called by a thread after it has exited all of
4295 * its handle blocks at interruption time.*/
4297 mono_thread_resume_interruption (void)
4299 MonoInternalThread *thread = mono_thread_internal_current ();
4300 gboolean still_aborting;
4302 /* The thread may already be stopping */
4306 LOCK_THREAD (thread);
4307 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4308 UNLOCK_THREAD (thread);
4310 /*This can happen if the protected block called Thread::ResetAbort*/
4311 if (!still_aborting)
4314 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4316 InterlockedIncrement (&thread_interruption_requested);
4318 mono_thread_info_self_interrupt ();
4320 return mono_thread_execute_interruption (thread);
4323 gboolean mono_thread_interruption_requested ()
4325 if (thread_interruption_requested) {
4326 MonoInternalThread *thread = mono_thread_internal_current ();
4327 /* The thread may already be stopping */
4329 return (thread->interruption_requested);
4334 static MonoException*
4335 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4337 MonoInternalThread *thread = mono_thread_internal_current ();
4339 /* The thread may already be stopping */
4343 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4344 MonoException* exc = mono_thread_execute_interruption (thread);
4352 * Performs the interruption of the current thread, if one has been requested,
4353 * and the thread is not running a protected wrapper.
4354 * Return the exception which needs to be thrown, if any.
4357 mono_thread_interruption_checkpoint (void)
4359 return mono_thread_interruption_checkpoint_request (FALSE);
4363 * Performs the interruption of the current thread, if one has been requested.
4364 * Return the exception which needs to be thrown, if any.
4367 mono_thread_force_interruption_checkpoint_noraise (void)
4369 return mono_thread_interruption_checkpoint_request (TRUE);
4373 * Performs the interruption of the current thread, if one has been requested.
4374 * Throw the exception which needs to be thrown, if any.
4377 mono_thread_force_interruption_checkpoint (void)
4381 ex = mono_thread_interruption_checkpoint_request (TRUE);
4383 mono_raise_exception (ex);
4387 * mono_thread_get_and_clear_pending_exception:
4389 * Return any pending exceptions for the current thread and clear it as a side effect.
4392 mono_thread_get_and_clear_pending_exception (void)
4394 MonoInternalThread *thread = mono_thread_internal_current ();
4396 /* The thread may already be stopping */
4400 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4401 return mono_thread_execute_interruption (thread);
4404 if (thread->pending_exception) {
4405 MonoException *exc = thread->pending_exception;
4407 thread->pending_exception = NULL;
4415 * mono_set_pending_exception:
4417 * Set the pending exception of the current thread to EXC.
4418 * The exception will be thrown when execution returns to managed code.
4421 mono_set_pending_exception (MonoException *exc)
4423 MonoInternalThread *thread = mono_thread_internal_current ();
4425 /* The thread may already be stopping */
4429 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4431 mono_thread_request_interruption (FALSE);
4435 * mono_thread_interruption_request_flag:
4437 * Returns the address of a flag that will be non-zero if an interruption has
4438 * been requested for a thread. The thread to interrupt may not be the current
4439 * thread, so an additional call to mono_thread_interruption_requested() or
4440 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4443 gint32* mono_thread_interruption_request_flag ()
4445 return &thread_interruption_requested;
4449 mono_thread_init_apartment_state (void)
4452 MonoInternalThread* thread = mono_thread_internal_current ();
4454 /* Positive return value indicates success, either
4455 * S_OK if this is first CoInitialize call, or
4456 * S_FALSE if CoInitialize already called, but with same
4457 * threading model. A negative value indicates failure,
4458 * probably due to trying to change the threading model.
4460 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4461 ? COINIT_APARTMENTTHREADED
4462 : COINIT_MULTITHREADED) < 0) {
4463 thread->apartment_state = ThreadApartmentState_Unknown;
4469 mono_thread_cleanup_apartment_state (void)
4472 MonoInternalThread* thread = mono_thread_internal_current ();
4474 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4481 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4483 LOCK_THREAD (thread);
4484 thread->state |= state;
4485 UNLOCK_THREAD (thread);
4489 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4491 LOCK_THREAD (thread);
4492 thread->state &= ~state;
4493 UNLOCK_THREAD (thread);
4497 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4499 gboolean ret = FALSE;
4501 LOCK_THREAD (thread);
4503 if ((thread->state & test) != 0) {
4507 UNLOCK_THREAD (thread);
4512 //static MonoClassField *execution_context_field;
4515 get_execution_context_addr (void)
4517 MonoDomain *domain = mono_domain_get ();
4518 guint32 offset = domain->execution_context_field_offset;
4521 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4524 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4526 mono_domain_lock (domain);
4527 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4528 mono_domain_unlock (domain);
4531 domain->execution_context_field_offset = offset;
4534 return (MonoObject**) mono_get_special_static_data (offset);
4538 mono_thread_get_execution_context (void)
4540 return *get_execution_context_addr ();
4544 mono_thread_set_execution_context (MonoObject *ec)
4546 *get_execution_context_addr () = ec;
4549 static gboolean has_tls_get = FALSE;
4552 mono_runtime_set_has_tls_get (gboolean val)
4558 mono_runtime_has_tls_get (void)
4564 mono_thread_kill (MonoInternalThread *thread, int signal)
4566 #ifdef __native_client__
4567 /* Workaround pthread_kill abort() in NaCl glibc. */
4570 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
4571 /* Win32 uses QueueUserAPC and callers of this are guarded */
4572 g_assert_not_reached ();
4574 # ifdef PTHREAD_POINTER_ID
4575 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4577 # ifdef USE_TKILL_ON_ANDROID
4578 if (thread->android_tid != 0) {
4580 int old_errno = errno;
4582 ret = tkill ((pid_t) thread->android_tid, signal);
4591 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4593 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4600 self_interrupt_thread (void *_unused)
4602 MonoThreadInfo *info = mono_thread_info_current ();
4603 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4604 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4605 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. */
4606 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4610 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4614 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4618 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4620 MonoJitInfo **dest = data;
4626 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4628 MonoJitInfo *ji = NULL;
4631 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4636 MonoInternalThread *thread;
4637 gboolean install_async_abort;
4638 gpointer interrupt_handle;
4641 static SuspendThreadResult
4642 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4644 AbortThreadData *data = ud;
4645 MonoInternalThread *thread = data->thread;
4646 MonoJitInfo *ji = NULL;
4647 gboolean protected_wrapper;
4648 gboolean running_managed;
4650 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4651 return MonoResumeThread;
4653 /*someone is already interrupting it*/
4654 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4655 return MonoResumeThread;
4657 InterlockedIncrement (&thread_interruption_requested);
4659 ji = mono_thread_info_get_last_managed (info);
4660 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4661 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4663 if (!protected_wrapper && running_managed) {
4664 /*We are in managed code*/
4665 /*Set the thread to call */
4666 if (data->install_async_abort)
4667 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4668 return MonoResumeThread;
4670 if (mono_thread_notify_pending_exc_fn)
4671 /* The JIT will notify the thread about the interruption */
4672 mono_thread_notify_pending_exc_fn (info);
4675 * This will cause waits to be broken.
4676 * It will also prevent the thread from entering a wait, so if the thread returns
4677 * from the wait before it receives the abort signal, it will just spin in the wait
4678 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4681 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4682 return MonoResumeThread;
4687 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4689 AbortThreadData data = { 0 };
4690 data.thread = thread;
4691 data.install_async_abort = install_async_abort;
4693 if (!mono_thread_info_new_interrupt_enabled ()) {
4694 signal_thread_state_change (thread);
4699 FIXME this is insanely broken, it doesn't cause interruption to happen
4700 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4702 if (thread == mono_thread_internal_current ()) {
4703 /* Do it synchronously */
4704 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4706 mono_raise_exception (exc);
4707 mono_thread_info_interrupt (thread->handle);
4711 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
4712 if (data.interrupt_handle)
4713 mono_thread_info_finish_interrupt (data.interrupt_handle);
4714 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4718 MonoInternalThread *thread;
4720 gpointer interrupt_handle;
4721 } SuspendThreadData;
4723 static SuspendThreadResult
4724 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4726 SuspendThreadData *data = ud;
4727 MonoInternalThread *thread = data->thread;
4728 MonoJitInfo *ji = NULL;
4729 gboolean protected_wrapper;
4730 gboolean running_managed;
4732 ji = mono_thread_info_get_last_managed (info);
4733 protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4734 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4736 if (running_managed && !protected_wrapper) {
4737 thread->state &= ~ThreadState_SuspendRequested;
4738 thread->state |= ThreadState_Suspended;
4739 return KeepSuspended;
4741 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4742 InterlockedIncrement (&thread_interruption_requested);
4743 if (data->interrupt)
4744 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4746 if (mono_thread_notify_pending_exc_fn && !running_managed)
4747 /* The JIT will notify the thread about the interruption */
4748 mono_thread_notify_pending_exc_fn (info);
4749 return MonoResumeThread;
4754 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4756 if (!mono_thread_info_new_interrupt_enabled ()) {
4757 signal_thread_state_change (thread);
4761 LOCK_THREAD (thread);
4762 if (thread == mono_thread_internal_current ()) {
4763 mono_thread_info_begin_self_suspend ();
4764 //XXX replace this with better named functions
4765 thread->state &= ~ThreadState_SuspendRequested;
4766 thread->state |= ThreadState_Suspended;
4767 UNLOCK_THREAD (thread);
4768 mono_thread_info_end_self_suspend ();
4770 SuspendThreadData data = { 0 };
4771 data.thread = thread;
4772 data.interrupt = interrupt;
4774 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
4775 if (data.interrupt_handle)
4776 mono_thread_info_finish_interrupt (data.interrupt_handle);
4777 UNLOCK_THREAD (thread);
4781 /*This is called with @thread synch_cs held and it must release it*/
4783 self_suspend_internal (MonoInternalThread *thread)
4785 if (!mono_thread_info_new_interrupt_enabled ()) {
4786 thread->state &= ~ThreadState_SuspendRequested;
4787 thread->state |= ThreadState_Suspended;
4788 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4789 if (thread->suspend_event == NULL) {
4790 UNLOCK_THREAD (thread);
4793 if (thread->suspended_event)
4794 SetEvent (thread->suspended_event);
4796 UNLOCK_THREAD (thread);
4798 if (shutting_down) {
4799 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4804 MONO_PREPARE_BLOCKING
4805 WaitForSingleObject (thread->suspend_event, INFINITE);
4806 MONO_FINISH_BLOCKING
4808 LOCK_THREAD (thread);
4810 CloseHandle (thread->suspend_event);
4811 thread->suspend_event = NULL;
4812 thread->state &= ~ThreadState_Suspended;
4814 /* The thread that requested the resume will have replaced this event
4815 * and will be waiting for it
4817 SetEvent (thread->resume_event);
4819 UNLOCK_THREAD (thread);
4823 mono_thread_info_begin_self_suspend ();
4824 thread->state &= ~ThreadState_SuspendRequested;
4825 thread->state |= ThreadState_Suspended;
4826 UNLOCK_THREAD (thread);
4827 mono_thread_info_end_self_suspend ();
4830 /*This is called with @thread synch_cs held and it must release it*/
4832 resume_thread_internal (MonoInternalThread *thread)
4834 if (!mono_thread_info_new_interrupt_enabled ()) {
4835 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4836 if (thread->resume_event == NULL) {
4837 UNLOCK_THREAD (thread);
4841 /* Awake the thread */
4842 SetEvent (thread->suspend_event);
4844 UNLOCK_THREAD (thread);
4846 /* Wait for the thread to awake */
4847 MONO_PREPARE_BLOCKING
4848 WaitForSingleObject (thread->resume_event, INFINITE);
4849 MONO_FINISH_BLOCKING
4851 CloseHandle (thread->resume_event);
4852 thread->resume_event = NULL;
4856 UNLOCK_THREAD (thread);
4857 /* Awake the thread */
4858 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4860 LOCK_THREAD (thread);
4861 thread->state &= ~ThreadState_Suspended;
4862 UNLOCK_THREAD (thread);
4868 * mono_thread_is_foreign:
4869 * @thread: the thread to query
4871 * This function allows one to determine if a thread was created by the mono runtime and has
4872 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4874 * Returns: true if @thread was not created by the runtime.
4877 mono_thread_is_foreign (MonoThread *thread)
4879 MonoThreadInfo *info = thread->internal_thread->thread_info;
4880 return info->runtime_thread == FALSE;
4884 * mono_add_joinable_thread:
4886 * Add TID to the list of joinable threads.
4887 * LOCKING: Acquires the threads lock.
4890 mono_threads_add_joinable_thread (gpointer tid)
4894 * We cannot detach from threads because it causes problems like
4895 * 2fd16f60/r114307. So we collect them and join them when
4896 * we have time (in he finalizer thread).
4898 joinable_threads_lock ();
4899 if (!joinable_threads)
4900 joinable_threads = g_hash_table_new (NULL, NULL);
4901 g_hash_table_insert (joinable_threads, tid, tid);
4902 joinable_thread_count ++;
4903 joinable_threads_unlock ();
4905 mono_gc_finalize_notify ();
4910 * mono_threads_join_threads:
4912 * Join all joinable threads. This is called from the finalizer thread.
4913 * LOCKING: Acquires the threads lock.
4916 mono_threads_join_threads (void)
4919 GHashTableIter iter;
4926 if (!joinable_thread_count)
4930 joinable_threads_lock ();
4932 if (g_hash_table_size (joinable_threads)) {
4933 g_hash_table_iter_init (&iter, joinable_threads);
4934 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4935 thread = (pthread_t)tid;
4936 g_hash_table_remove (joinable_threads, key);
4937 joinable_thread_count --;
4940 joinable_threads_unlock ();
4942 if (thread != pthread_self ())
4943 /* This shouldn't block */
4944 pthread_join (thread, NULL);
4955 * Wait for thread TID to exit.
4956 * LOCKING: Acquires the threads lock.
4959 mono_thread_join (gpointer tid)
4963 gboolean found = FALSE;
4965 joinable_threads_lock ();
4966 if (!joinable_threads)
4967 joinable_threads = g_hash_table_new (NULL, NULL);
4968 if (g_hash_table_lookup (joinable_threads, tid)) {
4969 g_hash_table_remove (joinable_threads, tid);
4970 joinable_thread_count --;
4973 joinable_threads_unlock ();
4976 thread = (pthread_t)tid;
4977 pthread_join (thread, NULL);