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 /* The TLS key that holds the MonoObject assigned to each thread */
160 static MonoNativeTlsKey current_object_key;
163 /* Protected by the threads lock */
164 static GHashTable *joinable_threads;
165 static int joinable_thread_count;
167 #ifdef MONO_HAVE_FAST_TLS
168 /* we need to use both the Tls* functions and __thread because
169 * the gc needs to see all the threads
171 MONO_FAST_TLS_DECLARE(tls_current_object);
172 #define SET_CURRENT_OBJECT(x) do { \
173 MONO_FAST_TLS_SET (tls_current_object, x); \
174 mono_native_tls_set_value (current_object_key, x); \
176 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
178 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
179 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
182 /* function called at thread start */
183 static MonoThreadStartCB mono_thread_start_cb = NULL;
185 /* function called at thread attach */
186 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
188 /* function called at thread cleanup */
189 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
191 /* function called to notify the runtime about a pending exception on the current thread */
192 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
194 /* The default stack size for each thread */
195 static guint32 default_stacksize = 0;
196 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
198 static void thread_adjust_static_data (MonoInternalThread *thread);
199 static void context_adjust_static_data (MonoAppContext *ctx);
200 static void mono_free_static_data (gpointer* static_data);
201 static void mono_init_static_data_info (StaticDataInfo *static_data);
202 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
203 static gboolean mono_thread_resume (MonoInternalThread* thread);
204 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
205 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
206 static void self_suspend_internal (MonoInternalThread *thread);
207 static gboolean resume_thread_internal (MonoInternalThread *thread);
209 static MonoException* mono_thread_execute_interruption ();
210 static void ref_stack_destroy (gpointer rs);
212 /* Spin lock for InterlockedXXX 64 bit functions */
213 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
214 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
215 static mono_mutex_t interlocked_mutex;
217 /* global count of thread interruptions requested */
218 static gint32 thread_interruption_requested = 0;
220 /* Event signaled when a thread changes its background mode */
221 static HANDLE background_change_event;
223 static gboolean shutting_down = FALSE;
225 static gint32 managed_thread_id_counter = 0;
228 mono_threads_lock (void)
231 mono_locks_acquire (&threads_mutex, ThreadsLock);
232 MONO_FINISH_TRY_BLOCKING;
236 mono_threads_unlock (void)
238 mono_locks_release (&threads_mutex, ThreadsLock);
243 get_next_managed_thread_id (void)
245 return InterlockedIncrement (&managed_thread_id_counter);
249 mono_thread_get_tls_key (void)
251 return current_object_key;
255 mono_thread_get_tls_offset (void)
258 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
262 static inline MonoNativeThreadId
263 thread_get_tid (MonoInternalThread *thread)
265 /* We store the tid as a guint64 to keep the object layout constant between platforms */
266 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
269 /* handle_store() and handle_remove() manage the array of threads that
270 * still need to be waited for when the main thread exits.
272 * If handle_store() returns FALSE the thread must not be started
273 * because Mono is shutting down.
275 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
277 mono_threads_lock ();
279 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
281 if (threads_starting_up)
282 mono_g_hash_table_remove (threads_starting_up, thread);
284 if (shutting_down && !force_attach) {
285 mono_threads_unlock ();
290 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
291 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
294 /* We don't need to duplicate thread->handle, because it is
295 * only closed when the thread object is finalized by the GC.
297 g_assert (thread->internal_thread);
298 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
299 thread->internal_thread);
301 mono_threads_unlock ();
306 static gboolean handle_remove(MonoInternalThread *thread)
309 gsize tid = thread->tid;
311 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
313 mono_threads_lock ();
316 /* We have to check whether the thread object for the
317 * tid is still the same in the table because the
318 * thread might have been destroyed and the tid reused
319 * in the meantime, in which case the tid would be in
320 * the table, but with another thread object.
322 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
323 mono_g_hash_table_remove (threads, (gpointer)tid);
332 mono_threads_unlock ();
334 /* Don't close the handle here, wait for the object finalizer
335 * to do it. Otherwise, the following race condition applies:
337 * 1) Thread exits (and handle_remove() closes the handle)
339 * 2) Some other handle is reassigned the same slot
341 * 3) Another thread tries to join the first thread, and
342 * blocks waiting for the reassigned handle to be signalled
343 * (which might never happen). This is possible, because the
344 * thread calling Join() still has a reference to the first
350 static void ensure_synch_cs_set (MonoInternalThread *thread)
352 mono_mutex_t *synch_cs;
354 if (thread->synch_cs != NULL) {
358 synch_cs = g_new0 (mono_mutex_t, 1);
359 mono_mutex_init_recursive (synch_cs);
361 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
362 synch_cs, NULL) != NULL) {
363 /* Another thread must have installed this CS */
364 mono_mutex_destroy (synch_cs);
370 lock_thread (MonoInternalThread *thread)
372 if (!thread->synch_cs)
373 ensure_synch_cs_set (thread);
375 g_assert (thread->synch_cs);
378 mono_mutex_lock (thread->synch_cs);
379 MONO_FINISH_TRY_BLOCKING;
383 unlock_thread (MonoInternalThread *thread)
385 mono_mutex_unlock (thread->synch_cs);
389 * NOTE: this function can be called also for threads different from the current one:
390 * make sure no code called from it will ever assume it is run on the thread that is
391 * getting cleaned up.
393 static void thread_cleanup (MonoInternalThread *thread)
395 g_assert (thread != NULL);
397 if (thread->abort_state_handle) {
398 mono_gchandle_free (thread->abort_state_handle);
399 thread->abort_state_handle = 0;
401 thread->abort_exc = NULL;
402 thread->current_appcontext = NULL;
405 * This is necessary because otherwise we might have
406 * cross-domain references which will not get cleaned up when
407 * the target domain is unloaded.
409 if (thread->cached_culture_info) {
411 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
412 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
416 * thread->synch_cs can be NULL if this was called after
417 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
418 * This can happen only during shutdown.
419 * The shutting_down flag is not always set, so we can't assert on it.
421 if (thread->synch_cs)
422 LOCK_THREAD (thread);
424 thread->state |= ThreadState_Stopped;
425 thread->state &= ~ThreadState_Background;
427 if (thread->synch_cs)
428 UNLOCK_THREAD (thread);
431 An interruption request has leaked to cleanup. Adjust the global counter.
433 This can happen is the abort source thread finds the abortee (this) thread
434 in unmanaged code. If this thread never trips back to managed code or check
435 the local flag it will be left set and positively unbalance the global counter.
437 Leaving the counter unbalanced will cause a performance degradation since all threads
438 will now keep checking their local flags all the time.
440 if (InterlockedExchange (&thread->interruption_requested, 0))
441 InterlockedDecrement (&thread_interruption_requested);
443 /* if the thread is not in the hash it has been removed already */
444 if (!handle_remove (thread)) {
445 if (thread == mono_thread_internal_current ()) {
446 mono_domain_unset ();
447 mono_memory_barrier ();
449 /* This needs to be called even if handle_remove () fails */
450 if (mono_thread_cleanup_fn)
451 mono_thread_cleanup_fn (thread_get_tid (thread));
454 mono_release_type_locks (thread);
456 mono_profiler_thread_end (thread->tid);
458 if (thread == mono_thread_internal_current ()) {
460 * This will signal async signal handlers that the thread has exited.
461 * The profiler callback needs this to be set, so it cannot be done earlier.
463 mono_domain_unset ();
464 mono_memory_barrier ();
467 if (thread == mono_thread_internal_current ())
468 mono_thread_pop_appdomain_ref ();
470 thread->cached_culture_info = NULL;
472 mono_free_static_data (thread->static_data);
473 thread->static_data = NULL;
474 ref_stack_destroy (thread->appdomain_refs);
475 thread->appdomain_refs = NULL;
477 if (mono_thread_cleanup_fn)
478 mono_thread_cleanup_fn (thread_get_tid (thread));
480 if (mono_gc_is_moving ()) {
481 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
482 thread->thread_pinning_ref = NULL;
487 * A special static data offset (guint32) consists of 3 parts:
489 * [0] 6-bit index into the array of chunks.
490 * [6] 25-bit offset into the array.
491 * [31] Bit indicating thread or context static.
496 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
507 } SpecialStaticOffset;
509 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
510 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
512 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
513 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
514 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
515 (((SpecialStaticOffset *) &(x))->fields.f)
518 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
520 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
522 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
523 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
525 return ((char *) thread->static_data [idx]) + off;
529 get_context_static_data (MonoAppContext *ctx, guint32 offset)
531 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
533 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
534 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
536 return ((char *) ctx->static_data [idx]) + off;
540 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
542 static MonoClassField *current_thread_field = NULL;
546 if (!current_thread_field) {
547 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
548 g_assert (current_thread_field);
551 mono_class_vtable (domain, mono_defaults.thread_class);
552 mono_domain_lock (domain);
553 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
554 mono_domain_unlock (domain);
557 return get_thread_static_data (thread, offset);
561 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
563 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
565 g_assert (current->obj.vtable->domain == domain);
567 g_assert (!*current_thread_ptr);
568 *current_thread_ptr = current;
572 create_thread_object (MonoDomain *domain)
574 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
575 return (MonoThread*)mono_gc_alloc_mature (vt);
579 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
581 MonoThread *thread = create_thread_object (domain);
582 MONO_OBJECT_SETREF (thread, internal_thread, internal);
586 static MonoInternalThread*
587 create_internal_thread (void)
589 MonoInternalThread *thread;
592 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
593 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
595 thread->synch_cs = g_new0 (mono_mutex_t, 1);
596 mono_mutex_init_recursive (thread->synch_cs);
598 thread->apartment_state = ThreadApartmentState_Unknown;
599 thread->managed_id = get_next_managed_thread_id ();
600 if (mono_gc_is_moving ()) {
601 thread->thread_pinning_ref = thread;
602 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
609 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
611 MonoDomain *domain = mono_get_root_domain ();
613 if (!candidate || candidate->obj.vtable->domain != domain)
614 candidate = new_thread_with_internal (domain, thread);
615 set_current_thread_for_domain (domain, thread, candidate);
616 g_assert (!thread->root_domain_thread);
617 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
620 static guint32 WINAPI start_wrapper_internal(void *data)
622 MonoThreadInfo *info;
623 StartInfo *start_info = (StartInfo *)data;
624 guint32 (*start_func)(void *);
628 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
631 MonoInternalThread *internal = start_info->obj->internal_thread;
632 MonoObject *start_delegate = start_info->delegate;
633 MonoDomain *domain = start_info->obj->obj.vtable->domain;
635 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
637 /* We can be sure start_info->obj->tid and
638 * start_info->obj->handle have been set, because the thread
639 * was created suspended, and these values were set before the
643 info = mono_thread_info_current ();
645 internal->thread_info = info;
646 internal->small_id = info->small_id;
650 SET_CURRENT_OBJECT (internal);
652 /* Every thread references the appdomain which created it */
653 mono_thread_push_appdomain_ref (domain);
655 if (!mono_domain_set (domain, FALSE)) {
656 /* No point in raising an appdomain_unloaded exception here */
657 /* FIXME: Cleanup here */
658 mono_thread_pop_appdomain_ref ();
662 start_func = start_info->func;
663 start_arg = start_info->obj->start_obj;
665 start_arg = start_info->start_arg;
667 /* We have to do this here because mono_thread_new_init()
668 requires that root_domain_thread is set up. */
669 thread_adjust_static_data (internal);
670 init_root_domain_thread (internal, start_info->obj);
672 /* This MUST be called before any managed code can be
673 * executed, as it calls the callback function that (for the
674 * jit) sets the lmf marker.
676 mono_thread_new_init (tid, &tid, start_func);
677 internal->stack_ptr = &tid;
679 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
681 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
683 /* On 2.0 profile (and higher), set explicitly since state might have been
685 if (internal->apartment_state == ThreadApartmentState_Unknown)
686 internal->apartment_state = ThreadApartmentState_MTA;
688 mono_thread_init_apartment_state ();
690 if(internal->start_notify!=NULL) {
691 /* Let the thread that called Start() know we're
694 ReleaseSemaphore (internal->start_notify, 1, NULL);
698 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
702 * Call this after calling start_notify, since the profiler callback might want
703 * to lock the thread, and the lock is held by thread_start () which waits for
706 mono_profiler_thread_start (tid);
708 /* if the name was set before starting, we didn't invoke the profiler callback */
709 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
710 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
711 mono_profiler_thread_name (internal->tid, tname);
714 /* start_func is set only for unmanaged start functions */
716 start_func (start_arg);
719 g_assert (start_delegate != NULL);
720 args [0] = start_arg;
721 /* we may want to handle the exception here. See comment below on unhandled exceptions */
722 mono_runtime_delegate_invoke (start_delegate, args, NULL);
725 /* If the thread calls ExitThread at all, this remaining code
726 * will not be executed, but the main thread will eventually
727 * call thread_cleanup() on this thread's behalf.
730 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
732 /* Do any cleanup needed for apartment state. This
733 * cannot be done in thread_cleanup since thread_cleanup could be
734 * called for a thread other than the current thread.
735 * mono_thread_cleanup_apartment_state cleans up apartment
736 * for the current thead */
737 mono_thread_cleanup_apartment_state ();
739 thread_cleanup (internal);
743 /* Remove the reference to the thread object in the TLS data,
744 * so the thread object can be finalized. This won't be
745 * reached if the thread threw an uncaught exception, so those
746 * thread handles will stay referenced :-( (This is due to
747 * missing support for scanning thread-specific data in the
748 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
751 SET_CURRENT_OBJECT (NULL);
756 static guint32 WINAPI start_wrapper(void *data)
760 /* Avoid scanning the frames above this frame during a GC */
761 mono_gc_set_stack_end ((void*)&dummy);
763 return start_wrapper_internal (data);
769 * Common thread creation code.
770 * LOCKING: Acquires the threads lock.
773 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
774 gboolean throw_on_failure)
776 HANDLE thread_handle;
777 MonoNativeThreadId tid;
778 guint32 create_flags;
781 * Join joinable threads to prevent running out of threads since the finalizer
782 * thread might be blocked/backlogged.
784 mono_threads_join_threads ();
786 mono_threads_lock ();
789 mono_threads_unlock ();
792 if (threads_starting_up == NULL) {
793 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
794 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
796 mono_g_hash_table_insert (threads_starting_up, thread, thread);
797 mono_threads_unlock ();
799 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
800 if (!internal->start_notify) {
801 mono_threads_lock ();
802 mono_g_hash_table_remove (threads_starting_up, thread);
803 mono_threads_unlock ();
804 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
810 stack_size = default_stacksize_for_thread (internal);
812 /* Create suspended, so we can do some housekeeping before the thread
815 create_flags = CREATE_SUSPENDED;
817 MONO_PREPARE_BLOCKING;
818 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
819 stack_size, create_flags, &tid);
820 MONO_FINISH_BLOCKING;
822 if (thread_handle == NULL) {
823 /* The thread couldn't be created, so throw an exception */
824 mono_threads_lock ();
825 mono_g_hash_table_remove (threads_starting_up, thread);
826 mono_threads_unlock ();
828 if (throw_on_failure)
829 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
831 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
834 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
836 internal->handle = thread_handle;
837 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
839 internal->threadpool_thread = threadpool_thread;
840 if (threadpool_thread)
841 mono_thread_set_state (internal, ThreadState_Background);
843 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
845 /* Only store the handle when the thread is about to be
846 * launched, to avoid the main thread deadlocking while trying
847 * to clean up a thread that will never be signalled.
849 if (!handle_store (thread, FALSE))
852 MONO_PREPARE_BLOCKING;
853 mono_thread_info_resume (tid);
854 MONO_FINISH_BLOCKING;
856 if (internal->start_notify) {
858 * Wait for the thread to set up its TLS data etc, so
859 * theres no potential race condition if someone tries
860 * to look up the data believing the thread has
863 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
865 MONO_PREPARE_BLOCKING;
866 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
867 MONO_FINISH_BLOCKING;
869 CloseHandle (internal->start_notify);
870 internal->start_notify = NULL;
873 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
878 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
880 if (mono_thread_start_cb) {
881 mono_thread_start_cb (tid, stack_start, func);
885 void mono_threads_set_default_stacksize (guint32 stacksize)
887 default_stacksize = stacksize;
890 guint32 mono_threads_get_default_stacksize (void)
892 return default_stacksize;
896 * mono_thread_create_internal:
898 * ARG should not be a GC reference.
901 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
904 MonoInternalThread *internal;
905 StartInfo *start_info;
908 thread = create_thread_object (domain);
909 internal = create_internal_thread ();
910 MONO_OBJECT_SETREF (thread, internal_thread, internal);
912 start_info = g_new0 (StartInfo, 1);
913 start_info->func = func;
914 start_info->obj = thread;
915 start_info->start_arg = arg;
917 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
921 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
922 if (mono_check_corlib_version () == NULL)
923 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
929 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
931 mono_thread_create_internal (domain, func, arg, FALSE, 0);
935 mono_thread_attach (MonoDomain *domain)
937 return mono_thread_attach_full (domain, FALSE);
941 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
943 MonoThreadInfo *info;
944 MonoInternalThread *thread;
945 MonoThread *current_thread;
946 HANDLE thread_handle;
947 MonoNativeThreadId tid;
949 if ((thread = mono_thread_internal_current ())) {
950 if (domain != mono_domain_get ())
951 mono_domain_set (domain, TRUE);
952 /* Already attached */
953 return mono_thread_current ();
956 if (!mono_gc_register_thread (&domain)) {
957 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.", mono_native_thread_id_get ());
960 thread = create_internal_thread ();
962 thread_handle = mono_thread_info_open_handle ();
963 g_assert (thread_handle);
965 tid=mono_native_thread_id_get ();
967 thread->handle = thread_handle;
968 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
969 thread->stack_ptr = &tid;
971 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
973 info = mono_thread_info_current ();
975 thread->thread_info = info;
976 thread->small_id = info->small_id;
978 current_thread = new_thread_with_internal (domain, thread);
980 if (!handle_store (current_thread, force_attach)) {
981 /* Mono is shutting down, so just wait for the end */
983 mono_thread_info_sleep (10000, NULL);
986 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
988 SET_CURRENT_OBJECT (thread);
989 mono_domain_set (domain, TRUE);
991 thread_adjust_static_data (thread);
993 init_root_domain_thread (thread, current_thread);
994 if (domain != mono_get_root_domain ())
995 set_current_thread_for_domain (domain, thread, current_thread);
998 if (mono_thread_attach_cb) {
1002 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1005 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1007 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1010 // FIXME: Need a separate callback
1011 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1013 return current_thread;
1017 mono_thread_detach_internal (MonoInternalThread *thread)
1019 g_return_if_fail (thread != NULL);
1021 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1023 thread_cleanup (thread);
1025 SET_CURRENT_OBJECT (NULL);
1026 mono_domain_unset ();
1028 /* Don't need to CloseHandle this thread, even though we took a
1029 * reference in mono_thread_attach (), because the GC will do it
1030 * when the Thread object is finalised.
1035 mono_thread_detach (MonoThread *thread)
1038 mono_thread_detach_internal (thread->internal_thread);
1042 * mono_thread_detach_if_exiting:
1044 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1045 * This should be used at the end of embedding code which calls into managed code, and which
1046 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1049 mono_thread_detach_if_exiting (void)
1051 if (mono_thread_info_is_exiting ()) {
1052 MonoInternalThread *thread;
1054 thread = mono_thread_internal_current ();
1056 mono_thread_detach_internal (thread);
1057 mono_thread_info_detach ();
1065 MonoInternalThread *thread = mono_thread_internal_current ();
1067 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1069 thread_cleanup (thread);
1070 SET_CURRENT_OBJECT (NULL);
1071 mono_domain_unset ();
1073 /* we could add a callback here for embedders to use. */
1074 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1075 exit (mono_environment_exitcode_get ());
1076 mono_thread_info_exit ();
1080 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1082 MonoInternalThread *internal = create_internal_thread ();
1084 internal->state = ThreadState_Unstarted;
1086 InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
1090 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1093 StartInfo *start_info;
1094 MonoInternalThread *internal;
1097 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1099 if (!this_obj->internal_thread)
1100 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1101 internal = this_obj->internal_thread;
1103 LOCK_THREAD (internal);
1105 if ((internal->state & ThreadState_Unstarted) == 0) {
1106 UNLOCK_THREAD (internal);
1107 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1111 if ((internal->state & ThreadState_Aborted) != 0) {
1112 UNLOCK_THREAD (internal);
1115 /* This is freed in start_wrapper */
1116 start_info = g_new0 (StartInfo, 1);
1117 start_info->func = NULL;
1118 start_info->start_arg = NULL;
1119 start_info->delegate = start;
1120 start_info->obj = this_obj;
1121 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1123 res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
1125 UNLOCK_THREAD (internal);
1129 internal->state &= ~ThreadState_Unstarted;
1131 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1133 UNLOCK_THREAD (internal);
1134 return internal->handle;
1138 * This is called from the finalizer of the internal thread object.
1141 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1143 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1146 * Since threads keep a reference to their thread object while running, by the time this function is called,
1147 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1148 * when thread_cleanup () can be called after this.
1151 CloseHandle (thread);
1153 if (this_obj->synch_cs) {
1154 mono_mutex_t *synch_cs = this_obj->synch_cs;
1155 this_obj->synch_cs = NULL;
1156 mono_mutex_destroy (synch_cs);
1160 if (this_obj->name) {
1161 void *name = this_obj->name;
1162 this_obj->name = NULL;
1168 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1171 MonoInternalThread *thread = mono_thread_internal_current ();
1173 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1175 mono_thread_current_check_pending_interrupt ();
1178 gboolean alerted = FALSE;
1180 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1182 MONO_PREPARE_BLOCKING
1183 res = mono_thread_info_sleep (ms, &alerted);
1184 MONO_FINISH_BLOCKING
1186 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1189 MonoException* exc = mono_thread_execute_interruption ();
1191 mono_raise_exception (exc);
1203 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1208 ves_icall_System_Threading_Thread_GetDomainID (void)
1210 return mono_domain_get()->domain_id;
1214 ves_icall_System_Threading_Thread_Yield (void)
1216 return mono_thread_info_yield ();
1220 * mono_thread_get_name:
1222 * Return the name of the thread. NAME_LEN is set to the length of the name.
1223 * Return NULL if the thread has no name. The returned memory is owned by the
1227 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1231 LOCK_THREAD (this_obj);
1233 if (!this_obj->name) {
1237 *name_len = this_obj->name_len;
1238 res = g_new (gunichar2, this_obj->name_len);
1239 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1242 UNLOCK_THREAD (this_obj);
1248 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1252 LOCK_THREAD (this_obj);
1254 if (!this_obj->name)
1257 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1259 UNLOCK_THREAD (this_obj);
1265 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1267 LOCK_THREAD (this_obj);
1269 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1270 UNLOCK_THREAD (this_obj);
1272 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1275 if (this_obj->name) {
1276 g_free (this_obj->name);
1277 this_obj->name_len = 0;
1280 this_obj->name = g_new (gunichar2, mono_string_length (name));
1281 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1282 this_obj->name_len = mono_string_length (name);
1285 this_obj->name = NULL;
1288 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1290 UNLOCK_THREAD (this_obj);
1292 if (this_obj->name && this_obj->tid) {
1293 char *tname = mono_string_to_utf8 (name);
1294 mono_profiler_thread_name (this_obj->tid, tname);
1295 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1301 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1303 mono_thread_set_name_internal (this_obj, name, TRUE);
1307 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
1309 return ThreadPriority_Lowest;
1313 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1317 /* If the array is already in the requested domain, we just return it,
1318 otherwise we return a copy in that domain. */
1320 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1327 if (mono_object_domain (arr) == domain)
1330 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1331 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1336 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1338 return byte_array_to_domain (arr, mono_get_root_domain ());
1342 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1344 return byte_array_to_domain (arr, mono_domain_get ());
1348 mono_thread_current (void)
1350 MonoDomain *domain = mono_domain_get ();
1351 MonoInternalThread *internal = mono_thread_internal_current ();
1352 MonoThread **current_thread_ptr;
1354 g_assert (internal);
1355 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1357 if (!*current_thread_ptr) {
1358 g_assert (domain != mono_get_root_domain ());
1359 *current_thread_ptr = new_thread_with_internal (domain, internal);
1361 return *current_thread_ptr;
1365 mono_thread_internal_current (void)
1367 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1368 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1373 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1375 MonoInternalThread *thread = this_obj->internal_thread;
1376 HANDLE handle = thread->handle;
1377 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1380 mono_thread_current_check_pending_interrupt ();
1382 LOCK_THREAD (thread);
1384 if ((thread->state & ThreadState_Unstarted) != 0) {
1385 UNLOCK_THREAD (thread);
1387 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1391 UNLOCK_THREAD (thread);
1396 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1398 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1400 MONO_PREPARE_BLOCKING;
1401 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1402 MONO_FINISH_BLOCKING;
1404 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1406 if(ret==WAIT_OBJECT_0) {
1407 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1412 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1418 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1426 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1428 MONO_PREPARE_BLOCKING;
1430 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1432 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1433 MONO_FINISH_BLOCKING;
1435 if (ret != WAIT_IO_COMPLETION)
1438 exc = mono_thread_execute_interruption ();
1440 mono_raise_exception (exc);
1445 /* Re-calculate ms according to the time passed */
1446 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1447 if (diff_ms >= ms) {
1451 wait = ms - diff_ms;
1457 /* FIXME: exitContext isnt documented */
1458 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1464 MonoObject *waitHandle;
1465 MonoInternalThread *thread = mono_thread_internal_current ();
1467 /* Do this WaitSleepJoin check before creating objects */
1468 mono_thread_current_check_pending_interrupt ();
1470 /* We fail in managed if the array has more than 64 elements */
1471 numhandles = (guint32)mono_array_length(mono_handles);
1472 handles = g_new0(HANDLE, numhandles);
1474 for(i = 0; i < numhandles; i++) {
1475 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1476 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1483 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1485 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1487 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1491 if(ret==WAIT_FAILED) {
1492 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
1494 } else if(ret==WAIT_TIMEOUT) {
1495 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
1502 /* FIXME: exitContext isnt documented */
1503 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1505 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1506 uintptr_t numhandles;
1509 MonoObject *waitHandle;
1510 MonoInternalThread *thread = mono_thread_internal_current ();
1512 /* Do this WaitSleepJoin check before creating objects */
1513 mono_thread_current_check_pending_interrupt ();
1515 numhandles = mono_array_length(mono_handles);
1516 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1519 for(i = 0; i < numhandles; i++) {
1520 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1521 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1528 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1530 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1532 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1534 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1537 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1539 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1540 return ret - WAIT_OBJECT_0;
1542 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1543 return ret - WAIT_ABANDONED_0;
1550 /* FIXME: exitContext isnt documented */
1551 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
1554 MonoInternalThread *thread = mono_thread_internal_current ();
1556 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1562 mono_thread_current_check_pending_interrupt ();
1564 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1566 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1568 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1570 if(ret==WAIT_FAILED) {
1571 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, mono_native_thread_id_get ()));
1573 } else if(ret==WAIT_TIMEOUT) {
1574 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, mono_native_thread_id_get ()));
1582 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1585 MonoInternalThread *thread = mono_thread_internal_current ();
1590 mono_thread_current_check_pending_interrupt ();
1592 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1594 MONO_PREPARE_BLOCKING;
1595 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1596 MONO_FINISH_BLOCKING;
1598 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1600 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1603 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1610 mutex = CreateMutex (NULL, owned, NULL);
1612 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1614 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1622 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1623 return(ReleaseMutex (handle));
1626 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1632 *error = ERROR_SUCCESS;
1634 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1636 *error = GetLastError ();
1643 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1650 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1652 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1653 mono_string_chars (name));
1655 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1663 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1667 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1672 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1676 *error = ERROR_SUCCESS;
1678 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1680 *error = GetLastError ();
1686 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1693 event = CreateEvent (NULL, manual, initial, NULL);
1695 event = CreateEvent (NULL, manual, initial,
1696 mono_string_chars (name));
1698 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1706 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1707 return (SetEvent(handle));
1710 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1711 return (ResetEvent(handle));
1715 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1716 CloseHandle (handle);
1719 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1725 *error = ERROR_SUCCESS;
1727 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1729 *error = GetLastError ();
1735 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1737 return InterlockedIncrement (location);
1740 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1742 #if SIZEOF_VOID_P == 4
1743 if (G_UNLIKELY ((size_t)location & 0x7)) {
1745 mono_interlocked_lock ();
1748 mono_interlocked_unlock ();
1752 return InterlockedIncrement64 (location);
1755 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1757 return InterlockedDecrement(location);
1760 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1762 #if SIZEOF_VOID_P == 4
1763 if (G_UNLIKELY ((size_t)location & 0x7)) {
1765 mono_interlocked_lock ();
1768 mono_interlocked_unlock ();
1772 return InterlockedDecrement64 (location);
1775 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1777 return InterlockedExchange(location, value);
1780 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1783 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1784 mono_gc_wbarrier_generic_nostore (location);
1788 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1790 return InterlockedExchangePointer(location, value);
1793 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1795 IntFloatUnion val, ret;
1798 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1804 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1806 #if SIZEOF_VOID_P == 4
1807 if (G_UNLIKELY ((size_t)location & 0x7)) {
1809 mono_interlocked_lock ();
1812 mono_interlocked_unlock ();
1816 return InterlockedExchange64 (location, value);
1820 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1822 LongDoubleUnion val, ret;
1825 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1830 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1832 return InterlockedCompareExchange(location, value, comparand);
1835 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1837 gint32 r = InterlockedCompareExchange(location, value, comparand);
1838 *success = r == comparand;
1842 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1845 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1846 mono_gc_wbarrier_generic_nostore (location);
1850 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1852 return InterlockedCompareExchangePointer(location, value, comparand);
1855 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1857 IntFloatUnion val, ret, cmp;
1860 cmp.fval = comparand;
1861 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1867 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1869 #if SIZEOF_VOID_P == 8
1870 LongDoubleUnion val, comp, ret;
1873 comp.fval = comparand;
1874 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1880 mono_interlocked_lock ();
1882 if (old == comparand)
1884 mono_interlocked_unlock ();
1891 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1893 #if SIZEOF_VOID_P == 4
1894 if (G_UNLIKELY ((size_t)location & 0x7)) {
1896 mono_interlocked_lock ();
1898 if (old == comparand)
1900 mono_interlocked_unlock ();
1904 return InterlockedCompareExchange64 (location, value, comparand);
1908 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1911 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1912 mono_gc_wbarrier_generic_nostore (location);
1917 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1920 res = InterlockedExchangePointer ((gpointer *)location, value);
1921 mono_gc_wbarrier_generic_nostore (location);
1926 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1928 return InterlockedAdd (location, value);
1932 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1934 #if SIZEOF_VOID_P == 4
1935 if (G_UNLIKELY ((size_t)location & 0x7)) {
1937 mono_interlocked_lock ();
1940 mono_interlocked_unlock ();
1944 return InterlockedAdd64 (location, value);
1948 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1950 #if SIZEOF_VOID_P == 4
1951 if (G_UNLIKELY ((size_t)location & 0x7)) {
1953 mono_interlocked_lock ();
1955 mono_interlocked_unlock ();
1959 return InterlockedRead64 (location);
1963 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1965 mono_memory_barrier ();
1969 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1971 mono_thread_clr_state (this, state);
1973 if (state & ThreadState_Background) {
1974 /* If the thread changes the background mode, the main thread has to
1975 * be notified, since it has to rebuild the list of threads to
1978 SetEvent (background_change_event);
1983 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1985 mono_thread_set_state (this, state);
1987 if (state & ThreadState_Background) {
1988 /* If the thread changes the background mode, the main thread has to
1989 * be notified, since it has to rebuild the list of threads to
1992 SetEvent (background_change_event);
1997 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2003 state = this->state;
2005 UNLOCK_THREAD (this);
2010 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2012 MonoInternalThread *current;
2014 MonoInternalThread *thread = this_obj->internal_thread;
2016 LOCK_THREAD (thread);
2018 current = mono_thread_internal_current ();
2020 thread->thread_interrupt_requested = TRUE;
2021 throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2023 UNLOCK_THREAD (thread);
2026 abort_thread_internal (thread, TRUE, FALSE);
2030 void mono_thread_current_check_pending_interrupt ()
2032 MonoInternalThread *thread = mono_thread_internal_current ();
2033 gboolean throw = FALSE;
2035 LOCK_THREAD (thread);
2037 if (thread->thread_interrupt_requested) {
2039 thread->thread_interrupt_requested = FALSE;
2042 UNLOCK_THREAD (thread);
2045 mono_raise_exception (mono_get_exception_thread_interrupted ());
2050 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2052 LOCK_THREAD (thread);
2054 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2055 (thread->state & ThreadState_StopRequested) != 0 ||
2056 (thread->state & ThreadState_Stopped) != 0)
2058 UNLOCK_THREAD (thread);
2062 if ((thread->state & ThreadState_Unstarted) != 0) {
2063 thread->state |= ThreadState_Aborted;
2064 UNLOCK_THREAD (thread);
2068 thread->state |= ThreadState_AbortRequested;
2069 if (thread->abort_state_handle)
2070 mono_gchandle_free (thread->abort_state_handle);
2072 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2073 g_assert (thread->abort_state_handle);
2075 thread->abort_state_handle = 0;
2077 thread->abort_exc = NULL;
2079 UNLOCK_THREAD (thread);
2081 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), thread, (gsize)thread->tid));
2083 /* During shutdown, we can't wait for other threads */
2085 /* Make sure the thread is awake */
2086 mono_thread_resume (thread);
2088 abort_thread_internal (thread, TRUE, TRUE);
2092 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2094 MonoInternalThread *thread = mono_thread_internal_current ();
2095 gboolean was_aborting;
2097 LOCK_THREAD (thread);
2098 was_aborting = thread->state & ThreadState_AbortRequested;
2099 thread->state &= ~ThreadState_AbortRequested;
2100 UNLOCK_THREAD (thread);
2102 if (!was_aborting) {
2103 const char *msg = "Unable to reset abort because no abort was requested";
2104 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2107 thread->abort_exc = NULL;
2108 if (thread->abort_state_handle) {
2109 mono_gchandle_free (thread->abort_state_handle);
2110 /* This is actually not necessary - the handle
2111 only counts if the exception is set */
2112 thread->abort_state_handle = 0;
2117 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2119 LOCK_THREAD (thread);
2121 thread->state &= ~ThreadState_AbortRequested;
2123 if (thread->abort_exc) {
2124 thread->abort_exc = NULL;
2125 if (thread->abort_state_handle) {
2126 mono_gchandle_free (thread->abort_state_handle);
2127 /* This is actually not necessary - the handle
2128 only counts if the exception is set */
2129 thread->abort_state_handle = 0;
2133 UNLOCK_THREAD (thread);
2137 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2139 MonoInternalThread *thread = this_obj->internal_thread;
2140 MonoObject *state, *deserialized = NULL, *exc;
2143 if (!thread->abort_state_handle)
2146 state = mono_gchandle_get_target (thread->abort_state_handle);
2149 domain = mono_domain_get ();
2150 if (mono_object_domain (state) == domain)
2153 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2155 if (!deserialized) {
2156 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2158 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2159 mono_set_pending_exception (invalid_op_exc);
2163 return deserialized;
2167 mono_thread_suspend (MonoInternalThread *thread)
2169 LOCK_THREAD (thread);
2171 if ((thread->state & ThreadState_Unstarted) != 0 ||
2172 (thread->state & ThreadState_Aborted) != 0 ||
2173 (thread->state & ThreadState_Stopped) != 0)
2175 UNLOCK_THREAD (thread);
2179 if ((thread->state & ThreadState_Suspended) != 0 ||
2180 (thread->state & ThreadState_SuspendRequested) != 0 ||
2181 (thread->state & ThreadState_StopRequested) != 0)
2183 UNLOCK_THREAD (thread);
2187 thread->state |= ThreadState_SuspendRequested;
2189 UNLOCK_THREAD (thread);
2191 suspend_thread_internal (thread, FALSE);
2196 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2198 if (!mono_thread_suspend (this_obj->internal_thread)) {
2199 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2205 mono_thread_resume (MonoInternalThread *thread)
2207 LOCK_THREAD (thread);
2209 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2210 thread->state &= ~ThreadState_SuspendRequested;
2211 UNLOCK_THREAD (thread);
2215 if ((thread->state & ThreadState_Suspended) == 0 ||
2216 (thread->state & ThreadState_Unstarted) != 0 ||
2217 (thread->state & ThreadState_Aborted) != 0 ||
2218 (thread->state & ThreadState_Stopped) != 0)
2220 UNLOCK_THREAD (thread);
2224 return resume_thread_internal (thread);
2228 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2230 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2231 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2237 mono_threads_is_critical_method (MonoMethod *method)
2239 switch (method->wrapper_type) {
2240 case MONO_WRAPPER_RUNTIME_INVOKE:
2241 case MONO_WRAPPER_XDOMAIN_INVOKE:
2242 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2249 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2254 if (mono_threads_is_critical_method (m)) {
2255 *((gboolean*)data) = TRUE;
2262 is_running_protected_wrapper (void)
2264 gboolean found = FALSE;
2265 mono_stack_walk (find_wrapper, &found);
2269 void mono_thread_internal_stop (MonoInternalThread *thread)
2271 LOCK_THREAD (thread);
2273 if ((thread->state & ThreadState_StopRequested) != 0 ||
2274 (thread->state & ThreadState_Stopped) != 0)
2276 UNLOCK_THREAD (thread);
2280 /* Make sure the thread is awake */
2281 mono_thread_resume (thread);
2283 thread->state |= ThreadState_StopRequested;
2284 thread->state &= ~ThreadState_AbortRequested;
2286 UNLOCK_THREAD (thread);
2288 abort_thread_internal (thread, TRUE, TRUE);
2291 void mono_thread_stop (MonoThread *thread)
2293 mono_thread_internal_stop (thread->internal_thread);
2297 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2300 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2305 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2308 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2313 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2316 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2321 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2324 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2329 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2332 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2333 return (void *) tmp;
2337 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2339 volatile MonoObject *tmp;
2340 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2341 return (MonoObject *) tmp;
2345 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2348 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2353 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2356 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2361 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2363 return InterlockedRead8 (ptr);
2367 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2369 return InterlockedRead16 (ptr);
2373 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2375 return InterlockedRead (ptr);
2379 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2381 #if SIZEOF_VOID_P == 4
2382 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2384 mono_interlocked_lock ();
2385 val = *(gint64*)ptr;
2386 mono_interlocked_unlock ();
2390 return InterlockedRead64 (ptr);
2394 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2396 return InterlockedReadPointer (ptr);
2400 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2404 #if SIZEOF_VOID_P == 4
2405 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2407 mono_interlocked_lock ();
2408 val = *(double*)ptr;
2409 mono_interlocked_unlock ();
2414 u.ival = InterlockedRead64 (ptr);
2420 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2424 u.ival = InterlockedRead (ptr);
2430 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2432 return InterlockedReadPointer (ptr);
2436 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2438 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2442 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2444 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2448 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2450 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2454 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2456 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2460 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2462 mono_atomic_store_release ((volatile void **) ptr, value);
2466 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2468 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2472 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2474 mono_atomic_store_release ((volatile double *) ptr, value);
2478 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2480 mono_atomic_store_release ((volatile float *) ptr, value);
2484 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2486 InterlockedWrite8 (ptr, value);
2490 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2492 InterlockedWrite16 (ptr, value);
2496 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2498 InterlockedWrite (ptr, value);
2502 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2504 #if SIZEOF_VOID_P == 4
2505 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2506 mono_interlocked_lock ();
2507 *(gint64*)ptr = value;
2508 mono_interlocked_unlock ();
2513 InterlockedWrite64 (ptr, value);
2517 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2519 InterlockedWritePointer (ptr, value);
2523 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2527 #if SIZEOF_VOID_P == 4
2528 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2529 mono_interlocked_lock ();
2530 *(double*)ptr = value;
2531 mono_interlocked_unlock ();
2538 InterlockedWrite64 (ptr, u.ival);
2542 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2548 InterlockedWrite (ptr, u.ival);
2552 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2554 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2558 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2560 mono_threads_lock ();
2562 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2565 contexts = g_hash_table_new (NULL, NULL);
2567 context_adjust_static_data (ctx);
2568 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2569 g_hash_table_insert (contexts, gch, gch);
2571 mono_threads_unlock ();
2573 mono_profiler_context_loaded (ctx);
2577 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2580 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2581 * cleanup in exceptional circumstances, we don't actually do any
2582 * cleanup work here. We instead do this when we iterate the `contexts`
2583 * hash table. The only purpose of this finalizer, at the moment, is to
2584 * notify the profiler.
2587 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2589 mono_profiler_context_unloaded (ctx);
2593 mono_thread_init_tls (void)
2595 MONO_FAST_TLS_INIT (tls_current_object);
2596 mono_native_tls_alloc (¤t_object_key, NULL);
2599 void mono_thread_init (MonoThreadStartCB start_cb,
2600 MonoThreadAttachCB attach_cb)
2602 mono_mutex_init_recursive(&threads_mutex);
2603 mono_mutex_init_recursive(&interlocked_mutex);
2604 mono_mutex_init_recursive(&joinable_threads_mutex);
2606 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2607 g_assert(background_change_event != NULL);
2609 mono_init_static_data_info (&thread_static_info);
2610 mono_init_static_data_info (&context_static_info);
2612 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2614 mono_thread_start_cb = start_cb;
2615 mono_thread_attach_cb = attach_cb;
2617 /* Get a pseudo handle to the current process. This is just a
2618 * kludge so that wapi can build a process handle if needed.
2619 * As a pseudo handle is returned, we don't need to clean
2622 GetCurrentProcess ();
2625 void mono_thread_cleanup (void)
2627 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2628 MonoThreadInfo *info;
2630 /* The main thread must abandon any held mutexes (particularly
2631 * important for named mutexes as they are shared across
2632 * processes, see bug 74680.) This will happen when the
2633 * thread exits, but if it's not running in a subthread it
2634 * won't exit in time.
2636 info = mono_thread_info_current ();
2637 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2641 /* This stuff needs more testing, it seems one of these
2642 * critical sections can be locked when mono_thread_cleanup is
2645 mono_mutex_destroy (&threads_mutex);
2646 mono_mutex_destroy (&interlocked_mutex);
2647 mono_mutex_destroy (&delayed_free_table_mutex);
2648 mono_mutex_destroy (&small_id_mutex);
2649 CloseHandle (background_change_event);
2652 mono_native_tls_free (current_object_key);
2656 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2658 mono_thread_cleanup_fn = func;
2662 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2664 thread->internal_thread->manage_callback = func;
2667 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2669 mono_thread_notify_pending_exc_fn = func;
2673 static void print_tids (gpointer key, gpointer value, gpointer user)
2675 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2676 * sizeof(uint) and a cast to uint would overflow
2678 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2679 * print this as a pointer.
2681 g_message ("Waiting for: %p", key);
2686 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2687 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2691 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2695 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2697 MONO_PREPARE_BLOCKING;
2698 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2699 MONO_FINISH_BLOCKING;
2701 if(ret==WAIT_FAILED) {
2702 /* See the comment in build_wait_tids() */
2703 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2707 for(i=0; i<wait->num; i++)
2708 CloseHandle (wait->handles[i]);
2710 if (ret == WAIT_TIMEOUT)
2713 for(i=0; i<wait->num; i++) {
2714 gsize tid = wait->threads[i]->tid;
2717 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2718 * it can still run io-layer etc. code. So wait for it to really exit.
2719 * FIXME: This won't join threads which are not in the joinable_hash yet.
2721 mono_thread_join ((gpointer)tid);
2723 mono_threads_lock ();
2724 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2725 /* This thread must have been killed, because
2726 * it hasn't cleaned itself up. (It's just
2727 * possible that the thread exited before the
2728 * parent thread had a chance to store the
2729 * handle, and now there is another pointer to
2730 * the already-exited thread stored. In this
2731 * case, we'll just get two
2732 * mono_profiler_thread_end() calls for the
2736 mono_threads_unlock ();
2737 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2738 thread_cleanup (wait->threads[i]);
2740 mono_threads_unlock ();
2745 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2747 guint32 i, ret, count;
2749 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2751 /* Add the thread state change event, so it wakes up if a thread changes
2752 * to background mode.
2755 if (count < MAXIMUM_WAIT_OBJECTS) {
2756 wait->handles [count] = background_change_event;
2760 MONO_PREPARE_BLOCKING;
2761 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2762 MONO_FINISH_BLOCKING;
2764 if(ret==WAIT_FAILED) {
2765 /* See the comment in build_wait_tids() */
2766 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2770 for(i=0; i<wait->num; i++)
2771 CloseHandle (wait->handles[i]);
2773 if (ret == WAIT_TIMEOUT)
2776 if (ret < wait->num) {
2777 gsize tid = wait->threads[ret]->tid;
2778 mono_threads_lock ();
2779 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2780 /* See comment in wait_for_tids about thread cleanup */
2781 mono_threads_unlock ();
2782 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2783 thread_cleanup (wait->threads [ret]);
2785 mono_threads_unlock ();
2789 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2791 struct wait_data *wait=(struct wait_data *)user;
2793 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2795 MonoInternalThread *thread=(MonoInternalThread *)value;
2797 /* Ignore background threads, we abort them later */
2798 /* Do not lock here since it is not needed and the caller holds threads_lock */
2799 if (thread->state & ThreadState_Background) {
2800 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2801 return; /* just leave, ignore */
2804 if (mono_gc_is_finalizer_internal_thread (thread)) {
2805 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2809 if (thread == mono_thread_internal_current ()) {
2810 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2814 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2815 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2819 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2820 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2824 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2825 if (handle == NULL) {
2826 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2830 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2831 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2832 wait->handles[wait->num]=handle;
2833 wait->threads[wait->num]=thread;
2836 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2838 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2843 /* Just ignore the rest, we can't do anything with
2850 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2852 struct wait_data *wait=(struct wait_data *)user;
2853 MonoNativeThreadId self = mono_native_thread_id_get ();
2854 MonoInternalThread *thread = value;
2857 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2860 /* The finalizer thread is not a background thread */
2861 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
2862 && (thread->state & ThreadState_Background) != 0
2863 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
2865 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2869 /* printf ("A: %d\n", wait->num); */
2870 wait->handles[wait->num]=thread->handle;
2871 wait->threads[wait->num]=thread;
2874 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2875 mono_thread_internal_stop (thread);
2879 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
2880 && !mono_gc_is_finalizer_internal_thread (thread);
2884 * mono_threads_set_shutting_down:
2886 * Is called by a thread that wants to shut down Mono. If the runtime is already
2887 * shutting down, the calling thread is suspended/stopped, and this function never
2891 mono_threads_set_shutting_down (void)
2893 MonoInternalThread *current_thread = mono_thread_internal_current ();
2895 mono_threads_lock ();
2897 if (shutting_down) {
2898 mono_threads_unlock ();
2900 /* Make sure we're properly suspended/stopped */
2902 LOCK_THREAD (current_thread);
2904 if ((current_thread->state & ThreadState_SuspendRequested) ||
2905 (current_thread->state & ThreadState_AbortRequested) ||
2906 (current_thread->state & ThreadState_StopRequested)) {
2907 UNLOCK_THREAD (current_thread);
2908 mono_thread_execute_interruption ();
2910 current_thread->state |= ThreadState_Stopped;
2911 UNLOCK_THREAD (current_thread);
2914 /*since we're killing the thread, unset the current domain.*/
2915 mono_domain_unset ();
2917 /* Wake up other threads potentially waiting for us */
2918 mono_thread_info_exit ();
2920 shutting_down = TRUE;
2922 /* Not really a background state change, but this will
2923 * interrupt the main thread if it is waiting for all
2924 * the other threads.
2926 SetEvent (background_change_event);
2928 mono_threads_unlock ();
2932 void mono_thread_manage (void)
2934 struct wait_data wait_data;
2935 struct wait_data *wait = &wait_data;
2937 memset (wait, 0, sizeof (struct wait_data));
2938 /* join each thread that's still running */
2939 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2941 mono_threads_lock ();
2943 THREAD_DEBUG (g_message("%s: No threads", __func__));
2944 mono_threads_unlock ();
2947 mono_threads_unlock ();
2950 mono_threads_lock ();
2951 if (shutting_down) {
2952 /* somebody else is shutting down */
2953 mono_threads_unlock ();
2956 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2957 mono_g_hash_table_foreach (threads, print_tids, NULL));
2959 ResetEvent (background_change_event);
2961 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2962 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2963 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2964 mono_threads_unlock ();
2966 /* Something to wait for */
2967 wait_for_tids_or_state_change (wait, INFINITE);
2969 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2970 } while(wait->num>0);
2972 /* Mono is shutting down, so just wait for the end */
2973 if (!mono_runtime_try_shutdown ()) {
2974 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2975 mono_thread_suspend (mono_thread_internal_current ());
2976 mono_thread_execute_interruption ();
2980 * Remove everything but the finalizer thread and self.
2981 * Also abort all the background threads
2984 mono_threads_lock ();
2987 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2988 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2989 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2991 mono_threads_unlock ();
2993 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2995 /* Something to wait for */
2996 wait_for_tids (wait, INFINITE);
2998 } while (wait->num > 0);
3001 * give the subthreads a chance to really quit (this is mainly needed
3002 * to get correct user and system times from getrusage/wait/time(1)).
3003 * This could be removed if we avoid pthread_detach() and use pthread_join().
3005 mono_thread_info_yield ();
3009 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3011 MonoInternalThread *thread = (MonoInternalThread*)value;
3012 struct wait_data *wait = (struct wait_data*)user_data;
3016 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3018 * This needs no locking.
3020 if ((thread->state & ThreadState_Suspended) != 0 ||
3021 (thread->state & ThreadState_Stopped) != 0)
3024 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3025 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3029 wait->handles [wait->num] = handle;
3030 wait->threads [wait->num] = thread;
3036 * mono_thread_suspend_all_other_threads:
3038 * Suspend all managed threads except the finalizer thread and this thread. It is
3039 * not possible to resume them later.
3041 void mono_thread_suspend_all_other_threads (void)
3043 struct wait_data wait_data;
3044 struct wait_data *wait = &wait_data;
3046 MonoNativeThreadId self = mono_native_thread_id_get ();
3047 guint32 eventidx = 0;
3048 gboolean starting, finished;
3050 memset (wait, 0, sizeof (struct wait_data));
3052 * The other threads could be in an arbitrary state at this point, i.e.
3053 * they could be starting up, shutting down etc. This means that there could be
3054 * threads which are not even in the threads hash table yet.
3058 * First we set a barrier which will be checked by all threads before they
3059 * are added to the threads hash table, and they will exit if the flag is set.
3060 * This ensures that no threads could be added to the hash later.
3061 * We will use shutting_down as the barrier for now.
3063 g_assert (shutting_down);
3066 * We make multiple calls to WaitForMultipleObjects since:
3067 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3068 * - some threads could exit without becoming suspended
3073 * Make a copy of the hashtable since we can't do anything with
3074 * threads while threads_mutex is held.
3077 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3078 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3079 mono_threads_lock ();
3080 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3081 mono_threads_unlock ();
3084 /* Get the suspended events that we'll be waiting for */
3085 for (i = 0; i < wait->num; ++i) {
3086 MonoInternalThread *thread = wait->threads [i];
3088 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3089 || mono_gc_is_finalizer_internal_thread (thread)
3090 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3092 //CloseHandle (wait->handles [i]);
3093 wait->threads [i] = NULL; /* ignore this thread in next loop */
3097 LOCK_THREAD (thread);
3099 if ((thread->state & ThreadState_Suspended) != 0 ||
3100 (thread->state & ThreadState_StopRequested) != 0 ||
3101 (thread->state & ThreadState_Stopped) != 0) {
3102 UNLOCK_THREAD (thread);
3103 CloseHandle (wait->handles [i]);
3104 wait->threads [i] = NULL; /* ignore this thread in next loop */
3110 /* Convert abort requests into suspend requests */
3111 if ((thread->state & ThreadState_AbortRequested) != 0)
3112 thread->state &= ~ThreadState_AbortRequested;
3114 thread->state |= ThreadState_SuspendRequested;
3116 UNLOCK_THREAD (thread);
3118 /* Signal the thread to suspend */
3119 suspend_thread_internal (thread, TRUE);
3121 if (eventidx <= 0) {
3123 * If there are threads which are starting up, we wait until they
3124 * are suspended when they try to register in the threads hash.
3125 * This is guaranteed to finish, since the threads which can create new
3126 * threads get suspended after a while.
3127 * FIXME: The finalizer thread can still create new threads.
3129 mono_threads_lock ();
3130 if (threads_starting_up)
3131 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3134 mono_threads_unlock ();
3136 mono_thread_info_sleep (100, NULL);
3144 MonoInternalThread *thread;
3145 MonoStackFrameInfo *frames;
3146 int nframes, max_frames;
3147 } ThreadDumpUserData;
3149 static gboolean thread_dump_requested;
3151 /* This needs to be async safe */
3153 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3155 ThreadDumpUserData *ud = data;
3157 if (ud->nframes < ud->max_frames) {
3158 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3165 /* This needs to be async safe */
3166 static SuspendThreadResult
3167 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3169 ThreadDumpUserData *user_data = ud;
3170 MonoInternalThread *thread = user_data->thread;
3173 /* This no longer works with remote unwinding */
3175 wapi_desc = wapi_current_thread_desc ();
3176 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3181 if (thread == mono_thread_internal_current ())
3182 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3184 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3186 return MonoResumeThread;
3190 dump_thread (gpointer key, gpointer value, gpointer user)
3192 ThreadDumpUserData *ud = user;
3193 MonoInternalThread *thread = value;
3194 GString* text = g_string_new (0);
3196 GError *error = NULL;
3199 ud->thread = thread;
3202 /* Collect frames for the thread */
3203 if (thread == mono_thread_internal_current ()) {
3204 get_thread_dump (mono_thread_info_current (), ud);
3206 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3210 * Do all the non async-safe work outside of get_thread_dump.
3213 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3215 g_string_append_printf (text, "\n\"%s\"", name);
3218 else if (thread->threadpool_thread) {
3219 g_string_append (text, "\n\"<threadpool thread>\"");
3221 g_string_append (text, "\n\"<unnamed thread>\"");
3224 for (i = 0; i < ud->nframes; ++i) {
3225 MonoStackFrameInfo *frame = &ud->frames [i];
3226 MonoMethod *method = NULL;
3228 if (frame->type == FRAME_TYPE_MANAGED)
3229 method = mono_jit_info_get_method (frame->ji);
3232 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3233 g_string_append_printf (text, " %s\n", location);
3236 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3240 fprintf (stdout, "%s", text->str);
3242 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3243 OutputDebugStringA(text->str);
3246 g_string_free (text, TRUE);
3251 mono_threads_perform_thread_dump (void)
3253 ThreadDumpUserData ud;
3255 if (!thread_dump_requested)
3258 printf ("Full thread dump:\n");
3260 memset (&ud, 0, sizeof (ud));
3261 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3262 ud.max_frames = 256;
3264 mono_threads_lock ();
3265 mono_g_hash_table_foreach (threads, dump_thread, &ud);
3266 mono_threads_unlock ();
3268 thread_dump_requested = FALSE;
3272 * mono_threads_request_thread_dump:
3274 * Ask all threads except the current to print their stacktrace to stdout.
3277 mono_threads_request_thread_dump (void)
3279 /*The new thread dump code runs out of the finalizer thread. */
3280 thread_dump_requested = TRUE;
3281 mono_gc_finalize_notify ();
3286 gint allocated; /* +1 so that refs [allocated] == NULL */
3290 typedef struct ref_stack RefStack;
3293 ref_stack_new (gint initial_size)
3297 initial_size = MAX (initial_size, 16) + 1;
3298 rs = g_new0 (RefStack, 1);
3299 rs->refs = g_new0 (gpointer, initial_size);
3300 rs->allocated = initial_size;
3305 ref_stack_destroy (gpointer ptr)
3316 ref_stack_push (RefStack *rs, gpointer ptr)
3318 g_assert (rs != NULL);
3320 if (rs->bottom >= rs->allocated) {
3321 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3322 rs->allocated <<= 1;
3323 rs->refs [rs->allocated] = NULL;
3325 rs->refs [rs->bottom++] = ptr;
3329 ref_stack_pop (RefStack *rs)
3331 if (rs == NULL || rs->bottom == 0)
3335 rs->refs [rs->bottom] = NULL;
3339 ref_stack_find (RefStack *rs, gpointer ptr)
3346 for (refs = rs->refs; refs && *refs; refs++) {
3354 * mono_thread_push_appdomain_ref:
3356 * Register that the current thread may have references to objects in domain
3357 * @domain on its stack. Each call to this function should be paired with a
3358 * call to pop_appdomain_ref.
3361 mono_thread_push_appdomain_ref (MonoDomain *domain)
3363 MonoInternalThread *thread = mono_thread_internal_current ();
3366 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3367 SPIN_LOCK (thread->lock_thread_id);
3368 if (thread->appdomain_refs == NULL)
3369 thread->appdomain_refs = ref_stack_new (16);
3370 ref_stack_push (thread->appdomain_refs, domain);
3371 SPIN_UNLOCK (thread->lock_thread_id);
3376 mono_thread_pop_appdomain_ref (void)
3378 MonoInternalThread *thread = mono_thread_internal_current ();
3381 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3382 SPIN_LOCK (thread->lock_thread_id);
3383 ref_stack_pop (thread->appdomain_refs);
3384 SPIN_UNLOCK (thread->lock_thread_id);
3389 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3392 SPIN_LOCK (thread->lock_thread_id);
3393 res = ref_stack_find (thread->appdomain_refs, domain);
3394 SPIN_UNLOCK (thread->lock_thread_id);
3399 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3401 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3404 typedef struct abort_appdomain_data {
3405 struct wait_data wait;
3407 } abort_appdomain_data;
3410 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3412 MonoInternalThread *thread = (MonoInternalThread*)value;
3413 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3414 MonoDomain *domain = data->domain;
3416 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3417 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3419 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3420 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3423 data->wait.handles [data->wait.num] = handle;
3424 data->wait.threads [data->wait.num] = thread;
3427 /* Just ignore the rest, we can't do anything with
3435 * mono_threads_abort_appdomain_threads:
3437 * Abort threads which has references to the given appdomain.
3440 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3442 #ifdef __native_client__
3446 abort_appdomain_data user_data;
3448 int orig_timeout = timeout;
3451 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3453 start_time = mono_msec_ticks ();
3455 mono_threads_lock ();
3457 user_data.domain = domain;
3458 user_data.wait.num = 0;
3459 /* This shouldn't take any locks */
3460 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3461 mono_threads_unlock ();
3463 if (user_data.wait.num > 0) {
3464 /* Abort the threads outside the threads lock */
3465 for (i = 0; i < user_data.wait.num; ++i)
3466 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3469 * We should wait for the threads either to abort, or to leave the
3470 * domain. We can't do the latter, so we wait with a timeout.
3472 wait_for_tids (&user_data.wait, 100);
3475 /* Update remaining time */
3476 timeout -= mono_msec_ticks () - start_time;
3477 start_time = mono_msec_ticks ();
3479 if (orig_timeout != -1 && timeout < 0)
3482 while (user_data.wait.num > 0);
3484 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3490 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3492 MonoInternalThread *thread = (MonoInternalThread*)value;
3493 MonoDomain *domain = (MonoDomain*)user_data;
3496 /* No locking needed here */
3497 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3499 if (thread->cached_culture_info) {
3500 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3501 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3502 if (obj && obj->vtable->domain == domain)
3503 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3509 * mono_threads_clear_cached_culture:
3511 * Clear the cached_current_culture from all threads if it is in the
3515 mono_threads_clear_cached_culture (MonoDomain *domain)
3517 mono_threads_lock ();
3518 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3519 mono_threads_unlock ();
3523 * mono_thread_get_undeniable_exception:
3525 * Return an exception which needs to be raised when leaving a catch clause.
3526 * This is used for undeniable exception propagation.
3529 mono_thread_get_undeniable_exception (void)
3531 MonoInternalThread *thread = mono_thread_internal_current ();
3533 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3535 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3536 * exception if the thread no longer references a dying appdomain.
3538 thread->abort_exc->trace_ips = NULL;
3539 thread->abort_exc->stack_trace = NULL;
3540 return thread->abort_exc;
3546 #if MONO_SMALL_CONFIG
3547 #define NUM_STATIC_DATA_IDX 4
3548 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3552 #define NUM_STATIC_DATA_IDX 8
3553 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3554 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3558 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3559 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3562 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3564 gpointer *static_data = addr;
3566 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3567 void **ptr = static_data [i];
3572 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3573 void **p = ptr + idx;
3576 mark_func ((MonoObject**)p, gc_data);
3582 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3584 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3588 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3590 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3594 * mono_alloc_static_data
3596 * Allocate memory blocks for storing threads or context static data
3599 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3601 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3604 gpointer* static_data = *static_data_ptr;
3606 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3607 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3609 if (mono_gc_user_markers_supported ()) {
3610 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3611 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3613 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3614 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3617 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3618 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3619 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3620 *static_data_ptr = static_data;
3621 static_data [0] = static_data;
3624 for (i = 1; i <= idx; ++i) {
3625 if (static_data [i])
3628 if (mono_gc_user_markers_supported ())
3629 static_data [i] = g_malloc0 (static_data_size [i]);
3631 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3632 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3633 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3638 mono_free_static_data (gpointer* static_data)
3641 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3642 gpointer p = static_data [i];
3646 * At this point, the static data pointer array is still registered with the
3647 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3648 * data. Freeing the individual arrays without first nulling their slots
3649 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3650 * such an already freed array. See bug #13813.
3652 static_data [i] = NULL;
3653 mono_memory_write_barrier ();
3654 if (mono_gc_user_markers_supported ())
3657 mono_gc_free_fixed (p);
3659 mono_gc_free_fixed (static_data);
3663 * mono_init_static_data_info
3665 * Initializes static data counters
3667 static void mono_init_static_data_info (StaticDataInfo *static_data)
3669 static_data->idx = 0;
3670 static_data->offset = 0;
3671 static_data->freelist = NULL;
3675 * mono_alloc_static_data_slot
3677 * Generates an offset for static data. static_data contains the counters
3678 * used to generate it.
3681 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3683 if (!static_data->idx && !static_data->offset) {
3685 * we use the first chunk of the first allocation also as
3686 * an array for the rest of the data
3688 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3690 static_data->offset += align - 1;
3691 static_data->offset &= ~(align - 1);
3692 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3693 static_data->idx ++;
3694 g_assert (size <= static_data_size [static_data->idx]);
3695 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3696 static_data->offset = 0;
3698 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3699 static_data->offset += size;
3704 * ensure thread static fields already allocated are valid for thread
3705 * This function is called when a thread is created or on thread attach.
3708 thread_adjust_static_data (MonoInternalThread *thread)
3710 mono_threads_lock ();
3711 if (thread_static_info.offset || thread_static_info.idx > 0) {
3712 /* get the current allocated size */
3713 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3714 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3716 mono_threads_unlock ();
3720 * LOCKING: requires that threads_mutex is held
3723 context_adjust_static_data (MonoAppContext *ctx)
3725 if (context_static_info.offset || context_static_info.idx > 0) {
3726 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3727 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3732 * LOCKING: requires that threads_mutex is held
3735 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3737 MonoInternalThread *thread = value;
3738 guint32 offset = GPOINTER_TO_UINT (user);
3740 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3744 * LOCKING: requires that threads_mutex is held
3747 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3749 uint32_t gch = GPOINTER_TO_INT (key);
3750 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3753 mono_gchandle_free (gch);
3754 return TRUE; // Remove this key/value pair
3757 guint32 offset = GPOINTER_TO_UINT (user);
3758 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3760 return FALSE; // Don't remove it
3763 static StaticDataFreeList*
3764 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3766 StaticDataFreeList* prev = NULL;
3767 StaticDataFreeList* tmp = static_data->freelist;
3769 if (tmp->size == size) {
3771 prev->next = tmp->next;
3773 static_data->freelist = tmp->next;
3782 #if SIZEOF_VOID_P == 4
3789 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3791 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3793 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3794 MonoBitSet *rb = sets [idx];
3795 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3796 offset /= sizeof (uintptr_t);
3797 /* offset is now the bitmap offset */
3798 for (int i = 0; i < numbits; ++i) {
3799 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3800 mono_bitset_set_fast (rb, offset + i);
3805 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3807 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3808 MonoBitSet *rb = sets [idx];
3809 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3810 offset /= sizeof (uintptr_t);
3811 /* offset is now the bitmap offset */
3812 for (int i = 0; i < size / sizeof (uintptr_t); i++)
3813 mono_bitset_clear_fast (rb, offset + i);
3817 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3819 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3821 StaticDataInfo *info;
3824 if (static_type == SPECIAL_STATIC_THREAD) {
3825 info = &thread_static_info;
3826 sets = thread_reference_bitmaps;
3828 info = &context_static_info;
3829 sets = context_reference_bitmaps;
3832 mono_threads_lock ();
3834 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3838 offset = item->offset;
3841 offset = mono_alloc_static_data_slot (info, size, align);
3844 update_reference_bitmap (sets, offset, bitmap, numbits);
3846 if (static_type == SPECIAL_STATIC_THREAD) {
3847 /* This can be called during startup */
3848 if (threads != NULL)
3849 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3851 if (contexts != NULL)
3852 g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3854 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3857 mono_threads_unlock ();
3863 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3865 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3867 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3868 return get_thread_static_data (thread, offset);
3870 return get_context_static_data (thread->current_appcontext, offset);
3875 mono_get_special_static_data (guint32 offset)
3877 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3886 * LOCKING: requires that threads_mutex is held
3889 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3891 MonoInternalThread *thread = value;
3892 OffsetSize *data = user;
3893 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3894 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3897 if (!thread->static_data || !thread->static_data [idx])
3899 ptr = ((char*) thread->static_data [idx]) + off;
3900 mono_gc_bzero_atomic (ptr, data->size);
3904 * LOCKING: requires that threads_mutex is held
3907 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3909 uint32_t gch = GPOINTER_TO_INT (key);
3910 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3913 mono_gchandle_free (gch);
3914 return TRUE; // Remove this key/value pair
3917 OffsetSize *data = user;
3918 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3919 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3922 if (!ctx->static_data || !ctx->static_data [idx])
3923 return FALSE; // Don't remove this key/value pair
3925 ptr = ((char*) ctx->static_data [idx]) + off;
3926 mono_gc_bzero_atomic (ptr, data->size);
3928 return FALSE; // Don't remove this key/value pair
3932 do_free_special_slot (guint32 offset, guint32 size)
3934 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3936 StaticDataInfo *info;
3938 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3939 info = &thread_static_info;
3940 sets = thread_reference_bitmaps;
3942 info = &context_static_info;
3943 sets = context_reference_bitmaps;
3946 guint32 data_offset = offset;
3947 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
3948 OffsetSize data = { data_offset, size };
3950 clear_reference_bitmap (sets, data.offset, data.size);
3952 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3953 if (threads != NULL)
3954 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3956 if (contexts != NULL)
3957 g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
3960 if (!mono_runtime_is_shutting_down ()) {
3961 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
3963 item->offset = offset;
3966 item->next = info->freelist;
3967 info->freelist = item;
3972 do_free_special (gpointer key, gpointer value, gpointer data)
3974 MonoClassField *field = key;
3975 guint32 offset = GPOINTER_TO_UINT (value);
3978 size = mono_type_size (field->type, &align);
3979 do_free_special_slot (offset, size);
3983 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3985 mono_threads_lock ();
3987 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3989 mono_threads_unlock ();
3993 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3995 /* Only ever called for ThreadLocal instances */
3996 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
3998 mono_threads_lock ();
3999 do_free_special_slot (offset, size);
4000 mono_threads_unlock ();
4004 static void CALLBACK dummy_apc (ULONG_PTR param)
4010 * mono_thread_execute_interruption
4012 * Performs the operation that the requested thread state requires (abort,
4015 static MonoException*
4016 mono_thread_execute_interruption (void)
4018 MonoInternalThread *thread = mono_thread_internal_current ();
4020 LOCK_THREAD (thread);
4022 /* MonoThread::interruption_requested can only be changed with atomics */
4023 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4024 /* this will consume pending APC calls */
4026 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4028 InterlockedDecrement (&thread_interruption_requested);
4030 /* Clear the interrupted flag of the thread so it can wait again */
4031 mono_thread_info_clear_self_interrupt ();
4034 if ((thread->state & ThreadState_AbortRequested) != 0) {
4035 UNLOCK_THREAD (thread);
4036 if (thread->abort_exc == NULL) {
4038 * This might be racy, but it has to be called outside the lock
4039 * since it calls managed code.
4041 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4043 return thread->abort_exc;
4045 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4046 self_suspend_internal (thread);
4049 else if ((thread->state & ThreadState_StopRequested) != 0) {
4050 /* FIXME: do this through the JIT? */
4052 UNLOCK_THREAD (thread);
4054 mono_thread_exit ();
4056 } else if (thread->pending_exception) {
4059 exc = thread->pending_exception;
4060 thread->pending_exception = NULL;
4062 UNLOCK_THREAD (thread);
4064 } else if (thread->thread_interrupt_requested) {
4066 thread->thread_interrupt_requested = FALSE;
4067 UNLOCK_THREAD (thread);
4069 return(mono_get_exception_thread_interrupted ());
4072 UNLOCK_THREAD (thread);
4078 * mono_thread_request_interruption
4080 * A signal handler can call this method to request the interruption of a
4081 * thread. The result of the interruption will depend on the current state of
4082 * the thread. If the result is an exception that needs to be throw, it is
4083 * provided as return value.
4086 mono_thread_request_interruption (gboolean running_managed)
4088 MonoInternalThread *thread = mono_thread_internal_current ();
4090 /* The thread may already be stopping */
4095 if (thread->interrupt_on_stop &&
4096 thread->state & ThreadState_StopRequested &&
4097 thread->state & ThreadState_Background)
4101 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4103 InterlockedIncrement (&thread_interruption_requested);
4105 if (!running_managed || is_running_protected_wrapper ()) {
4106 /* Can't stop while in unmanaged code. Increase the global interruption
4107 request count. When exiting the unmanaged method the count will be
4108 checked and the thread will be interrupted. */
4110 if (mono_thread_notify_pending_exc_fn && !running_managed)
4111 /* The JIT will notify the thread about the interruption */
4112 /* This shouldn't take any locks */
4113 mono_thread_notify_pending_exc_fn (NULL);
4115 /* this will awake the thread if it is in WaitForSingleObject
4117 /* Our implementation of this function ignores the func argument */
4119 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4121 mono_thread_info_self_interrupt ();
4126 return mono_thread_execute_interruption ();
4130 /*This function should be called by a thread after it has exited all of
4131 * its handle blocks at interruption time.*/
4133 mono_thread_resume_interruption (void)
4135 MonoInternalThread *thread = mono_thread_internal_current ();
4136 gboolean still_aborting;
4138 /* The thread may already be stopping */
4142 LOCK_THREAD (thread);
4143 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4144 UNLOCK_THREAD (thread);
4146 /*This can happen if the protected block called Thread::ResetAbort*/
4147 if (!still_aborting)
4150 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4152 InterlockedIncrement (&thread_interruption_requested);
4154 mono_thread_info_self_interrupt ();
4156 return mono_thread_execute_interruption ();
4159 gboolean mono_thread_interruption_requested ()
4161 if (thread_interruption_requested) {
4162 MonoInternalThread *thread = mono_thread_internal_current ();
4163 /* The thread may already be stopping */
4165 return (thread->interruption_requested);
4170 static MonoException*
4171 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4173 MonoInternalThread *thread = mono_thread_internal_current ();
4175 /* The thread may already be stopping */
4179 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4180 MonoException* exc = mono_thread_execute_interruption ();
4188 * Performs the interruption of the current thread, if one has been requested,
4189 * and the thread is not running a protected wrapper.
4190 * Return the exception which needs to be thrown, if any.
4193 mono_thread_interruption_checkpoint (void)
4195 return mono_thread_interruption_checkpoint_request (FALSE);
4199 * Performs the interruption of the current thread, if one has been requested.
4200 * Return the exception which needs to be thrown, if any.
4203 mono_thread_force_interruption_checkpoint_noraise (void)
4205 return mono_thread_interruption_checkpoint_request (TRUE);
4209 * Performs the interruption of the current thread, if one has been requested.
4210 * Throw the exception which needs to be thrown, if any.
4213 mono_thread_force_interruption_checkpoint (void)
4217 ex = mono_thread_interruption_checkpoint_request (TRUE);
4219 mono_raise_exception (ex);
4223 * mono_thread_get_and_clear_pending_exception:
4225 * Return any pending exceptions for the current thread and clear it as a side effect.
4228 mono_thread_get_and_clear_pending_exception (void)
4230 MonoInternalThread *thread = mono_thread_internal_current ();
4232 /* The thread may already be stopping */
4236 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4237 return mono_thread_execute_interruption ();
4240 if (thread->pending_exception) {
4241 MonoException *exc = thread->pending_exception;
4243 thread->pending_exception = NULL;
4251 * mono_set_pending_exception:
4253 * Set the pending exception of the current thread to EXC.
4254 * The exception will be thrown when execution returns to managed code.
4257 mono_set_pending_exception (MonoException *exc)
4259 MonoInternalThread *thread = mono_thread_internal_current ();
4261 /* The thread may already be stopping */
4265 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4267 mono_thread_request_interruption (FALSE);
4271 * mono_thread_interruption_request_flag:
4273 * Returns the address of a flag that will be non-zero if an interruption has
4274 * been requested for a thread. The thread to interrupt may not be the current
4275 * thread, so an additional call to mono_thread_interruption_requested() or
4276 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4279 gint32* mono_thread_interruption_request_flag ()
4281 return &thread_interruption_requested;
4285 mono_thread_init_apartment_state (void)
4288 MonoInternalThread* thread = mono_thread_internal_current ();
4290 /* Positive return value indicates success, either
4291 * S_OK if this is first CoInitialize call, or
4292 * S_FALSE if CoInitialize already called, but with same
4293 * threading model. A negative value indicates failure,
4294 * probably due to trying to change the threading model.
4296 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4297 ? COINIT_APARTMENTTHREADED
4298 : COINIT_MULTITHREADED) < 0) {
4299 thread->apartment_state = ThreadApartmentState_Unknown;
4305 mono_thread_cleanup_apartment_state (void)
4308 MonoInternalThread* thread = mono_thread_internal_current ();
4310 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4317 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4319 LOCK_THREAD (thread);
4320 thread->state |= state;
4321 UNLOCK_THREAD (thread);
4325 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4327 LOCK_THREAD (thread);
4328 thread->state &= ~state;
4329 UNLOCK_THREAD (thread);
4333 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4335 gboolean ret = FALSE;
4337 LOCK_THREAD (thread);
4339 if ((thread->state & test) != 0) {
4343 UNLOCK_THREAD (thread);
4348 static gboolean has_tls_get = FALSE;
4351 mono_runtime_set_has_tls_get (gboolean val)
4357 mono_runtime_has_tls_get (void)
4363 self_interrupt_thread (void *_unused)
4365 MonoThreadInfo *info = mono_thread_info_current ();
4366 MonoException *exc = mono_thread_execute_interruption ();
4367 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4368 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. */
4369 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4373 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4377 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4381 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4383 MonoJitInfo **dest = data;
4389 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4391 MonoJitInfo *ji = NULL;
4394 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4399 MonoInternalThread *thread;
4400 gboolean install_async_abort;
4401 MonoThreadInfoInterruptToken *interrupt_token;
4404 static SuspendThreadResult
4405 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4407 AbortThreadData *data = ud;
4408 MonoInternalThread *thread = data->thread;
4409 MonoJitInfo *ji = NULL;
4410 gboolean protected_wrapper;
4411 gboolean running_managed;
4413 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4414 return MonoResumeThread;
4416 /*someone is already interrupting it*/
4417 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4418 return MonoResumeThread;
4420 InterlockedIncrement (&thread_interruption_requested);
4422 ji = mono_thread_info_get_last_managed (info);
4423 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4424 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4426 if (!protected_wrapper && running_managed) {
4427 /*We are in managed code*/
4428 /*Set the thread to call */
4429 if (data->install_async_abort)
4430 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4431 return MonoResumeThread;
4433 if (mono_thread_notify_pending_exc_fn)
4434 /* The JIT will notify the thread about the interruption */
4435 mono_thread_notify_pending_exc_fn (info);
4438 * This will cause waits to be broken.
4439 * It will also prevent the thread from entering a wait, so if the thread returns
4440 * from the wait before it receives the abort signal, it will just spin in the wait
4441 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4444 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4446 return MonoResumeThread;
4451 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4453 AbortThreadData data = { 0 };
4454 data.thread = thread;
4455 data.install_async_abort = install_async_abort;
4458 FIXME this is insanely broken, it doesn't cause interruption to happen
4459 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4461 if (thread == mono_thread_internal_current ()) {
4462 /* Do it synchronously */
4463 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4465 mono_raise_exception (exc);
4467 mono_thread_info_self_interrupt ();
4472 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_critical, &data);
4473 if (data.interrupt_token)
4474 mono_thread_info_finish_interrupt (data.interrupt_token);
4475 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4479 MonoInternalThread *thread;
4481 MonoThreadInfoInterruptToken *interrupt_token;
4482 } SuspendThreadData;
4484 static SuspendThreadResult
4485 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4487 SuspendThreadData *data = ud;
4488 MonoInternalThread *thread = data->thread;
4489 MonoJitInfo *ji = NULL;
4490 gboolean protected_wrapper;
4491 gboolean running_managed;
4493 ji = mono_thread_info_get_last_managed (info);
4494 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4495 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4497 if (running_managed && !protected_wrapper) {
4498 thread->state &= ~ThreadState_SuspendRequested;
4499 thread->state |= ThreadState_Suspended;
4500 return KeepSuspended;
4502 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4503 InterlockedIncrement (&thread_interruption_requested);
4504 if (data->interrupt)
4505 data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
4507 if (mono_thread_notify_pending_exc_fn && !running_managed)
4508 /* The JIT will notify the thread about the interruption */
4509 mono_thread_notify_pending_exc_fn (info);
4510 return MonoResumeThread;
4515 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4517 LOCK_THREAD (thread);
4518 if (thread == mono_thread_internal_current ()) {
4519 mono_thread_info_begin_self_suspend ();
4520 //XXX replace this with better named functions
4521 thread->state &= ~ThreadState_SuspendRequested;
4522 thread->state |= ThreadState_Suspended;
4523 UNLOCK_THREAD (thread);
4524 mono_thread_info_end_self_suspend ();
4526 SuspendThreadData data = { 0 };
4527 data.thread = thread;
4528 data.interrupt = interrupt;
4530 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, suspend_thread_critical, &data);
4531 if (data.interrupt_token)
4532 mono_thread_info_finish_interrupt (data.interrupt_token);
4533 UNLOCK_THREAD (thread);
4537 /*This is called with @thread synch_cs held and it must release it*/
4539 self_suspend_internal (MonoInternalThread *thread)
4541 mono_thread_info_begin_self_suspend ();
4542 thread->state &= ~ThreadState_SuspendRequested;
4543 thread->state |= ThreadState_Suspended;
4544 UNLOCK_THREAD (thread);
4545 mono_thread_info_end_self_suspend ();
4548 /*This is called with @thread synch_cs held and it must release it*/
4550 resume_thread_internal (MonoInternalThread *thread)
4552 UNLOCK_THREAD (thread);
4553 /* Awake the thread */
4554 if (!mono_thread_info_resume (thread_get_tid (thread)))
4556 LOCK_THREAD (thread);
4557 thread->state &= ~ThreadState_Suspended;
4558 UNLOCK_THREAD (thread);
4564 * mono_thread_is_foreign:
4565 * @thread: the thread to query
4567 * This function allows one to determine if a thread was created by the mono runtime and has
4568 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4570 * Returns: true if @thread was not created by the runtime.
4573 mono_thread_is_foreign (MonoThread *thread)
4575 MonoThreadInfo *info = thread->internal_thread->thread_info;
4576 return info->runtime_thread == FALSE;
4580 * mono_add_joinable_thread:
4582 * Add TID to the list of joinable threads.
4583 * LOCKING: Acquires the threads lock.
4586 mono_threads_add_joinable_thread (gpointer tid)
4590 * We cannot detach from threads because it causes problems like
4591 * 2fd16f60/r114307. So we collect them and join them when
4592 * we have time (in he finalizer thread).
4594 joinable_threads_lock ();
4595 if (!joinable_threads)
4596 joinable_threads = g_hash_table_new (NULL, NULL);
4597 g_hash_table_insert (joinable_threads, tid, tid);
4598 joinable_thread_count ++;
4599 joinable_threads_unlock ();
4601 mono_gc_finalize_notify ();
4606 * mono_threads_join_threads:
4608 * Join all joinable threads. This is called from the finalizer thread.
4609 * LOCKING: Acquires the threads lock.
4612 mono_threads_join_threads (void)
4615 GHashTableIter iter;
4622 if (!joinable_thread_count)
4626 joinable_threads_lock ();
4628 if (g_hash_table_size (joinable_threads)) {
4629 g_hash_table_iter_init (&iter, joinable_threads);
4630 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4631 thread = (pthread_t)tid;
4632 g_hash_table_remove (joinable_threads, key);
4633 joinable_thread_count --;
4636 joinable_threads_unlock ();
4638 if (thread != pthread_self ())
4639 /* This shouldn't block */
4640 pthread_join (thread, NULL);
4651 * Wait for thread TID to exit.
4652 * LOCKING: Acquires the threads lock.
4655 mono_thread_join (gpointer tid)
4659 gboolean found = FALSE;
4661 joinable_threads_lock ();
4662 if (!joinable_threads)
4663 joinable_threads = g_hash_table_new (NULL, NULL);
4664 if (g_hash_table_lookup (joinable_threads, tid)) {
4665 g_hash_table_remove (joinable_threads, tid);
4666 joinable_thread_count --;
4669 joinable_threads_unlock ();
4672 thread = (pthread_t)tid;
4673 pthread_join (thread, NULL);
4678 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4680 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4681 mono_thread_interruption_checkpoint ();
4684 static inline gboolean
4685 is_appdomainunloaded_exception (MonoClass *klass)
4687 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4689 if (!app_domain_unloaded_exception_klass)
4690 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4691 g_assert (app_domain_unloaded_exception_klass);
4693 return klass == app_domain_unloaded_exception_klass;
4696 static inline gboolean
4697 is_threadabort_exception (MonoClass *klass)
4699 return klass == mono_defaults.threadabortexception_class;
4703 mono_thread_internal_unhandled_exception (MonoObject* exc)
4705 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4706 MonoClass *klass = exc->vtable->klass;
4707 if (is_threadabort_exception (klass)) {
4708 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4709 } else if (!is_appdomainunloaded_exception (klass)) {
4710 mono_unhandled_exception (exc);
4711 if (mono_environment_exitcode_get () == 1)