2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threads-types.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/environment.h>
26 #include <mono/metadata/monitor.h>
27 #include <mono/metadata/gc-internal.h>
28 #include <mono/metadata/marshal.h>
29 #include <mono/metadata/runtime.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/mono-debug-debugger.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internal.h>
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
51 #define USE_TKILL_ON_ANDROID 1
54 #ifdef PLATFORM_ANDROID
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid, int signal);
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func)(void *);
107 typedef struct _StaticDataFreeList StaticDataFreeList;
108 struct _StaticDataFreeList {
109 StaticDataFreeList *next;
117 StaticDataFreeList *freelist;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 static void mono_threads_lock (void);
130 static void mono_threads_unlock (void);
131 static mono_mutex_t threads_mutex;
133 /* Controls access to the 'joinable_threads' hash table */
134 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
135 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
136 static mono_mutex_t joinable_threads_mutex;
138 /* Holds current status of static data heap */
139 static StaticDataInfo thread_static_info;
140 static StaticDataInfo context_static_info;
142 /* The hash of existing threads (key is thread ID, value is
143 * MonoInternalThread*) that need joining before exit
145 static MonoGHashTable *threads=NULL;
147 /* List of app context GC handles.
148 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
150 static GHashTable *contexts = NULL;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable *threads_starting_up = NULL;
159 /* Maps a MonoThread to its start argument */
160 /* Protected by mono_threads_lock () */
161 static MonoGHashTable *thread_start_args = NULL;
163 /* The TLS key that holds the MonoObject assigned to each thread */
164 static MonoNativeTlsKey current_object_key;
167 /* Protected by the threads lock */
168 static GHashTable *joinable_threads;
169 static int joinable_thread_count;
171 #ifdef MONO_HAVE_FAST_TLS
172 /* we need to use both the Tls* functions and __thread because
173 * the gc needs to see all the threads
175 MONO_FAST_TLS_DECLARE(tls_current_object);
176 #define SET_CURRENT_OBJECT(x) do { \
177 MONO_FAST_TLS_SET (tls_current_object, x); \
178 mono_native_tls_set_value (current_object_key, x); \
180 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
182 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
183 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
186 /* function called at thread start */
187 static MonoThreadStartCB mono_thread_start_cb = NULL;
189 /* function called at thread attach */
190 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
192 /* function called at thread cleanup */
193 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
195 /* function called to notify the runtime about a pending exception on the current thread */
196 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
198 /* The default stack size for each thread */
199 static guint32 default_stacksize = 0;
200 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
202 static void thread_adjust_static_data (MonoInternalThread *thread);
203 static void context_adjust_static_data (MonoAppContext *ctx);
204 static void mono_free_static_data (gpointer* static_data);
205 static void mono_init_static_data_info (StaticDataInfo *static_data);
206 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
207 static gboolean mono_thread_resume (MonoInternalThread* thread);
208 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
209 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
210 static void self_suspend_internal (MonoInternalThread *thread);
211 static gboolean resume_thread_internal (MonoInternalThread *thread);
213 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
214 static void ref_stack_destroy (gpointer rs);
216 /* Spin lock for InterlockedXXX 64 bit functions */
217 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
218 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
219 static mono_mutex_t interlocked_mutex;
221 /* global count of thread interruptions requested */
222 static gint32 thread_interruption_requested = 0;
224 /* Event signaled when a thread changes its background mode */
225 static HANDLE background_change_event;
227 static gboolean shutting_down = FALSE;
229 static gint32 managed_thread_id_counter = 0;
233 mono_threads_lock (void)
236 mono_locks_acquire (&threads_mutex, ThreadsLock);
237 MONO_FINISH_TRY_BLOCKING
241 mono_threads_unlock (void)
243 mono_locks_release (&threads_mutex, ThreadsLock);
248 get_next_managed_thread_id (void)
250 return InterlockedIncrement (&managed_thread_id_counter);
254 mono_thread_get_tls_key (void)
256 return current_object_key;
260 mono_thread_get_tls_offset (void)
263 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
267 static inline MonoNativeThreadId
268 thread_get_tid (MonoInternalThread *thread)
270 /* We store the tid as a guint64 to keep the object layout constant between platforms */
271 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
274 /* handle_store() and handle_remove() manage the array of threads that
275 * still need to be waited for when the main thread exits.
277 * If handle_store() returns FALSE the thread must not be started
278 * because Mono is shutting down.
280 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
282 mono_threads_lock ();
284 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
286 if (threads_starting_up)
287 mono_g_hash_table_remove (threads_starting_up, thread);
289 if (shutting_down && !force_attach) {
290 mono_threads_unlock ();
295 MONO_GC_REGISTER_ROOT_FIXED (threads);
296 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
299 /* We don't need to duplicate thread->handle, because it is
300 * only closed when the thread object is finalized by the GC.
302 g_assert (thread->internal_thread);
303 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
304 thread->internal_thread);
306 mono_threads_unlock ();
311 static gboolean handle_remove(MonoInternalThread *thread)
314 gsize tid = thread->tid;
316 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
318 mono_threads_lock ();
321 /* We have to check whether the thread object for the
322 * tid is still the same in the table because the
323 * thread might have been destroyed and the tid reused
324 * in the meantime, in which case the tid would be in
325 * the table, but with another thread object.
327 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
328 mono_g_hash_table_remove (threads, (gpointer)tid);
337 mono_threads_unlock ();
339 /* Don't close the handle here, wait for the object finalizer
340 * to do it. Otherwise, the following race condition applies:
342 * 1) Thread exits (and handle_remove() closes the handle)
344 * 2) Some other handle is reassigned the same slot
346 * 3) Another thread tries to join the first thread, and
347 * blocks waiting for the reassigned handle to be signalled
348 * (which might never happen). This is possible, because the
349 * thread calling Join() still has a reference to the first
355 static void ensure_synch_cs_set (MonoInternalThread *thread)
357 mono_mutex_t *synch_cs;
359 if (thread->synch_cs != NULL) {
363 synch_cs = g_new0 (mono_mutex_t, 1);
364 mono_mutex_init_recursive (synch_cs);
366 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
367 synch_cs, NULL) != NULL) {
368 /* Another thread must have installed this CS */
369 mono_mutex_destroy (synch_cs);
375 lock_thread (MonoInternalThread *thread)
377 if (!thread->synch_cs)
378 ensure_synch_cs_set (thread);
380 g_assert (thread->synch_cs);
383 mono_mutex_lock (thread->synch_cs);
384 MONO_FINISH_TRY_BLOCKING
388 unlock_thread (MonoInternalThread *thread)
390 mono_mutex_unlock (thread->synch_cs);
394 * NOTE: this function can be called also for threads different from the current one:
395 * make sure no code called from it will ever assume it is run on the thread that is
396 * getting cleaned up.
398 static void thread_cleanup (MonoInternalThread *thread)
400 g_assert (thread != NULL);
402 if (thread->abort_state_handle) {
403 mono_gchandle_free (thread->abort_state_handle);
404 thread->abort_state_handle = 0;
406 thread->abort_exc = NULL;
407 thread->current_appcontext = NULL;
410 * This is necessary because otherwise we might have
411 * cross-domain references which will not get cleaned up when
412 * the target domain is unloaded.
414 if (thread->cached_culture_info) {
416 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
417 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
421 * thread->synch_cs can be NULL if this was called after
422 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
423 * This can happen only during shutdown.
424 * The shutting_down flag is not always set, so we can't assert on it.
426 if (thread->synch_cs)
427 LOCK_THREAD (thread);
429 thread->state |= ThreadState_Stopped;
430 thread->state &= ~ThreadState_Background;
432 if (thread->synch_cs)
433 UNLOCK_THREAD (thread);
436 An interruption request has leaked to cleanup. Adjust the global counter.
438 This can happen is the abort source thread finds the abortee (this) thread
439 in unmanaged code. If this thread never trips back to managed code or check
440 the local flag it will be left set and positively unbalance the global counter.
442 Leaving the counter unbalanced will cause a performance degradation since all threads
443 will now keep checking their local flags all the time.
445 if (InterlockedExchange (&thread->interruption_requested, 0))
446 InterlockedDecrement (&thread_interruption_requested);
448 /* if the thread is not in the hash it has been removed already */
449 if (!handle_remove (thread)) {
450 if (thread == mono_thread_internal_current ()) {
451 mono_domain_unset ();
452 mono_memory_barrier ();
454 /* This needs to be called even if handle_remove () fails */
455 if (mono_thread_cleanup_fn)
456 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
459 mono_release_type_locks (thread);
461 mono_profiler_thread_end (thread->tid);
463 if (thread == mono_thread_internal_current ()) {
465 * This will signal async signal handlers that the thread has exited.
466 * The profiler callback needs this to be set, so it cannot be done earlier.
468 mono_domain_unset ();
469 mono_memory_barrier ();
472 if (thread == mono_thread_internal_current ())
473 mono_thread_pop_appdomain_ref ();
475 thread->cached_culture_info = NULL;
477 mono_free_static_data (thread->static_data);
478 thread->static_data = NULL;
479 ref_stack_destroy (thread->appdomain_refs);
480 thread->appdomain_refs = NULL;
482 if (mono_thread_cleanup_fn)
483 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
485 if (mono_gc_is_moving ()) {
486 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
487 thread->thread_pinning_ref = NULL;
492 * A special static data offset (guint32) consists of 3 parts:
494 * [0] 6-bit index into the array of chunks.
495 * [6] 25-bit offset into the array.
496 * [31] Bit indicating thread or context static.
501 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
512 } SpecialStaticOffset;
514 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
515 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
517 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
518 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
519 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
520 (((SpecialStaticOffset *) &(x))->fields.f)
523 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
525 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
527 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
528 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
530 return ((char *) thread->static_data [idx]) + off;
534 get_context_static_data (MonoAppContext *ctx, guint32 offset)
536 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
538 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
539 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
541 return ((char *) ctx->static_data [idx]) + off;
545 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
547 static MonoClassField *current_thread_field = NULL;
551 if (!current_thread_field) {
552 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
553 g_assert (current_thread_field);
556 mono_class_vtable (domain, mono_defaults.thread_class);
557 mono_domain_lock (domain);
558 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
559 mono_domain_unlock (domain);
562 return get_thread_static_data (thread, offset);
566 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
568 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
570 g_assert (current->obj.vtable->domain == domain);
572 g_assert (!*current_thread_ptr);
573 *current_thread_ptr = current;
577 create_thread_object (MonoDomain *domain)
579 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
580 return (MonoThread*)mono_gc_alloc_mature (vt);
584 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
586 MonoThread *thread = create_thread_object (domain);
587 MONO_OBJECT_SETREF (thread, internal_thread, internal);
591 static MonoInternalThread*
592 create_internal_thread (void)
594 MonoInternalThread *thread;
597 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
598 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
600 thread->synch_cs = g_new0 (mono_mutex_t, 1);
601 mono_mutex_init_recursive (thread->synch_cs);
603 thread->apartment_state = ThreadApartmentState_Unknown;
604 thread->managed_id = get_next_managed_thread_id ();
605 if (mono_gc_is_moving ()) {
606 thread->thread_pinning_ref = thread;
607 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
614 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
616 MonoDomain *domain = mono_get_root_domain ();
618 if (!candidate || candidate->obj.vtable->domain != domain)
619 candidate = new_thread_with_internal (domain, thread);
620 set_current_thread_for_domain (domain, thread, candidate);
621 g_assert (!thread->root_domain_thread);
622 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
625 static guint32 WINAPI start_wrapper_internal(void *data)
627 MonoThreadInfo *info;
628 StartInfo *start_info = (StartInfo *)data;
629 guint32 (*start_func)(void *);
633 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
636 MonoInternalThread *internal = start_info->obj->internal_thread;
637 MonoObject *start_delegate = start_info->delegate;
638 MonoDomain *domain = start_info->obj->obj.vtable->domain;
640 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
642 /* We can be sure start_info->obj->tid and
643 * start_info->obj->handle have been set, because the thread
644 * was created suspended, and these values were set before the
648 info = mono_thread_info_current ();
650 internal->thread_info = info;
651 internal->small_id = info->small_id;
655 SET_CURRENT_OBJECT (internal);
657 /* Every thread references the appdomain which created it */
658 mono_thread_push_appdomain_ref (domain);
660 if (!mono_domain_set (domain, FALSE)) {
661 /* No point in raising an appdomain_unloaded exception here */
662 /* FIXME: Cleanup here */
663 mono_thread_pop_appdomain_ref ();
667 start_func = start_info->func;
668 start_arg = start_info->start_arg;
670 /* We have to do this here because mono_thread_new_init()
671 requires that root_domain_thread is set up. */
672 thread_adjust_static_data (internal);
673 init_root_domain_thread (internal, start_info->obj);
675 /* This MUST be called before any managed code can be
676 * executed, as it calls the callback function that (for the
677 * jit) sets the lmf marker.
679 mono_thread_new_init (tid, &tid, start_func);
680 internal->stack_ptr = &tid;
682 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
684 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
686 /* On 2.0 profile (and higher), set explicitly since state might have been
688 if (internal->apartment_state == ThreadApartmentState_Unknown)
689 internal->apartment_state = ThreadApartmentState_MTA;
691 mono_thread_init_apartment_state ();
693 if(internal->start_notify!=NULL) {
694 /* Let the thread that called Start() know we're
697 ReleaseSemaphore (internal->start_notify, 1, NULL);
700 mono_threads_lock ();
701 mono_g_hash_table_remove (thread_start_args, start_info->obj);
702 mono_threads_unlock ();
705 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
709 * Call this after calling start_notify, since the profiler callback might want
710 * to lock the thread, and the lock is held by thread_start () which waits for
713 mono_profiler_thread_start (tid);
715 /* if the name was set before starting, we didn't invoke the profiler callback */
716 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
717 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
718 mono_profiler_thread_name (internal->tid, tname);
721 /* start_func is set only for unmanaged start functions */
723 start_func (start_arg);
726 g_assert (start_delegate != NULL);
727 args [0] = start_arg;
728 /* we may want to handle the exception here. See comment below on unhandled exceptions */
729 mono_runtime_delegate_invoke (start_delegate, args, NULL);
732 /* If the thread calls ExitThread at all, this remaining code
733 * will not be executed, but the main thread will eventually
734 * call thread_cleanup() on this thread's behalf.
737 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
739 /* Do any cleanup needed for apartment state. This
740 * cannot be done in thread_cleanup since thread_cleanup could be
741 * called for a thread other than the current thread.
742 * mono_thread_cleanup_apartment_state cleans up apartment
743 * for the current thead */
744 mono_thread_cleanup_apartment_state ();
746 thread_cleanup (internal);
750 /* Remove the reference to the thread object in the TLS data,
751 * so the thread object can be finalized. This won't be
752 * reached if the thread threw an uncaught exception, so those
753 * thread handles will stay referenced :-( (This is due to
754 * missing support for scanning thread-specific data in the
755 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
758 SET_CURRENT_OBJECT (NULL);
763 static guint32 WINAPI start_wrapper(void *data)
767 /* Avoid scanning the frames above this frame during a GC */
768 mono_gc_set_stack_end ((void*)&dummy);
770 return start_wrapper_internal (data);
776 * Common thread creation code.
777 * LOCKING: Acquires the threads lock.
780 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
781 gboolean throw_on_failure)
783 HANDLE thread_handle;
784 MonoNativeThreadId tid;
785 guint32 create_flags;
788 * Join joinable threads to prevent running out of threads since the finalizer
789 * thread might be blocked/backlogged.
791 mono_threads_join_threads ();
793 mono_threads_lock ();
796 mono_threads_unlock ();
800 * The thread start argument may be an object reference, and there is
801 * no ref to keep it alive when the new thread is started but not yet
802 * registered with the collector. So we store it in a GC tracked hash
805 if (thread_start_args == NULL) {
806 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
807 thread_start_args = mono_g_hash_table_new (NULL, NULL);
809 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
810 if (threads_starting_up == NULL) {
811 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
812 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
814 mono_g_hash_table_insert (threads_starting_up, thread, thread);
815 mono_threads_unlock ();
817 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
818 if (!internal->start_notify) {
819 mono_threads_lock ();
820 mono_g_hash_table_remove (threads_starting_up, thread);
821 mono_threads_unlock ();
822 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
828 stack_size = default_stacksize_for_thread (internal);
830 /* Create suspended, so we can do some housekeeping before the thread
833 create_flags = CREATE_SUSPENDED;
835 MONO_PREPARE_BLOCKING
836 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
837 stack_size, create_flags, &tid);
840 if (thread_handle == NULL) {
841 /* The thread couldn't be created, so throw an exception */
842 mono_threads_lock ();
843 mono_g_hash_table_remove (threads_starting_up, thread);
844 mono_threads_unlock ();
846 if (throw_on_failure)
847 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
849 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
852 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
854 internal->handle = thread_handle;
855 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
857 internal->threadpool_thread = threadpool_thread;
858 if (threadpool_thread)
859 mono_thread_set_state (internal, ThreadState_Background);
861 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
863 /* Only store the handle when the thread is about to be
864 * launched, to avoid the main thread deadlocking while trying
865 * to clean up a thread that will never be signalled.
867 if (!handle_store (thread, FALSE))
870 MONO_PREPARE_BLOCKING
871 mono_thread_info_resume (tid);
874 if (internal->start_notify) {
876 * Wait for the thread to set up its TLS data etc, so
877 * theres no potential race condition if someone tries
878 * to look up the data believing the thread has
881 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
883 MONO_PREPARE_BLOCKING
884 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
887 CloseHandle (internal->start_notify);
888 internal->start_notify = NULL;
891 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
896 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
898 if (mono_thread_start_cb) {
899 mono_thread_start_cb (tid, stack_start, func);
903 void mono_threads_set_default_stacksize (guint32 stacksize)
905 default_stacksize = stacksize;
908 guint32 mono_threads_get_default_stacksize (void)
910 return default_stacksize;
914 * mono_thread_create_internal:
918 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
921 MonoInternalThread *internal;
922 StartInfo *start_info;
925 thread = create_thread_object (domain);
926 internal = create_internal_thread ();
927 MONO_OBJECT_SETREF (thread, internal_thread, internal);
929 start_info = g_new0 (StartInfo, 1);
930 start_info->func = func;
931 start_info->obj = thread;
932 start_info->start_arg = arg;
934 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
938 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
939 if (mono_check_corlib_version () == NULL)
940 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
946 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
948 mono_thread_create_internal (domain, func, arg, FALSE, 0);
952 mono_thread_attach (MonoDomain *domain)
954 return mono_thread_attach_full (domain, FALSE);
958 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
960 MonoThreadInfo *info;
961 MonoInternalThread *thread;
962 MonoThread *current_thread;
963 HANDLE thread_handle;
966 if ((thread = mono_thread_internal_current ())) {
967 if (domain != mono_domain_get ())
968 mono_domain_set (domain, TRUE);
969 /* Already attached */
970 return mono_thread_current ();
973 if (!mono_gc_register_thread (&domain)) {
974 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ());
977 thread = create_internal_thread ();
979 thread_handle = mono_thread_info_open_handle ();
980 g_assert (thread_handle);
982 tid=GetCurrentThreadId ();
984 thread->handle=thread_handle;
986 thread->stack_ptr = &tid;
988 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
990 info = mono_thread_info_current ();
992 thread->thread_info = info;
993 thread->small_id = info->small_id;
995 current_thread = new_thread_with_internal (domain, thread);
997 if (!handle_store (current_thread, force_attach)) {
998 /* Mono is shutting down, so just wait for the end */
1003 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
1005 SET_CURRENT_OBJECT (thread);
1006 mono_domain_set (domain, TRUE);
1008 thread_adjust_static_data (thread);
1010 init_root_domain_thread (thread, current_thread);
1011 if (domain != mono_get_root_domain ())
1012 set_current_thread_for_domain (domain, thread, current_thread);
1015 if (mono_thread_attach_cb) {
1019 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1022 mono_thread_attach_cb (tid, &tid);
1024 mono_thread_attach_cb (tid, staddr + stsize);
1027 // FIXME: Need a separate callback
1028 mono_profiler_thread_start (tid);
1030 return current_thread;
1034 mono_thread_detach_internal (MonoInternalThread *thread)
1036 g_return_if_fail (thread != NULL);
1038 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1040 thread_cleanup (thread);
1042 SET_CURRENT_OBJECT (NULL);
1043 mono_domain_unset ();
1045 /* Don't need to CloseHandle this thread, even though we took a
1046 * reference in mono_thread_attach (), because the GC will do it
1047 * when the Thread object is finalised.
1052 mono_thread_detach (MonoThread *thread)
1055 mono_thread_detach_internal (thread->internal_thread);
1059 * mono_thread_detach_if_exiting:
1061 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1062 * This should be used at the end of embedding code which calls into managed code, and which
1063 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1066 mono_thread_detach_if_exiting (void)
1068 if (mono_thread_info_is_exiting ()) {
1069 MonoInternalThread *thread;
1071 thread = mono_thread_internal_current ();
1073 mono_thread_detach_internal (thread);
1074 mono_thread_info_detach ();
1082 MonoInternalThread *thread = mono_thread_internal_current ();
1084 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1086 thread_cleanup (thread);
1087 SET_CURRENT_OBJECT (NULL);
1088 mono_domain_unset ();
1090 /* we could add a callback here for embedders to use. */
1091 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1092 exit (mono_environment_exitcode_get ());
1093 mono_thread_info_exit ();
1097 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1099 MonoInternalThread *internal = create_internal_thread ();
1101 internal->state = ThreadState_Unstarted;
1103 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1107 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
1110 StartInfo *start_info;
1111 MonoInternalThread *internal;
1114 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1116 if (!this->internal_thread)
1117 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1118 internal = this->internal_thread;
1120 LOCK_THREAD (internal);
1122 if ((internal->state & ThreadState_Unstarted) == 0) {
1123 UNLOCK_THREAD (internal);
1124 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1128 if ((internal->state & ThreadState_Aborted) != 0) {
1129 UNLOCK_THREAD (internal);
1132 /* This is freed in start_wrapper */
1133 start_info = g_new0 (StartInfo, 1);
1134 start_info->func = NULL;
1135 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1136 start_info->delegate = start;
1137 start_info->obj = this;
1138 g_assert (this->obj.vtable->domain == mono_domain_get ());
1140 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1142 UNLOCK_THREAD (internal);
1146 internal->state &= ~ThreadState_Unstarted;
1148 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1150 UNLOCK_THREAD (internal);
1151 return internal->handle;
1155 * This is called from the finalizer of the internal thread object.
1158 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1160 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1163 * Since threads keep a reference to their thread object while running, by the time this function is called,
1164 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1165 * when thread_cleanup () can be called after this.
1168 CloseHandle (thread);
1170 if (this->synch_cs) {
1171 mono_mutex_t *synch_cs = this->synch_cs;
1172 this->synch_cs = NULL;
1173 mono_mutex_destroy (synch_cs);
1178 void *name = this->name;
1185 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1188 MonoInternalThread *thread = mono_thread_internal_current ();
1190 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1192 mono_thread_current_check_pending_interrupt ();
1195 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1197 MONO_PREPARE_BLOCKING
1198 res = SleepEx(ms,TRUE);
1199 MONO_FINISH_BLOCKING
1201 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1203 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1204 MonoException* exc = mono_thread_execute_interruption (thread);
1206 mono_raise_exception (exc);
1218 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1223 ves_icall_System_Threading_Thread_GetDomainID (void)
1225 return mono_domain_get()->domain_id;
1229 ves_icall_System_Threading_Thread_Yield (void)
1231 return mono_thread_info_yield ();
1235 * mono_thread_get_name:
1237 * Return the name of the thread. NAME_LEN is set to the length of the name.
1238 * Return NULL if the thread has no name. The returned memory is owned by the
1242 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1246 LOCK_THREAD (this_obj);
1248 if (!this_obj->name) {
1252 *name_len = this_obj->name_len;
1253 res = g_new (gunichar2, this_obj->name_len);
1254 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1257 UNLOCK_THREAD (this_obj);
1263 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1267 LOCK_THREAD (this_obj);
1269 if (!this_obj->name)
1272 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1274 UNLOCK_THREAD (this_obj);
1280 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1282 LOCK_THREAD (this_obj);
1284 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1285 UNLOCK_THREAD (this_obj);
1287 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1290 if (this_obj->name) {
1291 g_free (this_obj->name);
1292 this_obj->name_len = 0;
1295 this_obj->name = g_new (gunichar2, mono_string_length (name));
1296 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1297 this_obj->name_len = mono_string_length (name);
1300 this_obj->name = NULL;
1303 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1305 UNLOCK_THREAD (this_obj);
1307 if (this_obj->name && this_obj->tid) {
1308 char *tname = mono_string_to_utf8 (name);
1309 mono_profiler_thread_name (this_obj->tid, tname);
1310 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1316 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1318 mono_thread_set_name_internal (this_obj, name, TRUE);
1322 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
1324 return ThreadPriority_Lowest;
1328 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this, int priority)
1332 /* If the array is already in the requested domain, we just return it,
1333 otherwise we return a copy in that domain. */
1335 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1342 if (mono_object_domain (arr) == domain)
1345 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1346 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1351 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1353 return byte_array_to_domain (arr, mono_get_root_domain ());
1357 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1359 return byte_array_to_domain (arr, mono_domain_get ());
1363 mono_thread_current (void)
1365 MonoDomain *domain = mono_domain_get ();
1366 MonoInternalThread *internal = mono_thread_internal_current ();
1367 MonoThread **current_thread_ptr;
1369 g_assert (internal);
1370 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1372 if (!*current_thread_ptr) {
1373 g_assert (domain != mono_get_root_domain ());
1374 *current_thread_ptr = new_thread_with_internal (domain, internal);
1376 return *current_thread_ptr;
1380 mono_thread_internal_current (void)
1382 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1383 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1388 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this, int ms)
1390 MonoInternalThread *this_obj = this->internal_thread;
1391 HANDLE thread = this_obj->handle;
1392 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1395 mono_thread_current_check_pending_interrupt ();
1397 LOCK_THREAD (this_obj);
1399 if ((this_obj->state & ThreadState_Unstarted) != 0) {
1400 UNLOCK_THREAD (this_obj);
1402 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1406 UNLOCK_THREAD (this_obj);
1411 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1413 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1415 MONO_PREPARE_BLOCKING
1416 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1417 MONO_FINISH_BLOCKING
1419 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1421 if(ret==WAIT_OBJECT_0) {
1422 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1427 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1433 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1441 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1443 MONO_PREPARE_BLOCKING
1445 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1447 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1448 MONO_FINISH_BLOCKING
1450 if (ret != WAIT_IO_COMPLETION)
1453 exc = mono_thread_execute_interruption (thread);
1455 mono_raise_exception (exc);
1460 /* Re-calculate ms according to the time passed */
1461 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1462 if (diff_ms >= ms) {
1466 wait = ms - diff_ms;
1472 /* FIXME: exitContext isnt documented */
1473 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1479 MonoObject *waitHandle;
1480 MonoInternalThread *thread = mono_thread_internal_current ();
1482 /* Do this WaitSleepJoin check before creating objects */
1483 mono_thread_current_check_pending_interrupt ();
1485 /* We fail in managed if the array has more than 64 elements */
1486 numhandles = (guint32)mono_array_length(mono_handles);
1487 handles = g_new0(HANDLE, numhandles);
1489 for(i = 0; i < numhandles; i++) {
1490 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1491 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1498 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1500 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1502 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1506 if(ret==WAIT_FAILED) {
1507 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1509 } else if(ret==WAIT_TIMEOUT) {
1510 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1517 /* FIXME: exitContext isnt documented */
1518 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1520 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1521 uintptr_t numhandles;
1524 MonoObject *waitHandle;
1525 MonoInternalThread *thread = mono_thread_internal_current ();
1527 /* Do this WaitSleepJoin check before creating objects */
1528 mono_thread_current_check_pending_interrupt ();
1530 numhandles = mono_array_length(mono_handles);
1531 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1534 for(i = 0; i < numhandles; i++) {
1535 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1536 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1543 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1545 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1547 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1549 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1552 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1554 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1555 return ret - WAIT_OBJECT_0;
1557 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1558 return ret - WAIT_ABANDONED_0;
1565 /* FIXME: exitContext isnt documented */
1566 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1569 MonoInternalThread *thread = mono_thread_internal_current ();
1571 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1577 mono_thread_current_check_pending_interrupt ();
1579 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1581 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1583 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1585 if(ret==WAIT_FAILED) {
1586 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1588 } else if(ret==WAIT_TIMEOUT) {
1589 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1597 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1600 MonoInternalThread *thread = mono_thread_internal_current ();
1605 mono_thread_current_check_pending_interrupt ();
1607 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1609 MONO_PREPARE_BLOCKING
1610 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1611 MONO_FINISH_BLOCKING
1613 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1615 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1618 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1625 mutex = CreateMutex (NULL, owned, NULL);
1627 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1629 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1637 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1638 return(ReleaseMutex (handle));
1641 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1647 *error = ERROR_SUCCESS;
1649 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1651 *error = GetLastError ();
1658 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1665 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1667 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1668 mono_string_chars (name));
1670 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1678 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1682 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1687 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1691 *error = ERROR_SUCCESS;
1693 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1695 *error = GetLastError ();
1701 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1708 event = CreateEvent (NULL, manual, initial, NULL);
1710 event = CreateEvent (NULL, manual, initial,
1711 mono_string_chars (name));
1713 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1721 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1722 return (SetEvent(handle));
1725 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1726 return (ResetEvent(handle));
1730 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1731 CloseHandle (handle);
1734 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1740 *error = ERROR_SUCCESS;
1742 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1744 *error = GetLastError ();
1750 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1752 return InterlockedIncrement (location);
1755 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1757 #if SIZEOF_VOID_P == 4
1758 if (G_UNLIKELY ((size_t)location & 0x7)) {
1760 mono_interlocked_lock ();
1763 mono_interlocked_unlock ();
1767 return InterlockedIncrement64 (location);
1770 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1772 return InterlockedDecrement(location);
1775 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1777 #if SIZEOF_VOID_P == 4
1778 if (G_UNLIKELY ((size_t)location & 0x7)) {
1780 mono_interlocked_lock ();
1783 mono_interlocked_unlock ();
1787 return InterlockedDecrement64 (location);
1790 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1792 return InterlockedExchange(location, value);
1795 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1798 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1799 mono_gc_wbarrier_generic_nostore (location);
1803 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1805 return InterlockedExchangePointer(location, value);
1808 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1810 IntFloatUnion val, ret;
1813 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1819 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1821 #if SIZEOF_VOID_P == 4
1822 if (G_UNLIKELY ((size_t)location & 0x7)) {
1824 mono_interlocked_lock ();
1827 mono_interlocked_unlock ();
1831 return InterlockedExchange64 (location, value);
1835 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1837 LongDoubleUnion val, ret;
1840 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1845 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1847 return InterlockedCompareExchange(location, value, comparand);
1850 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1852 gint32 r = InterlockedCompareExchange(location, value, comparand);
1853 *success = r == comparand;
1857 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1860 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1861 mono_gc_wbarrier_generic_nostore (location);
1865 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1867 return InterlockedCompareExchangePointer(location, value, comparand);
1870 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1872 IntFloatUnion val, ret, cmp;
1875 cmp.fval = comparand;
1876 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1882 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1884 #if SIZEOF_VOID_P == 8
1885 LongDoubleUnion val, comp, ret;
1888 comp.fval = comparand;
1889 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1895 mono_interlocked_lock ();
1897 if (old == comparand)
1899 mono_interlocked_unlock ();
1906 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1908 #if SIZEOF_VOID_P == 4
1909 if (G_UNLIKELY ((size_t)location & 0x7)) {
1911 mono_interlocked_lock ();
1913 if (old == comparand)
1915 mono_interlocked_unlock ();
1919 return InterlockedCompareExchange64 (location, value, comparand);
1923 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1926 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1927 mono_gc_wbarrier_generic_nostore (location);
1932 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1935 res = InterlockedExchangePointer ((gpointer *)location, value);
1936 mono_gc_wbarrier_generic_nostore (location);
1941 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1943 return InterlockedAdd (location, value);
1947 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1949 #if SIZEOF_VOID_P == 4
1950 if (G_UNLIKELY ((size_t)location & 0x7)) {
1952 mono_interlocked_lock ();
1955 mono_interlocked_unlock ();
1959 return InterlockedAdd64 (location, value);
1963 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1965 #if SIZEOF_VOID_P == 4
1966 if (G_UNLIKELY ((size_t)location & 0x7)) {
1968 mono_interlocked_lock ();
1970 mono_interlocked_unlock ();
1974 return InterlockedRead64 (location);
1978 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1980 mono_memory_barrier ();
1984 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1986 mono_thread_clr_state (this, state);
1988 if (state & ThreadState_Background) {
1989 /* If the thread changes the background mode, the main thread has to
1990 * be notified, since it has to rebuild the list of threads to
1993 SetEvent (background_change_event);
1998 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
2000 mono_thread_set_state (this, state);
2002 if (state & ThreadState_Background) {
2003 /* If the thread changes the background mode, the main thread has to
2004 * be notified, since it has to rebuild the list of threads to
2007 SetEvent (background_change_event);
2012 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2018 state = this->state;
2020 UNLOCK_THREAD (this);
2025 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this)
2027 MonoInternalThread *current;
2029 MonoInternalThread *this_obj = this->internal_thread;
2031 LOCK_THREAD (this_obj);
2033 current = mono_thread_internal_current ();
2035 this_obj->thread_interrupt_requested = TRUE;
2036 throw = current != this_obj && (this_obj->state & ThreadState_WaitSleepJoin);
2038 UNLOCK_THREAD (this_obj);
2041 abort_thread_internal (this_obj, TRUE, FALSE);
2045 void mono_thread_current_check_pending_interrupt ()
2047 MonoInternalThread *thread = mono_thread_internal_current ();
2048 gboolean throw = FALSE;
2050 LOCK_THREAD (thread);
2052 if (thread->thread_interrupt_requested) {
2054 thread->thread_interrupt_requested = FALSE;
2057 UNLOCK_THREAD (thread);
2060 mono_raise_exception (mono_get_exception_thread_interrupted ());
2065 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2067 LOCK_THREAD (thread);
2069 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2070 (thread->state & ThreadState_StopRequested) != 0 ||
2071 (thread->state & ThreadState_Stopped) != 0)
2073 UNLOCK_THREAD (thread);
2077 if ((thread->state & ThreadState_Unstarted) != 0) {
2078 thread->state |= ThreadState_Aborted;
2079 UNLOCK_THREAD (thread);
2083 thread->state |= ThreadState_AbortRequested;
2084 if (thread->abort_state_handle)
2085 mono_gchandle_free (thread->abort_state_handle);
2087 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2088 g_assert (thread->abort_state_handle);
2090 thread->abort_state_handle = 0;
2092 thread->abort_exc = NULL;
2094 UNLOCK_THREAD (thread);
2096 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2098 /* During shutdown, we can't wait for other threads */
2100 /* Make sure the thread is awake */
2101 mono_thread_resume (thread);
2103 abort_thread_internal (thread, TRUE, TRUE);
2107 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this)
2109 MonoInternalThread *thread = mono_thread_internal_current ();
2110 gboolean was_aborting;
2112 LOCK_THREAD (thread);
2113 was_aborting = thread->state & ThreadState_AbortRequested;
2114 thread->state &= ~ThreadState_AbortRequested;
2115 UNLOCK_THREAD (thread);
2117 if (!was_aborting) {
2118 const char *msg = "Unable to reset abort because no abort was requested";
2119 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2122 thread->abort_exc = NULL;
2123 if (thread->abort_state_handle) {
2124 mono_gchandle_free (thread->abort_state_handle);
2125 /* This is actually not necessary - the handle
2126 only counts if the exception is set */
2127 thread->abort_state_handle = 0;
2132 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2134 LOCK_THREAD (thread);
2136 thread->state &= ~ThreadState_AbortRequested;
2138 if (thread->abort_exc) {
2139 thread->abort_exc = NULL;
2140 if (thread->abort_state_handle) {
2141 mono_gchandle_free (thread->abort_state_handle);
2142 /* This is actually not necessary - the handle
2143 only counts if the exception is set */
2144 thread->abort_state_handle = 0;
2148 UNLOCK_THREAD (thread);
2152 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2154 MonoInternalThread *thread = this->internal_thread;
2155 MonoObject *state, *deserialized = NULL, *exc;
2158 if (!thread->abort_state_handle)
2161 state = mono_gchandle_get_target (thread->abort_state_handle);
2164 domain = mono_domain_get ();
2165 if (mono_object_domain (state) == domain)
2168 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2170 if (!deserialized) {
2171 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2173 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2174 mono_set_pending_exception (invalid_op_exc);
2178 return deserialized;
2182 mono_thread_suspend (MonoInternalThread *thread)
2184 LOCK_THREAD (thread);
2186 if ((thread->state & ThreadState_Unstarted) != 0 ||
2187 (thread->state & ThreadState_Aborted) != 0 ||
2188 (thread->state & ThreadState_Stopped) != 0)
2190 UNLOCK_THREAD (thread);
2194 if ((thread->state & ThreadState_Suspended) != 0 ||
2195 (thread->state & ThreadState_SuspendRequested) != 0 ||
2196 (thread->state & ThreadState_StopRequested) != 0)
2198 UNLOCK_THREAD (thread);
2202 thread->state |= ThreadState_SuspendRequested;
2204 UNLOCK_THREAD (thread);
2206 suspend_thread_internal (thread, FALSE);
2211 ves_icall_System_Threading_Thread_Suspend (MonoThread *this)
2213 if (!mono_thread_suspend (this->internal_thread)) {
2214 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2220 mono_thread_resume (MonoInternalThread *thread)
2222 LOCK_THREAD (thread);
2224 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2225 thread->state &= ~ThreadState_SuspendRequested;
2226 UNLOCK_THREAD (thread);
2230 if ((thread->state & ThreadState_Suspended) == 0 ||
2231 (thread->state & ThreadState_Unstarted) != 0 ||
2232 (thread->state & ThreadState_Aborted) != 0 ||
2233 (thread->state & ThreadState_Stopped) != 0)
2235 UNLOCK_THREAD (thread);
2239 return resume_thread_internal (thread);
2243 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2245 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2246 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2252 mono_threads_is_critical_method (MonoMethod *method)
2254 switch (method->wrapper_type) {
2255 case MONO_WRAPPER_RUNTIME_INVOKE:
2256 case MONO_WRAPPER_XDOMAIN_INVOKE:
2257 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2264 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2269 if (mono_threads_is_critical_method (m)) {
2270 *((gboolean*)data) = TRUE;
2277 is_running_protected_wrapper (void)
2279 gboolean found = FALSE;
2280 mono_stack_walk (find_wrapper, &found);
2284 void mono_thread_internal_stop (MonoInternalThread *thread)
2286 LOCK_THREAD (thread);
2288 if ((thread->state & ThreadState_StopRequested) != 0 ||
2289 (thread->state & ThreadState_Stopped) != 0)
2291 UNLOCK_THREAD (thread);
2295 /* Make sure the thread is awake */
2296 mono_thread_resume (thread);
2298 thread->state |= ThreadState_StopRequested;
2299 thread->state &= ~ThreadState_AbortRequested;
2301 UNLOCK_THREAD (thread);
2303 abort_thread_internal (thread, TRUE, TRUE);
2306 void mono_thread_stop (MonoThread *thread)
2308 mono_thread_internal_stop (thread->internal_thread);
2312 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2315 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2320 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2323 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2328 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2331 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2336 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2339 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2344 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2347 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2348 return (void *) tmp;
2352 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2354 volatile MonoObject *tmp;
2355 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2356 return (MonoObject *) tmp;
2360 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2363 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2368 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2371 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2376 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2378 return InterlockedRead8 (ptr);
2382 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2384 return InterlockedRead16 (ptr);
2388 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2390 return InterlockedRead (ptr);
2394 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2396 #if SIZEOF_VOID_P == 4
2397 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2399 mono_interlocked_lock ();
2400 val = *(gint64*)ptr;
2401 mono_interlocked_unlock ();
2405 return InterlockedRead64 (ptr);
2409 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2411 return InterlockedReadPointer (ptr);
2415 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2419 #if SIZEOF_VOID_P == 4
2420 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2422 mono_interlocked_lock ();
2423 val = *(double*)ptr;
2424 mono_interlocked_unlock ();
2429 u.ival = InterlockedRead64 (ptr);
2435 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2439 u.ival = InterlockedRead (ptr);
2445 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2447 return InterlockedReadPointer (ptr);
2451 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2453 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2457 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2459 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2463 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2465 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2469 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2471 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2475 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2477 mono_atomic_store_release ((volatile void **) ptr, value);
2481 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2483 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2487 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2489 mono_atomic_store_release ((volatile double *) ptr, value);
2493 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2495 mono_atomic_store_release ((volatile float *) ptr, value);
2499 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2501 InterlockedWrite8 (ptr, value);
2505 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2507 InterlockedWrite16 (ptr, value);
2511 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2513 InterlockedWrite (ptr, value);
2517 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2519 #if SIZEOF_VOID_P == 4
2520 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2521 mono_interlocked_lock ();
2522 *(gint64*)ptr = value;
2523 mono_interlocked_unlock ();
2528 InterlockedWrite64 (ptr, value);
2532 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2534 InterlockedWritePointer (ptr, value);
2538 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2542 #if SIZEOF_VOID_P == 4
2543 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2544 mono_interlocked_lock ();
2545 *(double*)ptr = value;
2546 mono_interlocked_unlock ();
2553 InterlockedWrite64 (ptr, u.ival);
2557 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2563 InterlockedWrite (ptr, u.ival);
2567 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2569 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2573 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2575 mono_threads_lock ();
2577 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2580 contexts = g_hash_table_new (NULL, NULL);
2582 context_adjust_static_data (ctx);
2583 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2584 g_hash_table_insert (contexts, gch, gch);
2586 mono_threads_unlock ();
2590 mono_thread_init_tls (void)
2592 MONO_FAST_TLS_INIT (tls_current_object);
2593 mono_native_tls_alloc (¤t_object_key, NULL);
2596 void mono_thread_init (MonoThreadStartCB start_cb,
2597 MonoThreadAttachCB attach_cb)
2599 mono_mutex_init_recursive(&threads_mutex);
2600 mono_mutex_init_recursive(&interlocked_mutex);
2601 mono_mutex_init_recursive(&joinable_threads_mutex);
2603 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2604 g_assert(background_change_event != NULL);
2606 mono_init_static_data_info (&thread_static_info);
2607 mono_init_static_data_info (&context_static_info);
2609 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2611 mono_thread_start_cb = start_cb;
2612 mono_thread_attach_cb = attach_cb;
2614 /* Get a pseudo handle to the current process. This is just a
2615 * kludge so that wapi can build a process handle if needed.
2616 * As a pseudo handle is returned, we don't need to clean
2619 GetCurrentProcess ();
2622 void mono_thread_cleanup (void)
2624 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2625 MonoThreadInfo *info;
2627 /* The main thread must abandon any held mutexes (particularly
2628 * important for named mutexes as they are shared across
2629 * processes, see bug 74680.) This will happen when the
2630 * thread exits, but if it's not running in a subthread it
2631 * won't exit in time.
2633 info = mono_thread_info_current ();
2634 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2638 /* This stuff needs more testing, it seems one of these
2639 * critical sections can be locked when mono_thread_cleanup is
2642 mono_mutex_destroy (&threads_mutex);
2643 mono_mutex_destroy (&interlocked_mutex);
2644 mono_mutex_destroy (&delayed_free_table_mutex);
2645 mono_mutex_destroy (&small_id_mutex);
2646 CloseHandle (background_change_event);
2649 mono_native_tls_free (current_object_key);
2653 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2655 mono_thread_cleanup_fn = func;
2659 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2661 thread->internal_thread->manage_callback = func;
2664 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2666 mono_thread_notify_pending_exc_fn = func;
2670 static void print_tids (gpointer key, gpointer value, gpointer user)
2672 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2673 * sizeof(uint) and a cast to uint would overflow
2675 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2676 * print this as a pointer.
2678 g_message ("Waiting for: %p", key);
2683 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2684 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2688 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2692 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2694 MONO_PREPARE_BLOCKING
2695 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2696 MONO_FINISH_BLOCKING
2698 if(ret==WAIT_FAILED) {
2699 /* See the comment in build_wait_tids() */
2700 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2704 for(i=0; i<wait->num; i++)
2705 CloseHandle (wait->handles[i]);
2707 if (ret == WAIT_TIMEOUT)
2710 for(i=0; i<wait->num; i++) {
2711 gsize tid = wait->threads[i]->tid;
2714 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2715 * it can still run io-layer etc. code. So wait for it to really exit.
2716 * FIXME: This won't join threads which are not in the joinable_hash yet.
2718 mono_thread_join ((gpointer)tid);
2720 mono_threads_lock ();
2721 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2722 /* This thread must have been killed, because
2723 * it hasn't cleaned itself up. (It's just
2724 * possible that the thread exited before the
2725 * parent thread had a chance to store the
2726 * handle, and now there is another pointer to
2727 * the already-exited thread stored. In this
2728 * case, we'll just get two
2729 * mono_profiler_thread_end() calls for the
2733 mono_threads_unlock ();
2734 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2735 thread_cleanup (wait->threads[i]);
2737 mono_threads_unlock ();
2742 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2744 guint32 i, ret, count;
2746 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2748 /* Add the thread state change event, so it wakes up if a thread changes
2749 * to background mode.
2752 if (count < MAXIMUM_WAIT_OBJECTS) {
2753 wait->handles [count] = background_change_event;
2757 MONO_PREPARE_BLOCKING
2758 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2759 MONO_FINISH_BLOCKING
2761 if(ret==WAIT_FAILED) {
2762 /* See the comment in build_wait_tids() */
2763 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2767 for(i=0; i<wait->num; i++)
2768 CloseHandle (wait->handles[i]);
2770 if (ret == WAIT_TIMEOUT)
2773 if (ret < wait->num) {
2774 gsize tid = wait->threads[ret]->tid;
2775 mono_threads_lock ();
2776 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2777 /* See comment in wait_for_tids about thread cleanup */
2778 mono_threads_unlock ();
2779 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2780 thread_cleanup (wait->threads [ret]);
2782 mono_threads_unlock ();
2786 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2788 struct wait_data *wait=(struct wait_data *)user;
2790 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2792 MonoInternalThread *thread=(MonoInternalThread *)value;
2794 /* Ignore background threads, we abort them later */
2795 /* Do not lock here since it is not needed and the caller holds threads_lock */
2796 if (thread->state & ThreadState_Background) {
2797 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2798 return; /* just leave, ignore */
2801 if (mono_gc_is_finalizer_internal_thread (thread)) {
2802 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2806 if (thread == mono_thread_internal_current ()) {
2807 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2811 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2812 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2816 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2817 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2821 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2822 if (handle == NULL) {
2823 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2827 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2828 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2829 wait->handles[wait->num]=handle;
2830 wait->threads[wait->num]=thread;
2833 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2835 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2840 /* Just ignore the rest, we can't do anything with
2847 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2849 struct wait_data *wait=(struct wait_data *)user;
2850 gsize self = GetCurrentThreadId ();
2851 MonoInternalThread *thread = value;
2854 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2857 /* The finalizer thread is not a background thread */
2858 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2859 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2861 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2865 /* printf ("A: %d\n", wait->num); */
2866 wait->handles[wait->num]=thread->handle;
2867 wait->threads[wait->num]=thread;
2870 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2871 mono_thread_internal_stop (thread);
2875 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2879 * mono_threads_set_shutting_down:
2881 * Is called by a thread that wants to shut down Mono. If the runtime is already
2882 * shutting down, the calling thread is suspended/stopped, and this function never
2886 mono_threads_set_shutting_down (void)
2888 MonoInternalThread *current_thread = mono_thread_internal_current ();
2890 mono_threads_lock ();
2892 if (shutting_down) {
2893 mono_threads_unlock ();
2895 /* Make sure we're properly suspended/stopped */
2897 LOCK_THREAD (current_thread);
2899 if ((current_thread->state & ThreadState_SuspendRequested) ||
2900 (current_thread->state & ThreadState_AbortRequested) ||
2901 (current_thread->state & ThreadState_StopRequested)) {
2902 UNLOCK_THREAD (current_thread);
2903 mono_thread_execute_interruption (current_thread);
2905 current_thread->state |= ThreadState_Stopped;
2906 UNLOCK_THREAD (current_thread);
2909 /*since we're killing the thread, unset the current domain.*/
2910 mono_domain_unset ();
2912 /* Wake up other threads potentially waiting for us */
2913 mono_thread_info_exit ();
2915 shutting_down = TRUE;
2917 /* Not really a background state change, but this will
2918 * interrupt the main thread if it is waiting for all
2919 * the other threads.
2921 SetEvent (background_change_event);
2923 mono_threads_unlock ();
2927 void mono_thread_manage (void)
2929 struct wait_data wait_data;
2930 struct wait_data *wait = &wait_data;
2932 memset (wait, 0, sizeof (struct wait_data));
2933 /* join each thread that's still running */
2934 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2936 mono_threads_lock ();
2938 THREAD_DEBUG (g_message("%s: No threads", __func__));
2939 mono_threads_unlock ();
2942 mono_threads_unlock ();
2945 mono_threads_lock ();
2946 if (shutting_down) {
2947 /* somebody else is shutting down */
2948 mono_threads_unlock ();
2951 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2952 mono_g_hash_table_foreach (threads, print_tids, NULL));
2954 ResetEvent (background_change_event);
2956 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2957 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2958 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2959 mono_threads_unlock ();
2961 /* Something to wait for */
2962 wait_for_tids_or_state_change (wait, INFINITE);
2964 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2965 } while(wait->num>0);
2967 /* Mono is shutting down, so just wait for the end */
2968 if (!mono_runtime_try_shutdown ()) {
2969 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2970 mono_thread_suspend (mono_thread_internal_current ());
2971 mono_thread_execute_interruption (mono_thread_internal_current ());
2975 * Remove everything but the finalizer thread and self.
2976 * Also abort all the background threads
2979 mono_threads_lock ();
2982 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2983 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2984 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2986 mono_threads_unlock ();
2988 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2990 /* Something to wait for */
2991 wait_for_tids (wait, INFINITE);
2993 } while (wait->num > 0);
2996 * give the subthreads a chance to really quit (this is mainly needed
2997 * to get correct user and system times from getrusage/wait/time(1)).
2998 * This could be removed if we avoid pthread_detach() and use pthread_join().
3000 mono_thread_info_yield ();
3003 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3005 MonoInternalThread *thread=(MonoInternalThread *)value;
3007 if(thread->tid != (gsize)user) {
3008 /*TerminateThread (thread->handle, -1);*/
3012 void mono_thread_abort_all_other_threads (void)
3014 gsize self = GetCurrentThreadId ();
3016 mono_threads_lock ();
3017 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3018 mono_g_hash_table_size (threads));
3019 mono_g_hash_table_foreach (threads, print_tids, NULL));
3021 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3023 mono_threads_unlock ();
3027 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3029 MonoInternalThread *thread = (MonoInternalThread*)value;
3030 struct wait_data *wait = (struct wait_data*)user_data;
3034 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3036 * This needs no locking.
3038 if ((thread->state & ThreadState_Suspended) != 0 ||
3039 (thread->state & ThreadState_Stopped) != 0)
3042 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3043 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3047 wait->handles [wait->num] = handle;
3048 wait->threads [wait->num] = thread;
3054 * mono_thread_suspend_all_other_threads:
3056 * Suspend all managed threads except the finalizer thread and this thread. It is
3057 * not possible to resume them later.
3059 void mono_thread_suspend_all_other_threads (void)
3061 struct wait_data wait_data;
3062 struct wait_data *wait = &wait_data;
3064 gsize self = GetCurrentThreadId ();
3065 guint32 eventidx = 0;
3066 gboolean starting, finished;
3068 memset (wait, 0, sizeof (struct wait_data));
3070 * The other threads could be in an arbitrary state at this point, i.e.
3071 * they could be starting up, shutting down etc. This means that there could be
3072 * threads which are not even in the threads hash table yet.
3076 * First we set a barrier which will be checked by all threads before they
3077 * are added to the threads hash table, and they will exit if the flag is set.
3078 * This ensures that no threads could be added to the hash later.
3079 * We will use shutting_down as the barrier for now.
3081 g_assert (shutting_down);
3084 * We make multiple calls to WaitForMultipleObjects since:
3085 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3086 * - some threads could exit without becoming suspended
3091 * Make a copy of the hashtable since we can't do anything with
3092 * threads while threads_mutex is held.
3095 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3096 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3097 mono_threads_lock ();
3098 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3099 mono_threads_unlock ();
3102 /* Get the suspended events that we'll be waiting for */
3103 for (i = 0; i < wait->num; ++i) {
3104 MonoInternalThread *thread = wait->threads [i];
3106 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3107 //CloseHandle (wait->handles [i]);
3108 wait->threads [i] = NULL; /* ignore this thread in next loop */
3112 LOCK_THREAD (thread);
3114 if ((thread->state & ThreadState_Suspended) != 0 ||
3115 (thread->state & ThreadState_StopRequested) != 0 ||
3116 (thread->state & ThreadState_Stopped) != 0) {
3117 UNLOCK_THREAD (thread);
3118 CloseHandle (wait->handles [i]);
3119 wait->threads [i] = NULL; /* ignore this thread in next loop */
3125 /* Convert abort requests into suspend requests */
3126 if ((thread->state & ThreadState_AbortRequested) != 0)
3127 thread->state &= ~ThreadState_AbortRequested;
3129 thread->state |= ThreadState_SuspendRequested;
3131 UNLOCK_THREAD (thread);
3133 /* Signal the thread to suspend */
3134 suspend_thread_internal (thread, TRUE);
3136 if (eventidx <= 0) {
3138 * If there are threads which are starting up, we wait until they
3139 * are suspended when they try to register in the threads hash.
3140 * This is guaranteed to finish, since the threads which can create new
3141 * threads get suspended after a while.
3142 * FIXME: The finalizer thread can still create new threads.
3144 mono_threads_lock ();
3145 if (threads_starting_up)
3146 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3149 mono_threads_unlock ();
3158 static gboolean thread_dump_requested;
3160 static G_GNUC_UNUSED gboolean
3161 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3163 GString *p = (GString*)data;
3164 MonoMethod *method = NULL;
3166 method = mono_jit_info_get_method (frame->ji);
3169 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3170 g_string_append_printf (p, " %s\n", location);
3173 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3178 static SuspendThreadResult
3179 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3181 MonoInternalThread *thread = ud;
3182 GString* text = g_string_new (0);
3184 GError *error = NULL;
3187 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3189 g_string_append_printf (text, "\n\"%s\"", name);
3192 else if (thread->threadpool_thread)
3193 g_string_append (text, "\n\"<threadpool thread>\"");
3195 g_string_append (text, "\n\"<unnamed thread>\"");
3198 /* This no longer works with remote unwinding */
3200 wapi_desc = wapi_current_thread_desc ();
3201 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3206 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);
3208 fprintf (stdout, "%s", text->str);
3210 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3211 OutputDebugStringA(text->str);
3214 g_string_free (text, TRUE);
3216 return MonoResumeThread;
3220 dump_thread (gpointer key, gpointer value, gpointer user)
3222 MonoInternalThread *thread = (MonoInternalThread *)value;
3224 if (thread == mono_thread_internal_current ())
3228 FIXME This still can hang if we stop a thread during malloc.
3229 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3230 that takes a callback and runs it with the target suspended.
3231 We probably should loop a bit around trying to get it to either managed code
3234 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
3238 mono_threads_perform_thread_dump (void)
3240 if (!thread_dump_requested)
3243 printf ("Full thread dump:\n");
3245 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3246 something needs then in the process.
3248 mono_loader_lock ();
3249 mono_domain_lock (mono_get_root_domain ());
3251 mono_threads_lock ();
3252 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3253 mono_threads_unlock ();
3255 mono_domain_unlock (mono_get_root_domain ());
3256 mono_loader_unlock ();
3258 thread_dump_requested = FALSE;
3262 * mono_threads_request_thread_dump:
3264 * Ask all threads except the current to print their stacktrace to stdout.
3267 mono_threads_request_thread_dump (void)
3269 /*The new thread dump code runs out of the finalizer thread. */
3270 thread_dump_requested = TRUE;
3271 mono_gc_finalize_notify ();
3276 gint allocated; /* +1 so that refs [allocated] == NULL */
3280 typedef struct ref_stack RefStack;
3283 ref_stack_new (gint initial_size)
3287 initial_size = MAX (initial_size, 16) + 1;
3288 rs = g_new0 (RefStack, 1);
3289 rs->refs = g_new0 (gpointer, initial_size);
3290 rs->allocated = initial_size;
3295 ref_stack_destroy (gpointer ptr)
3306 ref_stack_push (RefStack *rs, gpointer ptr)
3308 g_assert (rs != NULL);
3310 if (rs->bottom >= rs->allocated) {
3311 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3312 rs->allocated <<= 1;
3313 rs->refs [rs->allocated] = NULL;
3315 rs->refs [rs->bottom++] = ptr;
3319 ref_stack_pop (RefStack *rs)
3321 if (rs == NULL || rs->bottom == 0)
3325 rs->refs [rs->bottom] = NULL;
3329 ref_stack_find (RefStack *rs, gpointer ptr)
3336 for (refs = rs->refs; refs && *refs; refs++) {
3344 * mono_thread_push_appdomain_ref:
3346 * Register that the current thread may have references to objects in domain
3347 * @domain on its stack. Each call to this function should be paired with a
3348 * call to pop_appdomain_ref.
3351 mono_thread_push_appdomain_ref (MonoDomain *domain)
3353 MonoInternalThread *thread = mono_thread_internal_current ();
3356 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3357 SPIN_LOCK (thread->lock_thread_id);
3358 if (thread->appdomain_refs == NULL)
3359 thread->appdomain_refs = ref_stack_new (16);
3360 ref_stack_push (thread->appdomain_refs, domain);
3361 SPIN_UNLOCK (thread->lock_thread_id);
3366 mono_thread_pop_appdomain_ref (void)
3368 MonoInternalThread *thread = mono_thread_internal_current ();
3371 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3372 SPIN_LOCK (thread->lock_thread_id);
3373 ref_stack_pop (thread->appdomain_refs);
3374 SPIN_UNLOCK (thread->lock_thread_id);
3379 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3382 SPIN_LOCK (thread->lock_thread_id);
3383 res = ref_stack_find (thread->appdomain_refs, domain);
3384 SPIN_UNLOCK (thread->lock_thread_id);
3389 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3391 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3394 typedef struct abort_appdomain_data {
3395 struct wait_data wait;
3397 } abort_appdomain_data;
3400 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3402 MonoInternalThread *thread = (MonoInternalThread*)value;
3403 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3404 MonoDomain *domain = data->domain;
3406 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3407 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3409 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3410 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3413 data->wait.handles [data->wait.num] = handle;
3414 data->wait.threads [data->wait.num] = thread;
3417 /* Just ignore the rest, we can't do anything with
3425 * mono_threads_abort_appdomain_threads:
3427 * Abort threads which has references to the given appdomain.
3430 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3432 #ifdef __native_client__
3436 abort_appdomain_data user_data;
3438 int orig_timeout = timeout;
3441 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3443 start_time = mono_msec_ticks ();
3445 mono_threads_lock ();
3447 user_data.domain = domain;
3448 user_data.wait.num = 0;
3449 /* This shouldn't take any locks */
3450 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3451 mono_threads_unlock ();
3453 if (user_data.wait.num > 0) {
3454 /* Abort the threads outside the threads lock */
3455 for (i = 0; i < user_data.wait.num; ++i)
3456 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3459 * We should wait for the threads either to abort, or to leave the
3460 * domain. We can't do the latter, so we wait with a timeout.
3462 wait_for_tids (&user_data.wait, 100);
3465 /* Update remaining time */
3466 timeout -= mono_msec_ticks () - start_time;
3467 start_time = mono_msec_ticks ();
3469 if (orig_timeout != -1 && timeout < 0)
3472 while (user_data.wait.num > 0);
3474 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3480 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3482 MonoInternalThread *thread = (MonoInternalThread*)value;
3483 MonoDomain *domain = (MonoDomain*)user_data;
3486 /* No locking needed here */
3487 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3489 if (thread->cached_culture_info) {
3490 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3491 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3492 if (obj && obj->vtable->domain == domain)
3493 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3499 * mono_threads_clear_cached_culture:
3501 * Clear the cached_current_culture from all threads if it is in the
3505 mono_threads_clear_cached_culture (MonoDomain *domain)
3507 mono_threads_lock ();
3508 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3509 mono_threads_unlock ();
3513 * mono_thread_get_undeniable_exception:
3515 * Return an exception which needs to be raised when leaving a catch clause.
3516 * This is used for undeniable exception propagation.
3519 mono_thread_get_undeniable_exception (void)
3521 MonoInternalThread *thread = mono_thread_internal_current ();
3523 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3525 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3526 * exception if the thread no longer references a dying appdomain.
3528 thread->abort_exc->trace_ips = NULL;
3529 thread->abort_exc->stack_trace = NULL;
3530 return thread->abort_exc;
3536 #if MONO_SMALL_CONFIG
3537 #define NUM_STATIC_DATA_IDX 4
3538 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3542 #define NUM_STATIC_DATA_IDX 8
3543 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3544 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3548 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3549 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3552 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3554 gpointer *static_data = addr;
3556 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3557 void **ptr = static_data [i];
3562 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3563 void **p = ptr + idx;
3566 mark_func ((MonoObject**)p, gc_data);
3572 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3574 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3578 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3580 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3584 * mono_alloc_static_data
3586 * Allocate memory blocks for storing threads or context static data
3589 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3591 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3594 gpointer* static_data = *static_data_ptr;
3596 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3597 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3599 if (mono_gc_user_markers_supported ()) {
3600 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3601 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3603 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3604 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3607 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc);
3608 *static_data_ptr = static_data;
3609 static_data [0] = static_data;
3612 for (i = 1; i <= idx; ++i) {
3613 if (static_data [i])
3616 if (mono_gc_user_markers_supported ())
3617 static_data [i] = g_malloc0 (static_data_size [i]);
3619 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL);
3624 mono_free_static_data (gpointer* static_data)
3627 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3628 gpointer p = static_data [i];
3632 * At this point, the static data pointer array is still registered with the
3633 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3634 * data. Freeing the individual arrays without first nulling their slots
3635 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3636 * such an already freed array. See bug #13813.
3638 static_data [i] = NULL;
3639 mono_memory_write_barrier ();
3640 if (mono_gc_user_markers_supported ())
3643 mono_gc_free_fixed (p);
3645 mono_gc_free_fixed (static_data);
3649 * mono_init_static_data_info
3651 * Initializes static data counters
3653 static void mono_init_static_data_info (StaticDataInfo *static_data)
3655 static_data->idx = 0;
3656 static_data->offset = 0;
3657 static_data->freelist = NULL;
3661 * mono_alloc_static_data_slot
3663 * Generates an offset for static data. static_data contains the counters
3664 * used to generate it.
3667 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3669 if (!static_data->idx && !static_data->offset) {
3671 * we use the first chunk of the first allocation also as
3672 * an array for the rest of the data
3674 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3676 static_data->offset += align - 1;
3677 static_data->offset &= ~(align - 1);
3678 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3679 static_data->idx ++;
3680 g_assert (size <= static_data_size [static_data->idx]);
3681 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3682 static_data->offset = 0;
3684 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3685 static_data->offset += size;
3690 * ensure thread static fields already allocated are valid for thread
3691 * This function is called when a thread is created or on thread attach.
3694 thread_adjust_static_data (MonoInternalThread *thread)
3696 mono_threads_lock ();
3697 if (thread_static_info.offset || thread_static_info.idx > 0) {
3698 /* get the current allocated size */
3699 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3700 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3702 mono_threads_unlock ();
3706 * LOCKING: requires that threads_mutex is held
3709 context_adjust_static_data (MonoAppContext *ctx)
3711 if (context_static_info.offset || context_static_info.idx > 0) {
3712 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3713 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3718 * LOCKING: requires that threads_mutex is held
3721 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3723 MonoInternalThread *thread = value;
3724 guint32 offset = GPOINTER_TO_UINT (user);
3726 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3730 * LOCKING: requires that threads_mutex is held
3733 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3735 uint32_t gch = GPOINTER_TO_INT (key);
3736 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3739 mono_gchandle_free (gch);
3740 return TRUE; // Remove this key/value pair
3743 guint32 offset = GPOINTER_TO_UINT (user);
3744 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3746 return FALSE; // Don't remove it
3749 static StaticDataFreeList*
3750 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3752 StaticDataFreeList* prev = NULL;
3753 StaticDataFreeList* tmp = static_data->freelist;
3755 if (tmp->size == size) {
3757 prev->next = tmp->next;
3759 static_data->freelist = tmp->next;
3768 #if SIZEOF_VOID_P == 4
3775 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3777 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3779 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3780 MonoBitSet *rb = sets [idx];
3781 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3782 offset /= sizeof (uintptr_t);
3783 /* offset is now the bitmap offset */
3784 for (int i = 0; i < numbits; ++i) {
3785 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3786 mono_bitset_set_fast (rb, offset + i);
3791 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3793 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3794 MonoBitSet *rb = sets [idx];
3795 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3796 offset /= sizeof (uintptr_t);
3797 /* offset is now the bitmap offset */
3798 for (int i = 0; i < size / sizeof (uintptr_t); i++)
3799 mono_bitset_clear_fast (rb, offset + i);
3803 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3805 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3807 StaticDataInfo *info;
3810 if (static_type == SPECIAL_STATIC_THREAD) {
3811 info = &thread_static_info;
3812 sets = thread_reference_bitmaps;
3814 info = &context_static_info;
3815 sets = context_reference_bitmaps;
3818 mono_threads_lock ();
3820 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3824 offset = item->offset;
3827 offset = mono_alloc_static_data_slot (info, size, align);
3830 update_reference_bitmap (sets, offset, bitmap, numbits);
3832 if (static_type == SPECIAL_STATIC_THREAD) {
3833 /* This can be called during startup */
3834 if (threads != NULL)
3835 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3837 if (contexts != NULL)
3838 g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3840 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3843 mono_threads_unlock ();
3849 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3851 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3853 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3854 return get_thread_static_data (thread, offset);
3856 return get_context_static_data (thread->current_appcontext, offset);
3861 mono_get_special_static_data (guint32 offset)
3863 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3872 * LOCKING: requires that threads_mutex is held
3875 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3877 MonoInternalThread *thread = value;
3878 OffsetSize *data = user;
3879 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3880 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3883 if (!thread->static_data || !thread->static_data [idx])
3885 ptr = ((char*) thread->static_data [idx]) + off;
3886 mono_gc_bzero_atomic (ptr, data->size);
3890 * LOCKING: requires that threads_mutex is held
3893 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3895 uint32_t gch = GPOINTER_TO_INT (key);
3896 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3899 mono_gchandle_free (gch);
3900 return TRUE; // Remove this key/value pair
3903 OffsetSize *data = user;
3904 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3905 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3908 if (!ctx->static_data || !ctx->static_data [idx])
3909 return FALSE; // Don't remove this key/value pair
3911 ptr = ((char*) ctx->static_data [idx]) + off;
3912 mono_gc_bzero_atomic (ptr, data->size);
3914 return FALSE; // Don't remove this key/value pair
3918 do_free_special_slot (guint32 offset, guint32 size)
3920 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3922 StaticDataInfo *info;
3924 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3925 info = &thread_static_info;
3926 sets = thread_reference_bitmaps;
3928 info = &context_static_info;
3929 sets = context_reference_bitmaps;
3932 guint32 data_offset = offset;
3933 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
3934 OffsetSize data = { data_offset, size };
3936 clear_reference_bitmap (sets, data.offset, data.size);
3938 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3939 if (threads != NULL)
3940 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3942 if (contexts != NULL)
3943 g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
3946 if (!mono_runtime_is_shutting_down ()) {
3947 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
3949 item->offset = offset;
3952 item->next = info->freelist;
3953 info->freelist = item;
3958 do_free_special (gpointer key, gpointer value, gpointer data)
3960 MonoClassField *field = key;
3961 guint32 offset = GPOINTER_TO_UINT (value);
3964 size = mono_type_size (field->type, &align);
3965 do_free_special_slot (offset, size);
3969 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3971 mono_threads_lock ();
3973 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3975 mono_threads_unlock ();
3979 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3981 /* Only ever called for ThreadLocal instances */
3982 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
3984 mono_threads_lock ();
3985 do_free_special_slot (offset, size);
3986 mono_threads_unlock ();
3990 static void CALLBACK dummy_apc (ULONG_PTR param)
3996 * mono_thread_execute_interruption
3998 * Performs the operation that the requested thread state requires (abort,
4001 static MonoException*
4002 mono_thread_execute_interruption (MonoInternalThread *thread)
4004 LOCK_THREAD (thread);
4006 /* MonoThread::interruption_requested can only be changed with atomics */
4007 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4008 /* this will consume pending APC calls */
4010 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4012 InterlockedDecrement (&thread_interruption_requested);
4013 /* Clear the interrupted flag of the thread so it can wait again */
4014 mono_thread_info_clear_interruption ();
4017 if ((thread->state & ThreadState_AbortRequested) != 0) {
4018 UNLOCK_THREAD (thread);
4019 if (thread->abort_exc == NULL) {
4021 * This might be racy, but it has to be called outside the lock
4022 * since it calls managed code.
4024 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4026 return thread->abort_exc;
4028 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4029 self_suspend_internal (thread);
4032 else if ((thread->state & ThreadState_StopRequested) != 0) {
4033 /* FIXME: do this through the JIT? */
4035 UNLOCK_THREAD (thread);
4037 mono_thread_exit ();
4039 } else if (thread->pending_exception) {
4042 exc = thread->pending_exception;
4043 thread->pending_exception = NULL;
4045 UNLOCK_THREAD (thread);
4047 } else if (thread->thread_interrupt_requested) {
4049 thread->thread_interrupt_requested = FALSE;
4050 UNLOCK_THREAD (thread);
4052 return(mono_get_exception_thread_interrupted ());
4055 UNLOCK_THREAD (thread);
4061 * mono_thread_request_interruption
4063 * A signal handler can call this method to request the interruption of a
4064 * thread. The result of the interruption will depend on the current state of
4065 * the thread. If the result is an exception that needs to be throw, it is
4066 * provided as return value.
4069 mono_thread_request_interruption (gboolean running_managed)
4071 MonoInternalThread *thread = mono_thread_internal_current ();
4073 /* The thread may already be stopping */
4078 if (thread->interrupt_on_stop &&
4079 thread->state & ThreadState_StopRequested &&
4080 thread->state & ThreadState_Background)
4084 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4086 InterlockedIncrement (&thread_interruption_requested);
4088 if (!running_managed || is_running_protected_wrapper ()) {
4089 /* Can't stop while in unmanaged code. Increase the global interruption
4090 request count. When exiting the unmanaged method the count will be
4091 checked and the thread will be interrupted. */
4093 if (mono_thread_notify_pending_exc_fn && !running_managed)
4094 /* The JIT will notify the thread about the interruption */
4095 /* This shouldn't take any locks */
4096 mono_thread_notify_pending_exc_fn (NULL);
4098 /* this will awake the thread if it is in WaitForSingleObject
4100 /* Our implementation of this function ignores the func argument */
4102 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4104 mono_thread_info_self_interrupt ();
4109 return mono_thread_execute_interruption (thread);
4113 /*This function should be called by a thread after it has exited all of
4114 * its handle blocks at interruption time.*/
4116 mono_thread_resume_interruption (void)
4118 MonoInternalThread *thread = mono_thread_internal_current ();
4119 gboolean still_aborting;
4121 /* The thread may already be stopping */
4125 LOCK_THREAD (thread);
4126 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4127 UNLOCK_THREAD (thread);
4129 /*This can happen if the protected block called Thread::ResetAbort*/
4130 if (!still_aborting)
4133 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4135 InterlockedIncrement (&thread_interruption_requested);
4137 mono_thread_info_self_interrupt ();
4139 return mono_thread_execute_interruption (thread);
4142 gboolean mono_thread_interruption_requested ()
4144 if (thread_interruption_requested) {
4145 MonoInternalThread *thread = mono_thread_internal_current ();
4146 /* The thread may already be stopping */
4148 return (thread->interruption_requested);
4153 static MonoException*
4154 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4156 MonoInternalThread *thread = mono_thread_internal_current ();
4158 /* The thread may already be stopping */
4162 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4163 MonoException* exc = mono_thread_execute_interruption (thread);
4171 * Performs the interruption of the current thread, if one has been requested,
4172 * and the thread is not running a protected wrapper.
4173 * Return the exception which needs to be thrown, if any.
4176 mono_thread_interruption_checkpoint (void)
4178 return mono_thread_interruption_checkpoint_request (FALSE);
4182 * Performs the interruption of the current thread, if one has been requested.
4183 * Return the exception which needs to be thrown, if any.
4186 mono_thread_force_interruption_checkpoint_noraise (void)
4188 return mono_thread_interruption_checkpoint_request (TRUE);
4192 * Performs the interruption of the current thread, if one has been requested.
4193 * Throw the exception which needs to be thrown, if any.
4196 mono_thread_force_interruption_checkpoint (void)
4200 ex = mono_thread_interruption_checkpoint_request (TRUE);
4202 mono_raise_exception (ex);
4206 * mono_thread_get_and_clear_pending_exception:
4208 * Return any pending exceptions for the current thread and clear it as a side effect.
4211 mono_thread_get_and_clear_pending_exception (void)
4213 MonoInternalThread *thread = mono_thread_internal_current ();
4215 /* The thread may already be stopping */
4219 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4220 return mono_thread_execute_interruption (thread);
4223 if (thread->pending_exception) {
4224 MonoException *exc = thread->pending_exception;
4226 thread->pending_exception = NULL;
4234 * mono_set_pending_exception:
4236 * Set the pending exception of the current thread to EXC.
4237 * The exception will be thrown when execution returns to managed code.
4240 mono_set_pending_exception (MonoException *exc)
4242 MonoInternalThread *thread = mono_thread_internal_current ();
4244 /* The thread may already be stopping */
4248 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4250 mono_thread_request_interruption (FALSE);
4254 * mono_thread_interruption_request_flag:
4256 * Returns the address of a flag that will be non-zero if an interruption has
4257 * been requested for a thread. The thread to interrupt may not be the current
4258 * thread, so an additional call to mono_thread_interruption_requested() or
4259 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4262 gint32* mono_thread_interruption_request_flag ()
4264 return &thread_interruption_requested;
4268 mono_thread_init_apartment_state (void)
4271 MonoInternalThread* thread = mono_thread_internal_current ();
4273 /* Positive return value indicates success, either
4274 * S_OK if this is first CoInitialize call, or
4275 * S_FALSE if CoInitialize already called, but with same
4276 * threading model. A negative value indicates failure,
4277 * probably due to trying to change the threading model.
4279 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4280 ? COINIT_APARTMENTTHREADED
4281 : COINIT_MULTITHREADED) < 0) {
4282 thread->apartment_state = ThreadApartmentState_Unknown;
4288 mono_thread_cleanup_apartment_state (void)
4291 MonoInternalThread* thread = mono_thread_internal_current ();
4293 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4300 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4302 LOCK_THREAD (thread);
4303 thread->state |= state;
4304 UNLOCK_THREAD (thread);
4308 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4310 LOCK_THREAD (thread);
4311 thread->state &= ~state;
4312 UNLOCK_THREAD (thread);
4316 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4318 gboolean ret = FALSE;
4320 LOCK_THREAD (thread);
4322 if ((thread->state & test) != 0) {
4326 UNLOCK_THREAD (thread);
4331 static gboolean has_tls_get = FALSE;
4334 mono_runtime_set_has_tls_get (gboolean val)
4340 mono_runtime_has_tls_get (void)
4346 self_interrupt_thread (void *_unused)
4348 MonoThreadInfo *info = mono_thread_info_current ();
4349 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4350 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4351 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. */
4352 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4356 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4360 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4364 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4366 MonoJitInfo **dest = data;
4372 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4374 MonoJitInfo *ji = NULL;
4377 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4382 MonoInternalThread *thread;
4383 gboolean install_async_abort;
4384 gpointer interrupt_handle;
4387 static SuspendThreadResult
4388 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4390 AbortThreadData *data = ud;
4391 MonoInternalThread *thread = data->thread;
4392 MonoJitInfo *ji = NULL;
4393 gboolean protected_wrapper;
4394 gboolean running_managed;
4396 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4397 return MonoResumeThread;
4399 /*someone is already interrupting it*/
4400 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4401 return MonoResumeThread;
4403 InterlockedIncrement (&thread_interruption_requested);
4405 ji = mono_thread_info_get_last_managed (info);
4406 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4407 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4409 if (!protected_wrapper && running_managed) {
4410 /*We are in managed code*/
4411 /*Set the thread to call */
4412 if (data->install_async_abort)
4413 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4414 return MonoResumeThread;
4416 if (mono_thread_notify_pending_exc_fn)
4417 /* The JIT will notify the thread about the interruption */
4418 mono_thread_notify_pending_exc_fn (info);
4421 * This will cause waits to be broken.
4422 * It will also prevent the thread from entering a wait, so if the thread returns
4423 * from the wait before it receives the abort signal, it will just spin in the wait
4424 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4427 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4428 return MonoResumeThread;
4433 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4435 AbortThreadData data = { 0 };
4436 data.thread = thread;
4437 data.install_async_abort = install_async_abort;
4440 FIXME this is insanely broken, it doesn't cause interruption to happen
4441 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4443 if (thread == mono_thread_internal_current ()) {
4444 /* Do it synchronously */
4445 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4447 mono_raise_exception (exc);
4448 mono_thread_info_interrupt (thread->handle);
4452 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
4453 if (data.interrupt_handle)
4454 mono_thread_info_finish_interrupt (data.interrupt_handle);
4455 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4459 MonoInternalThread *thread;
4461 gpointer interrupt_handle;
4462 } SuspendThreadData;
4464 static SuspendThreadResult
4465 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4467 SuspendThreadData *data = ud;
4468 MonoInternalThread *thread = data->thread;
4469 MonoJitInfo *ji = NULL;
4470 gboolean protected_wrapper;
4471 gboolean running_managed;
4473 ji = mono_thread_info_get_last_managed (info);
4474 protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4475 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4477 if (running_managed && !protected_wrapper) {
4478 thread->state &= ~ThreadState_SuspendRequested;
4479 thread->state |= ThreadState_Suspended;
4480 return KeepSuspended;
4482 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4483 InterlockedIncrement (&thread_interruption_requested);
4484 if (data->interrupt)
4485 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4487 if (mono_thread_notify_pending_exc_fn && !running_managed)
4488 /* The JIT will notify the thread about the interruption */
4489 mono_thread_notify_pending_exc_fn (info);
4490 return MonoResumeThread;
4495 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4497 LOCK_THREAD (thread);
4498 if (thread == mono_thread_internal_current ()) {
4499 mono_thread_info_begin_self_suspend ();
4500 //XXX replace this with better named functions
4501 thread->state &= ~ThreadState_SuspendRequested;
4502 thread->state |= ThreadState_Suspended;
4503 UNLOCK_THREAD (thread);
4504 mono_thread_info_end_self_suspend ();
4506 SuspendThreadData data = { 0 };
4507 data.thread = thread;
4508 data.interrupt = interrupt;
4510 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
4511 if (data.interrupt_handle)
4512 mono_thread_info_finish_interrupt (data.interrupt_handle);
4513 UNLOCK_THREAD (thread);
4517 /*This is called with @thread synch_cs held and it must release it*/
4519 self_suspend_internal (MonoInternalThread *thread)
4521 mono_thread_info_begin_self_suspend ();
4522 thread->state &= ~ThreadState_SuspendRequested;
4523 thread->state |= ThreadState_Suspended;
4524 UNLOCK_THREAD (thread);
4525 mono_thread_info_end_self_suspend ();
4528 /*This is called with @thread synch_cs held and it must release it*/
4530 resume_thread_internal (MonoInternalThread *thread)
4532 UNLOCK_THREAD (thread);
4533 /* Awake the thread */
4534 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4536 LOCK_THREAD (thread);
4537 thread->state &= ~ThreadState_Suspended;
4538 UNLOCK_THREAD (thread);
4544 * mono_thread_is_foreign:
4545 * @thread: the thread to query
4547 * This function allows one to determine if a thread was created by the mono runtime and has
4548 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4550 * Returns: true if @thread was not created by the runtime.
4553 mono_thread_is_foreign (MonoThread *thread)
4555 MonoThreadInfo *info = thread->internal_thread->thread_info;
4556 return info->runtime_thread == FALSE;
4560 * mono_add_joinable_thread:
4562 * Add TID to the list of joinable threads.
4563 * LOCKING: Acquires the threads lock.
4566 mono_threads_add_joinable_thread (gpointer tid)
4570 * We cannot detach from threads because it causes problems like
4571 * 2fd16f60/r114307. So we collect them and join them when
4572 * we have time (in he finalizer thread).
4574 joinable_threads_lock ();
4575 if (!joinable_threads)
4576 joinable_threads = g_hash_table_new (NULL, NULL);
4577 g_hash_table_insert (joinable_threads, tid, tid);
4578 joinable_thread_count ++;
4579 joinable_threads_unlock ();
4581 mono_gc_finalize_notify ();
4586 * mono_threads_join_threads:
4588 * Join all joinable threads. This is called from the finalizer thread.
4589 * LOCKING: Acquires the threads lock.
4592 mono_threads_join_threads (void)
4595 GHashTableIter iter;
4602 if (!joinable_thread_count)
4606 joinable_threads_lock ();
4608 if (g_hash_table_size (joinable_threads)) {
4609 g_hash_table_iter_init (&iter, joinable_threads);
4610 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4611 thread = (pthread_t)tid;
4612 g_hash_table_remove (joinable_threads, key);
4613 joinable_thread_count --;
4616 joinable_threads_unlock ();
4618 if (thread != pthread_self ())
4619 /* This shouldn't block */
4620 pthread_join (thread, NULL);
4631 * Wait for thread TID to exit.
4632 * LOCKING: Acquires the threads lock.
4635 mono_thread_join (gpointer tid)
4639 gboolean found = FALSE;
4641 joinable_threads_lock ();
4642 if (!joinable_threads)
4643 joinable_threads = g_hash_table_new (NULL, NULL);
4644 if (g_hash_table_lookup (joinable_threads, tid)) {
4645 g_hash_table_remove (joinable_threads, tid);
4646 joinable_thread_count --;
4649 joinable_threads_unlock ();
4652 thread = (pthread_t)tid;
4653 pthread_join (thread, NULL);
4658 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4660 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4661 mono_thread_interruption_checkpoint ();
4664 static inline gboolean
4665 is_appdomainunloaded_exception (MonoClass *klass)
4667 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4669 if (!app_domain_unloaded_exception_klass)
4670 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4671 g_assert (app_domain_unloaded_exception_klass);
4673 return klass == app_domain_unloaded_exception_klass;
4676 static inline gboolean
4677 is_threadabort_exception (MonoClass *klass)
4679 return klass == mono_defaults.threadabortexception_class;
4683 mono_thread_internal_unhandled_exception (MonoObject* exc)
4685 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4686 MonoClass *klass = exc->vtable->klass;
4687 if (is_threadabort_exception (klass)) {
4688 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4689 } else if (!is_appdomainunloaded_exception (klass)) {
4690 mono_unhandled_exception (exc);
4691 if (mono_environment_exitcode_get () == 1)