2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threadpool.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internal.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/hazard-pointer.h>
41 #include <mono/utils/mono-tls.h>
42 #include <mono/utils/atomic.h>
43 #include <mono/utils/mono-memory-model.h>
45 #include <mono/metadata/gc-internal.h>
51 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
52 #define USE_TKILL_ON_ANDROID 1
55 #ifdef PLATFORM_ANDROID
58 #ifdef USE_TKILL_ON_ANDROID
59 extern int tkill (pid_t tid, int signal);
63 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
64 #define THREAD_DEBUG(a)
65 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
66 #define THREAD_WAIT_DEBUG(a)
67 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
68 #define LIBGC_DEBUG(a)
70 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
71 #define SPIN_LOCK(i) do { \
72 if (SPIN_TRYLOCK (i)) \
76 #define SPIN_UNLOCK(i) i = 0
78 #define LOCK_THREAD(thread) lock_thread((thread))
79 #define UNLOCK_THREAD(thread) unlock_thread((thread))
81 /* Provide this for systems with glib < 2.6 */
82 #ifndef G_GSIZE_FORMAT
83 # if GLIB_SIZEOF_LONG == 8
84 # define G_GSIZE_FORMAT "lu"
86 # define G_GSIZE_FORMAT "u"
92 guint32 (*func)(void *);
108 typedef struct _StaticDataFreeList StaticDataFreeList;
109 struct _StaticDataFreeList {
110 StaticDataFreeList *next;
118 StaticDataFreeList *freelist;
121 /* Number of cached culture objects in the MonoThread->cached_culture_info array
122 * (per-type): we use the first NUM entries for CultureInfo and the last for
123 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
125 #define NUM_CACHED_CULTURES 4
126 #define CULTURES_START_IDX 0
127 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
129 /* Controls access to the 'threads' hash table */
130 static void mono_threads_lock (void);
131 static void mono_threads_unlock (void);
132 static mono_mutex_t threads_mutex;
134 /* Controls access to the 'joinable_threads' hash table */
135 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
136 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
137 static mono_mutex_t joinable_threads_mutex;
139 /* Holds current status of static data heap */
140 static StaticDataInfo thread_static_info;
141 static StaticDataInfo context_static_info;
143 /* The hash of existing threads (key is thread ID, value is
144 * MonoInternalThread*) that need joining before exit
146 static MonoGHashTable *threads=NULL;
148 /* List of app context GC handles.
149 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
151 static GHashTable *contexts = NULL;
154 * Threads which are starting up and they are not in the 'threads' hash yet.
155 * When handle_store is called for a thread, it will be removed from this hash table.
156 * Protected by mono_threads_lock ().
158 static MonoGHashTable *threads_starting_up = NULL;
160 /* Maps a MonoThread to its start argument */
161 /* Protected by mono_threads_lock () */
162 static MonoGHashTable *thread_start_args = NULL;
164 /* The TLS key that holds the MonoObject assigned to each thread */
165 static MonoNativeTlsKey current_object_key;
168 /* Protected by the threads lock */
169 static GHashTable *joinable_threads;
170 static int joinable_thread_count;
172 #ifdef MONO_HAVE_FAST_TLS
173 /* we need to use both the Tls* functions and __thread because
174 * the gc needs to see all the threads
176 MONO_FAST_TLS_DECLARE(tls_current_object);
177 #define SET_CURRENT_OBJECT(x) do { \
178 MONO_FAST_TLS_SET (tls_current_object, x); \
179 mono_native_tls_set_value (current_object_key, x); \
181 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
183 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
184 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
187 /* function called at thread start */
188 static MonoThreadStartCB mono_thread_start_cb = NULL;
190 /* function called at thread attach */
191 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
193 /* function called at thread cleanup */
194 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
196 /* function called to notify the runtime about a pending exception on the current thread */
197 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
199 /* The default stack size for each thread */
200 static guint32 default_stacksize = 0;
201 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
203 static void thread_adjust_static_data (MonoInternalThread *thread);
204 static void context_adjust_static_data (MonoAppContext *ctx);
205 static void mono_free_static_data (gpointer* static_data);
206 static void mono_init_static_data_info (StaticDataInfo *static_data);
207 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
208 static gboolean mono_thread_resume (MonoInternalThread* thread);
209 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
210 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
211 static void self_suspend_internal (MonoInternalThread *thread);
212 static gboolean resume_thread_internal (MonoInternalThread *thread);
214 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
215 static void ref_stack_destroy (gpointer rs);
217 /* Spin lock for InterlockedXXX 64 bit functions */
218 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
219 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
220 static mono_mutex_t interlocked_mutex;
222 /* global count of thread interruptions requested */
223 static gint32 thread_interruption_requested = 0;
225 /* Event signaled when a thread changes its background mode */
226 static HANDLE background_change_event;
228 static gboolean shutting_down = FALSE;
230 static gint32 managed_thread_id_counter = 0;
234 mono_threads_lock (void)
237 mono_locks_acquire (&threads_mutex, ThreadsLock);
238 MONO_FINISH_TRY_BLOCKING
242 mono_threads_unlock (void)
244 mono_locks_release (&threads_mutex, ThreadsLock);
249 get_next_managed_thread_id (void)
251 return InterlockedIncrement (&managed_thread_id_counter);
255 mono_thread_get_tls_key (void)
257 return current_object_key;
261 mono_thread_get_tls_offset (void)
264 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
268 static inline MonoNativeThreadId
269 thread_get_tid (MonoInternalThread *thread)
271 /* We store the tid as a guint64 to keep the object layout constant between platforms */
272 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
275 /* handle_store() and handle_remove() manage the array of threads that
276 * still need to be waited for when the main thread exits.
278 * If handle_store() returns FALSE the thread must not be started
279 * because Mono is shutting down.
281 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
283 mono_threads_lock ();
285 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
287 if (threads_starting_up)
288 mono_g_hash_table_remove (threads_starting_up, thread);
290 if (shutting_down && !force_attach) {
291 mono_threads_unlock ();
296 MONO_GC_REGISTER_ROOT_FIXED (threads);
297 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
300 /* We don't need to duplicate thread->handle, because it is
301 * only closed when the thread object is finalized by the GC.
303 g_assert (thread->internal_thread);
304 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
305 thread->internal_thread);
307 mono_threads_unlock ();
312 static gboolean handle_remove(MonoInternalThread *thread)
315 gsize tid = thread->tid;
317 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
319 mono_threads_lock ();
322 /* We have to check whether the thread object for the
323 * tid is still the same in the table because the
324 * thread might have been destroyed and the tid reused
325 * in the meantime, in which case the tid would be in
326 * the table, but with another thread object.
328 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
329 mono_g_hash_table_remove (threads, (gpointer)tid);
338 mono_threads_unlock ();
340 /* Don't close the handle here, wait for the object finalizer
341 * to do it. Otherwise, the following race condition applies:
343 * 1) Thread exits (and handle_remove() closes the handle)
345 * 2) Some other handle is reassigned the same slot
347 * 3) Another thread tries to join the first thread, and
348 * blocks waiting for the reassigned handle to be signalled
349 * (which might never happen). This is possible, because the
350 * thread calling Join() still has a reference to the first
356 static void ensure_synch_cs_set (MonoInternalThread *thread)
358 mono_mutex_t *synch_cs;
360 if (thread->synch_cs != NULL) {
364 synch_cs = g_new0 (mono_mutex_t, 1);
365 mono_mutex_init_recursive (synch_cs);
367 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
368 synch_cs, NULL) != NULL) {
369 /* Another thread must have installed this CS */
370 mono_mutex_destroy (synch_cs);
376 lock_thread (MonoInternalThread *thread)
378 if (!thread->synch_cs)
379 ensure_synch_cs_set (thread);
381 g_assert (thread->synch_cs);
384 mono_mutex_lock (thread->synch_cs);
385 MONO_FINISH_TRY_BLOCKING
389 unlock_thread (MonoInternalThread *thread)
391 mono_mutex_unlock (thread->synch_cs);
395 * NOTE: this function can be called also for threads different from the current one:
396 * make sure no code called from it will ever assume it is run on the thread that is
397 * getting cleaned up.
399 static void thread_cleanup (MonoInternalThread *thread)
401 g_assert (thread != NULL);
403 if (thread->abort_state_handle) {
404 mono_gchandle_free (thread->abort_state_handle);
405 thread->abort_state_handle = 0;
407 thread->abort_exc = NULL;
408 thread->current_appcontext = NULL;
411 * This is necessary because otherwise we might have
412 * cross-domain references which will not get cleaned up when
413 * the target domain is unloaded.
415 if (thread->cached_culture_info) {
417 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
418 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
422 * thread->synch_cs can be NULL if this was called after
423 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
424 * This can happen only during shutdown.
425 * The shutting_down flag is not always set, so we can't assert on it.
427 if (thread->synch_cs)
428 LOCK_THREAD (thread);
430 thread->state |= ThreadState_Stopped;
431 thread->state &= ~ThreadState_Background;
433 if (thread->synch_cs)
434 UNLOCK_THREAD (thread);
437 An interruption request has leaked to cleanup. Adjust the global counter.
439 This can happen is the abort source thread finds the abortee (this) thread
440 in unmanaged code. If this thread never trips back to managed code or check
441 the local flag it will be left set and positively unbalance the global counter.
443 Leaving the counter unbalanced will cause a performance degradation since all threads
444 will now keep checking their local flags all the time.
446 if (InterlockedExchange (&thread->interruption_requested, 0))
447 InterlockedDecrement (&thread_interruption_requested);
449 /* if the thread is not in the hash it has been removed already */
450 if (!handle_remove (thread)) {
451 if (thread == mono_thread_internal_current ()) {
452 mono_domain_unset ();
453 mono_memory_barrier ();
455 /* This needs to be called even if handle_remove () fails */
456 if (mono_thread_cleanup_fn)
457 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
460 mono_release_type_locks (thread);
462 mono_profiler_thread_end (thread->tid);
464 if (thread == mono_thread_internal_current ()) {
466 * This will signal async signal handlers that the thread has exited.
467 * The profiler callback needs this to be set, so it cannot be done earlier.
469 mono_domain_unset ();
470 mono_memory_barrier ();
473 if (thread == mono_thread_internal_current ())
474 mono_thread_pop_appdomain_ref ();
476 thread->cached_culture_info = NULL;
478 mono_free_static_data (thread->static_data);
479 thread->static_data = NULL;
480 ref_stack_destroy (thread->appdomain_refs);
481 thread->appdomain_refs = NULL;
483 if (mono_thread_cleanup_fn)
484 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
486 if (mono_gc_is_moving ()) {
487 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
488 thread->thread_pinning_ref = NULL;
493 * A special static data offset (guint32) consists of 3 parts:
495 * [0] 6-bit index into the array of chunks.
496 * [6] 25-bit offset into the array.
497 * [31] Bit indicating thread or context static.
502 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
513 } SpecialStaticOffset;
515 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
516 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
518 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
519 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
520 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
521 (((SpecialStaticOffset *) &(x))->fields.f)
524 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
526 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
528 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
529 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
531 return ((char *) thread->static_data [idx]) + off;
535 get_context_static_data (MonoAppContext *ctx, guint32 offset)
537 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
539 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
540 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
542 return ((char *) ctx->static_data [idx]) + off;
546 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
548 static MonoClassField *current_thread_field = NULL;
552 if (!current_thread_field) {
553 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
554 g_assert (current_thread_field);
557 mono_class_vtable (domain, mono_defaults.thread_class);
558 mono_domain_lock (domain);
559 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
560 mono_domain_unlock (domain);
563 return get_thread_static_data (thread, offset);
567 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
569 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
571 g_assert (current->obj.vtable->domain == domain);
573 g_assert (!*current_thread_ptr);
574 *current_thread_ptr = current;
578 create_thread_object (MonoDomain *domain)
580 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
581 return (MonoThread*)mono_gc_alloc_mature (vt);
585 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
587 MonoThread *thread = create_thread_object (domain);
588 MONO_OBJECT_SETREF (thread, internal_thread, internal);
592 static MonoInternalThread*
593 create_internal_thread (void)
595 MonoInternalThread *thread;
598 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
599 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
601 thread->synch_cs = g_new0 (mono_mutex_t, 1);
602 mono_mutex_init_recursive (thread->synch_cs);
604 thread->apartment_state = ThreadApartmentState_Unknown;
605 thread->managed_id = get_next_managed_thread_id ();
606 if (mono_gc_is_moving ()) {
607 thread->thread_pinning_ref = thread;
608 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
615 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
617 MonoDomain *domain = mono_get_root_domain ();
619 if (!candidate || candidate->obj.vtable->domain != domain)
620 candidate = new_thread_with_internal (domain, thread);
621 set_current_thread_for_domain (domain, thread, candidate);
622 g_assert (!thread->root_domain_thread);
623 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
626 static guint32 WINAPI start_wrapper_internal(void *data)
628 MonoThreadInfo *info;
629 StartInfo *start_info = (StartInfo *)data;
630 guint32 (*start_func)(void *);
634 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
637 MonoInternalThread *internal = start_info->obj->internal_thread;
638 MonoObject *start_delegate = start_info->delegate;
639 MonoDomain *domain = start_info->obj->obj.vtable->domain;
641 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
643 /* We can be sure start_info->obj->tid and
644 * start_info->obj->handle have been set, because the thread
645 * was created suspended, and these values were set before the
649 info = mono_thread_info_current ();
651 internal->thread_info = info;
652 internal->small_id = info->small_id;
656 SET_CURRENT_OBJECT (internal);
658 /* Every thread references the appdomain which created it */
659 mono_thread_push_appdomain_ref (domain);
661 if (!mono_domain_set (domain, FALSE)) {
662 /* No point in raising an appdomain_unloaded exception here */
663 /* FIXME: Cleanup here */
664 mono_thread_pop_appdomain_ref ();
668 start_func = start_info->func;
669 start_arg = start_info->start_arg;
671 /* We have to do this here because mono_thread_new_init()
672 requires that root_domain_thread is set up. */
673 thread_adjust_static_data (internal);
674 init_root_domain_thread (internal, start_info->obj);
676 /* This MUST be called before any managed code can be
677 * executed, as it calls the callback function that (for the
678 * jit) sets the lmf marker.
680 mono_thread_new_init (tid, &tid, start_func);
681 internal->stack_ptr = &tid;
683 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
685 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
687 /* On 2.0 profile (and higher), set explicitly since state might have been
689 if (internal->apartment_state == ThreadApartmentState_Unknown)
690 internal->apartment_state = ThreadApartmentState_MTA;
692 mono_thread_init_apartment_state ();
694 if(internal->start_notify!=NULL) {
695 /* Let the thread that called Start() know we're
698 ReleaseSemaphore (internal->start_notify, 1, NULL);
701 mono_threads_lock ();
702 mono_g_hash_table_remove (thread_start_args, start_info->obj);
703 mono_threads_unlock ();
705 mono_thread_set_execution_context (start_info->obj->ec_to_set);
706 start_info->obj->ec_to_set = NULL;
709 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
713 * Call this after calling start_notify, since the profiler callback might want
714 * to lock the thread, and the lock is held by thread_start () which waits for
717 mono_profiler_thread_start (tid);
719 /* if the name was set before starting, we didn't invoke the profiler callback */
720 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
721 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
722 mono_profiler_thread_name (internal->tid, tname);
725 /* start_func is set only for unmanaged start functions */
727 start_func (start_arg);
730 g_assert (start_delegate != NULL);
731 args [0] = start_arg;
732 /* we may want to handle the exception here. See comment below on unhandled exceptions */
733 mono_runtime_delegate_invoke (start_delegate, args, NULL);
736 /* If the thread calls ExitThread at all, this remaining code
737 * will not be executed, but the main thread will eventually
738 * call thread_cleanup() on this thread's behalf.
741 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
743 /* Do any cleanup needed for apartment state. This
744 * cannot be done in thread_cleanup since thread_cleanup could be
745 * called for a thread other than the current thread.
746 * mono_thread_cleanup_apartment_state cleans up apartment
747 * for the current thead */
748 mono_thread_cleanup_apartment_state ();
750 thread_cleanup (internal);
754 /* Remove the reference to the thread object in the TLS data,
755 * so the thread object can be finalized. This won't be
756 * reached if the thread threw an uncaught exception, so those
757 * thread handles will stay referenced :-( (This is due to
758 * missing support for scanning thread-specific data in the
759 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
762 SET_CURRENT_OBJECT (NULL);
767 static guint32 WINAPI start_wrapper(void *data)
771 /* Avoid scanning the frames above this frame during a GC */
772 mono_gc_set_stack_end ((void*)&dummy);
774 return start_wrapper_internal (data);
780 * Common thread creation code.
781 * LOCKING: Acquires the threads lock.
784 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
785 gboolean throw_on_failure)
787 HANDLE thread_handle;
788 MonoNativeThreadId tid;
789 guint32 create_flags;
792 * Join joinable threads to prevent running out of threads since the finalizer
793 * thread might be blocked/backlogged.
795 mono_threads_join_threads ();
797 mono_threads_lock ();
800 mono_threads_unlock ();
804 * The thread start argument may be an object reference, and there is
805 * no ref to keep it alive when the new thread is started but not yet
806 * registered with the collector. So we store it in a GC tracked hash
809 if (thread_start_args == NULL) {
810 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
811 thread_start_args = mono_g_hash_table_new (NULL, NULL);
813 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
814 if (threads_starting_up == NULL) {
815 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
816 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
818 mono_g_hash_table_insert (threads_starting_up, thread, thread);
819 mono_threads_unlock ();
821 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
822 if (!internal->start_notify) {
823 mono_threads_lock ();
824 mono_g_hash_table_remove (threads_starting_up, thread);
825 mono_threads_unlock ();
826 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
832 stack_size = default_stacksize_for_thread (internal);
834 /* Create suspended, so we can do some housekeeping before the thread
837 create_flags = CREATE_SUSPENDED;
839 MONO_PREPARE_BLOCKING
840 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
841 stack_size, create_flags, &tid);
844 if (thread_handle == NULL) {
845 /* The thread couldn't be created, so throw an exception */
846 mono_threads_lock ();
847 mono_g_hash_table_remove (threads_starting_up, thread);
848 mono_threads_unlock ();
850 if (throw_on_failure)
851 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
853 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
856 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
858 internal->handle = thread_handle;
859 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
861 internal->threadpool_thread = threadpool_thread;
862 if (threadpool_thread)
863 mono_thread_set_state (internal, ThreadState_Background);
865 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
867 /* Only store the handle when the thread is about to be
868 * launched, to avoid the main thread deadlocking while trying
869 * to clean up a thread that will never be signalled.
871 if (!handle_store (thread, FALSE))
874 MONO_PREPARE_BLOCKING
875 mono_thread_info_resume (tid);
878 if (internal->start_notify) {
880 * Wait for the thread to set up its TLS data etc, so
881 * theres no potential race condition if someone tries
882 * to look up the data believing the thread has
885 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
887 MONO_PREPARE_BLOCKING
888 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
891 CloseHandle (internal->start_notify);
892 internal->start_notify = NULL;
895 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
900 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
902 if (mono_thread_start_cb) {
903 mono_thread_start_cb (tid, stack_start, func);
907 void mono_threads_set_default_stacksize (guint32 stacksize)
909 default_stacksize = stacksize;
912 guint32 mono_threads_get_default_stacksize (void)
914 return default_stacksize;
918 * mono_thread_create_internal:
922 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
925 MonoInternalThread *internal;
926 StartInfo *start_info;
929 thread = create_thread_object (domain);
930 internal = create_internal_thread ();
931 MONO_OBJECT_SETREF (thread, internal_thread, internal);
933 start_info = g_new0 (StartInfo, 1);
934 start_info->func = func;
935 start_info->obj = thread;
936 start_info->start_arg = arg;
938 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
942 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
943 if (mono_check_corlib_version () == NULL)
944 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
950 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
952 mono_thread_create_internal (domain, func, arg, FALSE, 0);
956 mono_thread_attach (MonoDomain *domain)
958 return mono_thread_attach_full (domain, FALSE);
962 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
964 MonoThreadInfo *info;
965 MonoInternalThread *thread;
966 MonoThread *current_thread;
967 HANDLE thread_handle;
970 if ((thread = mono_thread_internal_current ())) {
971 if (domain != mono_domain_get ())
972 mono_domain_set (domain, TRUE);
973 /* Already attached */
974 return mono_thread_current ();
977 if (!mono_gc_register_thread (&domain)) {
978 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 ());
981 thread = create_internal_thread ();
983 thread_handle = mono_thread_info_open_handle ();
984 g_assert (thread_handle);
986 tid=GetCurrentThreadId ();
988 thread->handle=thread_handle;
990 thread->stack_ptr = &tid;
992 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
994 info = mono_thread_info_current ();
996 thread->thread_info = info;
997 thread->small_id = info->small_id;
999 current_thread = new_thread_with_internal (domain, thread);
1001 if (!handle_store (current_thread, force_attach)) {
1002 /* Mono is shutting down, so just wait for the end */
1007 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
1009 SET_CURRENT_OBJECT (thread);
1010 mono_domain_set (domain, TRUE);
1012 thread_adjust_static_data (thread);
1014 init_root_domain_thread (thread, current_thread);
1015 if (domain != mono_get_root_domain ())
1016 set_current_thread_for_domain (domain, thread, current_thread);
1019 if (mono_thread_attach_cb) {
1023 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1026 mono_thread_attach_cb (tid, &tid);
1028 mono_thread_attach_cb (tid, staddr + stsize);
1031 // FIXME: Need a separate callback
1032 mono_profiler_thread_start (tid);
1034 return current_thread;
1038 mono_thread_detach_internal (MonoInternalThread *thread)
1040 g_return_if_fail (thread != NULL);
1042 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1044 thread_cleanup (thread);
1046 SET_CURRENT_OBJECT (NULL);
1047 mono_domain_unset ();
1049 /* Don't need to CloseHandle this thread, even though we took a
1050 * reference in mono_thread_attach (), because the GC will do it
1051 * when the Thread object is finalised.
1056 mono_thread_detach (MonoThread *thread)
1059 mono_thread_detach_internal (thread->internal_thread);
1063 * mono_thread_detach_if_exiting:
1065 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1066 * This should be used at the end of embedding code which calls into managed code, and which
1067 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1070 mono_thread_detach_if_exiting (void)
1072 if (mono_thread_info_is_exiting ()) {
1073 MonoInternalThread *thread;
1075 thread = mono_thread_internal_current ();
1077 mono_thread_detach_internal (thread);
1078 mono_thread_info_detach ();
1086 MonoInternalThread *thread = mono_thread_internal_current ();
1088 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1090 thread_cleanup (thread);
1091 SET_CURRENT_OBJECT (NULL);
1092 mono_domain_unset ();
1094 /* we could add a callback here for embedders to use. */
1095 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1096 exit (mono_environment_exitcode_get ());
1097 mono_thread_info_exit ();
1101 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1103 MonoInternalThread *internal = create_internal_thread ();
1105 internal->state = ThreadState_Unstarted;
1107 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1111 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
1114 StartInfo *start_info;
1115 MonoInternalThread *internal;
1118 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1120 if (!this->internal_thread)
1121 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1122 internal = this->internal_thread;
1124 LOCK_THREAD (internal);
1126 if ((internal->state & ThreadState_Unstarted) == 0) {
1127 UNLOCK_THREAD (internal);
1128 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1132 if ((internal->state & ThreadState_Aborted) != 0) {
1133 UNLOCK_THREAD (internal);
1136 /* This is freed in start_wrapper */
1137 start_info = g_new0 (StartInfo, 1);
1138 start_info->func = NULL;
1139 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1140 start_info->delegate = start;
1141 start_info->obj = this;
1142 g_assert (this->obj.vtable->domain == mono_domain_get ());
1144 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1146 UNLOCK_THREAD (internal);
1150 internal->state &= ~ThreadState_Unstarted;
1152 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1154 UNLOCK_THREAD (internal);
1155 return internal->handle;
1159 * This is called from the finalizer of the internal thread object.
1162 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1164 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1167 * Since threads keep a reference to their thread object while running, by the time this function is called,
1168 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1169 * when thread_cleanup () can be called after this.
1172 CloseHandle (thread);
1174 if (this->synch_cs) {
1175 mono_mutex_t *synch_cs = this->synch_cs;
1176 this->synch_cs = NULL;
1177 mono_mutex_destroy (synch_cs);
1182 void *name = this->name;
1189 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1192 MonoInternalThread *thread = mono_thread_internal_current ();
1194 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1196 mono_thread_current_check_pending_interrupt ();
1199 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1201 MONO_PREPARE_BLOCKING
1202 res = SleepEx(ms,TRUE);
1203 MONO_FINISH_BLOCKING
1205 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1207 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1208 MonoException* exc = mono_thread_execute_interruption (thread);
1210 mono_raise_exception (exc);
1222 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1227 ves_icall_System_Threading_Thread_GetDomainID (void)
1229 return mono_domain_get()->domain_id;
1233 ves_icall_System_Threading_Thread_Yield (void)
1235 return mono_thread_info_yield ();
1239 * mono_thread_get_name:
1241 * Return the name of the thread. NAME_LEN is set to the length of the name.
1242 * Return NULL if the thread has no name. The returned memory is owned by the
1246 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1250 LOCK_THREAD (this_obj);
1252 if (!this_obj->name) {
1256 *name_len = this_obj->name_len;
1257 res = g_new (gunichar2, this_obj->name_len);
1258 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1261 UNLOCK_THREAD (this_obj);
1267 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1271 LOCK_THREAD (this_obj);
1273 if (!this_obj->name)
1276 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1278 UNLOCK_THREAD (this_obj);
1284 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1286 LOCK_THREAD (this_obj);
1288 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1289 UNLOCK_THREAD (this_obj);
1291 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1294 if (this_obj->name) {
1295 g_free (this_obj->name);
1296 this_obj->name_len = 0;
1299 this_obj->name = g_new (gunichar2, mono_string_length (name));
1300 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1301 this_obj->name_len = mono_string_length (name);
1304 this_obj->name = NULL;
1307 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1309 UNLOCK_THREAD (this_obj);
1311 if (this_obj->name && this_obj->tid) {
1312 char *tname = mono_string_to_utf8 (name);
1313 mono_profiler_thread_name (this_obj->tid, tname);
1314 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1320 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1322 mono_thread_set_name_internal (this_obj, name, TRUE);
1326 ves_icall_System_Threading_Thread_GetPriority (MonoInternalThread *thread)
1328 return ThreadPriority_Lowest;
1332 ves_icall_System_Threading_Thread_SetPriority (MonoInternalThread *thread, int priority)
1336 /* If the array is already in the requested domain, we just return it,
1337 otherwise we return a copy in that domain. */
1339 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1346 if (mono_object_domain (arr) == domain)
1349 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1350 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1355 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1357 return byte_array_to_domain (arr, mono_get_root_domain ());
1361 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1363 return byte_array_to_domain (arr, mono_domain_get ());
1367 mono_thread_current (void)
1369 MonoDomain *domain = mono_domain_get ();
1370 MonoInternalThread *internal = mono_thread_internal_current ();
1371 MonoThread **current_thread_ptr;
1373 g_assert (internal);
1374 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1376 if (!*current_thread_ptr) {
1377 g_assert (domain != mono_get_root_domain ());
1378 *current_thread_ptr = new_thread_with_internal (domain, internal);
1380 return *current_thread_ptr;
1384 mono_thread_internal_current (void)
1386 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1387 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1392 ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1393 int ms, HANDLE thread)
1395 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1398 mono_thread_current_check_pending_interrupt ();
1402 if ((this->state & ThreadState_Unstarted) != 0) {
1403 UNLOCK_THREAD (this);
1405 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1409 UNLOCK_THREAD (this);
1414 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1416 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1418 MONO_PREPARE_BLOCKING
1419 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1420 MONO_FINISH_BLOCKING
1422 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1424 if(ret==WAIT_OBJECT_0) {
1425 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1430 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1436 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1444 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1446 MONO_PREPARE_BLOCKING
1448 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1450 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1451 MONO_FINISH_BLOCKING
1453 if (ret != WAIT_IO_COMPLETION)
1456 exc = mono_thread_execute_interruption (thread);
1458 mono_raise_exception (exc);
1463 /* Re-calculate ms according to the time passed */
1464 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1465 if (diff_ms >= ms) {
1469 wait = ms - diff_ms;
1475 /* FIXME: exitContext isnt documented */
1476 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1482 MonoObject *waitHandle;
1483 MonoInternalThread *thread = mono_thread_internal_current ();
1485 /* Do this WaitSleepJoin check before creating objects */
1486 mono_thread_current_check_pending_interrupt ();
1488 /* We fail in managed if the array has more than 64 elements */
1489 numhandles = (guint32)mono_array_length(mono_handles);
1490 handles = g_new0(HANDLE, numhandles);
1492 for(i = 0; i < numhandles; i++) {
1493 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1494 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1501 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1503 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1505 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1509 if(ret==WAIT_FAILED) {
1510 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1512 } else if(ret==WAIT_TIMEOUT) {
1513 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1520 /* FIXME: exitContext isnt documented */
1521 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1523 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1524 uintptr_t numhandles;
1527 MonoObject *waitHandle;
1528 MonoInternalThread *thread = mono_thread_internal_current ();
1530 /* Do this WaitSleepJoin check before creating objects */
1531 mono_thread_current_check_pending_interrupt ();
1533 numhandles = mono_array_length(mono_handles);
1534 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1537 for(i = 0; i < numhandles; i++) {
1538 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1539 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1546 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1548 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1550 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1552 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1555 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1557 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1558 return ret - WAIT_OBJECT_0;
1560 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1561 return ret - WAIT_ABANDONED_0;
1568 /* FIXME: exitContext isnt documented */
1569 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1572 MonoInternalThread *thread = mono_thread_internal_current ();
1574 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1580 mono_thread_current_check_pending_interrupt ();
1582 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1584 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1586 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1588 if(ret==WAIT_FAILED) {
1589 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1591 } else if(ret==WAIT_TIMEOUT) {
1592 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1600 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1603 MonoInternalThread *thread = mono_thread_internal_current ();
1608 mono_thread_current_check_pending_interrupt ();
1610 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1612 MONO_PREPARE_BLOCKING
1613 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1614 MONO_FINISH_BLOCKING
1616 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1618 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1621 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1628 mutex = CreateMutex (NULL, owned, NULL);
1630 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1632 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1640 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1641 return(ReleaseMutex (handle));
1644 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1650 *error = ERROR_SUCCESS;
1652 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1654 *error = GetLastError ();
1661 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1668 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1670 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1671 mono_string_chars (name));
1673 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1681 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1685 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1690 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1694 *error = ERROR_SUCCESS;
1696 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1698 *error = GetLastError ();
1704 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1711 event = CreateEvent (NULL, manual, initial, NULL);
1713 event = CreateEvent (NULL, manual, initial,
1714 mono_string_chars (name));
1716 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1724 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1725 return (SetEvent(handle));
1728 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1729 return (ResetEvent(handle));
1733 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1734 CloseHandle (handle);
1737 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1743 *error = ERROR_SUCCESS;
1745 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1747 *error = GetLastError ();
1753 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1755 return InterlockedIncrement (location);
1758 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1760 #if SIZEOF_VOID_P == 4
1761 if (G_UNLIKELY ((size_t)location & 0x7)) {
1763 mono_interlocked_lock ();
1766 mono_interlocked_unlock ();
1770 return InterlockedIncrement64 (location);
1773 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1775 return InterlockedDecrement(location);
1778 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1780 #if SIZEOF_VOID_P == 4
1781 if (G_UNLIKELY ((size_t)location & 0x7)) {
1783 mono_interlocked_lock ();
1786 mono_interlocked_unlock ();
1790 return InterlockedDecrement64 (location);
1793 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1795 return InterlockedExchange(location, value);
1798 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1801 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1802 mono_gc_wbarrier_generic_nostore (location);
1806 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1808 return InterlockedExchangePointer(location, value);
1811 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1813 IntFloatUnion val, ret;
1816 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1822 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1824 #if SIZEOF_VOID_P == 4
1825 if (G_UNLIKELY ((size_t)location & 0x7)) {
1827 mono_interlocked_lock ();
1830 mono_interlocked_unlock ();
1834 return InterlockedExchange64 (location, value);
1838 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1840 LongDoubleUnion val, ret;
1843 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1848 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1850 return InterlockedCompareExchange(location, value, comparand);
1853 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1855 gint32 r = InterlockedCompareExchange(location, value, comparand);
1856 *success = r == comparand;
1860 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1863 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1864 mono_gc_wbarrier_generic_nostore (location);
1868 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1870 return InterlockedCompareExchangePointer(location, value, comparand);
1873 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1875 IntFloatUnion val, ret, cmp;
1878 cmp.fval = comparand;
1879 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1885 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1887 #if SIZEOF_VOID_P == 8
1888 LongDoubleUnion val, comp, ret;
1891 comp.fval = comparand;
1892 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1898 mono_interlocked_lock ();
1900 if (old == comparand)
1902 mono_interlocked_unlock ();
1909 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1911 #if SIZEOF_VOID_P == 4
1912 if (G_UNLIKELY ((size_t)location & 0x7)) {
1914 mono_interlocked_lock ();
1916 if (old == comparand)
1918 mono_interlocked_unlock ();
1922 return InterlockedCompareExchange64 (location, value, comparand);
1926 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1929 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1930 mono_gc_wbarrier_generic_nostore (location);
1935 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1938 res = InterlockedExchangePointer ((gpointer *)location, value);
1939 mono_gc_wbarrier_generic_nostore (location);
1944 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1946 return InterlockedAdd (location, value);
1950 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1952 #if SIZEOF_VOID_P == 4
1953 if (G_UNLIKELY ((size_t)location & 0x7)) {
1955 mono_interlocked_lock ();
1958 mono_interlocked_unlock ();
1962 return InterlockedAdd64 (location, value);
1966 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1968 #if SIZEOF_VOID_P == 4
1969 if (G_UNLIKELY ((size_t)location & 0x7)) {
1971 mono_interlocked_lock ();
1973 mono_interlocked_unlock ();
1977 return InterlockedRead64 (location);
1981 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1983 mono_memory_barrier ();
1987 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1989 mono_thread_clr_state (this, state);
1991 if (state & ThreadState_Background) {
1992 /* If the thread changes the background mode, the main thread has to
1993 * be notified, since it has to rebuild the list of threads to
1996 SetEvent (background_change_event);
2001 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
2003 mono_thread_set_state (this, state);
2005 if (state & ThreadState_Background) {
2006 /* If the thread changes the background mode, the main thread has to
2007 * be notified, since it has to rebuild the list of threads to
2010 SetEvent (background_change_event);
2015 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2021 state = this->state;
2023 UNLOCK_THREAD (this);
2028 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
2030 MonoInternalThread *current;
2035 current = mono_thread_internal_current ();
2037 this->thread_interrupt_requested = TRUE;
2038 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
2040 UNLOCK_THREAD (this);
2043 abort_thread_internal (this, TRUE, FALSE);
2047 void mono_thread_current_check_pending_interrupt ()
2049 MonoInternalThread *thread = mono_thread_internal_current ();
2050 gboolean throw = FALSE;
2052 LOCK_THREAD (thread);
2054 if (thread->thread_interrupt_requested) {
2056 thread->thread_interrupt_requested = FALSE;
2059 UNLOCK_THREAD (thread);
2062 mono_raise_exception (mono_get_exception_thread_interrupted ());
2067 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2069 LOCK_THREAD (thread);
2071 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2072 (thread->state & ThreadState_StopRequested) != 0 ||
2073 (thread->state & ThreadState_Stopped) != 0)
2075 UNLOCK_THREAD (thread);
2079 if ((thread->state & ThreadState_Unstarted) != 0) {
2080 thread->state |= ThreadState_Aborted;
2081 UNLOCK_THREAD (thread);
2085 thread->state |= ThreadState_AbortRequested;
2086 if (thread->abort_state_handle)
2087 mono_gchandle_free (thread->abort_state_handle);
2089 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2090 g_assert (thread->abort_state_handle);
2092 thread->abort_state_handle = 0;
2094 thread->abort_exc = NULL;
2096 UNLOCK_THREAD (thread);
2098 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2100 /* During shutdown, we can't wait for other threads */
2102 /* Make sure the thread is awake */
2103 mono_thread_resume (thread);
2105 abort_thread_internal (thread, TRUE, TRUE);
2109 ves_icall_System_Threading_Thread_ResetAbort (void)
2111 MonoInternalThread *thread = mono_thread_internal_current ();
2112 gboolean was_aborting;
2114 LOCK_THREAD (thread);
2115 was_aborting = thread->state & ThreadState_AbortRequested;
2116 thread->state &= ~ThreadState_AbortRequested;
2117 UNLOCK_THREAD (thread);
2119 if (!was_aborting) {
2120 const char *msg = "Unable to reset abort because no abort was requested";
2121 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2124 thread->abort_exc = NULL;
2125 if (thread->abort_state_handle) {
2126 mono_gchandle_free (thread->abort_state_handle);
2127 /* This is actually not necessary - the handle
2128 only counts if the exception is set */
2129 thread->abort_state_handle = 0;
2134 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2136 LOCK_THREAD (thread);
2138 thread->state &= ~ThreadState_AbortRequested;
2140 if (thread->abort_exc) {
2141 thread->abort_exc = NULL;
2142 if (thread->abort_state_handle) {
2143 mono_gchandle_free (thread->abort_state_handle);
2144 /* This is actually not necessary - the handle
2145 only counts if the exception is set */
2146 thread->abort_state_handle = 0;
2150 UNLOCK_THREAD (thread);
2154 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2156 MonoInternalThread *thread = this->internal_thread;
2157 MonoObject *state, *deserialized = NULL, *exc;
2160 if (!thread->abort_state_handle)
2163 state = mono_gchandle_get_target (thread->abort_state_handle);
2166 domain = mono_domain_get ();
2167 if (mono_object_domain (state) == domain)
2170 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2172 if (!deserialized) {
2173 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2175 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2176 mono_set_pending_exception (invalid_op_exc);
2180 return deserialized;
2184 mono_thread_suspend (MonoInternalThread *thread)
2186 LOCK_THREAD (thread);
2188 if ((thread->state & ThreadState_Unstarted) != 0 ||
2189 (thread->state & ThreadState_Aborted) != 0 ||
2190 (thread->state & ThreadState_Stopped) != 0)
2192 UNLOCK_THREAD (thread);
2196 if ((thread->state & ThreadState_Suspended) != 0 ||
2197 (thread->state & ThreadState_SuspendRequested) != 0 ||
2198 (thread->state & ThreadState_StopRequested) != 0)
2200 UNLOCK_THREAD (thread);
2204 thread->state |= ThreadState_SuspendRequested;
2206 UNLOCK_THREAD (thread);
2208 suspend_thread_internal (thread, FALSE);
2213 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2215 if (!mono_thread_suspend (thread)) {
2216 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2222 mono_thread_resume (MonoInternalThread *thread)
2224 LOCK_THREAD (thread);
2226 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2227 thread->state &= ~ThreadState_SuspendRequested;
2228 UNLOCK_THREAD (thread);
2232 if ((thread->state & ThreadState_Suspended) == 0 ||
2233 (thread->state & ThreadState_Unstarted) != 0 ||
2234 (thread->state & ThreadState_Aborted) != 0 ||
2235 (thread->state & ThreadState_Stopped) != 0)
2237 UNLOCK_THREAD (thread);
2241 return resume_thread_internal (thread);
2245 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2247 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2248 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2254 mono_threads_is_critical_method (MonoMethod *method)
2256 switch (method->wrapper_type) {
2257 case MONO_WRAPPER_RUNTIME_INVOKE:
2258 case MONO_WRAPPER_XDOMAIN_INVOKE:
2259 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2266 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2271 if (mono_threads_is_critical_method (m)) {
2272 *((gboolean*)data) = TRUE;
2279 is_running_protected_wrapper (void)
2281 gboolean found = FALSE;
2282 mono_stack_walk (find_wrapper, &found);
2286 void mono_thread_internal_stop (MonoInternalThread *thread)
2288 LOCK_THREAD (thread);
2290 if ((thread->state & ThreadState_StopRequested) != 0 ||
2291 (thread->state & ThreadState_Stopped) != 0)
2293 UNLOCK_THREAD (thread);
2297 /* Make sure the thread is awake */
2298 mono_thread_resume (thread);
2300 thread->state |= ThreadState_StopRequested;
2301 thread->state &= ~ThreadState_AbortRequested;
2303 UNLOCK_THREAD (thread);
2305 abort_thread_internal (thread, TRUE, TRUE);
2308 void mono_thread_stop (MonoThread *thread)
2310 mono_thread_internal_stop (thread->internal_thread);
2314 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2317 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2322 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2325 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2330 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2333 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2338 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2341 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2346 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2349 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2350 return (void *) tmp;
2354 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2356 volatile MonoObject *tmp;
2357 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2358 return (MonoObject *) tmp;
2362 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2365 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2370 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2373 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2378 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2380 return InterlockedRead8 (ptr);
2384 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2386 return InterlockedRead16 (ptr);
2390 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2392 return InterlockedRead (ptr);
2396 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2398 #if SIZEOF_VOID_P == 4
2399 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2401 mono_interlocked_lock ();
2402 val = *(gint64*)ptr;
2403 mono_interlocked_unlock ();
2407 return InterlockedRead64 (ptr);
2411 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2413 return InterlockedReadPointer (ptr);
2417 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2421 #if SIZEOF_VOID_P == 4
2422 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2424 mono_interlocked_lock ();
2425 val = *(double*)ptr;
2426 mono_interlocked_unlock ();
2431 u.ival = InterlockedRead64 (ptr);
2437 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2441 u.ival = InterlockedRead (ptr);
2447 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2449 return InterlockedReadPointer (ptr);
2453 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2455 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2459 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2461 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2465 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2467 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2471 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2473 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2477 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2479 mono_atomic_store_release ((volatile void **) ptr, value);
2483 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2485 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2489 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2491 mono_atomic_store_release ((volatile double *) ptr, value);
2495 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2497 mono_atomic_store_release ((volatile float *) ptr, value);
2501 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2503 InterlockedWrite8 (ptr, value);
2507 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2509 InterlockedWrite16 (ptr, value);
2513 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2515 InterlockedWrite (ptr, value);
2519 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2521 #if SIZEOF_VOID_P == 4
2522 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2523 mono_interlocked_lock ();
2524 *(gint64*)ptr = value;
2525 mono_interlocked_unlock ();
2530 InterlockedWrite64 (ptr, value);
2534 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2536 InterlockedWritePointer (ptr, value);
2540 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2544 #if SIZEOF_VOID_P == 4
2545 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2546 mono_interlocked_lock ();
2547 *(double*)ptr = value;
2548 mono_interlocked_unlock ();
2555 InterlockedWrite64 (ptr, u.ival);
2559 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2565 InterlockedWrite (ptr, u.ival);
2569 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2571 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2575 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2577 mono_threads_lock ();
2579 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2582 contexts = g_hash_table_new (NULL, NULL);
2584 context_adjust_static_data (ctx);
2585 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2586 g_hash_table_insert (contexts, gch, gch);
2588 mono_threads_unlock ();
2592 mono_thread_init_tls (void)
2594 MONO_FAST_TLS_INIT (tls_current_object);
2595 mono_native_tls_alloc (¤t_object_key, NULL);
2598 void mono_thread_init (MonoThreadStartCB start_cb,
2599 MonoThreadAttachCB attach_cb)
2601 mono_mutex_init_recursive(&threads_mutex);
2602 mono_mutex_init_recursive(&interlocked_mutex);
2603 mono_mutex_init_recursive(&joinable_threads_mutex);
2605 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2606 g_assert(background_change_event != NULL);
2608 mono_init_static_data_info (&thread_static_info);
2609 mono_init_static_data_info (&context_static_info);
2611 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2613 mono_thread_start_cb = start_cb;
2614 mono_thread_attach_cb = attach_cb;
2616 /* Get a pseudo handle to the current process. This is just a
2617 * kludge so that wapi can build a process handle if needed.
2618 * As a pseudo handle is returned, we don't need to clean
2621 GetCurrentProcess ();
2624 void mono_thread_cleanup (void)
2626 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2627 MonoThreadInfo *info;
2629 /* The main thread must abandon any held mutexes (particularly
2630 * important for named mutexes as they are shared across
2631 * processes, see bug 74680.) This will happen when the
2632 * thread exits, but if it's not running in a subthread it
2633 * won't exit in time.
2635 info = mono_thread_info_current ();
2636 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2640 /* This stuff needs more testing, it seems one of these
2641 * critical sections can be locked when mono_thread_cleanup is
2644 mono_mutex_destroy (&threads_mutex);
2645 mono_mutex_destroy (&interlocked_mutex);
2646 mono_mutex_destroy (&delayed_free_table_mutex);
2647 mono_mutex_destroy (&small_id_mutex);
2648 CloseHandle (background_change_event);
2651 mono_native_tls_free (current_object_key);
2655 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2657 mono_thread_cleanup_fn = func;
2661 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2663 thread->internal_thread->manage_callback = func;
2666 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2668 mono_thread_notify_pending_exc_fn = func;
2672 static void print_tids (gpointer key, gpointer value, gpointer user)
2674 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2675 * sizeof(uint) and a cast to uint would overflow
2677 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2678 * print this as a pointer.
2680 g_message ("Waiting for: %p", key);
2685 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2686 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2690 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2694 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2696 MONO_PREPARE_BLOCKING
2697 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2698 MONO_FINISH_BLOCKING
2700 if(ret==WAIT_FAILED) {
2701 /* See the comment in build_wait_tids() */
2702 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2706 for(i=0; i<wait->num; i++)
2707 CloseHandle (wait->handles[i]);
2709 if (ret == WAIT_TIMEOUT)
2712 for(i=0; i<wait->num; i++) {
2713 gsize tid = wait->threads[i]->tid;
2716 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2717 * it can still run io-layer etc. code. So wait for it to really exit.
2718 * FIXME: This won't join threads which are not in the joinable_hash yet.
2720 mono_thread_join ((gpointer)tid);
2722 mono_threads_lock ();
2723 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2724 /* This thread must have been killed, because
2725 * it hasn't cleaned itself up. (It's just
2726 * possible that the thread exited before the
2727 * parent thread had a chance to store the
2728 * handle, and now there is another pointer to
2729 * the already-exited thread stored. In this
2730 * case, we'll just get two
2731 * mono_profiler_thread_end() calls for the
2735 mono_threads_unlock ();
2736 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2737 thread_cleanup (wait->threads[i]);
2739 mono_threads_unlock ();
2744 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2746 guint32 i, ret, count;
2748 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2750 /* Add the thread state change event, so it wakes up if a thread changes
2751 * to background mode.
2754 if (count < MAXIMUM_WAIT_OBJECTS) {
2755 wait->handles [count] = background_change_event;
2759 MONO_PREPARE_BLOCKING
2760 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2761 MONO_FINISH_BLOCKING
2763 if(ret==WAIT_FAILED) {
2764 /* See the comment in build_wait_tids() */
2765 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2769 for(i=0; i<wait->num; i++)
2770 CloseHandle (wait->handles[i]);
2772 if (ret == WAIT_TIMEOUT)
2775 if (ret < wait->num) {
2776 gsize tid = wait->threads[ret]->tid;
2777 mono_threads_lock ();
2778 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2779 /* See comment in wait_for_tids about thread cleanup */
2780 mono_threads_unlock ();
2781 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2782 thread_cleanup (wait->threads [ret]);
2784 mono_threads_unlock ();
2788 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2790 struct wait_data *wait=(struct wait_data *)user;
2792 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2794 MonoInternalThread *thread=(MonoInternalThread *)value;
2796 /* Ignore background threads, we abort them later */
2797 /* Do not lock here since it is not needed and the caller holds threads_lock */
2798 if (thread->state & ThreadState_Background) {
2799 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2800 return; /* just leave, ignore */
2803 if (mono_gc_is_finalizer_internal_thread (thread)) {
2804 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2808 if (thread == mono_thread_internal_current ()) {
2809 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2813 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2814 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2818 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2819 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2823 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2824 if (handle == NULL) {
2825 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2829 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2830 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2831 wait->handles[wait->num]=handle;
2832 wait->threads[wait->num]=thread;
2835 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2837 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2842 /* Just ignore the rest, we can't do anything with
2849 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2851 struct wait_data *wait=(struct wait_data *)user;
2852 gsize self = GetCurrentThreadId ();
2853 MonoInternalThread *thread = value;
2856 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2859 /* The finalizer thread is not a background thread */
2860 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2861 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2863 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2867 /* printf ("A: %d\n", wait->num); */
2868 wait->handles[wait->num]=thread->handle;
2869 wait->threads[wait->num]=thread;
2872 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2873 mono_thread_internal_stop (thread);
2877 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2881 * mono_threads_set_shutting_down:
2883 * Is called by a thread that wants to shut down Mono. If the runtime is already
2884 * shutting down, the calling thread is suspended/stopped, and this function never
2888 mono_threads_set_shutting_down (void)
2890 MonoInternalThread *current_thread = mono_thread_internal_current ();
2892 mono_threads_lock ();
2894 if (shutting_down) {
2895 mono_threads_unlock ();
2897 /* Make sure we're properly suspended/stopped */
2899 LOCK_THREAD (current_thread);
2901 if ((current_thread->state & ThreadState_SuspendRequested) ||
2902 (current_thread->state & ThreadState_AbortRequested) ||
2903 (current_thread->state & ThreadState_StopRequested)) {
2904 UNLOCK_THREAD (current_thread);
2905 mono_thread_execute_interruption (current_thread);
2907 current_thread->state |= ThreadState_Stopped;
2908 UNLOCK_THREAD (current_thread);
2911 /*since we're killing the thread, unset the current domain.*/
2912 mono_domain_unset ();
2914 /* Wake up other threads potentially waiting for us */
2915 mono_thread_info_exit ();
2917 shutting_down = TRUE;
2919 /* Not really a background state change, but this will
2920 * interrupt the main thread if it is waiting for all
2921 * the other threads.
2923 SetEvent (background_change_event);
2925 mono_threads_unlock ();
2929 void mono_thread_manage (void)
2931 struct wait_data wait_data;
2932 struct wait_data *wait = &wait_data;
2934 memset (wait, 0, sizeof (struct wait_data));
2935 /* join each thread that's still running */
2936 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2938 mono_threads_lock ();
2940 THREAD_DEBUG (g_message("%s: No threads", __func__));
2941 mono_threads_unlock ();
2944 mono_threads_unlock ();
2947 mono_threads_lock ();
2948 if (shutting_down) {
2949 /* somebody else is shutting down */
2950 mono_threads_unlock ();
2953 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2954 mono_g_hash_table_foreach (threads, print_tids, NULL));
2956 ResetEvent (background_change_event);
2958 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2959 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2960 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2961 mono_threads_unlock ();
2963 /* Something to wait for */
2964 wait_for_tids_or_state_change (wait, INFINITE);
2966 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2967 } while(wait->num>0);
2969 /* Mono is shutting down, so just wait for the end */
2970 if (!mono_runtime_try_shutdown ()) {
2971 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2972 mono_thread_suspend (mono_thread_internal_current ());
2973 mono_thread_execute_interruption (mono_thread_internal_current ());
2977 * Remove everything but the finalizer thread and self.
2978 * Also abort all the background threads
2981 mono_threads_lock ();
2984 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2985 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2986 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2988 mono_threads_unlock ();
2990 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2992 /* Something to wait for */
2993 wait_for_tids (wait, INFINITE);
2995 } while (wait->num > 0);
2998 * give the subthreads a chance to really quit (this is mainly needed
2999 * to get correct user and system times from getrusage/wait/time(1)).
3000 * This could be removed if we avoid pthread_detach() and use pthread_join().
3002 mono_thread_info_yield ();
3005 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3007 MonoInternalThread *thread=(MonoInternalThread *)value;
3009 if(thread->tid != (gsize)user) {
3010 /*TerminateThread (thread->handle, -1);*/
3014 void mono_thread_abort_all_other_threads (void)
3016 gsize self = GetCurrentThreadId ();
3018 mono_threads_lock ();
3019 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3020 mono_g_hash_table_size (threads));
3021 mono_g_hash_table_foreach (threads, print_tids, NULL));
3023 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3025 mono_threads_unlock ();
3029 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3031 MonoInternalThread *thread = (MonoInternalThread*)value;
3032 struct wait_data *wait = (struct wait_data*)user_data;
3036 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3038 * This needs no locking.
3040 if ((thread->state & ThreadState_Suspended) != 0 ||
3041 (thread->state & ThreadState_Stopped) != 0)
3044 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3045 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3049 wait->handles [wait->num] = handle;
3050 wait->threads [wait->num] = thread;
3056 * mono_thread_suspend_all_other_threads:
3058 * Suspend all managed threads except the finalizer thread and this thread. It is
3059 * not possible to resume them later.
3061 void mono_thread_suspend_all_other_threads (void)
3063 struct wait_data wait_data;
3064 struct wait_data *wait = &wait_data;
3066 gsize self = GetCurrentThreadId ();
3067 guint32 eventidx = 0;
3068 gboolean starting, finished;
3070 memset (wait, 0, sizeof (struct wait_data));
3072 * The other threads could be in an arbitrary state at this point, i.e.
3073 * they could be starting up, shutting down etc. This means that there could be
3074 * threads which are not even in the threads hash table yet.
3078 * First we set a barrier which will be checked by all threads before they
3079 * are added to the threads hash table, and they will exit if the flag is set.
3080 * This ensures that no threads could be added to the hash later.
3081 * We will use shutting_down as the barrier for now.
3083 g_assert (shutting_down);
3086 * We make multiple calls to WaitForMultipleObjects since:
3087 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3088 * - some threads could exit without becoming suspended
3093 * Make a copy of the hashtable since we can't do anything with
3094 * threads while threads_mutex is held.
3097 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3098 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3099 mono_threads_lock ();
3100 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3101 mono_threads_unlock ();
3104 /* Get the suspended events that we'll be waiting for */
3105 for (i = 0; i < wait->num; ++i) {
3106 MonoInternalThread *thread = wait->threads [i];
3108 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3109 //CloseHandle (wait->handles [i]);
3110 wait->threads [i] = NULL; /* ignore this thread in next loop */
3114 LOCK_THREAD (thread);
3116 if ((thread->state & ThreadState_Suspended) != 0 ||
3117 (thread->state & ThreadState_StopRequested) != 0 ||
3118 (thread->state & ThreadState_Stopped) != 0) {
3119 UNLOCK_THREAD (thread);
3120 CloseHandle (wait->handles [i]);
3121 wait->threads [i] = NULL; /* ignore this thread in next loop */
3127 /* Convert abort requests into suspend requests */
3128 if ((thread->state & ThreadState_AbortRequested) != 0)
3129 thread->state &= ~ThreadState_AbortRequested;
3131 thread->state |= ThreadState_SuspendRequested;
3133 UNLOCK_THREAD (thread);
3135 /* Signal the thread to suspend */
3136 suspend_thread_internal (thread, TRUE);
3138 if (eventidx <= 0) {
3140 * If there are threads which are starting up, we wait until they
3141 * are suspended when they try to register in the threads hash.
3142 * This is guaranteed to finish, since the threads which can create new
3143 * threads get suspended after a while.
3144 * FIXME: The finalizer thread can still create new threads.
3146 mono_threads_lock ();
3147 if (threads_starting_up)
3148 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3151 mono_threads_unlock ();
3160 static gboolean thread_dump_requested;
3162 static G_GNUC_UNUSED gboolean
3163 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3165 GString *p = (GString*)data;
3166 MonoMethod *method = NULL;
3168 method = mono_jit_info_get_method (frame->ji);
3171 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3172 g_string_append_printf (p, " %s\n", location);
3175 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3180 static SuspendThreadResult
3181 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3183 MonoInternalThread *thread = ud;
3184 GString* text = g_string_new (0);
3186 GError *error = NULL;
3189 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3191 g_string_append_printf (text, "\n\"%s\"", name);
3194 else if (thread->threadpool_thread)
3195 g_string_append (text, "\n\"<threadpool thread>\"");
3197 g_string_append (text, "\n\"<unnamed thread>\"");
3200 /* This no longer works with remote unwinding */
3202 wapi_desc = wapi_current_thread_desc ();
3203 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3208 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);
3210 fprintf (stdout, "%s", text->str);
3212 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3213 OutputDebugStringA(text->str);
3216 g_string_free (text, TRUE);
3218 return MonoResumeThread;
3222 dump_thread (gpointer key, gpointer value, gpointer user)
3224 MonoInternalThread *thread = (MonoInternalThread *)value;
3226 if (thread == mono_thread_internal_current ())
3230 FIXME This still can hang if we stop a thread during malloc.
3231 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3232 that takes a callback and runs it with the target suspended.
3233 We probably should loop a bit around trying to get it to either managed code
3236 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
3240 mono_threads_perform_thread_dump (void)
3242 if (!thread_dump_requested)
3245 printf ("Full thread dump:\n");
3247 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3248 something needs then in the process.
3250 mono_loader_lock ();
3251 mono_domain_lock (mono_get_root_domain ());
3253 mono_threads_lock ();
3254 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3255 mono_threads_unlock ();
3257 mono_domain_unlock (mono_get_root_domain ());
3258 mono_loader_unlock ();
3260 thread_dump_requested = FALSE;
3264 * mono_threads_request_thread_dump:
3266 * Ask all threads except the current to print their stacktrace to stdout.
3269 mono_threads_request_thread_dump (void)
3271 /*The new thread dump code runs out of the finalizer thread. */
3272 thread_dump_requested = TRUE;
3273 mono_gc_finalize_notify ();
3278 gint allocated; /* +1 so that refs [allocated] == NULL */
3282 typedef struct ref_stack RefStack;
3285 ref_stack_new (gint initial_size)
3289 initial_size = MAX (initial_size, 16) + 1;
3290 rs = g_new0 (RefStack, 1);
3291 rs->refs = g_new0 (gpointer, initial_size);
3292 rs->allocated = initial_size;
3297 ref_stack_destroy (gpointer ptr)
3308 ref_stack_push (RefStack *rs, gpointer ptr)
3310 g_assert (rs != NULL);
3312 if (rs->bottom >= rs->allocated) {
3313 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3314 rs->allocated <<= 1;
3315 rs->refs [rs->allocated] = NULL;
3317 rs->refs [rs->bottom++] = ptr;
3321 ref_stack_pop (RefStack *rs)
3323 if (rs == NULL || rs->bottom == 0)
3327 rs->refs [rs->bottom] = NULL;
3331 ref_stack_find (RefStack *rs, gpointer ptr)
3338 for (refs = rs->refs; refs && *refs; refs++) {
3346 * mono_thread_push_appdomain_ref:
3348 * Register that the current thread may have references to objects in domain
3349 * @domain on its stack. Each call to this function should be paired with a
3350 * call to pop_appdomain_ref.
3353 mono_thread_push_appdomain_ref (MonoDomain *domain)
3355 MonoInternalThread *thread = mono_thread_internal_current ();
3358 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3359 SPIN_LOCK (thread->lock_thread_id);
3360 if (thread->appdomain_refs == NULL)
3361 thread->appdomain_refs = ref_stack_new (16);
3362 ref_stack_push (thread->appdomain_refs, domain);
3363 SPIN_UNLOCK (thread->lock_thread_id);
3368 mono_thread_pop_appdomain_ref (void)
3370 MonoInternalThread *thread = mono_thread_internal_current ();
3373 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3374 SPIN_LOCK (thread->lock_thread_id);
3375 ref_stack_pop (thread->appdomain_refs);
3376 SPIN_UNLOCK (thread->lock_thread_id);
3381 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3384 SPIN_LOCK (thread->lock_thread_id);
3385 res = ref_stack_find (thread->appdomain_refs, domain);
3386 SPIN_UNLOCK (thread->lock_thread_id);
3391 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3393 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3396 typedef struct abort_appdomain_data {
3397 struct wait_data wait;
3399 } abort_appdomain_data;
3402 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3404 MonoInternalThread *thread = (MonoInternalThread*)value;
3405 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3406 MonoDomain *domain = data->domain;
3408 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3409 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3411 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3412 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3415 data->wait.handles [data->wait.num] = handle;
3416 data->wait.threads [data->wait.num] = thread;
3419 /* Just ignore the rest, we can't do anything with
3427 * mono_threads_abort_appdomain_threads:
3429 * Abort threads which has references to the given appdomain.
3432 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3434 #ifdef __native_client__
3438 abort_appdomain_data user_data;
3440 int orig_timeout = timeout;
3443 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3445 start_time = mono_msec_ticks ();
3447 mono_threads_lock ();
3449 user_data.domain = domain;
3450 user_data.wait.num = 0;
3451 /* This shouldn't take any locks */
3452 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3453 mono_threads_unlock ();
3455 if (user_data.wait.num > 0) {
3456 /* Abort the threads outside the threads lock */
3457 for (i = 0; i < user_data.wait.num; ++i)
3458 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3461 * We should wait for the threads either to abort, or to leave the
3462 * domain. We can't do the latter, so we wait with a timeout.
3464 wait_for_tids (&user_data.wait, 100);
3467 /* Update remaining time */
3468 timeout -= mono_msec_ticks () - start_time;
3469 start_time = mono_msec_ticks ();
3471 if (orig_timeout != -1 && timeout < 0)
3474 while (user_data.wait.num > 0);
3476 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3482 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3484 MonoInternalThread *thread = (MonoInternalThread*)value;
3485 MonoDomain *domain = (MonoDomain*)user_data;
3488 /* No locking needed here */
3489 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3491 if (thread->cached_culture_info) {
3492 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3493 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3494 if (obj && obj->vtable->domain == domain)
3495 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3501 * mono_threads_clear_cached_culture:
3503 * Clear the cached_current_culture from all threads if it is in the
3507 mono_threads_clear_cached_culture (MonoDomain *domain)
3509 mono_threads_lock ();
3510 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3511 mono_threads_unlock ();
3515 * mono_thread_get_undeniable_exception:
3517 * Return an exception which needs to be raised when leaving a catch clause.
3518 * This is used for undeniable exception propagation.
3521 mono_thread_get_undeniable_exception (void)
3523 MonoInternalThread *thread = mono_thread_internal_current ();
3525 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3527 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3528 * exception if the thread no longer references a dying appdomain.
3530 thread->abort_exc->trace_ips = NULL;
3531 thread->abort_exc->stack_trace = NULL;
3532 return thread->abort_exc;
3538 #if MONO_SMALL_CONFIG
3539 #define NUM_STATIC_DATA_IDX 4
3540 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3544 #define NUM_STATIC_DATA_IDX 8
3545 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3546 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3550 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3551 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3554 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3556 gpointer *static_data = addr;
3558 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3559 void **ptr = static_data [i];
3564 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3565 void **p = ptr + idx;
3568 mark_func (p, gc_data);
3574 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3576 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3580 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3582 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3586 * mono_alloc_static_data
3588 * Allocate memory blocks for storing threads or context static data
3591 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3593 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3596 gpointer* static_data = *static_data_ptr;
3598 static void *tls_desc = NULL;
3599 static void *ctx_desc = NULL;
3601 if (mono_gc_user_markers_supported ()) {
3603 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3606 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3609 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc);
3610 *static_data_ptr = static_data;
3611 static_data [0] = static_data;
3614 for (i = 1; i <= idx; ++i) {
3615 if (static_data [i])
3618 if (mono_gc_user_markers_supported ())
3619 static_data [i] = g_malloc0 (static_data_size [i]);
3621 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3626 mono_free_static_data (gpointer* static_data)
3629 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3630 gpointer p = static_data [i];
3634 * At this point, the static data pointer array is still registered with the
3635 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3636 * data. Freeing the individual arrays without first nulling their slots
3637 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3638 * such an already freed array. See bug #13813.
3640 static_data [i] = NULL;
3641 mono_memory_write_barrier ();
3642 if (mono_gc_user_markers_supported ())
3645 mono_gc_free_fixed (p);
3647 mono_gc_free_fixed (static_data);
3651 * mono_init_static_data_info
3653 * Initializes static data counters
3655 static void mono_init_static_data_info (StaticDataInfo *static_data)
3657 static_data->idx = 0;
3658 static_data->offset = 0;
3659 static_data->freelist = NULL;
3663 * mono_alloc_static_data_slot
3665 * Generates an offset for static data. static_data contains the counters
3666 * used to generate it.
3669 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3671 if (!static_data->idx && !static_data->offset) {
3673 * we use the first chunk of the first allocation also as
3674 * an array for the rest of the data
3676 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3678 static_data->offset += align - 1;
3679 static_data->offset &= ~(align - 1);
3680 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3681 static_data->idx ++;
3682 g_assert (size <= static_data_size [static_data->idx]);
3683 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3684 static_data->offset = 0;
3686 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3687 static_data->offset += size;
3692 * ensure thread static fields already allocated are valid for thread
3693 * This function is called when a thread is created or on thread attach.
3696 thread_adjust_static_data (MonoInternalThread *thread)
3698 mono_threads_lock ();
3699 if (thread_static_info.offset || thread_static_info.idx > 0) {
3700 /* get the current allocated size */
3701 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3702 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3704 mono_threads_unlock ();
3708 context_adjust_static_data (MonoAppContext *ctx)
3710 mono_threads_lock ();
3712 if (context_static_info.offset || context_static_info.idx > 0) {
3713 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3714 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3717 mono_threads_unlock ();
3721 * LOCKING: requires that threads_mutex is held
3724 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3726 MonoInternalThread *thread = value;
3727 guint32 offset = GPOINTER_TO_UINT (user);
3729 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3733 * LOCKING: requires that threads_mutex is held
3736 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3738 uint32_t gch = GPOINTER_TO_INT (key);
3739 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3742 g_hash_table_remove (contexts, key);
3743 mono_gchandle_free (gch);
3747 guint32 offset = GPOINTER_TO_UINT (user);
3748 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3751 static StaticDataFreeList*
3752 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3754 StaticDataFreeList* prev = NULL;
3755 StaticDataFreeList* tmp = static_data->freelist;
3757 if (tmp->size == size) {
3759 prev->next = tmp->next;
3761 static_data->freelist = tmp->next;
3770 #if SIZEOF_VOID_P == 4
3777 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3779 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3781 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3782 MonoBitSet *rb = sets [idx];
3783 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3784 offset /= sizeof (uintptr_t);
3785 /* offset is now the bitmap offset */
3786 for (int i = 0; i < numbits; ++i) {
3787 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3788 mono_bitset_set_fast (rb, offset + i);
3793 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3795 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3796 MonoBitSet *rb = sets [idx];
3797 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3798 offset /= sizeof (uintptr_t);
3799 /* offset is now the bitmap offset */
3800 for (int i = 0; i < size / sizeof (uintptr_t); i++)
3801 mono_bitset_clear_fast (rb, offset + i);
3805 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3807 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3809 StaticDataInfo *info;
3812 if (static_type == SPECIAL_STATIC_THREAD) {
3813 info = &thread_static_info;
3814 sets = thread_reference_bitmaps;
3816 info = &context_static_info;
3817 sets = context_reference_bitmaps;
3820 mono_threads_lock ();
3822 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3826 offset = item->offset;
3829 offset = mono_alloc_static_data_slot (info, size, align);
3832 update_reference_bitmap (sets, offset, bitmap, numbits);
3834 if (static_type == SPECIAL_STATIC_THREAD) {
3835 /* This can be called during startup */
3836 if (threads != NULL)
3837 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3839 if (contexts != NULL)
3840 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3842 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3845 mono_threads_unlock ();
3851 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3853 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3855 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3856 return get_thread_static_data (thread, offset);
3858 return get_context_static_data (thread->current_appcontext, offset);
3863 mono_get_special_static_data (guint32 offset)
3865 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3874 * LOCKING: requires that threads_mutex is held
3877 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3879 MonoInternalThread *thread = value;
3880 OffsetSize *data = user;
3881 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3882 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3885 if (!thread->static_data || !thread->static_data [idx])
3887 ptr = ((char*) thread->static_data [idx]) + off;
3888 mono_gc_bzero_atomic (ptr, data->size);
3892 * LOCKING: requires that threads_mutex is held
3895 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3897 uint32_t gch = GPOINTER_TO_INT (key);
3898 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3901 g_hash_table_remove (contexts, key);
3902 mono_gchandle_free (gch);
3906 OffsetSize *data = user;
3907 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3908 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3911 if (!ctx->static_data || !ctx->static_data [idx])
3914 ptr = ((char*) ctx->static_data [idx]) + off;
3915 mono_gc_bzero_atomic (ptr, data->size);
3919 do_free_special_slot (guint32 offset, guint32 size)
3921 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3923 StaticDataInfo *info;
3925 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3926 info = &thread_static_info;
3927 sets = thread_reference_bitmaps;
3929 info = &context_static_info;
3930 sets = context_reference_bitmaps;
3933 guint32 data_offset = offset;
3934 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
3935 OffsetSize data = { data_offset, size };
3937 clear_reference_bitmap (sets, data.offset, data.size);
3939 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3940 if (threads != NULL)
3941 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3943 if (contexts != NULL)
3944 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
3947 if (!mono_runtime_is_shutting_down ()) {
3948 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
3950 item->offset = offset;
3953 item->next = info->freelist;
3954 info->freelist = item;
3959 do_free_special (gpointer key, gpointer value, gpointer data)
3961 MonoClassField *field = key;
3962 guint32 offset = GPOINTER_TO_UINT (value);
3965 size = mono_type_size (field->type, &align);
3966 do_free_special_slot (offset, size);
3970 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3972 mono_threads_lock ();
3974 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3976 mono_threads_unlock ();
3980 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3982 /* Only ever called for ThreadLocal instances */
3983 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
3985 mono_threads_lock ();
3986 do_free_special_slot (offset, size);
3987 mono_threads_unlock ();
3991 * allocates room in the thread local area for storing an instance of the struct type
3992 * the allocation is kept track of in domain->tlsrec_list.
3995 mono_thread_alloc_tls (MonoReflectionType *type)
3997 MonoDomain *domain = mono_domain_get ();
3999 MonoTlsDataRecord *tlsrec;
4002 gsize default_bitmap [4] = {0};
4003 uint32_t tls_offset;
4007 klass = mono_class_from_mono_type (type->type);
4008 /* TlsDatum is a struct, so we subtract the object header size offset */
4009 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
4010 size = mono_type_size (type->type, &align);
4011 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
4012 if (bitmap != default_bitmap)
4014 tlsrec = g_new0 (MonoTlsDataRecord, 1);
4015 tlsrec->tls_offset = tls_offset;
4016 tlsrec->size = size;
4017 mono_domain_lock (domain);
4018 tlsrec->next = domain->tlsrec_list;
4019 domain->tlsrec_list = tlsrec;
4020 mono_domain_unlock (domain);
4025 destroy_tls (MonoDomain *domain, uint32_t tls_offset)
4027 MonoTlsDataRecord *prev = NULL;
4028 MonoTlsDataRecord *cur;
4031 mono_domain_lock (domain);
4032 cur = domain->tlsrec_list;
4034 if (cur->tls_offset == tls_offset) {
4036 prev->next = cur->next;
4038 domain->tlsrec_list = cur->next;
4046 mono_domain_unlock (domain);
4048 mono_special_static_data_free_slot (tls_offset, size);
4052 mono_thread_destroy_tls (uint32_t tls_offset)
4054 destroy_tls (mono_domain_get (), tls_offset);
4058 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
4061 mono_thread_destroy_domain_tls (MonoDomain *domain)
4063 while (domain->tlsrec_list)
4064 destroy_tls (domain, domain->tlsrec_list->tls_offset);
4068 /* local tls data to get locals_slot from a thread */
4070 /* index in the locals_slot array */
4075 * LOCKING: requires that threads_mutex is held
4078 clear_thread_local_slot (gpointer key, gpointer value, gpointer user_data)
4080 MonoInternalThread *thread = (MonoInternalThread *) value;
4081 LocalSlotID *sid = user_data;
4083 int idx = ACCESS_SPECIAL_STATIC_OFFSET (sid->offset, index);
4084 int off = ACCESS_SPECIAL_STATIC_OFFSET (sid->offset, offset);
4086 if (!thread->static_data || !thread->static_data [idx])
4089 MonoArray *slots_array = *(MonoArray **)(((char *) thread->static_data [idx]) + off);
4091 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4094 mono_array_set (slots_array, MonoObject *, sid->slot, NULL);
4098 * LOCKING: requires that threads_mutex is held
4101 clear_context_local_slot (gpointer key, gpointer value, gpointer user_data)
4103 uint32_t gch = GPOINTER_TO_UINT (key);
4104 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
4107 g_hash_table_remove (contexts, key);
4108 mono_gchandle_free (gch);
4112 LocalSlotID *sid = user_data;
4114 int idx = ACCESS_SPECIAL_STATIC_OFFSET (sid->offset, index);
4115 int off = ACCESS_SPECIAL_STATIC_OFFSET (sid->offset, offset);
4117 if (!ctx->static_data || !ctx->static_data [idx])
4120 MonoArray *slots_array = *(MonoArray **) (((char *) ctx->static_data [idx]) + off);
4122 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4125 mono_array_set (slots_array, MonoObject *, sid->slot, NULL);
4129 static void CALLBACK dummy_apc (ULONG_PTR param)
4135 * mono_thread_execute_interruption
4137 * Performs the operation that the requested thread state requires (abort,
4140 static MonoException*
4141 mono_thread_execute_interruption (MonoInternalThread *thread)
4143 LOCK_THREAD (thread);
4145 /* MonoThread::interruption_requested can only be changed with atomics */
4146 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4147 /* this will consume pending APC calls */
4149 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4151 InterlockedDecrement (&thread_interruption_requested);
4152 /* Clear the interrupted flag of the thread so it can wait again */
4153 mono_thread_info_clear_interruption ();
4156 if ((thread->state & ThreadState_AbortRequested) != 0) {
4157 UNLOCK_THREAD (thread);
4158 if (thread->abort_exc == NULL) {
4160 * This might be racy, but it has to be called outside the lock
4161 * since it calls managed code.
4163 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4165 return thread->abort_exc;
4167 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4168 self_suspend_internal (thread);
4171 else if ((thread->state & ThreadState_StopRequested) != 0) {
4172 /* FIXME: do this through the JIT? */
4174 UNLOCK_THREAD (thread);
4176 mono_thread_exit ();
4178 } else if (thread->pending_exception) {
4181 exc = thread->pending_exception;
4182 thread->pending_exception = NULL;
4184 UNLOCK_THREAD (thread);
4186 } else if (thread->thread_interrupt_requested) {
4188 thread->thread_interrupt_requested = FALSE;
4189 UNLOCK_THREAD (thread);
4191 return(mono_get_exception_thread_interrupted ());
4194 UNLOCK_THREAD (thread);
4200 * mono_thread_request_interruption
4202 * A signal handler can call this method to request the interruption of a
4203 * thread. The result of the interruption will depend on the current state of
4204 * the thread. If the result is an exception that needs to be throw, it is
4205 * provided as return value.
4208 mono_thread_request_interruption (gboolean running_managed)
4210 MonoInternalThread *thread = mono_thread_internal_current ();
4212 /* The thread may already be stopping */
4217 if (thread->interrupt_on_stop &&
4218 thread->state & ThreadState_StopRequested &&
4219 thread->state & ThreadState_Background)
4223 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4225 InterlockedIncrement (&thread_interruption_requested);
4227 if (!running_managed || is_running_protected_wrapper ()) {
4228 /* Can't stop while in unmanaged code. Increase the global interruption
4229 request count. When exiting the unmanaged method the count will be
4230 checked and the thread will be interrupted. */
4232 if (mono_thread_notify_pending_exc_fn && !running_managed)
4233 /* The JIT will notify the thread about the interruption */
4234 /* This shouldn't take any locks */
4235 mono_thread_notify_pending_exc_fn (NULL);
4237 /* this will awake the thread if it is in WaitForSingleObject
4239 /* Our implementation of this function ignores the func argument */
4241 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4243 mono_thread_info_self_interrupt ();
4248 return mono_thread_execute_interruption (thread);
4252 /*This function should be called by a thread after it has exited all of
4253 * its handle blocks at interruption time.*/
4255 mono_thread_resume_interruption (void)
4257 MonoInternalThread *thread = mono_thread_internal_current ();
4258 gboolean still_aborting;
4260 /* The thread may already be stopping */
4264 LOCK_THREAD (thread);
4265 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4266 UNLOCK_THREAD (thread);
4268 /*This can happen if the protected block called Thread::ResetAbort*/
4269 if (!still_aborting)
4272 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4274 InterlockedIncrement (&thread_interruption_requested);
4276 mono_thread_info_self_interrupt ();
4278 return mono_thread_execute_interruption (thread);
4281 gboolean mono_thread_interruption_requested ()
4283 if (thread_interruption_requested) {
4284 MonoInternalThread *thread = mono_thread_internal_current ();
4285 /* The thread may already be stopping */
4287 return (thread->interruption_requested);
4292 static MonoException*
4293 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4295 MonoInternalThread *thread = mono_thread_internal_current ();
4297 /* The thread may already be stopping */
4301 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4302 MonoException* exc = mono_thread_execute_interruption (thread);
4310 * Performs the interruption of the current thread, if one has been requested,
4311 * and the thread is not running a protected wrapper.
4312 * Return the exception which needs to be thrown, if any.
4315 mono_thread_interruption_checkpoint (void)
4317 return mono_thread_interruption_checkpoint_request (FALSE);
4321 * Performs the interruption of the current thread, if one has been requested.
4322 * Return the exception which needs to be thrown, if any.
4325 mono_thread_force_interruption_checkpoint_noraise (void)
4327 return mono_thread_interruption_checkpoint_request (TRUE);
4331 * Performs the interruption of the current thread, if one has been requested.
4332 * Throw the exception which needs to be thrown, if any.
4335 mono_thread_force_interruption_checkpoint (void)
4339 ex = mono_thread_interruption_checkpoint_request (TRUE);
4341 mono_raise_exception (ex);
4345 * mono_thread_get_and_clear_pending_exception:
4347 * Return any pending exceptions for the current thread and clear it as a side effect.
4350 mono_thread_get_and_clear_pending_exception (void)
4352 MonoInternalThread *thread = mono_thread_internal_current ();
4354 /* The thread may already be stopping */
4358 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4359 return mono_thread_execute_interruption (thread);
4362 if (thread->pending_exception) {
4363 MonoException *exc = thread->pending_exception;
4365 thread->pending_exception = NULL;
4373 * mono_set_pending_exception:
4375 * Set the pending exception of the current thread to EXC.
4376 * The exception will be thrown when execution returns to managed code.
4379 mono_set_pending_exception (MonoException *exc)
4381 MonoInternalThread *thread = mono_thread_internal_current ();
4383 /* The thread may already be stopping */
4387 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4389 mono_thread_request_interruption (FALSE);
4393 * mono_thread_interruption_request_flag:
4395 * Returns the address of a flag that will be non-zero if an interruption has
4396 * been requested for a thread. The thread to interrupt may not be the current
4397 * thread, so an additional call to mono_thread_interruption_requested() or
4398 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4401 gint32* mono_thread_interruption_request_flag ()
4403 return &thread_interruption_requested;
4407 mono_thread_init_apartment_state (void)
4410 MonoInternalThread* thread = mono_thread_internal_current ();
4412 /* Positive return value indicates success, either
4413 * S_OK if this is first CoInitialize call, or
4414 * S_FALSE if CoInitialize already called, but with same
4415 * threading model. A negative value indicates failure,
4416 * probably due to trying to change the threading model.
4418 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4419 ? COINIT_APARTMENTTHREADED
4420 : COINIT_MULTITHREADED) < 0) {
4421 thread->apartment_state = ThreadApartmentState_Unknown;
4427 mono_thread_cleanup_apartment_state (void)
4430 MonoInternalThread* thread = mono_thread_internal_current ();
4432 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4439 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4441 LOCK_THREAD (thread);
4442 thread->state |= state;
4443 UNLOCK_THREAD (thread);
4447 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4449 LOCK_THREAD (thread);
4450 thread->state &= ~state;
4451 UNLOCK_THREAD (thread);
4455 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4457 gboolean ret = FALSE;
4459 LOCK_THREAD (thread);
4461 if ((thread->state & test) != 0) {
4465 UNLOCK_THREAD (thread);
4470 //static MonoClassField *execution_context_field;
4473 get_execution_context_addr (void)
4475 MonoDomain *domain = mono_domain_get ();
4476 guint32 offset = domain->execution_context_field_offset;
4479 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4482 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4484 mono_domain_lock (domain);
4485 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4486 mono_domain_unlock (domain);
4489 domain->execution_context_field_offset = offset;
4492 return (MonoObject**) mono_get_special_static_data (offset);
4496 mono_thread_get_execution_context (void)
4498 return *get_execution_context_addr ();
4502 mono_thread_set_execution_context (MonoObject *ec)
4504 *get_execution_context_addr () = ec;
4507 static gboolean has_tls_get = FALSE;
4510 mono_runtime_set_has_tls_get (gboolean val)
4516 mono_runtime_has_tls_get (void)
4522 self_interrupt_thread (void *_unused)
4524 MonoThreadInfo *info = mono_thread_info_current ();
4525 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4526 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4527 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. */
4528 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4532 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4536 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4540 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4542 MonoJitInfo **dest = data;
4548 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4550 MonoJitInfo *ji = NULL;
4553 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4558 MonoInternalThread *thread;
4559 gboolean install_async_abort;
4560 gpointer interrupt_handle;
4563 static SuspendThreadResult
4564 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4566 AbortThreadData *data = ud;
4567 MonoInternalThread *thread = data->thread;
4568 MonoJitInfo *ji = NULL;
4569 gboolean protected_wrapper;
4570 gboolean running_managed;
4572 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4573 return MonoResumeThread;
4575 /*someone is already interrupting it*/
4576 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4577 return MonoResumeThread;
4579 InterlockedIncrement (&thread_interruption_requested);
4581 ji = mono_thread_info_get_last_managed (info);
4582 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4583 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4585 if (!protected_wrapper && running_managed) {
4586 /*We are in managed code*/
4587 /*Set the thread to call */
4588 if (data->install_async_abort)
4589 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4590 return MonoResumeThread;
4592 if (mono_thread_notify_pending_exc_fn)
4593 /* The JIT will notify the thread about the interruption */
4594 mono_thread_notify_pending_exc_fn (info);
4597 * This will cause waits to be broken.
4598 * It will also prevent the thread from entering a wait, so if the thread returns
4599 * from the wait before it receives the abort signal, it will just spin in the wait
4600 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4603 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4604 return MonoResumeThread;
4609 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4611 AbortThreadData data = { 0 };
4612 data.thread = thread;
4613 data.install_async_abort = install_async_abort;
4616 FIXME this is insanely broken, it doesn't cause interruption to happen
4617 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4619 if (thread == mono_thread_internal_current ()) {
4620 /* Do it synchronously */
4621 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4623 mono_raise_exception (exc);
4624 mono_thread_info_interrupt (thread->handle);
4628 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
4629 if (data.interrupt_handle)
4630 mono_thread_info_finish_interrupt (data.interrupt_handle);
4631 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4635 MonoInternalThread *thread;
4637 gpointer interrupt_handle;
4638 } SuspendThreadData;
4640 static SuspendThreadResult
4641 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4643 SuspendThreadData *data = ud;
4644 MonoInternalThread *thread = data->thread;
4645 MonoJitInfo *ji = NULL;
4646 gboolean protected_wrapper;
4647 gboolean running_managed;
4649 ji = mono_thread_info_get_last_managed (info);
4650 protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4651 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4653 if (running_managed && !protected_wrapper) {
4654 thread->state &= ~ThreadState_SuspendRequested;
4655 thread->state |= ThreadState_Suspended;
4656 return KeepSuspended;
4658 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4659 InterlockedIncrement (&thread_interruption_requested);
4660 if (data->interrupt)
4661 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4663 if (mono_thread_notify_pending_exc_fn && !running_managed)
4664 /* The JIT will notify the thread about the interruption */
4665 mono_thread_notify_pending_exc_fn (info);
4666 return MonoResumeThread;
4671 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4673 LOCK_THREAD (thread);
4674 if (thread == mono_thread_internal_current ()) {
4675 mono_thread_info_begin_self_suspend ();
4676 //XXX replace this with better named functions
4677 thread->state &= ~ThreadState_SuspendRequested;
4678 thread->state |= ThreadState_Suspended;
4679 UNLOCK_THREAD (thread);
4680 mono_thread_info_end_self_suspend ();
4682 SuspendThreadData data = { 0 };
4683 data.thread = thread;
4684 data.interrupt = interrupt;
4686 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
4687 if (data.interrupt_handle)
4688 mono_thread_info_finish_interrupt (data.interrupt_handle);
4689 UNLOCK_THREAD (thread);
4693 /*This is called with @thread synch_cs held and it must release it*/
4695 self_suspend_internal (MonoInternalThread *thread)
4697 mono_thread_info_begin_self_suspend ();
4698 thread->state &= ~ThreadState_SuspendRequested;
4699 thread->state |= ThreadState_Suspended;
4700 UNLOCK_THREAD (thread);
4701 mono_thread_info_end_self_suspend ();
4704 /*This is called with @thread synch_cs held and it must release it*/
4706 resume_thread_internal (MonoInternalThread *thread)
4708 UNLOCK_THREAD (thread);
4709 /* Awake the thread */
4710 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4712 LOCK_THREAD (thread);
4713 thread->state &= ~ThreadState_Suspended;
4714 UNLOCK_THREAD (thread);
4720 * mono_thread_is_foreign:
4721 * @thread: the thread to query
4723 * This function allows one to determine if a thread was created by the mono runtime and has
4724 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4726 * Returns: true if @thread was not created by the runtime.
4729 mono_thread_is_foreign (MonoThread *thread)
4731 MonoThreadInfo *info = thread->internal_thread->thread_info;
4732 return info->runtime_thread == FALSE;
4736 * mono_add_joinable_thread:
4738 * Add TID to the list of joinable threads.
4739 * LOCKING: Acquires the threads lock.
4742 mono_threads_add_joinable_thread (gpointer tid)
4746 * We cannot detach from threads because it causes problems like
4747 * 2fd16f60/r114307. So we collect them and join them when
4748 * we have time (in he finalizer thread).
4750 joinable_threads_lock ();
4751 if (!joinable_threads)
4752 joinable_threads = g_hash_table_new (NULL, NULL);
4753 g_hash_table_insert (joinable_threads, tid, tid);
4754 joinable_thread_count ++;
4755 joinable_threads_unlock ();
4757 mono_gc_finalize_notify ();
4762 * mono_threads_join_threads:
4764 * Join all joinable threads. This is called from the finalizer thread.
4765 * LOCKING: Acquires the threads lock.
4768 mono_threads_join_threads (void)
4771 GHashTableIter iter;
4778 if (!joinable_thread_count)
4782 joinable_threads_lock ();
4784 if (g_hash_table_size (joinable_threads)) {
4785 g_hash_table_iter_init (&iter, joinable_threads);
4786 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4787 thread = (pthread_t)tid;
4788 g_hash_table_remove (joinable_threads, key);
4789 joinable_thread_count --;
4792 joinable_threads_unlock ();
4794 if (thread != pthread_self ())
4795 /* This shouldn't block */
4796 pthread_join (thread, NULL);
4807 * Wait for thread TID to exit.
4808 * LOCKING: Acquires the threads lock.
4811 mono_thread_join (gpointer tid)
4815 gboolean found = FALSE;
4817 joinable_threads_lock ();
4818 if (!joinable_threads)
4819 joinable_threads = g_hash_table_new (NULL, NULL);
4820 if (g_hash_table_lookup (joinable_threads, tid)) {
4821 g_hash_table_remove (joinable_threads, tid);
4822 joinable_thread_count --;
4825 joinable_threads_unlock ();
4828 thread = (pthread_t)tid;
4829 pthread_join (thread, NULL);