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 (MonoInternalThread *thread);
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__, GetCurrentThreadId ()));
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 /* We have to do this here because mono_thread_new_init()
666 requires that root_domain_thread is set up. */
667 thread_adjust_static_data (internal);
668 init_root_domain_thread (internal, start_info->obj);
670 /* This MUST be called before any managed code can be
671 * executed, as it calls the callback function that (for the
672 * jit) sets the lmf marker.
674 mono_thread_new_init (tid, &tid, start_func);
675 internal->stack_ptr = &tid;
677 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
679 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
681 /* On 2.0 profile (and higher), set explicitly since state might have been
683 if (internal->apartment_state == ThreadApartmentState_Unknown)
684 internal->apartment_state = ThreadApartmentState_MTA;
686 mono_thread_init_apartment_state ();
688 if(internal->start_notify!=NULL) {
689 /* Let the thread that called Start() know we're
692 ReleaseSemaphore (internal->start_notify, 1, NULL);
696 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
700 * Call this after calling start_notify, since the profiler callback might want
701 * to lock the thread, and the lock is held by thread_start () which waits for
704 mono_profiler_thread_start (tid);
706 /* if the name was set before starting, we didn't invoke the profiler callback */
707 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
708 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
709 mono_profiler_thread_name (internal->tid, tname);
712 /* start_func is set only for unmanaged start functions */
714 start_func (start_arg);
717 g_assert (start_delegate != NULL);
718 args [0] = start_arg;
719 /* we may want to handle the exception here. See comment below on unhandled exceptions */
720 mono_runtime_delegate_invoke (start_delegate, args, NULL);
723 /* If the thread calls ExitThread at all, this remaining code
724 * will not be executed, but the main thread will eventually
725 * call thread_cleanup() on this thread's behalf.
728 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
730 /* Do any cleanup needed for apartment state. This
731 * cannot be done in thread_cleanup since thread_cleanup could be
732 * called for a thread other than the current thread.
733 * mono_thread_cleanup_apartment_state cleans up apartment
734 * for the current thead */
735 mono_thread_cleanup_apartment_state ();
737 thread_cleanup (internal);
741 /* Remove the reference to the thread object in the TLS data,
742 * so the thread object can be finalized. This won't be
743 * reached if the thread threw an uncaught exception, so those
744 * thread handles will stay referenced :-( (This is due to
745 * missing support for scanning thread-specific data in the
746 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
749 SET_CURRENT_OBJECT (NULL);
754 static guint32 WINAPI start_wrapper(void *data)
758 /* Avoid scanning the frames above this frame during a GC */
759 mono_gc_set_stack_end ((void*)&dummy);
761 return start_wrapper_internal (data);
767 * Common thread creation code.
768 * LOCKING: Acquires the threads lock.
771 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
772 gboolean throw_on_failure)
774 HANDLE thread_handle;
775 MonoNativeThreadId tid;
776 guint32 create_flags;
779 * Join joinable threads to prevent running out of threads since the finalizer
780 * thread might be blocked/backlogged.
782 mono_threads_join_threads ();
784 mono_threads_lock ();
787 mono_threads_unlock ();
790 if (threads_starting_up == NULL) {
791 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
792 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
794 mono_g_hash_table_insert (threads_starting_up, thread, thread);
795 mono_threads_unlock ();
797 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
798 if (!internal->start_notify) {
799 mono_threads_lock ();
800 mono_g_hash_table_remove (threads_starting_up, thread);
801 mono_threads_unlock ();
802 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
808 stack_size = default_stacksize_for_thread (internal);
810 /* Create suspended, so we can do some housekeeping before the thread
813 create_flags = CREATE_SUSPENDED;
815 MONO_PREPARE_BLOCKING;
816 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
817 stack_size, create_flags, &tid);
818 MONO_FINISH_BLOCKING;
820 if (thread_handle == NULL) {
821 /* The thread couldn't be created, so throw an exception */
822 mono_threads_lock ();
823 mono_g_hash_table_remove (threads_starting_up, thread);
824 mono_threads_unlock ();
826 if (throw_on_failure)
827 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
829 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
832 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
834 internal->handle = thread_handle;
835 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
837 internal->threadpool_thread = threadpool_thread;
838 if (threadpool_thread)
839 mono_thread_set_state (internal, ThreadState_Background);
841 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
843 /* Only store the handle when the thread is about to be
844 * launched, to avoid the main thread deadlocking while trying
845 * to clean up a thread that will never be signalled.
847 if (!handle_store (thread, FALSE))
850 MONO_PREPARE_BLOCKING;
851 mono_thread_info_resume (tid);
852 MONO_FINISH_BLOCKING;
854 if (internal->start_notify) {
856 * Wait for the thread to set up its TLS data etc, so
857 * theres no potential race condition if someone tries
858 * to look up the data believing the thread has
861 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
863 MONO_PREPARE_BLOCKING;
864 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
865 MONO_FINISH_BLOCKING;
867 CloseHandle (internal->start_notify);
868 internal->start_notify = NULL;
871 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
876 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
878 if (mono_thread_start_cb) {
879 mono_thread_start_cb (tid, stack_start, func);
883 void mono_threads_set_default_stacksize (guint32 stacksize)
885 default_stacksize = stacksize;
888 guint32 mono_threads_get_default_stacksize (void)
890 return default_stacksize;
894 * mono_thread_create_internal:
896 * ARG should not be a GC reference.
899 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
902 MonoInternalThread *internal;
903 StartInfo *start_info;
906 thread = create_thread_object (domain);
907 internal = create_internal_thread ();
908 MONO_OBJECT_SETREF (thread, internal_thread, internal);
910 start_info = g_new0 (StartInfo, 1);
911 start_info->func = func;
912 start_info->obj = thread;
913 start_info->start_arg = arg;
915 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
919 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
920 if (mono_check_corlib_version () == NULL)
921 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
927 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
929 mono_thread_create_internal (domain, func, arg, FALSE, 0);
933 mono_thread_attach (MonoDomain *domain)
935 return mono_thread_attach_full (domain, FALSE);
939 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
941 MonoThreadInfo *info;
942 MonoInternalThread *thread;
943 MonoThread *current_thread;
944 HANDLE thread_handle;
947 if ((thread = mono_thread_internal_current ())) {
948 if (domain != mono_domain_get ())
949 mono_domain_set (domain, TRUE);
950 /* Already attached */
951 return mono_thread_current ();
954 if (!mono_gc_register_thread (&domain)) {
955 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ());
958 thread = create_internal_thread ();
960 thread_handle = mono_thread_info_open_handle ();
961 g_assert (thread_handle);
963 tid=GetCurrentThreadId ();
965 thread->handle = thread_handle;
967 thread->stack_ptr = &tid;
969 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
971 info = mono_thread_info_current ();
973 thread->thread_info = info;
974 thread->small_id = info->small_id;
976 current_thread = new_thread_with_internal (domain, thread);
978 if (!handle_store (current_thread, force_attach)) {
979 /* Mono is shutting down, so just wait for the end */
984 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
986 SET_CURRENT_OBJECT (thread);
987 mono_domain_set (domain, TRUE);
989 thread_adjust_static_data (thread);
991 init_root_domain_thread (thread, current_thread);
992 if (domain != mono_get_root_domain ())
993 set_current_thread_for_domain (domain, thread, current_thread);
996 if (mono_thread_attach_cb) {
1000 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1003 mono_thread_attach_cb (tid, &tid);
1005 mono_thread_attach_cb (tid, staddr + stsize);
1008 // FIXME: Need a separate callback
1009 mono_profiler_thread_start (tid);
1011 return current_thread;
1015 mono_thread_detach_internal (MonoInternalThread *thread)
1017 g_return_if_fail (thread != NULL);
1019 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1021 thread_cleanup (thread);
1023 SET_CURRENT_OBJECT (NULL);
1024 mono_domain_unset ();
1026 /* Don't need to CloseHandle this thread, even though we took a
1027 * reference in mono_thread_attach (), because the GC will do it
1028 * when the Thread object is finalised.
1033 mono_thread_detach (MonoThread *thread)
1036 mono_thread_detach_internal (thread->internal_thread);
1040 * mono_thread_detach_if_exiting:
1042 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1043 * This should be used at the end of embedding code which calls into managed code, and which
1044 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1047 mono_thread_detach_if_exiting (void)
1049 if (mono_thread_info_is_exiting ()) {
1050 MonoInternalThread *thread;
1052 thread = mono_thread_internal_current ();
1054 mono_thread_detach_internal (thread);
1055 mono_thread_info_detach ();
1063 MonoInternalThread *thread = mono_thread_internal_current ();
1065 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1067 thread_cleanup (thread);
1068 SET_CURRENT_OBJECT (NULL);
1069 mono_domain_unset ();
1071 /* we could add a callback here for embedders to use. */
1072 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1073 exit (mono_environment_exitcode_get ());
1074 mono_thread_info_exit ();
1078 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1080 MonoInternalThread *internal = create_internal_thread ();
1082 internal->state = ThreadState_Unstarted;
1084 InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
1088 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1091 StartInfo *start_info;
1092 MonoInternalThread *internal;
1095 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1097 if (!this_obj->internal_thread)
1098 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1099 internal = this_obj->internal_thread;
1101 LOCK_THREAD (internal);
1103 if ((internal->state & ThreadState_Unstarted) == 0) {
1104 UNLOCK_THREAD (internal);
1105 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1109 if ((internal->state & ThreadState_Aborted) != 0) {
1110 UNLOCK_THREAD (internal);
1113 /* This is freed in start_wrapper */
1114 start_info = g_new0 (StartInfo, 1);
1115 start_info->func = NULL;
1116 start_info->start_arg = NULL;
1117 start_info->delegate = start;
1118 start_info->obj = this_obj;
1119 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1121 res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
1123 UNLOCK_THREAD (internal);
1127 internal->state &= ~ThreadState_Unstarted;
1129 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1131 UNLOCK_THREAD (internal);
1132 return internal->handle;
1136 * This is called from the finalizer of the internal thread object.
1139 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1141 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1144 * Since threads keep a reference to their thread object while running, by the time this function is called,
1145 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1146 * when thread_cleanup () can be called after this.
1149 CloseHandle (thread);
1151 if (this_obj->synch_cs) {
1152 mono_mutex_t *synch_cs = this_obj->synch_cs;
1153 this_obj->synch_cs = NULL;
1154 mono_mutex_destroy (synch_cs);
1158 if (this_obj->name) {
1159 void *name = this_obj->name;
1160 this_obj->name = NULL;
1166 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1169 MonoInternalThread *thread = mono_thread_internal_current ();
1171 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1173 mono_thread_current_check_pending_interrupt ();
1176 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1178 MONO_PREPARE_BLOCKING;
1179 res = SleepEx(ms,TRUE);
1180 MONO_FINISH_BLOCKING;
1182 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1184 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1185 MonoException* exc = mono_thread_execute_interruption (thread);
1187 mono_raise_exception (exc);
1199 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1204 ves_icall_System_Threading_Thread_GetDomainID (void)
1206 return mono_domain_get()->domain_id;
1210 ves_icall_System_Threading_Thread_Yield (void)
1212 return mono_thread_info_yield ();
1216 * mono_thread_get_name:
1218 * Return the name of the thread. NAME_LEN is set to the length of the name.
1219 * Return NULL if the thread has no name. The returned memory is owned by the
1223 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1227 LOCK_THREAD (this_obj);
1229 if (!this_obj->name) {
1233 *name_len = this_obj->name_len;
1234 res = g_new (gunichar2, this_obj->name_len);
1235 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1238 UNLOCK_THREAD (this_obj);
1244 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1248 LOCK_THREAD (this_obj);
1250 if (!this_obj->name)
1253 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1255 UNLOCK_THREAD (this_obj);
1261 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1263 LOCK_THREAD (this_obj);
1265 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1266 UNLOCK_THREAD (this_obj);
1268 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1271 if (this_obj->name) {
1272 g_free (this_obj->name);
1273 this_obj->name_len = 0;
1276 this_obj->name = g_new (gunichar2, mono_string_length (name));
1277 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1278 this_obj->name_len = mono_string_length (name);
1281 this_obj->name = NULL;
1284 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1286 UNLOCK_THREAD (this_obj);
1288 if (this_obj->name && this_obj->tid) {
1289 char *tname = mono_string_to_utf8 (name);
1290 mono_profiler_thread_name (this_obj->tid, tname);
1291 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1297 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1299 mono_thread_set_name_internal (this_obj, name, TRUE);
1303 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
1305 return ThreadPriority_Lowest;
1309 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1313 /* If the array is already in the requested domain, we just return it,
1314 otherwise we return a copy in that domain. */
1316 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1323 if (mono_object_domain (arr) == domain)
1326 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1327 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1332 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1334 return byte_array_to_domain (arr, mono_get_root_domain ());
1338 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1340 return byte_array_to_domain (arr, mono_domain_get ());
1344 mono_thread_current (void)
1346 MonoDomain *domain = mono_domain_get ();
1347 MonoInternalThread *internal = mono_thread_internal_current ();
1348 MonoThread **current_thread_ptr;
1350 g_assert (internal);
1351 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1353 if (!*current_thread_ptr) {
1354 g_assert (domain != mono_get_root_domain ());
1355 *current_thread_ptr = new_thread_with_internal (domain, internal);
1357 return *current_thread_ptr;
1361 mono_thread_internal_current (void)
1363 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1364 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1369 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1371 MonoInternalThread *thread = this_obj->internal_thread;
1372 HANDLE handle = thread->handle;
1373 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1376 mono_thread_current_check_pending_interrupt ();
1378 LOCK_THREAD (thread);
1380 if ((thread->state & ThreadState_Unstarted) != 0) {
1381 UNLOCK_THREAD (thread);
1383 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1387 UNLOCK_THREAD (thread);
1392 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1394 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1396 MONO_PREPARE_BLOCKING;
1397 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1398 MONO_FINISH_BLOCKING;
1400 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1402 if(ret==WAIT_OBJECT_0) {
1403 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1408 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1414 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1422 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1424 MONO_PREPARE_BLOCKING;
1426 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1428 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1429 MONO_FINISH_BLOCKING;
1431 if (ret != WAIT_IO_COMPLETION)
1434 exc = mono_thread_execute_interruption (thread);
1436 mono_raise_exception (exc);
1441 /* Re-calculate ms according to the time passed */
1442 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1443 if (diff_ms >= ms) {
1447 wait = ms - diff_ms;
1453 /* FIXME: exitContext isnt documented */
1454 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1460 MonoObject *waitHandle;
1461 MonoInternalThread *thread = mono_thread_internal_current ();
1463 /* Do this WaitSleepJoin check before creating objects */
1464 mono_thread_current_check_pending_interrupt ();
1466 /* We fail in managed if the array has more than 64 elements */
1467 numhandles = (guint32)mono_array_length(mono_handles);
1468 handles = g_new0(HANDLE, numhandles);
1470 for(i = 0; i < numhandles; i++) {
1471 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1472 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1479 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1481 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1483 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1487 if(ret==WAIT_FAILED) {
1488 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1490 } else if(ret==WAIT_TIMEOUT) {
1491 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1498 /* FIXME: exitContext isnt documented */
1499 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1501 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1502 uintptr_t numhandles;
1505 MonoObject *waitHandle;
1506 MonoInternalThread *thread = mono_thread_internal_current ();
1508 /* Do this WaitSleepJoin check before creating objects */
1509 mono_thread_current_check_pending_interrupt ();
1511 numhandles = mono_array_length(mono_handles);
1512 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1515 for(i = 0; i < numhandles; i++) {
1516 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1517 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1524 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1526 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1528 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1530 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1533 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1535 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1536 return ret - WAIT_OBJECT_0;
1538 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1539 return ret - WAIT_ABANDONED_0;
1546 /* FIXME: exitContext isnt documented */
1547 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
1550 MonoInternalThread *thread = mono_thread_internal_current ();
1552 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1558 mono_thread_current_check_pending_interrupt ();
1560 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1562 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1564 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1566 if(ret==WAIT_FAILED) {
1567 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1569 } else if(ret==WAIT_TIMEOUT) {
1570 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1578 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1581 MonoInternalThread *thread = mono_thread_internal_current ();
1586 mono_thread_current_check_pending_interrupt ();
1588 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1590 MONO_PREPARE_BLOCKING;
1591 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1592 MONO_FINISH_BLOCKING;
1594 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1596 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1599 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1606 mutex = CreateMutex (NULL, owned, NULL);
1608 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1610 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1618 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1619 return(ReleaseMutex (handle));
1622 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1628 *error = ERROR_SUCCESS;
1630 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1632 *error = GetLastError ();
1639 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1646 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1648 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1649 mono_string_chars (name));
1651 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1659 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1663 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1668 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1672 *error = ERROR_SUCCESS;
1674 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1676 *error = GetLastError ();
1682 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1689 event = CreateEvent (NULL, manual, initial, NULL);
1691 event = CreateEvent (NULL, manual, initial,
1692 mono_string_chars (name));
1694 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1702 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1703 return (SetEvent(handle));
1706 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1707 return (ResetEvent(handle));
1711 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1712 CloseHandle (handle);
1715 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1721 *error = ERROR_SUCCESS;
1723 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1725 *error = GetLastError ();
1731 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1733 return InterlockedIncrement (location);
1736 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1738 #if SIZEOF_VOID_P == 4
1739 if (G_UNLIKELY ((size_t)location & 0x7)) {
1741 mono_interlocked_lock ();
1744 mono_interlocked_unlock ();
1748 return InterlockedIncrement64 (location);
1751 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1753 return InterlockedDecrement(location);
1756 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1758 #if SIZEOF_VOID_P == 4
1759 if (G_UNLIKELY ((size_t)location & 0x7)) {
1761 mono_interlocked_lock ();
1764 mono_interlocked_unlock ();
1768 return InterlockedDecrement64 (location);
1771 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1773 return InterlockedExchange(location, value);
1776 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1779 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1780 mono_gc_wbarrier_generic_nostore (location);
1784 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1786 return InterlockedExchangePointer(location, value);
1789 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1791 IntFloatUnion val, ret;
1794 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1800 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1802 #if SIZEOF_VOID_P == 4
1803 if (G_UNLIKELY ((size_t)location & 0x7)) {
1805 mono_interlocked_lock ();
1808 mono_interlocked_unlock ();
1812 return InterlockedExchange64 (location, value);
1816 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1818 LongDoubleUnion val, ret;
1821 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1826 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1828 return InterlockedCompareExchange(location, value, comparand);
1831 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1833 gint32 r = InterlockedCompareExchange(location, value, comparand);
1834 *success = r == comparand;
1838 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1841 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1842 mono_gc_wbarrier_generic_nostore (location);
1846 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1848 return InterlockedCompareExchangePointer(location, value, comparand);
1851 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1853 IntFloatUnion val, ret, cmp;
1856 cmp.fval = comparand;
1857 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1863 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1865 #if SIZEOF_VOID_P == 8
1866 LongDoubleUnion val, comp, ret;
1869 comp.fval = comparand;
1870 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1876 mono_interlocked_lock ();
1878 if (old == comparand)
1880 mono_interlocked_unlock ();
1887 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1889 #if SIZEOF_VOID_P == 4
1890 if (G_UNLIKELY ((size_t)location & 0x7)) {
1892 mono_interlocked_lock ();
1894 if (old == comparand)
1896 mono_interlocked_unlock ();
1900 return InterlockedCompareExchange64 (location, value, comparand);
1904 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1907 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1908 mono_gc_wbarrier_generic_nostore (location);
1913 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1916 res = InterlockedExchangePointer ((gpointer *)location, value);
1917 mono_gc_wbarrier_generic_nostore (location);
1922 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1924 return InterlockedAdd (location, value);
1928 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1930 #if SIZEOF_VOID_P == 4
1931 if (G_UNLIKELY ((size_t)location & 0x7)) {
1933 mono_interlocked_lock ();
1936 mono_interlocked_unlock ();
1940 return InterlockedAdd64 (location, value);
1944 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1946 #if SIZEOF_VOID_P == 4
1947 if (G_UNLIKELY ((size_t)location & 0x7)) {
1949 mono_interlocked_lock ();
1951 mono_interlocked_unlock ();
1955 return InterlockedRead64 (location);
1959 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1961 mono_memory_barrier ();
1965 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1967 mono_thread_clr_state (this, state);
1969 if (state & ThreadState_Background) {
1970 /* If the thread changes the background mode, the main thread has to
1971 * be notified, since it has to rebuild the list of threads to
1974 SetEvent (background_change_event);
1979 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1981 mono_thread_set_state (this, state);
1983 if (state & ThreadState_Background) {
1984 /* If the thread changes the background mode, the main thread has to
1985 * be notified, since it has to rebuild the list of threads to
1988 SetEvent (background_change_event);
1993 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1999 state = this->state;
2001 UNLOCK_THREAD (this);
2006 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2008 MonoInternalThread *current;
2010 MonoInternalThread *thread = this_obj->internal_thread;
2012 LOCK_THREAD (thread);
2014 current = mono_thread_internal_current ();
2016 thread->thread_interrupt_requested = TRUE;
2017 throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2019 UNLOCK_THREAD (thread);
2022 abort_thread_internal (thread, TRUE, FALSE);
2026 void mono_thread_current_check_pending_interrupt ()
2028 MonoInternalThread *thread = mono_thread_internal_current ();
2029 gboolean throw = FALSE;
2031 LOCK_THREAD (thread);
2033 if (thread->thread_interrupt_requested) {
2035 thread->thread_interrupt_requested = FALSE;
2038 UNLOCK_THREAD (thread);
2041 mono_raise_exception (mono_get_exception_thread_interrupted ());
2046 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2048 LOCK_THREAD (thread);
2050 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2051 (thread->state & ThreadState_StopRequested) != 0 ||
2052 (thread->state & ThreadState_Stopped) != 0)
2054 UNLOCK_THREAD (thread);
2058 if ((thread->state & ThreadState_Unstarted) != 0) {
2059 thread->state |= ThreadState_Aborted;
2060 UNLOCK_THREAD (thread);
2064 thread->state |= ThreadState_AbortRequested;
2065 if (thread->abort_state_handle)
2066 mono_gchandle_free (thread->abort_state_handle);
2068 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2069 g_assert (thread->abort_state_handle);
2071 thread->abort_state_handle = 0;
2073 thread->abort_exc = NULL;
2075 UNLOCK_THREAD (thread);
2077 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2079 /* During shutdown, we can't wait for other threads */
2081 /* Make sure the thread is awake */
2082 mono_thread_resume (thread);
2084 abort_thread_internal (thread, TRUE, TRUE);
2088 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2090 MonoInternalThread *thread = mono_thread_internal_current ();
2091 gboolean was_aborting;
2093 LOCK_THREAD (thread);
2094 was_aborting = thread->state & ThreadState_AbortRequested;
2095 thread->state &= ~ThreadState_AbortRequested;
2096 UNLOCK_THREAD (thread);
2098 if (!was_aborting) {
2099 const char *msg = "Unable to reset abort because no abort was requested";
2100 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2103 thread->abort_exc = NULL;
2104 if (thread->abort_state_handle) {
2105 mono_gchandle_free (thread->abort_state_handle);
2106 /* This is actually not necessary - the handle
2107 only counts if the exception is set */
2108 thread->abort_state_handle = 0;
2113 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2115 LOCK_THREAD (thread);
2117 thread->state &= ~ThreadState_AbortRequested;
2119 if (thread->abort_exc) {
2120 thread->abort_exc = NULL;
2121 if (thread->abort_state_handle) {
2122 mono_gchandle_free (thread->abort_state_handle);
2123 /* This is actually not necessary - the handle
2124 only counts if the exception is set */
2125 thread->abort_state_handle = 0;
2129 UNLOCK_THREAD (thread);
2133 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2135 MonoInternalThread *thread = this_obj->internal_thread;
2136 MonoObject *state, *deserialized = NULL, *exc;
2139 if (!thread->abort_state_handle)
2142 state = mono_gchandle_get_target (thread->abort_state_handle);
2145 domain = mono_domain_get ();
2146 if (mono_object_domain (state) == domain)
2149 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2151 if (!deserialized) {
2152 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2154 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2155 mono_set_pending_exception (invalid_op_exc);
2159 return deserialized;
2163 mono_thread_suspend (MonoInternalThread *thread)
2165 LOCK_THREAD (thread);
2167 if ((thread->state & ThreadState_Unstarted) != 0 ||
2168 (thread->state & ThreadState_Aborted) != 0 ||
2169 (thread->state & ThreadState_Stopped) != 0)
2171 UNLOCK_THREAD (thread);
2175 if ((thread->state & ThreadState_Suspended) != 0 ||
2176 (thread->state & ThreadState_SuspendRequested) != 0 ||
2177 (thread->state & ThreadState_StopRequested) != 0)
2179 UNLOCK_THREAD (thread);
2183 thread->state |= ThreadState_SuspendRequested;
2185 UNLOCK_THREAD (thread);
2187 suspend_thread_internal (thread, FALSE);
2192 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2194 if (!mono_thread_suspend (this_obj->internal_thread)) {
2195 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2201 mono_thread_resume (MonoInternalThread *thread)
2203 LOCK_THREAD (thread);
2205 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2206 thread->state &= ~ThreadState_SuspendRequested;
2207 UNLOCK_THREAD (thread);
2211 if ((thread->state & ThreadState_Suspended) == 0 ||
2212 (thread->state & ThreadState_Unstarted) != 0 ||
2213 (thread->state & ThreadState_Aborted) != 0 ||
2214 (thread->state & ThreadState_Stopped) != 0)
2216 UNLOCK_THREAD (thread);
2220 return resume_thread_internal (thread);
2224 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2226 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2227 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2233 mono_threads_is_critical_method (MonoMethod *method)
2235 switch (method->wrapper_type) {
2236 case MONO_WRAPPER_RUNTIME_INVOKE:
2237 case MONO_WRAPPER_XDOMAIN_INVOKE:
2238 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2245 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2250 if (mono_threads_is_critical_method (m)) {
2251 *((gboolean*)data) = TRUE;
2258 is_running_protected_wrapper (void)
2260 gboolean found = FALSE;
2261 mono_stack_walk (find_wrapper, &found);
2265 void mono_thread_internal_stop (MonoInternalThread *thread)
2267 LOCK_THREAD (thread);
2269 if ((thread->state & ThreadState_StopRequested) != 0 ||
2270 (thread->state & ThreadState_Stopped) != 0)
2272 UNLOCK_THREAD (thread);
2276 /* Make sure the thread is awake */
2277 mono_thread_resume (thread);
2279 thread->state |= ThreadState_StopRequested;
2280 thread->state &= ~ThreadState_AbortRequested;
2282 UNLOCK_THREAD (thread);
2284 abort_thread_internal (thread, TRUE, TRUE);
2287 void mono_thread_stop (MonoThread *thread)
2289 mono_thread_internal_stop (thread->internal_thread);
2293 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2296 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2301 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2304 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2309 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2312 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2317 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2320 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2325 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2328 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2329 return (void *) tmp;
2333 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2335 volatile MonoObject *tmp;
2336 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2337 return (MonoObject *) tmp;
2341 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2344 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2349 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2352 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2357 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2359 return InterlockedRead8 (ptr);
2363 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2365 return InterlockedRead16 (ptr);
2369 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2371 return InterlockedRead (ptr);
2375 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2377 #if SIZEOF_VOID_P == 4
2378 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2380 mono_interlocked_lock ();
2381 val = *(gint64*)ptr;
2382 mono_interlocked_unlock ();
2386 return InterlockedRead64 (ptr);
2390 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2392 return InterlockedReadPointer (ptr);
2396 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2400 #if SIZEOF_VOID_P == 4
2401 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2403 mono_interlocked_lock ();
2404 val = *(double*)ptr;
2405 mono_interlocked_unlock ();
2410 u.ival = InterlockedRead64 (ptr);
2416 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2420 u.ival = InterlockedRead (ptr);
2426 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2428 return InterlockedReadPointer (ptr);
2432 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2434 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2438 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2440 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2444 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2446 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2450 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2452 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2456 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2458 mono_atomic_store_release ((volatile void **) ptr, value);
2462 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2464 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2468 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2470 mono_atomic_store_release ((volatile double *) ptr, value);
2474 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2476 mono_atomic_store_release ((volatile float *) ptr, value);
2480 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2482 InterlockedWrite8 (ptr, value);
2486 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2488 InterlockedWrite16 (ptr, value);
2492 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2494 InterlockedWrite (ptr, value);
2498 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2500 #if SIZEOF_VOID_P == 4
2501 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2502 mono_interlocked_lock ();
2503 *(gint64*)ptr = value;
2504 mono_interlocked_unlock ();
2509 InterlockedWrite64 (ptr, value);
2513 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2515 InterlockedWritePointer (ptr, value);
2519 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2523 #if SIZEOF_VOID_P == 4
2524 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2525 mono_interlocked_lock ();
2526 *(double*)ptr = value;
2527 mono_interlocked_unlock ();
2534 InterlockedWrite64 (ptr, u.ival);
2538 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2544 InterlockedWrite (ptr, u.ival);
2548 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2550 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2554 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2556 mono_threads_lock ();
2558 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2561 contexts = g_hash_table_new (NULL, NULL);
2563 context_adjust_static_data (ctx);
2564 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2565 g_hash_table_insert (contexts, gch, gch);
2567 mono_threads_unlock ();
2569 mono_profiler_context_loaded (ctx);
2573 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2576 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2577 * cleanup in exceptional circumstances, we don't actually do any
2578 * cleanup work here. We instead do this when we iterate the `contexts`
2579 * hash table. The only purpose of this finalizer, at the moment, is to
2580 * notify the profiler.
2583 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2585 mono_profiler_context_unloaded (ctx);
2589 mono_thread_init_tls (void)
2591 MONO_FAST_TLS_INIT (tls_current_object);
2592 mono_native_tls_alloc (¤t_object_key, NULL);
2595 void mono_thread_init (MonoThreadStartCB start_cb,
2596 MonoThreadAttachCB attach_cb)
2598 mono_mutex_init_recursive(&threads_mutex);
2599 mono_mutex_init_recursive(&interlocked_mutex);
2600 mono_mutex_init_recursive(&joinable_threads_mutex);
2602 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2603 g_assert(background_change_event != NULL);
2605 mono_init_static_data_info (&thread_static_info);
2606 mono_init_static_data_info (&context_static_info);
2608 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2610 mono_thread_start_cb = start_cb;
2611 mono_thread_attach_cb = attach_cb;
2613 /* Get a pseudo handle to the current process. This is just a
2614 * kludge so that wapi can build a process handle if needed.
2615 * As a pseudo handle is returned, we don't need to clean
2618 GetCurrentProcess ();
2621 void mono_thread_cleanup (void)
2623 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2624 MonoThreadInfo *info;
2626 /* The main thread must abandon any held mutexes (particularly
2627 * important for named mutexes as they are shared across
2628 * processes, see bug 74680.) This will happen when the
2629 * thread exits, but if it's not running in a subthread it
2630 * won't exit in time.
2632 info = mono_thread_info_current ();
2633 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2637 /* This stuff needs more testing, it seems one of these
2638 * critical sections can be locked when mono_thread_cleanup is
2641 mono_mutex_destroy (&threads_mutex);
2642 mono_mutex_destroy (&interlocked_mutex);
2643 mono_mutex_destroy (&delayed_free_table_mutex);
2644 mono_mutex_destroy (&small_id_mutex);
2645 CloseHandle (background_change_event);
2648 mono_native_tls_free (current_object_key);
2652 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2654 mono_thread_cleanup_fn = func;
2658 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2660 thread->internal_thread->manage_callback = func;
2663 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2665 mono_thread_notify_pending_exc_fn = func;
2669 static void print_tids (gpointer key, gpointer value, gpointer user)
2671 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2672 * sizeof(uint) and a cast to uint would overflow
2674 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2675 * print this as a pointer.
2677 g_message ("Waiting for: %p", key);
2682 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2683 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2687 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2691 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2693 MONO_PREPARE_BLOCKING;
2694 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2695 MONO_FINISH_BLOCKING;
2697 if(ret==WAIT_FAILED) {
2698 /* See the comment in build_wait_tids() */
2699 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2703 for(i=0; i<wait->num; i++)
2704 CloseHandle (wait->handles[i]);
2706 if (ret == WAIT_TIMEOUT)
2709 for(i=0; i<wait->num; i++) {
2710 gsize tid = wait->threads[i]->tid;
2713 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2714 * it can still run io-layer etc. code. So wait for it to really exit.
2715 * FIXME: This won't join threads which are not in the joinable_hash yet.
2717 mono_thread_join ((gpointer)tid);
2719 mono_threads_lock ();
2720 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2721 /* This thread must have been killed, because
2722 * it hasn't cleaned itself up. (It's just
2723 * possible that the thread exited before the
2724 * parent thread had a chance to store the
2725 * handle, and now there is another pointer to
2726 * the already-exited thread stored. In this
2727 * case, we'll just get two
2728 * mono_profiler_thread_end() calls for the
2732 mono_threads_unlock ();
2733 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2734 thread_cleanup (wait->threads[i]);
2736 mono_threads_unlock ();
2741 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2743 guint32 i, ret, count;
2745 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2747 /* Add the thread state change event, so it wakes up if a thread changes
2748 * to background mode.
2751 if (count < MAXIMUM_WAIT_OBJECTS) {
2752 wait->handles [count] = background_change_event;
2756 MONO_PREPARE_BLOCKING;
2757 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2758 MONO_FINISH_BLOCKING;
2760 if(ret==WAIT_FAILED) {
2761 /* See the comment in build_wait_tids() */
2762 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2766 for(i=0; i<wait->num; i++)
2767 CloseHandle (wait->handles[i]);
2769 if (ret == WAIT_TIMEOUT)
2772 if (ret < wait->num) {
2773 gsize tid = wait->threads[ret]->tid;
2774 mono_threads_lock ();
2775 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2776 /* See comment in wait_for_tids about thread cleanup */
2777 mono_threads_unlock ();
2778 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2779 thread_cleanup (wait->threads [ret]);
2781 mono_threads_unlock ();
2785 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2787 struct wait_data *wait=(struct wait_data *)user;
2789 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2791 MonoInternalThread *thread=(MonoInternalThread *)value;
2793 /* Ignore background threads, we abort them later */
2794 /* Do not lock here since it is not needed and the caller holds threads_lock */
2795 if (thread->state & ThreadState_Background) {
2796 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2797 return; /* just leave, ignore */
2800 if (mono_gc_is_finalizer_internal_thread (thread)) {
2801 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2805 if (thread == mono_thread_internal_current ()) {
2806 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2810 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2811 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2815 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2816 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2820 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2821 if (handle == NULL) {
2822 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2826 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2827 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2828 wait->handles[wait->num]=handle;
2829 wait->threads[wait->num]=thread;
2832 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2834 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2839 /* Just ignore the rest, we can't do anything with
2846 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2848 struct wait_data *wait=(struct wait_data *)user;
2849 gsize self = GetCurrentThreadId ();
2850 MonoInternalThread *thread = value;
2853 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2856 /* The finalizer thread is not a background thread */
2857 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2858 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2860 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2864 /* printf ("A: %d\n", wait->num); */
2865 wait->handles[wait->num]=thread->handle;
2866 wait->threads[wait->num]=thread;
2869 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2870 mono_thread_internal_stop (thread);
2874 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2878 * mono_threads_set_shutting_down:
2880 * Is called by a thread that wants to shut down Mono. If the runtime is already
2881 * shutting down, the calling thread is suspended/stopped, and this function never
2885 mono_threads_set_shutting_down (void)
2887 MonoInternalThread *current_thread = mono_thread_internal_current ();
2889 mono_threads_lock ();
2891 if (shutting_down) {
2892 mono_threads_unlock ();
2894 /* Make sure we're properly suspended/stopped */
2896 LOCK_THREAD (current_thread);
2898 if ((current_thread->state & ThreadState_SuspendRequested) ||
2899 (current_thread->state & ThreadState_AbortRequested) ||
2900 (current_thread->state & ThreadState_StopRequested)) {
2901 UNLOCK_THREAD (current_thread);
2902 mono_thread_execute_interruption (current_thread);
2904 current_thread->state |= ThreadState_Stopped;
2905 UNLOCK_THREAD (current_thread);
2908 /*since we're killing the thread, unset the current domain.*/
2909 mono_domain_unset ();
2911 /* Wake up other threads potentially waiting for us */
2912 mono_thread_info_exit ();
2914 shutting_down = TRUE;
2916 /* Not really a background state change, but this will
2917 * interrupt the main thread if it is waiting for all
2918 * the other threads.
2920 SetEvent (background_change_event);
2922 mono_threads_unlock ();
2926 void mono_thread_manage (void)
2928 struct wait_data wait_data;
2929 struct wait_data *wait = &wait_data;
2931 memset (wait, 0, sizeof (struct wait_data));
2932 /* join each thread that's still running */
2933 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2935 mono_threads_lock ();
2937 THREAD_DEBUG (g_message("%s: No threads", __func__));
2938 mono_threads_unlock ();
2941 mono_threads_unlock ();
2944 mono_threads_lock ();
2945 if (shutting_down) {
2946 /* somebody else is shutting down */
2947 mono_threads_unlock ();
2950 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2951 mono_g_hash_table_foreach (threads, print_tids, NULL));
2953 ResetEvent (background_change_event);
2955 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2956 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2957 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2958 mono_threads_unlock ();
2960 /* Something to wait for */
2961 wait_for_tids_or_state_change (wait, INFINITE);
2963 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2964 } while(wait->num>0);
2966 /* Mono is shutting down, so just wait for the end */
2967 if (!mono_runtime_try_shutdown ()) {
2968 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2969 mono_thread_suspend (mono_thread_internal_current ());
2970 mono_thread_execute_interruption (mono_thread_internal_current ());
2974 * Remove everything but the finalizer thread and self.
2975 * Also abort all the background threads
2978 mono_threads_lock ();
2981 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2982 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2983 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2985 mono_threads_unlock ();
2987 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2989 /* Something to wait for */
2990 wait_for_tids (wait, INFINITE);
2992 } while (wait->num > 0);
2995 * give the subthreads a chance to really quit (this is mainly needed
2996 * to get correct user and system times from getrusage/wait/time(1)).
2997 * This could be removed if we avoid pthread_detach() and use pthread_join().
2999 mono_thread_info_yield ();
3002 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3004 MonoInternalThread *thread=(MonoInternalThread *)value;
3006 if(thread->tid != (gsize)user) {
3007 /*TerminateThread (thread->handle, -1);*/
3011 void mono_thread_abort_all_other_threads (void)
3013 gsize self = GetCurrentThreadId ();
3015 mono_threads_lock ();
3016 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3017 mono_g_hash_table_size (threads));
3018 mono_g_hash_table_foreach (threads, print_tids, NULL));
3020 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3022 mono_threads_unlock ();
3026 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3028 MonoInternalThread *thread = (MonoInternalThread*)value;
3029 struct wait_data *wait = (struct wait_data*)user_data;
3033 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3035 * This needs no locking.
3037 if ((thread->state & ThreadState_Suspended) != 0 ||
3038 (thread->state & ThreadState_Stopped) != 0)
3041 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3042 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3046 wait->handles [wait->num] = handle;
3047 wait->threads [wait->num] = thread;
3053 * mono_thread_suspend_all_other_threads:
3055 * Suspend all managed threads except the finalizer thread and this thread. It is
3056 * not possible to resume them later.
3058 void mono_thread_suspend_all_other_threads (void)
3060 struct wait_data wait_data;
3061 struct wait_data *wait = &wait_data;
3063 gsize self = GetCurrentThreadId ();
3064 guint32 eventidx = 0;
3065 gboolean starting, finished;
3067 memset (wait, 0, sizeof (struct wait_data));
3069 * The other threads could be in an arbitrary state at this point, i.e.
3070 * they could be starting up, shutting down etc. This means that there could be
3071 * threads which are not even in the threads hash table yet.
3075 * First we set a barrier which will be checked by all threads before they
3076 * are added to the threads hash table, and they will exit if the flag is set.
3077 * This ensures that no threads could be added to the hash later.
3078 * We will use shutting_down as the barrier for now.
3080 g_assert (shutting_down);
3083 * We make multiple calls to WaitForMultipleObjects since:
3084 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3085 * - some threads could exit without becoming suspended
3090 * Make a copy of the hashtable since we can't do anything with
3091 * threads while threads_mutex is held.
3094 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3095 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3096 mono_threads_lock ();
3097 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3098 mono_threads_unlock ();
3101 /* Get the suspended events that we'll be waiting for */
3102 for (i = 0; i < wait->num; ++i) {
3103 MonoInternalThread *thread = wait->threads [i];
3105 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3106 //CloseHandle (wait->handles [i]);
3107 wait->threads [i] = NULL; /* ignore this thread in next loop */
3111 LOCK_THREAD (thread);
3113 if ((thread->state & ThreadState_Suspended) != 0 ||
3114 (thread->state & ThreadState_StopRequested) != 0 ||
3115 (thread->state & ThreadState_Stopped) != 0) {
3116 UNLOCK_THREAD (thread);
3117 CloseHandle (wait->handles [i]);
3118 wait->threads [i] = NULL; /* ignore this thread in next loop */
3124 /* Convert abort requests into suspend requests */
3125 if ((thread->state & ThreadState_AbortRequested) != 0)
3126 thread->state &= ~ThreadState_AbortRequested;
3128 thread->state |= ThreadState_SuspendRequested;
3130 UNLOCK_THREAD (thread);
3132 /* Signal the thread to suspend */
3133 suspend_thread_internal (thread, TRUE);
3135 if (eventidx <= 0) {
3137 * If there are threads which are starting up, we wait until they
3138 * are suspended when they try to register in the threads hash.
3139 * This is guaranteed to finish, since the threads which can create new
3140 * threads get suspended after a while.
3141 * FIXME: The finalizer thread can still create new threads.
3143 mono_threads_lock ();
3144 if (threads_starting_up)
3145 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3148 mono_threads_unlock ();
3157 static gboolean thread_dump_requested;
3159 static G_GNUC_UNUSED gboolean
3160 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3162 GString *p = (GString*)data;
3163 MonoMethod *method = NULL;
3164 if (frame->type == FRAME_TYPE_MANAGED)
3165 method = mono_jit_info_get_method (frame->ji);
3168 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3169 g_string_append_printf (p, " %s\n", location);
3172 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3177 static SuspendThreadResult
3178 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3180 MonoInternalThread *thread = ud;
3181 GString* text = g_string_new (0);
3183 GError *error = NULL;
3186 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3188 g_string_append_printf (text, "\n\"%s\"", name);
3191 else if (thread->threadpool_thread)
3192 g_string_append (text, "\n\"<threadpool thread>\"");
3194 g_string_append (text, "\n\"<unnamed thread>\"");
3197 /* This no longer works with remote unwinding */
3199 wapi_desc = wapi_current_thread_desc ();
3200 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3205 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, text);
3207 fprintf (stdout, "%s", text->str);
3209 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3210 OutputDebugStringA(text->str);
3213 g_string_free (text, TRUE);
3215 return MonoResumeThread;
3219 dump_thread (gpointer key, gpointer value, gpointer user)
3221 MonoInternalThread *thread = (MonoInternalThread *)value;
3223 if (thread == mono_thread_internal_current ())
3227 FIXME This still can hang if we stop a thread during malloc.
3228 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3229 that takes a callback and runs it with the target suspended.
3230 We probably should loop a bit around trying to get it to either managed code
3233 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, print_thread_dump, thread);
3237 mono_threads_perform_thread_dump (void)
3239 if (!thread_dump_requested)
3242 printf ("Full thread dump:\n");
3244 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3245 something needs then in the process.
3247 mono_loader_lock ();
3248 mono_domain_lock (mono_get_root_domain ());
3250 mono_threads_lock ();
3251 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3252 mono_threads_unlock ();
3254 mono_domain_unlock (mono_get_root_domain ());
3255 mono_loader_unlock ();
3257 thread_dump_requested = FALSE;
3261 * mono_threads_request_thread_dump:
3263 * Ask all threads except the current to print their stacktrace to stdout.
3266 mono_threads_request_thread_dump (void)
3268 /*The new thread dump code runs out of the finalizer thread. */
3269 thread_dump_requested = TRUE;
3270 mono_gc_finalize_notify ();
3275 gint allocated; /* +1 so that refs [allocated] == NULL */
3279 typedef struct ref_stack RefStack;
3282 ref_stack_new (gint initial_size)
3286 initial_size = MAX (initial_size, 16) + 1;
3287 rs = g_new0 (RefStack, 1);
3288 rs->refs = g_new0 (gpointer, initial_size);
3289 rs->allocated = initial_size;
3294 ref_stack_destroy (gpointer ptr)
3305 ref_stack_push (RefStack *rs, gpointer ptr)
3307 g_assert (rs != NULL);
3309 if (rs->bottom >= rs->allocated) {
3310 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3311 rs->allocated <<= 1;
3312 rs->refs [rs->allocated] = NULL;
3314 rs->refs [rs->bottom++] = ptr;
3318 ref_stack_pop (RefStack *rs)
3320 if (rs == NULL || rs->bottom == 0)
3324 rs->refs [rs->bottom] = NULL;
3328 ref_stack_find (RefStack *rs, gpointer ptr)
3335 for (refs = rs->refs; refs && *refs; refs++) {
3343 * mono_thread_push_appdomain_ref:
3345 * Register that the current thread may have references to objects in domain
3346 * @domain on its stack. Each call to this function should be paired with a
3347 * call to pop_appdomain_ref.
3350 mono_thread_push_appdomain_ref (MonoDomain *domain)
3352 MonoInternalThread *thread = mono_thread_internal_current ();
3355 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3356 SPIN_LOCK (thread->lock_thread_id);
3357 if (thread->appdomain_refs == NULL)
3358 thread->appdomain_refs = ref_stack_new (16);
3359 ref_stack_push (thread->appdomain_refs, domain);
3360 SPIN_UNLOCK (thread->lock_thread_id);
3365 mono_thread_pop_appdomain_ref (void)
3367 MonoInternalThread *thread = mono_thread_internal_current ();
3370 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3371 SPIN_LOCK (thread->lock_thread_id);
3372 ref_stack_pop (thread->appdomain_refs);
3373 SPIN_UNLOCK (thread->lock_thread_id);
3378 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3381 SPIN_LOCK (thread->lock_thread_id);
3382 res = ref_stack_find (thread->appdomain_refs, domain);
3383 SPIN_UNLOCK (thread->lock_thread_id);
3388 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3390 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3393 typedef struct abort_appdomain_data {
3394 struct wait_data wait;
3396 } abort_appdomain_data;
3399 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3401 MonoInternalThread *thread = (MonoInternalThread*)value;
3402 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3403 MonoDomain *domain = data->domain;
3405 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3406 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3408 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3409 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3412 data->wait.handles [data->wait.num] = handle;
3413 data->wait.threads [data->wait.num] = thread;
3416 /* Just ignore the rest, we can't do anything with
3424 * mono_threads_abort_appdomain_threads:
3426 * Abort threads which has references to the given appdomain.
3429 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3431 #ifdef __native_client__
3435 abort_appdomain_data user_data;
3437 int orig_timeout = timeout;
3440 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3442 start_time = mono_msec_ticks ();
3444 mono_threads_lock ();
3446 user_data.domain = domain;
3447 user_data.wait.num = 0;
3448 /* This shouldn't take any locks */
3449 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3450 mono_threads_unlock ();
3452 if (user_data.wait.num > 0) {
3453 /* Abort the threads outside the threads lock */
3454 for (i = 0; i < user_data.wait.num; ++i)
3455 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3458 * We should wait for the threads either to abort, or to leave the
3459 * domain. We can't do the latter, so we wait with a timeout.
3461 wait_for_tids (&user_data.wait, 100);
3464 /* Update remaining time */
3465 timeout -= mono_msec_ticks () - start_time;
3466 start_time = mono_msec_ticks ();
3468 if (orig_timeout != -1 && timeout < 0)
3471 while (user_data.wait.num > 0);
3473 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3479 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3481 MonoInternalThread *thread = (MonoInternalThread*)value;
3482 MonoDomain *domain = (MonoDomain*)user_data;
3485 /* No locking needed here */
3486 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3488 if (thread->cached_culture_info) {
3489 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3490 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3491 if (obj && obj->vtable->domain == domain)
3492 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3498 * mono_threads_clear_cached_culture:
3500 * Clear the cached_current_culture from all threads if it is in the
3504 mono_threads_clear_cached_culture (MonoDomain *domain)
3506 mono_threads_lock ();
3507 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3508 mono_threads_unlock ();
3512 * mono_thread_get_undeniable_exception:
3514 * Return an exception which needs to be raised when leaving a catch clause.
3515 * This is used for undeniable exception propagation.
3518 mono_thread_get_undeniable_exception (void)
3520 MonoInternalThread *thread = mono_thread_internal_current ();
3522 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3524 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3525 * exception if the thread no longer references a dying appdomain.
3527 thread->abort_exc->trace_ips = NULL;
3528 thread->abort_exc->stack_trace = NULL;
3529 return thread->abort_exc;
3535 #if MONO_SMALL_CONFIG
3536 #define NUM_STATIC_DATA_IDX 4
3537 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3541 #define NUM_STATIC_DATA_IDX 8
3542 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3543 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3547 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3548 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3551 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3553 gpointer *static_data = addr;
3555 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3556 void **ptr = static_data [i];
3561 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3562 void **p = ptr + idx;
3565 mark_func ((MonoObject**)p, gc_data);
3571 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3573 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3577 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3579 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3583 * mono_alloc_static_data
3585 * Allocate memory blocks for storing threads or context static data
3588 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3590 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3593 gpointer* static_data = *static_data_ptr;
3595 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3596 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3598 if (mono_gc_user_markers_supported ()) {
3599 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3600 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3602 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3603 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3606 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3607 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3608 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3609 *static_data_ptr = static_data;
3610 static_data [0] = static_data;
3613 for (i = 1; i <= idx; ++i) {
3614 if (static_data [i])
3617 if (mono_gc_user_markers_supported ())
3618 static_data [i] = g_malloc0 (static_data_size [i]);
3620 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3621 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3622 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3627 mono_free_static_data (gpointer* static_data)
3630 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3631 gpointer p = static_data [i];
3635 * At this point, the static data pointer array is still registered with the
3636 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3637 * data. Freeing the individual arrays without first nulling their slots
3638 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3639 * such an already freed array. See bug #13813.
3641 static_data [i] = NULL;
3642 mono_memory_write_barrier ();
3643 if (mono_gc_user_markers_supported ())
3646 mono_gc_free_fixed (p);
3648 mono_gc_free_fixed (static_data);
3652 * mono_init_static_data_info
3654 * Initializes static data counters
3656 static void mono_init_static_data_info (StaticDataInfo *static_data)
3658 static_data->idx = 0;
3659 static_data->offset = 0;
3660 static_data->freelist = NULL;
3664 * mono_alloc_static_data_slot
3666 * Generates an offset for static data. static_data contains the counters
3667 * used to generate it.
3670 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3672 if (!static_data->idx && !static_data->offset) {
3674 * we use the first chunk of the first allocation also as
3675 * an array for the rest of the data
3677 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3679 static_data->offset += align - 1;
3680 static_data->offset &= ~(align - 1);
3681 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3682 static_data->idx ++;
3683 g_assert (size <= static_data_size [static_data->idx]);
3684 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3685 static_data->offset = 0;
3687 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3688 static_data->offset += size;
3693 * ensure thread static fields already allocated are valid for thread
3694 * This function is called when a thread is created or on thread attach.
3697 thread_adjust_static_data (MonoInternalThread *thread)
3699 mono_threads_lock ();
3700 if (thread_static_info.offset || thread_static_info.idx > 0) {
3701 /* get the current allocated size */
3702 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3703 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3705 mono_threads_unlock ();
3709 * LOCKING: requires that threads_mutex is held
3712 context_adjust_static_data (MonoAppContext *ctx)
3714 if (context_static_info.offset || context_static_info.idx > 0) {
3715 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3716 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3721 * LOCKING: requires that threads_mutex is held
3724 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3726 MonoInternalThread *thread = value;
3727 guint32 offset = GPOINTER_TO_UINT (user);
3729 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3733 * LOCKING: requires that threads_mutex is held
3736 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3738 uint32_t gch = GPOINTER_TO_INT (key);
3739 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3742 mono_gchandle_free (gch);
3743 return TRUE; // Remove this key/value pair
3746 guint32 offset = GPOINTER_TO_UINT (user);
3747 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3749 return FALSE; // Don't remove it
3752 static StaticDataFreeList*
3753 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3755 StaticDataFreeList* prev = NULL;
3756 StaticDataFreeList* tmp = static_data->freelist;
3758 if (tmp->size == size) {
3760 prev->next = tmp->next;
3762 static_data->freelist = tmp->next;
3771 #if SIZEOF_VOID_P == 4
3778 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3780 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3782 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3783 MonoBitSet *rb = sets [idx];
3784 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3785 offset /= sizeof (uintptr_t);
3786 /* offset is now the bitmap offset */
3787 for (int i = 0; i < numbits; ++i) {
3788 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3789 mono_bitset_set_fast (rb, offset + i);
3794 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3796 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3797 MonoBitSet *rb = sets [idx];
3798 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3799 offset /= sizeof (uintptr_t);
3800 /* offset is now the bitmap offset */
3801 for (int i = 0; i < size / sizeof (uintptr_t); i++)
3802 mono_bitset_clear_fast (rb, offset + i);
3806 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3808 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3810 StaticDataInfo *info;
3813 if (static_type == SPECIAL_STATIC_THREAD) {
3814 info = &thread_static_info;
3815 sets = thread_reference_bitmaps;
3817 info = &context_static_info;
3818 sets = context_reference_bitmaps;
3821 mono_threads_lock ();
3823 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3827 offset = item->offset;
3830 offset = mono_alloc_static_data_slot (info, size, align);
3833 update_reference_bitmap (sets, offset, bitmap, numbits);
3835 if (static_type == SPECIAL_STATIC_THREAD) {
3836 /* This can be called during startup */
3837 if (threads != NULL)
3838 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3840 if (contexts != NULL)
3841 g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3843 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3846 mono_threads_unlock ();
3852 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3854 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3856 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3857 return get_thread_static_data (thread, offset);
3859 return get_context_static_data (thread->current_appcontext, offset);
3864 mono_get_special_static_data (guint32 offset)
3866 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3875 * LOCKING: requires that threads_mutex is held
3878 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3880 MonoInternalThread *thread = value;
3881 OffsetSize *data = user;
3882 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3883 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3886 if (!thread->static_data || !thread->static_data [idx])
3888 ptr = ((char*) thread->static_data [idx]) + off;
3889 mono_gc_bzero_atomic (ptr, data->size);
3893 * LOCKING: requires that threads_mutex is held
3896 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3898 uint32_t gch = GPOINTER_TO_INT (key);
3899 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3902 mono_gchandle_free (gch);
3903 return TRUE; // Remove this key/value pair
3906 OffsetSize *data = user;
3907 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3908 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3911 if (!ctx->static_data || !ctx->static_data [idx])
3912 return FALSE; // Don't remove this key/value pair
3914 ptr = ((char*) ctx->static_data [idx]) + off;
3915 mono_gc_bzero_atomic (ptr, data->size);
3917 return FALSE; // Don't remove this key/value pair
3921 do_free_special_slot (guint32 offset, guint32 size)
3923 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3925 StaticDataInfo *info;
3927 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3928 info = &thread_static_info;
3929 sets = thread_reference_bitmaps;
3931 info = &context_static_info;
3932 sets = context_reference_bitmaps;
3935 guint32 data_offset = offset;
3936 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
3937 OffsetSize data = { data_offset, size };
3939 clear_reference_bitmap (sets, data.offset, data.size);
3941 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3942 if (threads != NULL)
3943 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3945 if (contexts != NULL)
3946 g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
3949 if (!mono_runtime_is_shutting_down ()) {
3950 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
3952 item->offset = offset;
3955 item->next = info->freelist;
3956 info->freelist = item;
3961 do_free_special (gpointer key, gpointer value, gpointer data)
3963 MonoClassField *field = key;
3964 guint32 offset = GPOINTER_TO_UINT (value);
3967 size = mono_type_size (field->type, &align);
3968 do_free_special_slot (offset, size);
3972 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3974 mono_threads_lock ();
3976 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3978 mono_threads_unlock ();
3982 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3984 /* Only ever called for ThreadLocal instances */
3985 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
3987 mono_threads_lock ();
3988 do_free_special_slot (offset, size);
3989 mono_threads_unlock ();
3993 static void CALLBACK dummy_apc (ULONG_PTR param)
3999 * mono_thread_execute_interruption
4001 * Performs the operation that the requested thread state requires (abort,
4004 static MonoException*
4005 mono_thread_execute_interruption (MonoInternalThread *thread)
4007 LOCK_THREAD (thread);
4009 /* MonoThread::interruption_requested can only be changed with atomics */
4010 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4011 /* this will consume pending APC calls */
4013 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4015 InterlockedDecrement (&thread_interruption_requested);
4017 /* Clear the interrupted flag of the thread so it can wait again */
4018 mono_thread_info_clear_self_interrupt ();
4021 if ((thread->state & ThreadState_AbortRequested) != 0) {
4022 UNLOCK_THREAD (thread);
4023 if (thread->abort_exc == NULL) {
4025 * This might be racy, but it has to be called outside the lock
4026 * since it calls managed code.
4028 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4030 return thread->abort_exc;
4032 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4033 self_suspend_internal (thread);
4036 else if ((thread->state & ThreadState_StopRequested) != 0) {
4037 /* FIXME: do this through the JIT? */
4039 UNLOCK_THREAD (thread);
4041 mono_thread_exit ();
4043 } else if (thread->pending_exception) {
4046 exc = thread->pending_exception;
4047 thread->pending_exception = NULL;
4049 UNLOCK_THREAD (thread);
4051 } else if (thread->thread_interrupt_requested) {
4053 thread->thread_interrupt_requested = FALSE;
4054 UNLOCK_THREAD (thread);
4056 return(mono_get_exception_thread_interrupted ());
4059 UNLOCK_THREAD (thread);
4065 * mono_thread_request_interruption
4067 * A signal handler can call this method to request the interruption of a
4068 * thread. The result of the interruption will depend on the current state of
4069 * the thread. If the result is an exception that needs to be throw, it is
4070 * provided as return value.
4073 mono_thread_request_interruption (gboolean running_managed)
4075 MonoInternalThread *thread = mono_thread_internal_current ();
4077 /* The thread may already be stopping */
4082 if (thread->interrupt_on_stop &&
4083 thread->state & ThreadState_StopRequested &&
4084 thread->state & ThreadState_Background)
4088 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4090 InterlockedIncrement (&thread_interruption_requested);
4092 if (!running_managed || is_running_protected_wrapper ()) {
4093 /* Can't stop while in unmanaged code. Increase the global interruption
4094 request count. When exiting the unmanaged method the count will be
4095 checked and the thread will be interrupted. */
4097 if (mono_thread_notify_pending_exc_fn && !running_managed)
4098 /* The JIT will notify the thread about the interruption */
4099 /* This shouldn't take any locks */
4100 mono_thread_notify_pending_exc_fn (NULL);
4102 /* this will awake the thread if it is in WaitForSingleObject
4104 /* Our implementation of this function ignores the func argument */
4106 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4108 mono_thread_info_self_interrupt ();
4113 return mono_thread_execute_interruption (thread);
4117 /*This function should be called by a thread after it has exited all of
4118 * its handle blocks at interruption time.*/
4120 mono_thread_resume_interruption (void)
4122 MonoInternalThread *thread = mono_thread_internal_current ();
4123 gboolean still_aborting;
4125 /* The thread may already be stopping */
4129 LOCK_THREAD (thread);
4130 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4131 UNLOCK_THREAD (thread);
4133 /*This can happen if the protected block called Thread::ResetAbort*/
4134 if (!still_aborting)
4137 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4139 InterlockedIncrement (&thread_interruption_requested);
4141 mono_thread_info_self_interrupt ();
4143 return mono_thread_execute_interruption (thread);
4146 gboolean mono_thread_interruption_requested ()
4148 if (thread_interruption_requested) {
4149 MonoInternalThread *thread = mono_thread_internal_current ();
4150 /* The thread may already be stopping */
4152 return (thread->interruption_requested);
4157 static MonoException*
4158 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4160 MonoInternalThread *thread = mono_thread_internal_current ();
4162 /* The thread may already be stopping */
4166 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4167 MonoException* exc = mono_thread_execute_interruption (thread);
4175 * Performs the interruption of the current thread, if one has been requested,
4176 * and the thread is not running a protected wrapper.
4177 * Return the exception which needs to be thrown, if any.
4180 mono_thread_interruption_checkpoint (void)
4182 return mono_thread_interruption_checkpoint_request (FALSE);
4186 * Performs the interruption of the current thread, if one has been requested.
4187 * Return the exception which needs to be thrown, if any.
4190 mono_thread_force_interruption_checkpoint_noraise (void)
4192 return mono_thread_interruption_checkpoint_request (TRUE);
4196 * Performs the interruption of the current thread, if one has been requested.
4197 * Throw the exception which needs to be thrown, if any.
4200 mono_thread_force_interruption_checkpoint (void)
4204 ex = mono_thread_interruption_checkpoint_request (TRUE);
4206 mono_raise_exception (ex);
4210 * mono_thread_get_and_clear_pending_exception:
4212 * Return any pending exceptions for the current thread and clear it as a side effect.
4215 mono_thread_get_and_clear_pending_exception (void)
4217 MonoInternalThread *thread = mono_thread_internal_current ();
4219 /* The thread may already be stopping */
4223 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4224 return mono_thread_execute_interruption (thread);
4227 if (thread->pending_exception) {
4228 MonoException *exc = thread->pending_exception;
4230 thread->pending_exception = NULL;
4238 * mono_set_pending_exception:
4240 * Set the pending exception of the current thread to EXC.
4241 * The exception will be thrown when execution returns to managed code.
4244 mono_set_pending_exception (MonoException *exc)
4246 MonoInternalThread *thread = mono_thread_internal_current ();
4248 /* The thread may already be stopping */
4252 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4254 mono_thread_request_interruption (FALSE);
4258 * mono_thread_interruption_request_flag:
4260 * Returns the address of a flag that will be non-zero if an interruption has
4261 * been requested for a thread. The thread to interrupt may not be the current
4262 * thread, so an additional call to mono_thread_interruption_requested() or
4263 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4266 gint32* mono_thread_interruption_request_flag ()
4268 return &thread_interruption_requested;
4272 mono_thread_init_apartment_state (void)
4275 MonoInternalThread* thread = mono_thread_internal_current ();
4277 /* Positive return value indicates success, either
4278 * S_OK if this is first CoInitialize call, or
4279 * S_FALSE if CoInitialize already called, but with same
4280 * threading model. A negative value indicates failure,
4281 * probably due to trying to change the threading model.
4283 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4284 ? COINIT_APARTMENTTHREADED
4285 : COINIT_MULTITHREADED) < 0) {
4286 thread->apartment_state = ThreadApartmentState_Unknown;
4292 mono_thread_cleanup_apartment_state (void)
4295 MonoInternalThread* thread = mono_thread_internal_current ();
4297 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4304 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4306 LOCK_THREAD (thread);
4307 thread->state |= state;
4308 UNLOCK_THREAD (thread);
4312 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4314 LOCK_THREAD (thread);
4315 thread->state &= ~state;
4316 UNLOCK_THREAD (thread);
4320 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4322 gboolean ret = FALSE;
4324 LOCK_THREAD (thread);
4326 if ((thread->state & test) != 0) {
4330 UNLOCK_THREAD (thread);
4335 static gboolean has_tls_get = FALSE;
4338 mono_runtime_set_has_tls_get (gboolean val)
4344 mono_runtime_has_tls_get (void)
4350 self_interrupt_thread (void *_unused)
4352 MonoThreadInfo *info = mono_thread_info_current ();
4353 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4354 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4355 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. */
4356 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4360 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4364 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4368 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4370 MonoJitInfo **dest = data;
4376 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4378 MonoJitInfo *ji = NULL;
4381 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4386 MonoInternalThread *thread;
4387 gboolean install_async_abort;
4388 MonoThreadInfoInterruptToken *interrupt_token;
4391 static SuspendThreadResult
4392 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4394 AbortThreadData *data = ud;
4395 MonoInternalThread *thread = data->thread;
4396 MonoJitInfo *ji = NULL;
4397 gboolean protected_wrapper;
4398 gboolean running_managed;
4400 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4401 return MonoResumeThread;
4403 /*someone is already interrupting it*/
4404 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4405 return MonoResumeThread;
4407 InterlockedIncrement (&thread_interruption_requested);
4409 ji = mono_thread_info_get_last_managed (info);
4410 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4411 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4413 if (!protected_wrapper && running_managed) {
4414 /*We are in managed code*/
4415 /*Set the thread to call */
4416 if (data->install_async_abort)
4417 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4418 return MonoResumeThread;
4420 if (mono_thread_notify_pending_exc_fn)
4421 /* The JIT will notify the thread about the interruption */
4422 mono_thread_notify_pending_exc_fn (info);
4425 * This will cause waits to be broken.
4426 * It will also prevent the thread from entering a wait, so if the thread returns
4427 * from the wait before it receives the abort signal, it will just spin in the wait
4428 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4431 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4433 return MonoResumeThread;
4438 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4440 AbortThreadData data = { 0 };
4441 data.thread = thread;
4442 data.install_async_abort = install_async_abort;
4445 FIXME this is insanely broken, it doesn't cause interruption to happen
4446 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4448 if (thread == mono_thread_internal_current ()) {
4449 /* Do it synchronously */
4450 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4452 mono_raise_exception (exc);
4454 mono_thread_info_self_interrupt ();
4459 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_critical, &data);
4460 if (data.interrupt_token)
4461 mono_thread_info_finish_interrupt (data.interrupt_token);
4462 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4466 MonoInternalThread *thread;
4468 MonoThreadInfoInterruptToken *interrupt_token;
4469 } SuspendThreadData;
4471 static SuspendThreadResult
4472 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4474 SuspendThreadData *data = ud;
4475 MonoInternalThread *thread = data->thread;
4476 MonoJitInfo *ji = NULL;
4477 gboolean protected_wrapper;
4478 gboolean running_managed;
4480 ji = mono_thread_info_get_last_managed (info);
4481 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4482 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4484 if (running_managed && !protected_wrapper) {
4485 thread->state &= ~ThreadState_SuspendRequested;
4486 thread->state |= ThreadState_Suspended;
4487 return KeepSuspended;
4489 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4490 InterlockedIncrement (&thread_interruption_requested);
4491 if (data->interrupt)
4492 data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
4494 if (mono_thread_notify_pending_exc_fn && !running_managed)
4495 /* The JIT will notify the thread about the interruption */
4496 mono_thread_notify_pending_exc_fn (info);
4497 return MonoResumeThread;
4502 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4504 LOCK_THREAD (thread);
4505 if (thread == mono_thread_internal_current ()) {
4506 mono_thread_info_begin_self_suspend ();
4507 //XXX replace this with better named functions
4508 thread->state &= ~ThreadState_SuspendRequested;
4509 thread->state |= ThreadState_Suspended;
4510 UNLOCK_THREAD (thread);
4511 mono_thread_info_end_self_suspend ();
4513 SuspendThreadData data = { 0 };
4514 data.thread = thread;
4515 data.interrupt = interrupt;
4517 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, suspend_thread_critical, &data);
4518 if (data.interrupt_token)
4519 mono_thread_info_finish_interrupt (data.interrupt_token);
4520 UNLOCK_THREAD (thread);
4524 /*This is called with @thread synch_cs held and it must release it*/
4526 self_suspend_internal (MonoInternalThread *thread)
4528 mono_thread_info_begin_self_suspend ();
4529 thread->state &= ~ThreadState_SuspendRequested;
4530 thread->state |= ThreadState_Suspended;
4531 UNLOCK_THREAD (thread);
4532 mono_thread_info_end_self_suspend ();
4535 /*This is called with @thread synch_cs held and it must release it*/
4537 resume_thread_internal (MonoInternalThread *thread)
4539 UNLOCK_THREAD (thread);
4540 /* Awake the thread */
4541 if (!mono_thread_info_resume (thread_get_tid (thread)))
4543 LOCK_THREAD (thread);
4544 thread->state &= ~ThreadState_Suspended;
4545 UNLOCK_THREAD (thread);
4551 * mono_thread_is_foreign:
4552 * @thread: the thread to query
4554 * This function allows one to determine if a thread was created by the mono runtime and has
4555 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4557 * Returns: true if @thread was not created by the runtime.
4560 mono_thread_is_foreign (MonoThread *thread)
4562 MonoThreadInfo *info = thread->internal_thread->thread_info;
4563 return info->runtime_thread == FALSE;
4567 * mono_add_joinable_thread:
4569 * Add TID to the list of joinable threads.
4570 * LOCKING: Acquires the threads lock.
4573 mono_threads_add_joinable_thread (gpointer tid)
4577 * We cannot detach from threads because it causes problems like
4578 * 2fd16f60/r114307. So we collect them and join them when
4579 * we have time (in he finalizer thread).
4581 joinable_threads_lock ();
4582 if (!joinable_threads)
4583 joinable_threads = g_hash_table_new (NULL, NULL);
4584 g_hash_table_insert (joinable_threads, tid, tid);
4585 joinable_thread_count ++;
4586 joinable_threads_unlock ();
4588 mono_gc_finalize_notify ();
4593 * mono_threads_join_threads:
4595 * Join all joinable threads. This is called from the finalizer thread.
4596 * LOCKING: Acquires the threads lock.
4599 mono_threads_join_threads (void)
4602 GHashTableIter iter;
4609 if (!joinable_thread_count)
4613 joinable_threads_lock ();
4615 if (g_hash_table_size (joinable_threads)) {
4616 g_hash_table_iter_init (&iter, joinable_threads);
4617 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4618 thread = (pthread_t)tid;
4619 g_hash_table_remove (joinable_threads, key);
4620 joinable_thread_count --;
4623 joinable_threads_unlock ();
4625 if (thread != pthread_self ())
4626 /* This shouldn't block */
4627 pthread_join (thread, NULL);
4638 * Wait for thread TID to exit.
4639 * LOCKING: Acquires the threads lock.
4642 mono_thread_join (gpointer tid)
4646 gboolean found = FALSE;
4648 joinable_threads_lock ();
4649 if (!joinable_threads)
4650 joinable_threads = g_hash_table_new (NULL, NULL);
4651 if (g_hash_table_lookup (joinable_threads, tid)) {
4652 g_hash_table_remove (joinable_threads, tid);
4653 joinable_thread_count --;
4656 joinable_threads_unlock ();
4659 thread = (pthread_t)tid;
4660 pthread_join (thread, NULL);
4665 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4667 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4668 mono_thread_interruption_checkpoint ();
4671 static inline gboolean
4672 is_appdomainunloaded_exception (MonoClass *klass)
4674 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4676 if (!app_domain_unloaded_exception_klass)
4677 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4678 g_assert (app_domain_unloaded_exception_klass);
4680 return klass == app_domain_unloaded_exception_klass;
4683 static inline gboolean
4684 is_threadabort_exception (MonoClass *klass)
4686 return klass == mono_defaults.threadabortexception_class;
4690 mono_thread_internal_unhandled_exception (MonoObject* exc)
4692 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4693 MonoClass *klass = exc->vtable->klass;
4694 if (is_threadabort_exception (klass)) {
4695 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4696 } else if (!is_appdomainunloaded_exception (klass)) {
4697 mono_unhandled_exception (exc);
4698 if (mono_environment_exitcode_get () == 1)