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/threads-types.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/environment.h>
26 #include <mono/metadata/monitor.h>
27 #include <mono/metadata/gc-internal.h>
28 #include <mono/metadata/marshal.h>
29 #include <mono/metadata/runtime.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/mono-debug-debugger.h>
33 #include <mono/utils/monobitset.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 _StaticDataFreeList StaticDataFreeList;
108 struct _StaticDataFreeList {
109 StaticDataFreeList *next;
117 StaticDataFreeList *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 the 'joinable_threads' hash table */
134 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
135 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
136 static mono_mutex_t joinable_threads_mutex;
138 /* Holds current status of static data heap */
139 static StaticDataInfo thread_static_info;
140 static StaticDataInfo context_static_info;
142 /* The hash of existing threads (key is thread ID, value is
143 * MonoInternalThread*) that need joining before exit
145 static MonoGHashTable *threads=NULL;
147 /* List of app context GC handles.
148 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
150 static GHashTable *contexts = 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 context_adjust_static_data (MonoAppContext *ctx);
204 static void mono_free_static_data (gpointer* static_data);
205 static void mono_init_static_data_info (StaticDataInfo *static_data);
206 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
207 static gboolean mono_thread_resume (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);
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 * A special static data offset (guint32) consists of 3 parts:
494 * [0] 6-bit index into the array of chunks.
495 * [6] 25-bit offset into the array.
496 * [31] Bit indicating thread or context static.
501 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
512 } SpecialStaticOffset;
514 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
515 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
517 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
518 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
519 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
520 (((SpecialStaticOffset *) &(x))->fields.f)
523 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
525 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
527 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
528 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
530 return ((char *) thread->static_data [idx]) + off;
534 get_context_static_data (MonoAppContext *ctx, guint32 offset)
536 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
538 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
539 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
541 return ((char *) ctx->static_data [idx]) + off;
545 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
547 static MonoClassField *current_thread_field = NULL;
551 if (!current_thread_field) {
552 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
553 g_assert (current_thread_field);
556 mono_class_vtable (domain, mono_defaults.thread_class);
557 mono_domain_lock (domain);
558 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
559 mono_domain_unlock (domain);
562 return get_thread_static_data (thread, offset);
566 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
568 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
570 g_assert (current->obj.vtable->domain == domain);
572 g_assert (!*current_thread_ptr);
573 *current_thread_ptr = current;
577 create_thread_object (MonoDomain *domain)
579 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
580 return (MonoThread*)mono_gc_alloc_mature (vt);
584 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
586 MonoThread *thread = create_thread_object (domain);
587 MONO_OBJECT_SETREF (thread, internal_thread, internal);
591 static MonoInternalThread*
592 create_internal_thread (void)
594 MonoInternalThread *thread;
597 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
598 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
600 thread->synch_cs = g_new0 (mono_mutex_t, 1);
601 mono_mutex_init_recursive (thread->synch_cs);
603 thread->apartment_state = ThreadApartmentState_Unknown;
604 thread->managed_id = get_next_managed_thread_id ();
605 if (mono_gc_is_moving ()) {
606 thread->thread_pinning_ref = thread;
607 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
614 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
616 MonoDomain *domain = mono_get_root_domain ();
618 if (!candidate || candidate->obj.vtable->domain != domain)
619 candidate = new_thread_with_internal (domain, thread);
620 set_current_thread_for_domain (domain, thread, candidate);
621 g_assert (!thread->root_domain_thread);
622 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
625 static guint32 WINAPI start_wrapper_internal(void *data)
627 MonoThreadInfo *info;
628 StartInfo *start_info = (StartInfo *)data;
629 guint32 (*start_func)(void *);
633 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
636 MonoInternalThread *internal = start_info->obj->internal_thread;
637 MonoObject *start_delegate = start_info->delegate;
638 MonoDomain *domain = start_info->obj->obj.vtable->domain;
640 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
642 /* We can be sure start_info->obj->tid and
643 * start_info->obj->handle have been set, because the thread
644 * was created suspended, and these values were set before the
648 info = mono_thread_info_current ();
650 internal->thread_info = info;
651 internal->small_id = info->small_id;
655 SET_CURRENT_OBJECT (internal);
657 /* Every thread references the appdomain which created it */
658 mono_thread_push_appdomain_ref (domain);
660 if (!mono_domain_set (domain, FALSE)) {
661 /* No point in raising an appdomain_unloaded exception here */
662 /* FIXME: Cleanup here */
663 mono_thread_pop_appdomain_ref ();
667 start_func = start_info->func;
668 start_arg = start_info->start_arg;
670 /* We have to do this here because mono_thread_new_init()
671 requires that root_domain_thread is set up. */
672 thread_adjust_static_data (internal);
673 init_root_domain_thread (internal, start_info->obj);
675 /* This MUST be called before any managed code can be
676 * executed, as it calls the callback function that (for the
677 * jit) sets the lmf marker.
679 mono_thread_new_init (tid, &tid, start_func);
680 internal->stack_ptr = &tid;
682 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
684 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
686 /* On 2.0 profile (and higher), set explicitly since state might have been
688 if (internal->apartment_state == ThreadApartmentState_Unknown)
689 internal->apartment_state = ThreadApartmentState_MTA;
691 mono_thread_init_apartment_state ();
693 if(internal->start_notify!=NULL) {
694 /* Let the thread that called Start() know we're
697 ReleaseSemaphore (internal->start_notify, 1, NULL);
700 mono_threads_lock ();
701 mono_g_hash_table_remove (thread_start_args, start_info->obj);
702 mono_threads_unlock ();
705 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
709 * Call this after calling start_notify, since the profiler callback might want
710 * to lock the thread, and the lock is held by thread_start () which waits for
713 mono_profiler_thread_start (tid);
715 /* if the name was set before starting, we didn't invoke the profiler callback */
716 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
717 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
718 mono_profiler_thread_name (internal->tid, tname);
721 /* start_func is set only for unmanaged start functions */
723 start_func (start_arg);
726 g_assert (start_delegate != NULL);
727 args [0] = start_arg;
728 /* we may want to handle the exception here. See comment below on unhandled exceptions */
729 mono_runtime_delegate_invoke (start_delegate, args, NULL);
732 /* If the thread calls ExitThread at all, this remaining code
733 * will not be executed, but the main thread will eventually
734 * call thread_cleanup() on this thread's behalf.
737 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
739 /* Do any cleanup needed for apartment state. This
740 * cannot be done in thread_cleanup since thread_cleanup could be
741 * called for a thread other than the current thread.
742 * mono_thread_cleanup_apartment_state cleans up apartment
743 * for the current thead */
744 mono_thread_cleanup_apartment_state ();
746 thread_cleanup (internal);
750 /* Remove the reference to the thread object in the TLS data,
751 * so the thread object can be finalized. This won't be
752 * reached if the thread threw an uncaught exception, so those
753 * thread handles will stay referenced :-( (This is due to
754 * missing support for scanning thread-specific data in the
755 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
758 SET_CURRENT_OBJECT (NULL);
763 static guint32 WINAPI start_wrapper(void *data)
767 /* Avoid scanning the frames above this frame during a GC */
768 mono_gc_set_stack_end ((void*)&dummy);
770 return start_wrapper_internal (data);
776 * Common thread creation code.
777 * LOCKING: Acquires the threads lock.
780 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
781 gboolean throw_on_failure)
783 HANDLE thread_handle;
784 MonoNativeThreadId tid;
785 guint32 create_flags;
788 * Join joinable threads to prevent running out of threads since the finalizer
789 * thread might be blocked/backlogged.
791 mono_threads_join_threads ();
793 mono_threads_lock ();
796 mono_threads_unlock ();
800 * The thread start argument may be an object reference, and there is
801 * no ref to keep it alive when the new thread is started but not yet
802 * registered with the collector. So we store it in a GC tracked hash
805 if (thread_start_args == NULL) {
806 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
807 thread_start_args = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_CONSERVATIVE_GC);
809 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
810 if (threads_starting_up == NULL) {
811 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
812 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
814 mono_g_hash_table_insert (threads_starting_up, thread, thread);
815 mono_threads_unlock ();
817 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
818 if (!internal->start_notify) {
819 mono_threads_lock ();
820 mono_g_hash_table_remove (threads_starting_up, thread);
821 mono_threads_unlock ();
822 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
828 stack_size = default_stacksize_for_thread (internal);
830 /* Create suspended, so we can do some housekeeping before the thread
833 create_flags = CREATE_SUSPENDED;
835 MONO_PREPARE_BLOCKING;
836 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
837 stack_size, create_flags, &tid);
838 MONO_FINISH_BLOCKING;
840 if (thread_handle == NULL) {
841 /* The thread couldn't be created, so throw an exception */
842 mono_threads_lock ();
843 mono_g_hash_table_remove (threads_starting_up, thread);
844 mono_threads_unlock ();
846 if (throw_on_failure)
847 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
849 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
852 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
854 internal->handle = thread_handle;
855 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
857 internal->threadpool_thread = threadpool_thread;
858 if (threadpool_thread)
859 mono_thread_set_state (internal, ThreadState_Background);
861 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
863 /* Only store the handle when the thread is about to be
864 * launched, to avoid the main thread deadlocking while trying
865 * to clean up a thread that will never be signalled.
867 if (!handle_store (thread, FALSE))
870 MONO_PREPARE_BLOCKING;
871 mono_thread_info_resume (tid);
872 MONO_FINISH_BLOCKING;
874 if (internal->start_notify) {
876 * Wait for the thread to set up its TLS data etc, so
877 * theres no potential race condition if someone tries
878 * to look up the data believing the thread has
881 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
883 MONO_PREPARE_BLOCKING;
884 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
885 MONO_FINISH_BLOCKING;
887 CloseHandle (internal->start_notify);
888 internal->start_notify = NULL;
891 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
896 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
898 if (mono_thread_start_cb) {
899 mono_thread_start_cb (tid, stack_start, func);
903 void mono_threads_set_default_stacksize (guint32 stacksize)
905 default_stacksize = stacksize;
908 guint32 mono_threads_get_default_stacksize (void)
910 return default_stacksize;
914 * mono_thread_create_internal:
918 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
921 MonoInternalThread *internal;
922 StartInfo *start_info;
925 thread = create_thread_object (domain);
926 internal = create_internal_thread ();
927 MONO_OBJECT_SETREF (thread, internal_thread, internal);
929 start_info = g_new0 (StartInfo, 1);
930 start_info->func = func;
931 start_info->obj = thread;
932 start_info->start_arg = arg;
934 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
938 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
939 if (mono_check_corlib_version () == NULL)
940 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
946 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
948 mono_thread_create_internal (domain, func, arg, FALSE, 0);
952 mono_thread_attach (MonoDomain *domain)
954 return mono_thread_attach_full (domain, FALSE);
958 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
960 MonoThreadInfo *info;
961 MonoInternalThread *thread;
962 MonoThread *current_thread;
963 HANDLE thread_handle;
966 if ((thread = mono_thread_internal_current ())) {
967 if (domain != mono_domain_get ())
968 mono_domain_set (domain, TRUE);
969 /* Already attached */
970 return mono_thread_current ();
973 if (!mono_gc_register_thread (&domain)) {
974 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 ());
977 thread = create_internal_thread ();
979 thread_handle = mono_thread_info_open_handle ();
980 g_assert (thread_handle);
982 tid=GetCurrentThreadId ();
984 thread->handle=thread_handle;
986 thread->stack_ptr = &tid;
988 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
990 info = mono_thread_info_current ();
992 thread->thread_info = info;
993 thread->small_id = info->small_id;
995 current_thread = new_thread_with_internal (domain, thread);
997 if (!handle_store (current_thread, force_attach)) {
998 /* Mono is shutting down, so just wait for the end */
1003 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
1005 SET_CURRENT_OBJECT (thread);
1006 mono_domain_set (domain, TRUE);
1008 thread_adjust_static_data (thread);
1010 init_root_domain_thread (thread, current_thread);
1011 if (domain != mono_get_root_domain ())
1012 set_current_thread_for_domain (domain, thread, current_thread);
1015 if (mono_thread_attach_cb) {
1019 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1022 mono_thread_attach_cb (tid, &tid);
1024 mono_thread_attach_cb (tid, staddr + stsize);
1027 // FIXME: Need a separate callback
1028 mono_profiler_thread_start (tid);
1030 return current_thread;
1034 mono_thread_detach_internal (MonoInternalThread *thread)
1036 g_return_if_fail (thread != NULL);
1038 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1040 thread_cleanup (thread);
1042 SET_CURRENT_OBJECT (NULL);
1043 mono_domain_unset ();
1045 /* Don't need to CloseHandle this thread, even though we took a
1046 * reference in mono_thread_attach (), because the GC will do it
1047 * when the Thread object is finalised.
1052 mono_thread_detach (MonoThread *thread)
1055 mono_thread_detach_internal (thread->internal_thread);
1059 * mono_thread_detach_if_exiting:
1061 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1062 * This should be used at the end of embedding code which calls into managed code, and which
1063 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1066 mono_thread_detach_if_exiting (void)
1068 if (mono_thread_info_is_exiting ()) {
1069 MonoInternalThread *thread;
1071 thread = mono_thread_internal_current ();
1073 mono_thread_detach_internal (thread);
1074 mono_thread_info_detach ();
1082 MonoInternalThread *thread = mono_thread_internal_current ();
1084 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1086 thread_cleanup (thread);
1087 SET_CURRENT_OBJECT (NULL);
1088 mono_domain_unset ();
1090 /* we could add a callback here for embedders to use. */
1091 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1092 exit (mono_environment_exitcode_get ());
1093 mono_thread_info_exit ();
1097 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1099 MonoInternalThread *internal = create_internal_thread ();
1101 internal->state = ThreadState_Unstarted;
1103 InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
1107 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1110 StartInfo *start_info;
1111 MonoInternalThread *internal;
1114 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1116 if (!this_obj->internal_thread)
1117 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1118 internal = this_obj->internal_thread;
1120 LOCK_THREAD (internal);
1122 if ((internal->state & ThreadState_Unstarted) == 0) {
1123 UNLOCK_THREAD (internal);
1124 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1128 if ((internal->state & ThreadState_Aborted) != 0) {
1129 UNLOCK_THREAD (internal);
1132 /* This is freed in start_wrapper */
1133 start_info = g_new0 (StartInfo, 1);
1134 start_info->func = NULL;
1135 start_info->start_arg = this_obj->start_obj; /* FIXME: GC object stored in unmanaged memory */
1136 start_info->delegate = start;
1137 start_info->obj = this_obj;
1138 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1140 res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
1142 UNLOCK_THREAD (internal);
1146 internal->state &= ~ThreadState_Unstarted;
1148 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1150 UNLOCK_THREAD (internal);
1151 return internal->handle;
1155 * This is called from the finalizer of the internal thread object.
1158 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1160 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1163 * Since threads keep a reference to their thread object while running, by the time this function is called,
1164 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1165 * when thread_cleanup () can be called after this.
1168 CloseHandle (thread);
1170 if (this_obj->synch_cs) {
1171 mono_mutex_t *synch_cs = this_obj->synch_cs;
1172 this_obj->synch_cs = NULL;
1173 mono_mutex_destroy (synch_cs);
1177 if (this_obj->name) {
1178 void *name = this_obj->name;
1179 this_obj->name = NULL;
1185 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1188 MonoInternalThread *thread = mono_thread_internal_current ();
1190 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1192 mono_thread_current_check_pending_interrupt ();
1195 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1197 MONO_PREPARE_BLOCKING;
1198 res = SleepEx(ms,TRUE);
1199 MONO_FINISH_BLOCKING;
1201 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1203 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1204 MonoException* exc = mono_thread_execute_interruption (thread);
1206 mono_raise_exception (exc);
1218 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1223 ves_icall_System_Threading_Thread_GetDomainID (void)
1225 return mono_domain_get()->domain_id;
1229 ves_icall_System_Threading_Thread_Yield (void)
1231 return mono_thread_info_yield ();
1235 * mono_thread_get_name:
1237 * Return the name of the thread. NAME_LEN is set to the length of the name.
1238 * Return NULL if the thread has no name. The returned memory is owned by the
1242 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1246 LOCK_THREAD (this_obj);
1248 if (!this_obj->name) {
1252 *name_len = this_obj->name_len;
1253 res = g_new (gunichar2, this_obj->name_len);
1254 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1257 UNLOCK_THREAD (this_obj);
1263 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1267 LOCK_THREAD (this_obj);
1269 if (!this_obj->name)
1272 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1274 UNLOCK_THREAD (this_obj);
1280 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1282 LOCK_THREAD (this_obj);
1284 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1285 UNLOCK_THREAD (this_obj);
1287 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1290 if (this_obj->name) {
1291 g_free (this_obj->name);
1292 this_obj->name_len = 0;
1295 this_obj->name = g_new (gunichar2, mono_string_length (name));
1296 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1297 this_obj->name_len = mono_string_length (name);
1300 this_obj->name = NULL;
1303 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1305 UNLOCK_THREAD (this_obj);
1307 if (this_obj->name && this_obj->tid) {
1308 char *tname = mono_string_to_utf8 (name);
1309 mono_profiler_thread_name (this_obj->tid, tname);
1310 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1316 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1318 mono_thread_set_name_internal (this_obj, name, TRUE);
1322 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
1324 return ThreadPriority_Lowest;
1328 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1332 /* If the array is already in the requested domain, we just return it,
1333 otherwise we return a copy in that domain. */
1335 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1342 if (mono_object_domain (arr) == domain)
1345 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1346 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1351 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1353 return byte_array_to_domain (arr, mono_get_root_domain ());
1357 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1359 return byte_array_to_domain (arr, mono_domain_get ());
1363 mono_thread_current (void)
1365 MonoDomain *domain = mono_domain_get ();
1366 MonoInternalThread *internal = mono_thread_internal_current ();
1367 MonoThread **current_thread_ptr;
1369 g_assert (internal);
1370 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1372 if (!*current_thread_ptr) {
1373 g_assert (domain != mono_get_root_domain ());
1374 *current_thread_ptr = new_thread_with_internal (domain, internal);
1376 return *current_thread_ptr;
1380 mono_thread_internal_current (void)
1382 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1383 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1388 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1390 MonoInternalThread *thread = this_obj->internal_thread;
1391 HANDLE handle = thread->handle;
1392 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1395 mono_thread_current_check_pending_interrupt ();
1397 LOCK_THREAD (thread);
1399 if ((thread->state & ThreadState_Unstarted) != 0) {
1400 UNLOCK_THREAD (thread);
1402 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1406 UNLOCK_THREAD (thread);
1411 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1413 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1415 MONO_PREPARE_BLOCKING;
1416 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1417 MONO_FINISH_BLOCKING;
1419 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1421 if(ret==WAIT_OBJECT_0) {
1422 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1427 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1433 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1441 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1443 MONO_PREPARE_BLOCKING;
1445 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1447 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1448 MONO_FINISH_BLOCKING;
1450 if (ret != WAIT_IO_COMPLETION)
1453 exc = mono_thread_execute_interruption (thread);
1455 mono_raise_exception (exc);
1460 /* Re-calculate ms according to the time passed */
1461 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1462 if (diff_ms >= ms) {
1466 wait = ms - diff_ms;
1472 /* FIXME: exitContext isnt documented */
1473 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1479 MonoObject *waitHandle;
1480 MonoInternalThread *thread = mono_thread_internal_current ();
1482 /* Do this WaitSleepJoin check before creating objects */
1483 mono_thread_current_check_pending_interrupt ();
1485 /* We fail in managed if the array has more than 64 elements */
1486 numhandles = (guint32)mono_array_length(mono_handles);
1487 handles = g_new0(HANDLE, numhandles);
1489 for(i = 0; i < numhandles; i++) {
1490 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1491 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1498 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1500 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1502 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1506 if(ret==WAIT_FAILED) {
1507 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1509 } else if(ret==WAIT_TIMEOUT) {
1510 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1517 /* FIXME: exitContext isnt documented */
1518 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1520 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1521 uintptr_t numhandles;
1524 MonoObject *waitHandle;
1525 MonoInternalThread *thread = mono_thread_internal_current ();
1527 /* Do this WaitSleepJoin check before creating objects */
1528 mono_thread_current_check_pending_interrupt ();
1530 numhandles = mono_array_length(mono_handles);
1531 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1534 for(i = 0; i < numhandles; i++) {
1535 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1536 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1543 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1545 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1547 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1549 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1552 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1554 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1555 return ret - WAIT_OBJECT_0;
1557 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1558 return ret - WAIT_ABANDONED_0;
1565 /* FIXME: exitContext isnt documented */
1566 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
1569 MonoInternalThread *thread = mono_thread_internal_current ();
1571 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1577 mono_thread_current_check_pending_interrupt ();
1579 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1581 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1583 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1585 if(ret==WAIT_FAILED) {
1586 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1588 } else if(ret==WAIT_TIMEOUT) {
1589 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1597 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1600 MonoInternalThread *thread = mono_thread_internal_current ();
1605 mono_thread_current_check_pending_interrupt ();
1607 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1609 MONO_PREPARE_BLOCKING;
1610 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1611 MONO_FINISH_BLOCKING;
1613 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1615 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1618 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1625 mutex = CreateMutex (NULL, owned, NULL);
1627 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1629 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1637 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1638 return(ReleaseMutex (handle));
1641 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1647 *error = ERROR_SUCCESS;
1649 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1651 *error = GetLastError ();
1658 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1665 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1667 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1668 mono_string_chars (name));
1670 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1678 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1682 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1687 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1691 *error = ERROR_SUCCESS;
1693 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1695 *error = GetLastError ();
1701 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1708 event = CreateEvent (NULL, manual, initial, NULL);
1710 event = CreateEvent (NULL, manual, initial,
1711 mono_string_chars (name));
1713 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1721 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1722 return (SetEvent(handle));
1725 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1726 return (ResetEvent(handle));
1730 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1731 CloseHandle (handle);
1734 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1740 *error = ERROR_SUCCESS;
1742 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1744 *error = GetLastError ();
1750 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1752 return InterlockedIncrement (location);
1755 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1757 #if SIZEOF_VOID_P == 4
1758 if (G_UNLIKELY ((size_t)location & 0x7)) {
1760 mono_interlocked_lock ();
1763 mono_interlocked_unlock ();
1767 return InterlockedIncrement64 (location);
1770 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1772 return InterlockedDecrement(location);
1775 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1777 #if SIZEOF_VOID_P == 4
1778 if (G_UNLIKELY ((size_t)location & 0x7)) {
1780 mono_interlocked_lock ();
1783 mono_interlocked_unlock ();
1787 return InterlockedDecrement64 (location);
1790 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1792 return InterlockedExchange(location, value);
1795 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1798 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1799 mono_gc_wbarrier_generic_nostore (location);
1803 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1805 return InterlockedExchangePointer(location, value);
1808 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1810 IntFloatUnion val, ret;
1813 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1819 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1821 #if SIZEOF_VOID_P == 4
1822 if (G_UNLIKELY ((size_t)location & 0x7)) {
1824 mono_interlocked_lock ();
1827 mono_interlocked_unlock ();
1831 return InterlockedExchange64 (location, value);
1835 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1837 LongDoubleUnion val, ret;
1840 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1845 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1847 return InterlockedCompareExchange(location, value, comparand);
1850 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1852 gint32 r = InterlockedCompareExchange(location, value, comparand);
1853 *success = r == comparand;
1857 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1860 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1861 mono_gc_wbarrier_generic_nostore (location);
1865 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1867 return InterlockedCompareExchangePointer(location, value, comparand);
1870 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1872 IntFloatUnion val, ret, cmp;
1875 cmp.fval = comparand;
1876 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1882 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1884 #if SIZEOF_VOID_P == 8
1885 LongDoubleUnion val, comp, ret;
1888 comp.fval = comparand;
1889 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1895 mono_interlocked_lock ();
1897 if (old == comparand)
1899 mono_interlocked_unlock ();
1906 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1908 #if SIZEOF_VOID_P == 4
1909 if (G_UNLIKELY ((size_t)location & 0x7)) {
1911 mono_interlocked_lock ();
1913 if (old == comparand)
1915 mono_interlocked_unlock ();
1919 return InterlockedCompareExchange64 (location, value, comparand);
1923 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1926 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1927 mono_gc_wbarrier_generic_nostore (location);
1932 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1935 res = InterlockedExchangePointer ((gpointer *)location, value);
1936 mono_gc_wbarrier_generic_nostore (location);
1941 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1943 return InterlockedAdd (location, value);
1947 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1949 #if SIZEOF_VOID_P == 4
1950 if (G_UNLIKELY ((size_t)location & 0x7)) {
1952 mono_interlocked_lock ();
1955 mono_interlocked_unlock ();
1959 return InterlockedAdd64 (location, value);
1963 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1965 #if SIZEOF_VOID_P == 4
1966 if (G_UNLIKELY ((size_t)location & 0x7)) {
1968 mono_interlocked_lock ();
1970 mono_interlocked_unlock ();
1974 return InterlockedRead64 (location);
1978 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1980 mono_memory_barrier ();
1984 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1986 mono_thread_clr_state (this, state);
1988 if (state & ThreadState_Background) {
1989 /* If the thread changes the background mode, the main thread has to
1990 * be notified, since it has to rebuild the list of threads to
1993 SetEvent (background_change_event);
1998 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
2000 mono_thread_set_state (this, state);
2002 if (state & ThreadState_Background) {
2003 /* If the thread changes the background mode, the main thread has to
2004 * be notified, since it has to rebuild the list of threads to
2007 SetEvent (background_change_event);
2012 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2018 state = this->state;
2020 UNLOCK_THREAD (this);
2025 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2027 MonoInternalThread *current;
2029 MonoInternalThread *thread = this_obj->internal_thread;
2031 LOCK_THREAD (thread);
2033 current = mono_thread_internal_current ();
2035 thread->thread_interrupt_requested = TRUE;
2036 throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2038 UNLOCK_THREAD (thread);
2041 abort_thread_internal (thread, TRUE, FALSE);
2045 void mono_thread_current_check_pending_interrupt ()
2047 MonoInternalThread *thread = mono_thread_internal_current ();
2048 gboolean throw = FALSE;
2050 LOCK_THREAD (thread);
2052 if (thread->thread_interrupt_requested) {
2054 thread->thread_interrupt_requested = FALSE;
2057 UNLOCK_THREAD (thread);
2060 mono_raise_exception (mono_get_exception_thread_interrupted ());
2065 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2067 LOCK_THREAD (thread);
2069 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2070 (thread->state & ThreadState_StopRequested) != 0 ||
2071 (thread->state & ThreadState_Stopped) != 0)
2073 UNLOCK_THREAD (thread);
2077 if ((thread->state & ThreadState_Unstarted) != 0) {
2078 thread->state |= ThreadState_Aborted;
2079 UNLOCK_THREAD (thread);
2083 thread->state |= ThreadState_AbortRequested;
2084 if (thread->abort_state_handle)
2085 mono_gchandle_free (thread->abort_state_handle);
2087 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2088 g_assert (thread->abort_state_handle);
2090 thread->abort_state_handle = 0;
2092 thread->abort_exc = NULL;
2094 UNLOCK_THREAD (thread);
2096 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2098 /* During shutdown, we can't wait for other threads */
2100 /* Make sure the thread is awake */
2101 mono_thread_resume (thread);
2103 abort_thread_internal (thread, TRUE, TRUE);
2107 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2109 MonoInternalThread *thread = mono_thread_internal_current ();
2110 gboolean was_aborting;
2112 LOCK_THREAD (thread);
2113 was_aborting = thread->state & ThreadState_AbortRequested;
2114 thread->state &= ~ThreadState_AbortRequested;
2115 UNLOCK_THREAD (thread);
2117 if (!was_aborting) {
2118 const char *msg = "Unable to reset abort because no abort was requested";
2119 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2122 thread->abort_exc = NULL;
2123 if (thread->abort_state_handle) {
2124 mono_gchandle_free (thread->abort_state_handle);
2125 /* This is actually not necessary - the handle
2126 only counts if the exception is set */
2127 thread->abort_state_handle = 0;
2132 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2134 LOCK_THREAD (thread);
2136 thread->state &= ~ThreadState_AbortRequested;
2138 if (thread->abort_exc) {
2139 thread->abort_exc = NULL;
2140 if (thread->abort_state_handle) {
2141 mono_gchandle_free (thread->abort_state_handle);
2142 /* This is actually not necessary - the handle
2143 only counts if the exception is set */
2144 thread->abort_state_handle = 0;
2148 UNLOCK_THREAD (thread);
2152 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2154 MonoInternalThread *thread = this_obj->internal_thread;
2155 MonoObject *state, *deserialized = NULL, *exc;
2158 if (!thread->abort_state_handle)
2161 state = mono_gchandle_get_target (thread->abort_state_handle);
2164 domain = mono_domain_get ();
2165 if (mono_object_domain (state) == domain)
2168 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2170 if (!deserialized) {
2171 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2173 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2174 mono_set_pending_exception (invalid_op_exc);
2178 return deserialized;
2182 mono_thread_suspend (MonoInternalThread *thread)
2184 LOCK_THREAD (thread);
2186 if ((thread->state & ThreadState_Unstarted) != 0 ||
2187 (thread->state & ThreadState_Aborted) != 0 ||
2188 (thread->state & ThreadState_Stopped) != 0)
2190 UNLOCK_THREAD (thread);
2194 if ((thread->state & ThreadState_Suspended) != 0 ||
2195 (thread->state & ThreadState_SuspendRequested) != 0 ||
2196 (thread->state & ThreadState_StopRequested) != 0)
2198 UNLOCK_THREAD (thread);
2202 thread->state |= ThreadState_SuspendRequested;
2204 UNLOCK_THREAD (thread);
2206 suspend_thread_internal (thread, FALSE);
2211 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2213 if (!mono_thread_suspend (this_obj->internal_thread)) {
2214 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2220 mono_thread_resume (MonoInternalThread *thread)
2222 LOCK_THREAD (thread);
2224 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2225 thread->state &= ~ThreadState_SuspendRequested;
2226 UNLOCK_THREAD (thread);
2230 if ((thread->state & ThreadState_Suspended) == 0 ||
2231 (thread->state & ThreadState_Unstarted) != 0 ||
2232 (thread->state & ThreadState_Aborted) != 0 ||
2233 (thread->state & ThreadState_Stopped) != 0)
2235 UNLOCK_THREAD (thread);
2239 return resume_thread_internal (thread);
2243 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2245 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2246 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2252 mono_threads_is_critical_method (MonoMethod *method)
2254 switch (method->wrapper_type) {
2255 case MONO_WRAPPER_RUNTIME_INVOKE:
2256 case MONO_WRAPPER_XDOMAIN_INVOKE:
2257 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2264 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2269 if (mono_threads_is_critical_method (m)) {
2270 *((gboolean*)data) = TRUE;
2277 is_running_protected_wrapper (void)
2279 gboolean found = FALSE;
2280 mono_stack_walk (find_wrapper, &found);
2284 void mono_thread_internal_stop (MonoInternalThread *thread)
2286 LOCK_THREAD (thread);
2288 if ((thread->state & ThreadState_StopRequested) != 0 ||
2289 (thread->state & ThreadState_Stopped) != 0)
2291 UNLOCK_THREAD (thread);
2295 /* Make sure the thread is awake */
2296 mono_thread_resume (thread);
2298 thread->state |= ThreadState_StopRequested;
2299 thread->state &= ~ThreadState_AbortRequested;
2301 UNLOCK_THREAD (thread);
2303 abort_thread_internal (thread, TRUE, TRUE);
2306 void mono_thread_stop (MonoThread *thread)
2308 mono_thread_internal_stop (thread->internal_thread);
2312 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2315 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2320 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2323 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2328 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2331 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2336 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2339 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2344 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2347 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2348 return (void *) tmp;
2352 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2354 volatile MonoObject *tmp;
2355 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2356 return (MonoObject *) tmp;
2360 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2363 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2368 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2371 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2376 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2378 return InterlockedRead8 (ptr);
2382 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2384 return InterlockedRead16 (ptr);
2388 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2390 return InterlockedRead (ptr);
2394 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2396 #if SIZEOF_VOID_P == 4
2397 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2399 mono_interlocked_lock ();
2400 val = *(gint64*)ptr;
2401 mono_interlocked_unlock ();
2405 return InterlockedRead64 (ptr);
2409 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2411 return InterlockedReadPointer (ptr);
2415 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2419 #if SIZEOF_VOID_P == 4
2420 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2422 mono_interlocked_lock ();
2423 val = *(double*)ptr;
2424 mono_interlocked_unlock ();
2429 u.ival = InterlockedRead64 (ptr);
2435 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2439 u.ival = InterlockedRead (ptr);
2445 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2447 return InterlockedReadPointer (ptr);
2451 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2453 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2457 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2459 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2463 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2465 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2469 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2471 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2475 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2477 mono_atomic_store_release ((volatile void **) ptr, value);
2481 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2483 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2487 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2489 mono_atomic_store_release ((volatile double *) ptr, value);
2493 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2495 mono_atomic_store_release ((volatile float *) ptr, value);
2499 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2501 InterlockedWrite8 (ptr, value);
2505 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2507 InterlockedWrite16 (ptr, value);
2511 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2513 InterlockedWrite (ptr, value);
2517 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2519 #if SIZEOF_VOID_P == 4
2520 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2521 mono_interlocked_lock ();
2522 *(gint64*)ptr = value;
2523 mono_interlocked_unlock ();
2528 InterlockedWrite64 (ptr, value);
2532 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2534 InterlockedWritePointer (ptr, value);
2538 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2542 #if SIZEOF_VOID_P == 4
2543 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2544 mono_interlocked_lock ();
2545 *(double*)ptr = value;
2546 mono_interlocked_unlock ();
2553 InterlockedWrite64 (ptr, u.ival);
2557 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2563 InterlockedWrite (ptr, u.ival);
2567 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2569 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2573 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2575 mono_threads_lock ();
2577 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2580 contexts = g_hash_table_new (NULL, NULL);
2582 context_adjust_static_data (ctx);
2583 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2584 g_hash_table_insert (contexts, gch, gch);
2586 mono_threads_unlock ();
2588 mono_profiler_context_loaded (ctx);
2592 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2595 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2596 * cleanup in exceptional circumstances, we don't actually do any
2597 * cleanup work here. We instead do this when we iterate the `contexts`
2598 * hash table. The only purpose of this finalizer, at the moment, is to
2599 * notify the profiler.
2602 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2604 mono_profiler_context_unloaded (ctx);
2608 mono_thread_init_tls (void)
2610 MONO_FAST_TLS_INIT (tls_current_object);
2611 mono_native_tls_alloc (¤t_object_key, NULL);
2614 void mono_thread_init (MonoThreadStartCB start_cb,
2615 MonoThreadAttachCB attach_cb)
2617 mono_mutex_init_recursive(&threads_mutex);
2618 mono_mutex_init_recursive(&interlocked_mutex);
2619 mono_mutex_init_recursive(&joinable_threads_mutex);
2621 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2622 g_assert(background_change_event != NULL);
2624 mono_init_static_data_info (&thread_static_info);
2625 mono_init_static_data_info (&context_static_info);
2627 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2629 mono_thread_start_cb = start_cb;
2630 mono_thread_attach_cb = attach_cb;
2632 /* Get a pseudo handle to the current process. This is just a
2633 * kludge so that wapi can build a process handle if needed.
2634 * As a pseudo handle is returned, we don't need to clean
2637 GetCurrentProcess ();
2640 void mono_thread_cleanup (void)
2642 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2643 MonoThreadInfo *info;
2645 /* The main thread must abandon any held mutexes (particularly
2646 * important for named mutexes as they are shared across
2647 * processes, see bug 74680.) This will happen when the
2648 * thread exits, but if it's not running in a subthread it
2649 * won't exit in time.
2651 info = mono_thread_info_current ();
2652 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2656 /* This stuff needs more testing, it seems one of these
2657 * critical sections can be locked when mono_thread_cleanup is
2660 mono_mutex_destroy (&threads_mutex);
2661 mono_mutex_destroy (&interlocked_mutex);
2662 mono_mutex_destroy (&delayed_free_table_mutex);
2663 mono_mutex_destroy (&small_id_mutex);
2664 CloseHandle (background_change_event);
2667 mono_native_tls_free (current_object_key);
2671 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2673 mono_thread_cleanup_fn = func;
2677 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2679 thread->internal_thread->manage_callback = func;
2682 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2684 mono_thread_notify_pending_exc_fn = func;
2688 static void print_tids (gpointer key, gpointer value, gpointer user)
2690 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2691 * sizeof(uint) and a cast to uint would overflow
2693 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2694 * print this as a pointer.
2696 g_message ("Waiting for: %p", key);
2701 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2702 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2706 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2710 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2712 MONO_PREPARE_BLOCKING;
2713 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2714 MONO_FINISH_BLOCKING;
2716 if(ret==WAIT_FAILED) {
2717 /* See the comment in build_wait_tids() */
2718 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2722 for(i=0; i<wait->num; i++)
2723 CloseHandle (wait->handles[i]);
2725 if (ret == WAIT_TIMEOUT)
2728 for(i=0; i<wait->num; i++) {
2729 gsize tid = wait->threads[i]->tid;
2732 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2733 * it can still run io-layer etc. code. So wait for it to really exit.
2734 * FIXME: This won't join threads which are not in the joinable_hash yet.
2736 mono_thread_join ((gpointer)tid);
2738 mono_threads_lock ();
2739 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2740 /* This thread must have been killed, because
2741 * it hasn't cleaned itself up. (It's just
2742 * possible that the thread exited before the
2743 * parent thread had a chance to store the
2744 * handle, and now there is another pointer to
2745 * the already-exited thread stored. In this
2746 * case, we'll just get two
2747 * mono_profiler_thread_end() calls for the
2751 mono_threads_unlock ();
2752 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2753 thread_cleanup (wait->threads[i]);
2755 mono_threads_unlock ();
2760 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2762 guint32 i, ret, count;
2764 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2766 /* Add the thread state change event, so it wakes up if a thread changes
2767 * to background mode.
2770 if (count < MAXIMUM_WAIT_OBJECTS) {
2771 wait->handles [count] = background_change_event;
2775 MONO_PREPARE_BLOCKING;
2776 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2777 MONO_FINISH_BLOCKING;
2779 if(ret==WAIT_FAILED) {
2780 /* See the comment in build_wait_tids() */
2781 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2785 for(i=0; i<wait->num; i++)
2786 CloseHandle (wait->handles[i]);
2788 if (ret == WAIT_TIMEOUT)
2791 if (ret < wait->num) {
2792 gsize tid = wait->threads[ret]->tid;
2793 mono_threads_lock ();
2794 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2795 /* See comment in wait_for_tids about thread cleanup */
2796 mono_threads_unlock ();
2797 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2798 thread_cleanup (wait->threads [ret]);
2800 mono_threads_unlock ();
2804 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2806 struct wait_data *wait=(struct wait_data *)user;
2808 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2810 MonoInternalThread *thread=(MonoInternalThread *)value;
2812 /* Ignore background threads, we abort them later */
2813 /* Do not lock here since it is not needed and the caller holds threads_lock */
2814 if (thread->state & ThreadState_Background) {
2815 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2816 return; /* just leave, ignore */
2819 if (mono_gc_is_finalizer_internal_thread (thread)) {
2820 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2824 if (thread == mono_thread_internal_current ()) {
2825 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2829 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2830 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2834 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2835 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2839 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2840 if (handle == NULL) {
2841 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2845 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2846 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2847 wait->handles[wait->num]=handle;
2848 wait->threads[wait->num]=thread;
2851 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2853 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2858 /* Just ignore the rest, we can't do anything with
2865 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2867 struct wait_data *wait=(struct wait_data *)user;
2868 gsize self = GetCurrentThreadId ();
2869 MonoInternalThread *thread = value;
2872 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2875 /* The finalizer thread is not a background thread */
2876 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2877 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2879 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2883 /* printf ("A: %d\n", wait->num); */
2884 wait->handles[wait->num]=thread->handle;
2885 wait->threads[wait->num]=thread;
2888 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2889 mono_thread_internal_stop (thread);
2893 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2897 * mono_threads_set_shutting_down:
2899 * Is called by a thread that wants to shut down Mono. If the runtime is already
2900 * shutting down, the calling thread is suspended/stopped, and this function never
2904 mono_threads_set_shutting_down (void)
2906 MonoInternalThread *current_thread = mono_thread_internal_current ();
2908 mono_threads_lock ();
2910 if (shutting_down) {
2911 mono_threads_unlock ();
2913 /* Make sure we're properly suspended/stopped */
2915 LOCK_THREAD (current_thread);
2917 if ((current_thread->state & ThreadState_SuspendRequested) ||
2918 (current_thread->state & ThreadState_AbortRequested) ||
2919 (current_thread->state & ThreadState_StopRequested)) {
2920 UNLOCK_THREAD (current_thread);
2921 mono_thread_execute_interruption (current_thread);
2923 current_thread->state |= ThreadState_Stopped;
2924 UNLOCK_THREAD (current_thread);
2927 /*since we're killing the thread, unset the current domain.*/
2928 mono_domain_unset ();
2930 /* Wake up other threads potentially waiting for us */
2931 mono_thread_info_exit ();
2933 shutting_down = TRUE;
2935 /* Not really a background state change, but this will
2936 * interrupt the main thread if it is waiting for all
2937 * the other threads.
2939 SetEvent (background_change_event);
2941 mono_threads_unlock ();
2945 void mono_thread_manage (void)
2947 struct wait_data wait_data;
2948 struct wait_data *wait = &wait_data;
2950 memset (wait, 0, sizeof (struct wait_data));
2951 /* join each thread that's still running */
2952 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2954 mono_threads_lock ();
2956 THREAD_DEBUG (g_message("%s: No threads", __func__));
2957 mono_threads_unlock ();
2960 mono_threads_unlock ();
2963 mono_threads_lock ();
2964 if (shutting_down) {
2965 /* somebody else is shutting down */
2966 mono_threads_unlock ();
2969 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2970 mono_g_hash_table_foreach (threads, print_tids, NULL));
2972 ResetEvent (background_change_event);
2974 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2975 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2976 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2977 mono_threads_unlock ();
2979 /* Something to wait for */
2980 wait_for_tids_or_state_change (wait, INFINITE);
2982 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2983 } while(wait->num>0);
2985 /* Mono is shutting down, so just wait for the end */
2986 if (!mono_runtime_try_shutdown ()) {
2987 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2988 mono_thread_suspend (mono_thread_internal_current ());
2989 mono_thread_execute_interruption (mono_thread_internal_current ());
2993 * Remove everything but the finalizer thread and self.
2994 * Also abort all the background threads
2997 mono_threads_lock ();
3000 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3001 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3002 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3004 mono_threads_unlock ();
3006 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3008 /* Something to wait for */
3009 wait_for_tids (wait, INFINITE);
3011 } while (wait->num > 0);
3014 * give the subthreads a chance to really quit (this is mainly needed
3015 * to get correct user and system times from getrusage/wait/time(1)).
3016 * This could be removed if we avoid pthread_detach() and use pthread_join().
3018 mono_thread_info_yield ();
3021 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3023 MonoInternalThread *thread=(MonoInternalThread *)value;
3025 if(thread->tid != (gsize)user) {
3026 /*TerminateThread (thread->handle, -1);*/
3030 void mono_thread_abort_all_other_threads (void)
3032 gsize self = GetCurrentThreadId ();
3034 mono_threads_lock ();
3035 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3036 mono_g_hash_table_size (threads));
3037 mono_g_hash_table_foreach (threads, print_tids, NULL));
3039 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3041 mono_threads_unlock ();
3045 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3047 MonoInternalThread *thread = (MonoInternalThread*)value;
3048 struct wait_data *wait = (struct wait_data*)user_data;
3052 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3054 * This needs no locking.
3056 if ((thread->state & ThreadState_Suspended) != 0 ||
3057 (thread->state & ThreadState_Stopped) != 0)
3060 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3061 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3065 wait->handles [wait->num] = handle;
3066 wait->threads [wait->num] = thread;
3072 * mono_thread_suspend_all_other_threads:
3074 * Suspend all managed threads except the finalizer thread and this thread. It is
3075 * not possible to resume them later.
3077 void mono_thread_suspend_all_other_threads (void)
3079 struct wait_data wait_data;
3080 struct wait_data *wait = &wait_data;
3082 gsize self = GetCurrentThreadId ();
3083 guint32 eventidx = 0;
3084 gboolean starting, finished;
3086 memset (wait, 0, sizeof (struct wait_data));
3088 * The other threads could be in an arbitrary state at this point, i.e.
3089 * they could be starting up, shutting down etc. This means that there could be
3090 * threads which are not even in the threads hash table yet.
3094 * First we set a barrier which will be checked by all threads before they
3095 * are added to the threads hash table, and they will exit if the flag is set.
3096 * This ensures that no threads could be added to the hash later.
3097 * We will use shutting_down as the barrier for now.
3099 g_assert (shutting_down);
3102 * We make multiple calls to WaitForMultipleObjects since:
3103 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3104 * - some threads could exit without becoming suspended
3109 * Make a copy of the hashtable since we can't do anything with
3110 * threads while threads_mutex is held.
3113 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3114 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3115 mono_threads_lock ();
3116 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3117 mono_threads_unlock ();
3120 /* Get the suspended events that we'll be waiting for */
3121 for (i = 0; i < wait->num; ++i) {
3122 MonoInternalThread *thread = wait->threads [i];
3124 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3125 //CloseHandle (wait->handles [i]);
3126 wait->threads [i] = NULL; /* ignore this thread in next loop */
3130 LOCK_THREAD (thread);
3132 if ((thread->state & ThreadState_Suspended) != 0 ||
3133 (thread->state & ThreadState_StopRequested) != 0 ||
3134 (thread->state & ThreadState_Stopped) != 0) {
3135 UNLOCK_THREAD (thread);
3136 CloseHandle (wait->handles [i]);
3137 wait->threads [i] = NULL; /* ignore this thread in next loop */
3143 /* Convert abort requests into suspend requests */
3144 if ((thread->state & ThreadState_AbortRequested) != 0)
3145 thread->state &= ~ThreadState_AbortRequested;
3147 thread->state |= ThreadState_SuspendRequested;
3149 UNLOCK_THREAD (thread);
3151 /* Signal the thread to suspend */
3152 suspend_thread_internal (thread, TRUE);
3154 if (eventidx <= 0) {
3156 * If there are threads which are starting up, we wait until they
3157 * are suspended when they try to register in the threads hash.
3158 * This is guaranteed to finish, since the threads which can create new
3159 * threads get suspended after a while.
3160 * FIXME: The finalizer thread can still create new threads.
3162 mono_threads_lock ();
3163 if (threads_starting_up)
3164 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3167 mono_threads_unlock ();
3176 static gboolean thread_dump_requested;
3178 static G_GNUC_UNUSED gboolean
3179 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3181 GString *p = (GString*)data;
3182 MonoMethod *method = NULL;
3183 if (frame->type == FRAME_TYPE_MANAGED)
3184 method = mono_jit_info_get_method (frame->ji);
3187 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3188 g_string_append_printf (p, " %s\n", location);
3191 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3196 static SuspendThreadResult
3197 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3199 MonoInternalThread *thread = ud;
3200 GString* text = g_string_new (0);
3202 GError *error = NULL;
3205 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3207 g_string_append_printf (text, "\n\"%s\"", name);
3210 else if (thread->threadpool_thread)
3211 g_string_append (text, "\n\"<threadpool thread>\"");
3213 g_string_append (text, "\n\"<unnamed thread>\"");
3216 /* This no longer works with remote unwinding */
3218 wapi_desc = wapi_current_thread_desc ();
3219 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3224 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);
3226 fprintf (stdout, "%s", text->str);
3228 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3229 OutputDebugStringA(text->str);
3232 g_string_free (text, TRUE);
3234 return MonoResumeThread;
3238 dump_thread (gpointer key, gpointer value, gpointer user)
3240 MonoInternalThread *thread = (MonoInternalThread *)value;
3242 if (thread == mono_thread_internal_current ())
3246 FIXME This still can hang if we stop a thread during malloc.
3247 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3248 that takes a callback and runs it with the target suspended.
3249 We probably should loop a bit around trying to get it to either managed code
3252 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
3256 mono_threads_perform_thread_dump (void)
3258 if (!thread_dump_requested)
3261 printf ("Full thread dump:\n");
3263 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3264 something needs then in the process.
3266 mono_loader_lock ();
3267 mono_domain_lock (mono_get_root_domain ());
3269 mono_threads_lock ();
3270 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3271 mono_threads_unlock ();
3273 mono_domain_unlock (mono_get_root_domain ());
3274 mono_loader_unlock ();
3276 thread_dump_requested = FALSE;
3280 * mono_threads_request_thread_dump:
3282 * Ask all threads except the current to print their stacktrace to stdout.
3285 mono_threads_request_thread_dump (void)
3287 /*The new thread dump code runs out of the finalizer thread. */
3288 thread_dump_requested = TRUE;
3289 mono_gc_finalize_notify ();
3294 gint allocated; /* +1 so that refs [allocated] == NULL */
3298 typedef struct ref_stack RefStack;
3301 ref_stack_new (gint initial_size)
3305 initial_size = MAX (initial_size, 16) + 1;
3306 rs = g_new0 (RefStack, 1);
3307 rs->refs = g_new0 (gpointer, initial_size);
3308 rs->allocated = initial_size;
3313 ref_stack_destroy (gpointer ptr)
3324 ref_stack_push (RefStack *rs, gpointer ptr)
3326 g_assert (rs != NULL);
3328 if (rs->bottom >= rs->allocated) {
3329 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3330 rs->allocated <<= 1;
3331 rs->refs [rs->allocated] = NULL;
3333 rs->refs [rs->bottom++] = ptr;
3337 ref_stack_pop (RefStack *rs)
3339 if (rs == NULL || rs->bottom == 0)
3343 rs->refs [rs->bottom] = NULL;
3347 ref_stack_find (RefStack *rs, gpointer ptr)
3354 for (refs = rs->refs; refs && *refs; refs++) {
3362 * mono_thread_push_appdomain_ref:
3364 * Register that the current thread may have references to objects in domain
3365 * @domain on its stack. Each call to this function should be paired with a
3366 * call to pop_appdomain_ref.
3369 mono_thread_push_appdomain_ref (MonoDomain *domain)
3371 MonoInternalThread *thread = mono_thread_internal_current ();
3374 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3375 SPIN_LOCK (thread->lock_thread_id);
3376 if (thread->appdomain_refs == NULL)
3377 thread->appdomain_refs = ref_stack_new (16);
3378 ref_stack_push (thread->appdomain_refs, domain);
3379 SPIN_UNLOCK (thread->lock_thread_id);
3384 mono_thread_pop_appdomain_ref (void)
3386 MonoInternalThread *thread = mono_thread_internal_current ();
3389 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3390 SPIN_LOCK (thread->lock_thread_id);
3391 ref_stack_pop (thread->appdomain_refs);
3392 SPIN_UNLOCK (thread->lock_thread_id);
3397 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3400 SPIN_LOCK (thread->lock_thread_id);
3401 res = ref_stack_find (thread->appdomain_refs, domain);
3402 SPIN_UNLOCK (thread->lock_thread_id);
3407 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3409 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3412 typedef struct abort_appdomain_data {
3413 struct wait_data wait;
3415 } abort_appdomain_data;
3418 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3420 MonoInternalThread *thread = (MonoInternalThread*)value;
3421 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3422 MonoDomain *domain = data->domain;
3424 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3425 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3427 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3428 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3431 data->wait.handles [data->wait.num] = handle;
3432 data->wait.threads [data->wait.num] = thread;
3435 /* Just ignore the rest, we can't do anything with
3443 * mono_threads_abort_appdomain_threads:
3445 * Abort threads which has references to the given appdomain.
3448 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3450 #ifdef __native_client__
3454 abort_appdomain_data user_data;
3456 int orig_timeout = timeout;
3459 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3461 start_time = mono_msec_ticks ();
3463 mono_threads_lock ();
3465 user_data.domain = domain;
3466 user_data.wait.num = 0;
3467 /* This shouldn't take any locks */
3468 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3469 mono_threads_unlock ();
3471 if (user_data.wait.num > 0) {
3472 /* Abort the threads outside the threads lock */
3473 for (i = 0; i < user_data.wait.num; ++i)
3474 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3477 * We should wait for the threads either to abort, or to leave the
3478 * domain. We can't do the latter, so we wait with a timeout.
3480 wait_for_tids (&user_data.wait, 100);
3483 /* Update remaining time */
3484 timeout -= mono_msec_ticks () - start_time;
3485 start_time = mono_msec_ticks ();
3487 if (orig_timeout != -1 && timeout < 0)
3490 while (user_data.wait.num > 0);
3492 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3498 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3500 MonoInternalThread *thread = (MonoInternalThread*)value;
3501 MonoDomain *domain = (MonoDomain*)user_data;
3504 /* No locking needed here */
3505 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3507 if (thread->cached_culture_info) {
3508 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3509 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3510 if (obj && obj->vtable->domain == domain)
3511 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3517 * mono_threads_clear_cached_culture:
3519 * Clear the cached_current_culture from all threads if it is in the
3523 mono_threads_clear_cached_culture (MonoDomain *domain)
3525 mono_threads_lock ();
3526 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3527 mono_threads_unlock ();
3531 * mono_thread_get_undeniable_exception:
3533 * Return an exception which needs to be raised when leaving a catch clause.
3534 * This is used for undeniable exception propagation.
3537 mono_thread_get_undeniable_exception (void)
3539 MonoInternalThread *thread = mono_thread_internal_current ();
3541 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3543 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3544 * exception if the thread no longer references a dying appdomain.
3546 thread->abort_exc->trace_ips = NULL;
3547 thread->abort_exc->stack_trace = NULL;
3548 return thread->abort_exc;
3554 #if MONO_SMALL_CONFIG
3555 #define NUM_STATIC_DATA_IDX 4
3556 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3560 #define NUM_STATIC_DATA_IDX 8
3561 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3562 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3566 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3567 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3570 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3572 gpointer *static_data = addr;
3574 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3575 void **ptr = static_data [i];
3580 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3581 void **p = ptr + idx;
3584 mark_func ((MonoObject**)p, gc_data);
3590 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3592 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3596 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3598 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3602 * mono_alloc_static_data
3604 * Allocate memory blocks for storing threads or context static data
3607 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3609 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3612 gpointer* static_data = *static_data_ptr;
3614 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3615 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3617 if (mono_gc_user_markers_supported ()) {
3618 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3619 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3621 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3622 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3625 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc);
3626 *static_data_ptr = static_data;
3627 static_data [0] = static_data;
3630 for (i = 1; i <= idx; ++i) {
3631 if (static_data [i])
3634 if (mono_gc_user_markers_supported ())
3635 static_data [i] = g_malloc0 (static_data_size [i]);
3637 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL);
3642 mono_free_static_data (gpointer* static_data)
3645 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3646 gpointer p = static_data [i];
3650 * At this point, the static data pointer array is still registered with the
3651 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3652 * data. Freeing the individual arrays without first nulling their slots
3653 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3654 * such an already freed array. See bug #13813.
3656 static_data [i] = NULL;
3657 mono_memory_write_barrier ();
3658 if (mono_gc_user_markers_supported ())
3661 mono_gc_free_fixed (p);
3663 mono_gc_free_fixed (static_data);
3667 * mono_init_static_data_info
3669 * Initializes static data counters
3671 static void mono_init_static_data_info (StaticDataInfo *static_data)
3673 static_data->idx = 0;
3674 static_data->offset = 0;
3675 static_data->freelist = NULL;
3679 * mono_alloc_static_data_slot
3681 * Generates an offset for static data. static_data contains the counters
3682 * used to generate it.
3685 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3687 if (!static_data->idx && !static_data->offset) {
3689 * we use the first chunk of the first allocation also as
3690 * an array for the rest of the data
3692 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3694 static_data->offset += align - 1;
3695 static_data->offset &= ~(align - 1);
3696 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3697 static_data->idx ++;
3698 g_assert (size <= static_data_size [static_data->idx]);
3699 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3700 static_data->offset = 0;
3702 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3703 static_data->offset += size;
3708 * ensure thread static fields already allocated are valid for thread
3709 * This function is called when a thread is created or on thread attach.
3712 thread_adjust_static_data (MonoInternalThread *thread)
3714 mono_threads_lock ();
3715 if (thread_static_info.offset || thread_static_info.idx > 0) {
3716 /* get the current allocated size */
3717 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3718 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3720 mono_threads_unlock ();
3724 * LOCKING: requires that threads_mutex is held
3727 context_adjust_static_data (MonoAppContext *ctx)
3729 if (context_static_info.offset || context_static_info.idx > 0) {
3730 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3731 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3736 * LOCKING: requires that threads_mutex is held
3739 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3741 MonoInternalThread *thread = value;
3742 guint32 offset = GPOINTER_TO_UINT (user);
3744 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3748 * LOCKING: requires that threads_mutex is held
3751 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3753 uint32_t gch = GPOINTER_TO_INT (key);
3754 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3757 mono_gchandle_free (gch);
3758 return TRUE; // Remove this key/value pair
3761 guint32 offset = GPOINTER_TO_UINT (user);
3762 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3764 return FALSE; // Don't remove it
3767 static StaticDataFreeList*
3768 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3770 StaticDataFreeList* prev = NULL;
3771 StaticDataFreeList* tmp = static_data->freelist;
3773 if (tmp->size == size) {
3775 prev->next = tmp->next;
3777 static_data->freelist = tmp->next;
3786 #if SIZEOF_VOID_P == 4
3793 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3795 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3797 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3798 MonoBitSet *rb = sets [idx];
3799 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3800 offset /= sizeof (uintptr_t);
3801 /* offset is now the bitmap offset */
3802 for (int i = 0; i < numbits; ++i) {
3803 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3804 mono_bitset_set_fast (rb, offset + i);
3809 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3811 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3812 MonoBitSet *rb = sets [idx];
3813 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3814 offset /= sizeof (uintptr_t);
3815 /* offset is now the bitmap offset */
3816 for (int i = 0; i < size / sizeof (uintptr_t); i++)
3817 mono_bitset_clear_fast (rb, offset + i);
3821 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3823 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3825 StaticDataInfo *info;
3828 if (static_type == SPECIAL_STATIC_THREAD) {
3829 info = &thread_static_info;
3830 sets = thread_reference_bitmaps;
3832 info = &context_static_info;
3833 sets = context_reference_bitmaps;
3836 mono_threads_lock ();
3838 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3842 offset = item->offset;
3845 offset = mono_alloc_static_data_slot (info, size, align);
3848 update_reference_bitmap (sets, offset, bitmap, numbits);
3850 if (static_type == SPECIAL_STATIC_THREAD) {
3851 /* This can be called during startup */
3852 if (threads != NULL)
3853 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3855 if (contexts != NULL)
3856 g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3858 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3861 mono_threads_unlock ();
3867 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3869 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3871 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3872 return get_thread_static_data (thread, offset);
3874 return get_context_static_data (thread->current_appcontext, offset);
3879 mono_get_special_static_data (guint32 offset)
3881 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3890 * LOCKING: requires that threads_mutex is held
3893 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3895 MonoInternalThread *thread = value;
3896 OffsetSize *data = user;
3897 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3898 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3901 if (!thread->static_data || !thread->static_data [idx])
3903 ptr = ((char*) thread->static_data [idx]) + off;
3904 mono_gc_bzero_atomic (ptr, data->size);
3908 * LOCKING: requires that threads_mutex is held
3911 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3913 uint32_t gch = GPOINTER_TO_INT (key);
3914 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3917 mono_gchandle_free (gch);
3918 return TRUE; // Remove this key/value pair
3921 OffsetSize *data = user;
3922 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3923 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3926 if (!ctx->static_data || !ctx->static_data [idx])
3927 return FALSE; // Don't remove this key/value pair
3929 ptr = ((char*) ctx->static_data [idx]) + off;
3930 mono_gc_bzero_atomic (ptr, data->size);
3932 return FALSE; // Don't remove this key/value pair
3936 do_free_special_slot (guint32 offset, guint32 size)
3938 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3940 StaticDataInfo *info;
3942 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3943 info = &thread_static_info;
3944 sets = thread_reference_bitmaps;
3946 info = &context_static_info;
3947 sets = context_reference_bitmaps;
3950 guint32 data_offset = offset;
3951 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
3952 OffsetSize data = { data_offset, size };
3954 clear_reference_bitmap (sets, data.offset, data.size);
3956 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3957 if (threads != NULL)
3958 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3960 if (contexts != NULL)
3961 g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
3964 if (!mono_runtime_is_shutting_down ()) {
3965 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
3967 item->offset = offset;
3970 item->next = info->freelist;
3971 info->freelist = item;
3976 do_free_special (gpointer key, gpointer value, gpointer data)
3978 MonoClassField *field = key;
3979 guint32 offset = GPOINTER_TO_UINT (value);
3982 size = mono_type_size (field->type, &align);
3983 do_free_special_slot (offset, size);
3987 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3989 mono_threads_lock ();
3991 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3993 mono_threads_unlock ();
3997 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3999 /* Only ever called for ThreadLocal instances */
4000 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
4002 mono_threads_lock ();
4003 do_free_special_slot (offset, size);
4004 mono_threads_unlock ();
4008 static void CALLBACK dummy_apc (ULONG_PTR param)
4014 * mono_thread_execute_interruption
4016 * Performs the operation that the requested thread state requires (abort,
4019 static MonoException*
4020 mono_thread_execute_interruption (MonoInternalThread *thread)
4022 LOCK_THREAD (thread);
4024 /* MonoThread::interruption_requested can only be changed with atomics */
4025 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4026 /* this will consume pending APC calls */
4028 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4030 InterlockedDecrement (&thread_interruption_requested);
4032 /* Clear the interrupted flag of the thread so it can wait again */
4033 mono_thread_info_clear_self_interrupt ();
4036 if ((thread->state & ThreadState_AbortRequested) != 0) {
4037 UNLOCK_THREAD (thread);
4038 if (thread->abort_exc == NULL) {
4040 * This might be racy, but it has to be called outside the lock
4041 * since it calls managed code.
4043 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4045 return thread->abort_exc;
4047 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4048 self_suspend_internal (thread);
4051 else if ((thread->state & ThreadState_StopRequested) != 0) {
4052 /* FIXME: do this through the JIT? */
4054 UNLOCK_THREAD (thread);
4056 mono_thread_exit ();
4058 } else if (thread->pending_exception) {
4061 exc = thread->pending_exception;
4062 thread->pending_exception = NULL;
4064 UNLOCK_THREAD (thread);
4066 } else if (thread->thread_interrupt_requested) {
4068 thread->thread_interrupt_requested = FALSE;
4069 UNLOCK_THREAD (thread);
4071 return(mono_get_exception_thread_interrupted ());
4074 UNLOCK_THREAD (thread);
4080 * mono_thread_request_interruption
4082 * A signal handler can call this method to request the interruption of a
4083 * thread. The result of the interruption will depend on the current state of
4084 * the thread. If the result is an exception that needs to be throw, it is
4085 * provided as return value.
4088 mono_thread_request_interruption (gboolean running_managed)
4090 MonoInternalThread *thread = mono_thread_internal_current ();
4092 /* The thread may already be stopping */
4097 if (thread->interrupt_on_stop &&
4098 thread->state & ThreadState_StopRequested &&
4099 thread->state & ThreadState_Background)
4103 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4105 InterlockedIncrement (&thread_interruption_requested);
4107 if (!running_managed || is_running_protected_wrapper ()) {
4108 /* Can't stop while in unmanaged code. Increase the global interruption
4109 request count. When exiting the unmanaged method the count will be
4110 checked and the thread will be interrupted. */
4112 if (mono_thread_notify_pending_exc_fn && !running_managed)
4113 /* The JIT will notify the thread about the interruption */
4114 /* This shouldn't take any locks */
4115 mono_thread_notify_pending_exc_fn (NULL);
4117 /* this will awake the thread if it is in WaitForSingleObject
4119 /* Our implementation of this function ignores the func argument */
4121 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4123 mono_thread_info_self_interrupt ();
4128 return mono_thread_execute_interruption (thread);
4132 /*This function should be called by a thread after it has exited all of
4133 * its handle blocks at interruption time.*/
4135 mono_thread_resume_interruption (void)
4137 MonoInternalThread *thread = mono_thread_internal_current ();
4138 gboolean still_aborting;
4140 /* The thread may already be stopping */
4144 LOCK_THREAD (thread);
4145 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4146 UNLOCK_THREAD (thread);
4148 /*This can happen if the protected block called Thread::ResetAbort*/
4149 if (!still_aborting)
4152 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4154 InterlockedIncrement (&thread_interruption_requested);
4156 mono_thread_info_self_interrupt ();
4158 return mono_thread_execute_interruption (thread);
4161 gboolean mono_thread_interruption_requested ()
4163 if (thread_interruption_requested) {
4164 MonoInternalThread *thread = mono_thread_internal_current ();
4165 /* The thread may already be stopping */
4167 return (thread->interruption_requested);
4172 static MonoException*
4173 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4175 MonoInternalThread *thread = mono_thread_internal_current ();
4177 /* The thread may already be stopping */
4181 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4182 MonoException* exc = mono_thread_execute_interruption (thread);
4190 * Performs the interruption of the current thread, if one has been requested,
4191 * and the thread is not running a protected wrapper.
4192 * Return the exception which needs to be thrown, if any.
4195 mono_thread_interruption_checkpoint (void)
4197 return mono_thread_interruption_checkpoint_request (FALSE);
4201 * Performs the interruption of the current thread, if one has been requested.
4202 * Return the exception which needs to be thrown, if any.
4205 mono_thread_force_interruption_checkpoint_noraise (void)
4207 return mono_thread_interruption_checkpoint_request (TRUE);
4211 * Performs the interruption of the current thread, if one has been requested.
4212 * Throw the exception which needs to be thrown, if any.
4215 mono_thread_force_interruption_checkpoint (void)
4219 ex = mono_thread_interruption_checkpoint_request (TRUE);
4221 mono_raise_exception (ex);
4225 * mono_thread_get_and_clear_pending_exception:
4227 * Return any pending exceptions for the current thread and clear it as a side effect.
4230 mono_thread_get_and_clear_pending_exception (void)
4232 MonoInternalThread *thread = mono_thread_internal_current ();
4234 /* The thread may already be stopping */
4238 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4239 return mono_thread_execute_interruption (thread);
4242 if (thread->pending_exception) {
4243 MonoException *exc = thread->pending_exception;
4245 thread->pending_exception = NULL;
4253 * mono_set_pending_exception:
4255 * Set the pending exception of the current thread to EXC.
4256 * The exception will be thrown when execution returns to managed code.
4259 mono_set_pending_exception (MonoException *exc)
4261 MonoInternalThread *thread = mono_thread_internal_current ();
4263 /* The thread may already be stopping */
4267 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4269 mono_thread_request_interruption (FALSE);
4273 * mono_thread_interruption_request_flag:
4275 * Returns the address of a flag that will be non-zero if an interruption has
4276 * been requested for a thread. The thread to interrupt may not be the current
4277 * thread, so an additional call to mono_thread_interruption_requested() or
4278 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4281 gint32* mono_thread_interruption_request_flag ()
4283 return &thread_interruption_requested;
4287 mono_thread_init_apartment_state (void)
4290 MonoInternalThread* thread = mono_thread_internal_current ();
4292 /* Positive return value indicates success, either
4293 * S_OK if this is first CoInitialize call, or
4294 * S_FALSE if CoInitialize already called, but with same
4295 * threading model. A negative value indicates failure,
4296 * probably due to trying to change the threading model.
4298 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4299 ? COINIT_APARTMENTTHREADED
4300 : COINIT_MULTITHREADED) < 0) {
4301 thread->apartment_state = ThreadApartmentState_Unknown;
4307 mono_thread_cleanup_apartment_state (void)
4310 MonoInternalThread* thread = mono_thread_internal_current ();
4312 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4319 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4321 LOCK_THREAD (thread);
4322 thread->state |= state;
4323 UNLOCK_THREAD (thread);
4327 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4329 LOCK_THREAD (thread);
4330 thread->state &= ~state;
4331 UNLOCK_THREAD (thread);
4335 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4337 gboolean ret = FALSE;
4339 LOCK_THREAD (thread);
4341 if ((thread->state & test) != 0) {
4345 UNLOCK_THREAD (thread);
4350 static gboolean has_tls_get = FALSE;
4353 mono_runtime_set_has_tls_get (gboolean val)
4359 mono_runtime_has_tls_get (void)
4365 self_interrupt_thread (void *_unused)
4367 MonoThreadInfo *info = mono_thread_info_current ();
4368 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4369 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4370 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. */
4371 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4375 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4379 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4383 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4385 MonoJitInfo **dest = data;
4391 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4393 MonoJitInfo *ji = NULL;
4396 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4401 MonoInternalThread *thread;
4402 gboolean install_async_abort;
4403 MonoThreadInfoInterruptToken *interrupt_token;
4406 static SuspendThreadResult
4407 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4409 AbortThreadData *data = ud;
4410 MonoInternalThread *thread = data->thread;
4411 MonoJitInfo *ji = NULL;
4412 gboolean protected_wrapper;
4413 gboolean running_managed;
4415 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4416 return MonoResumeThread;
4418 /*someone is already interrupting it*/
4419 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4420 return MonoResumeThread;
4422 InterlockedIncrement (&thread_interruption_requested);
4424 ji = mono_thread_info_get_last_managed (info);
4425 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4426 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4428 if (!protected_wrapper && running_managed) {
4429 /*We are in managed code*/
4430 /*Set the thread to call */
4431 if (data->install_async_abort)
4432 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4433 return MonoResumeThread;
4435 if (mono_thread_notify_pending_exc_fn)
4436 /* The JIT will notify the thread about the interruption */
4437 mono_thread_notify_pending_exc_fn (info);
4440 * This will cause waits to be broken.
4441 * It will also prevent the thread from entering a wait, so if the thread returns
4442 * from the wait before it receives the abort signal, it will just spin in the wait
4443 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4446 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4448 return MonoResumeThread;
4453 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4455 AbortThreadData data = { 0 };
4456 data.thread = thread;
4457 data.install_async_abort = install_async_abort;
4460 FIXME this is insanely broken, it doesn't cause interruption to happen
4461 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4463 if (thread == mono_thread_internal_current ()) {
4464 /* Do it synchronously */
4465 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4467 mono_raise_exception (exc);
4469 mono_thread_info_self_interrupt ();
4474 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
4475 if (data.interrupt_token)
4476 mono_thread_info_finish_interrupt (data.interrupt_token);
4477 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4481 MonoInternalThread *thread;
4483 MonoThreadInfoInterruptToken *interrupt_token;
4484 } SuspendThreadData;
4486 static SuspendThreadResult
4487 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4489 SuspendThreadData *data = ud;
4490 MonoInternalThread *thread = data->thread;
4491 MonoJitInfo *ji = NULL;
4492 gboolean protected_wrapper;
4493 gboolean running_managed;
4495 ji = mono_thread_info_get_last_managed (info);
4496 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4497 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4499 if (running_managed && !protected_wrapper) {
4500 thread->state &= ~ThreadState_SuspendRequested;
4501 thread->state |= ThreadState_Suspended;
4502 return KeepSuspended;
4504 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4505 InterlockedIncrement (&thread_interruption_requested);
4506 if (data->interrupt)
4507 data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
4509 if (mono_thread_notify_pending_exc_fn && !running_managed)
4510 /* The JIT will notify the thread about the interruption */
4511 mono_thread_notify_pending_exc_fn (info);
4512 return MonoResumeThread;
4517 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4519 LOCK_THREAD (thread);
4520 if (thread == mono_thread_internal_current ()) {
4521 mono_thread_info_begin_self_suspend ();
4522 //XXX replace this with better named functions
4523 thread->state &= ~ThreadState_SuspendRequested;
4524 thread->state |= ThreadState_Suspended;
4525 UNLOCK_THREAD (thread);
4526 mono_thread_info_end_self_suspend ();
4528 SuspendThreadData data = { 0 };
4529 data.thread = thread;
4530 data.interrupt = interrupt;
4532 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
4533 if (data.interrupt_token)
4534 mono_thread_info_finish_interrupt (data.interrupt_token);
4535 UNLOCK_THREAD (thread);
4539 /*This is called with @thread synch_cs held and it must release it*/
4541 self_suspend_internal (MonoInternalThread *thread)
4543 mono_thread_info_begin_self_suspend ();
4544 thread->state &= ~ThreadState_SuspendRequested;
4545 thread->state |= ThreadState_Suspended;
4546 UNLOCK_THREAD (thread);
4547 mono_thread_info_end_self_suspend ();
4550 /*This is called with @thread synch_cs held and it must release it*/
4552 resume_thread_internal (MonoInternalThread *thread)
4554 UNLOCK_THREAD (thread);
4555 /* Awake the thread */
4556 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4558 LOCK_THREAD (thread);
4559 thread->state &= ~ThreadState_Suspended;
4560 UNLOCK_THREAD (thread);
4566 * mono_thread_is_foreign:
4567 * @thread: the thread to query
4569 * This function allows one to determine if a thread was created by the mono runtime and has
4570 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4572 * Returns: true if @thread was not created by the runtime.
4575 mono_thread_is_foreign (MonoThread *thread)
4577 MonoThreadInfo *info = thread->internal_thread->thread_info;
4578 return info->runtime_thread == FALSE;
4582 * mono_add_joinable_thread:
4584 * Add TID to the list of joinable threads.
4585 * LOCKING: Acquires the threads lock.
4588 mono_threads_add_joinable_thread (gpointer tid)
4592 * We cannot detach from threads because it causes problems like
4593 * 2fd16f60/r114307. So we collect them and join them when
4594 * we have time (in he finalizer thread).
4596 joinable_threads_lock ();
4597 if (!joinable_threads)
4598 joinable_threads = g_hash_table_new (NULL, NULL);
4599 g_hash_table_insert (joinable_threads, tid, tid);
4600 joinable_thread_count ++;
4601 joinable_threads_unlock ();
4603 mono_gc_finalize_notify ();
4608 * mono_threads_join_threads:
4610 * Join all joinable threads. This is called from the finalizer thread.
4611 * LOCKING: Acquires the threads lock.
4614 mono_threads_join_threads (void)
4617 GHashTableIter iter;
4624 if (!joinable_thread_count)
4628 joinable_threads_lock ();
4630 if (g_hash_table_size (joinable_threads)) {
4631 g_hash_table_iter_init (&iter, joinable_threads);
4632 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4633 thread = (pthread_t)tid;
4634 g_hash_table_remove (joinable_threads, key);
4635 joinable_thread_count --;
4638 joinable_threads_unlock ();
4640 if (thread != pthread_self ())
4641 /* This shouldn't block */
4642 pthread_join (thread, NULL);
4653 * Wait for thread TID to exit.
4654 * LOCKING: Acquires the threads lock.
4657 mono_thread_join (gpointer tid)
4661 gboolean found = FALSE;
4663 joinable_threads_lock ();
4664 if (!joinable_threads)
4665 joinable_threads = g_hash_table_new (NULL, NULL);
4666 if (g_hash_table_lookup (joinable_threads, tid)) {
4667 g_hash_table_remove (joinable_threads, tid);
4668 joinable_thread_count --;
4671 joinable_threads_unlock ();
4674 thread = (pthread_t)tid;
4675 pthread_join (thread, NULL);
4680 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4682 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4683 mono_thread_interruption_checkpoint ();
4686 static inline gboolean
4687 is_appdomainunloaded_exception (MonoClass *klass)
4689 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4691 if (!app_domain_unloaded_exception_klass)
4692 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4693 g_assert (app_domain_unloaded_exception_klass);
4695 return klass == app_domain_unloaded_exception_klass;
4698 static inline gboolean
4699 is_threadabort_exception (MonoClass *klass)
4701 return klass == mono_defaults.threadabortexception_class;
4705 mono_thread_internal_unhandled_exception (MonoObject* exc)
4707 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4708 MonoClass *klass = exc->vtable->klass;
4709 if (is_threadabort_exception (klass)) {
4710 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4711 } else if (!is_appdomainunloaded_exception (klass)) {
4712 mono_unhandled_exception (exc);
4713 if (mono_environment_exitcode_get () == 1)