2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threads-types.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/environment.h>
26 #include <mono/metadata/monitor.h>
27 #include <mono/metadata/gc-internal.h>
28 #include <mono/metadata/marshal.h>
29 #include <mono/metadata/runtime.h>
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/mono-debug-debugger.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internal.h>
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
51 #define USE_TKILL_ON_ANDROID 1
54 #ifdef PLATFORM_ANDROID
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid, int signal);
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func)(void *);
107 typedef struct _StaticDataFreeList StaticDataFreeList;
108 struct _StaticDataFreeList {
109 StaticDataFreeList *next;
117 StaticDataFreeList *freelist;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 static void mono_threads_lock (void);
130 static void mono_threads_unlock (void);
131 static mono_mutex_t threads_mutex;
133 /* Controls access to the 'joinable_threads' hash table */
134 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
135 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
136 static mono_mutex_t joinable_threads_mutex;
138 /* Holds current status of static data heap */
139 static StaticDataInfo thread_static_info;
140 static StaticDataInfo context_static_info;
142 /* The hash of existing threads (key is thread ID, value is
143 * MonoInternalThread*) that need joining before exit
145 static MonoGHashTable *threads=NULL;
147 /* List of app context GC handles.
148 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
150 static GHashTable *contexts = NULL;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable *threads_starting_up = NULL;
159 /* Maps a MonoThread to its start argument */
160 /* Protected by mono_threads_lock () */
161 static MonoGHashTable *thread_start_args = NULL;
163 /* The TLS key that holds the MonoObject assigned to each thread */
164 static MonoNativeTlsKey current_object_key;
167 /* Protected by the threads lock */
168 static GHashTable *joinable_threads;
169 static int joinable_thread_count;
171 #ifdef MONO_HAVE_FAST_TLS
172 /* we need to use both the Tls* functions and __thread because
173 * the gc needs to see all the threads
175 MONO_FAST_TLS_DECLARE(tls_current_object);
176 #define SET_CURRENT_OBJECT(x) do { \
177 MONO_FAST_TLS_SET (tls_current_object, x); \
178 mono_native_tls_set_value (current_object_key, x); \
180 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
182 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
183 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
186 /* function called at thread start */
187 static MonoThreadStartCB mono_thread_start_cb = NULL;
189 /* function called at thread attach */
190 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
192 /* function called at thread cleanup */
193 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
195 /* function called to notify the runtime about a pending exception on the current thread */
196 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
198 /* The default stack size for each thread */
199 static guint32 default_stacksize = 0;
200 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
202 static void thread_adjust_static_data (MonoInternalThread *thread);
203 static void context_adjust_static_data (MonoAppContext *ctx);
204 static void mono_free_static_data (gpointer* static_data);
205 static void mono_init_static_data_info (StaticDataInfo *static_data);
206 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
207 static gboolean mono_thread_resume (MonoInternalThread* thread);
208 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
209 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
210 static void self_suspend_internal (MonoInternalThread *thread);
211 static gboolean resume_thread_internal (MonoInternalThread *thread);
213 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
214 static void ref_stack_destroy (gpointer rs);
216 /* Spin lock for InterlockedXXX 64 bit functions */
217 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
218 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
219 static mono_mutex_t interlocked_mutex;
221 /* global count of thread interruptions requested */
222 static gint32 thread_interruption_requested = 0;
224 /* Event signaled when a thread changes its background mode */
225 static HANDLE background_change_event;
227 static gboolean shutting_down = FALSE;
229 static gint32 managed_thread_id_counter = 0;
232 mono_threads_lock (void)
235 mono_locks_acquire (&threads_mutex, ThreadsLock);
236 MONO_FINISH_TRY_BLOCKING;
240 mono_threads_unlock (void)
242 mono_locks_release (&threads_mutex, ThreadsLock);
247 get_next_managed_thread_id (void)
249 return InterlockedIncrement (&managed_thread_id_counter);
253 mono_thread_get_tls_key (void)
255 return current_object_key;
259 mono_thread_get_tls_offset (void)
262 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
266 static inline MonoNativeThreadId
267 thread_get_tid (MonoInternalThread *thread)
269 /* We store the tid as a guint64 to keep the object layout constant between platforms */
270 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
273 /* handle_store() and handle_remove() manage the array of threads that
274 * still need to be waited for when the main thread exits.
276 * If handle_store() returns FALSE the thread must not be started
277 * because Mono is shutting down.
279 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
281 mono_threads_lock ();
283 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
285 if (threads_starting_up)
286 mono_g_hash_table_remove (threads_starting_up, thread);
288 if (shutting_down && !force_attach) {
289 mono_threads_unlock ();
294 MONO_GC_REGISTER_ROOT_FIXED (threads);
295 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
298 /* We don't need to duplicate thread->handle, because it is
299 * only closed when the thread object is finalized by the GC.
301 g_assert (thread->internal_thread);
302 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
303 thread->internal_thread);
305 mono_threads_unlock ();
310 static gboolean handle_remove(MonoInternalThread *thread)
313 gsize tid = thread->tid;
315 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
317 mono_threads_lock ();
320 /* We have to check whether the thread object for the
321 * tid is still the same in the table because the
322 * thread might have been destroyed and the tid reused
323 * in the meantime, in which case the tid would be in
324 * the table, but with another thread object.
326 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
327 mono_g_hash_table_remove (threads, (gpointer)tid);
336 mono_threads_unlock ();
338 /* Don't close the handle here, wait for the object finalizer
339 * to do it. Otherwise, the following race condition applies:
341 * 1) Thread exits (and handle_remove() closes the handle)
343 * 2) Some other handle is reassigned the same slot
345 * 3) Another thread tries to join the first thread, and
346 * blocks waiting for the reassigned handle to be signalled
347 * (which might never happen). This is possible, because the
348 * thread calling Join() still has a reference to the first
354 static void ensure_synch_cs_set (MonoInternalThread *thread)
356 mono_mutex_t *synch_cs;
358 if (thread->synch_cs != NULL) {
362 synch_cs = g_new0 (mono_mutex_t, 1);
363 mono_mutex_init_recursive (synch_cs);
365 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
366 synch_cs, NULL) != NULL) {
367 /* Another thread must have installed this CS */
368 mono_mutex_destroy (synch_cs);
374 lock_thread (MonoInternalThread *thread)
376 if (!thread->synch_cs)
377 ensure_synch_cs_set (thread);
379 g_assert (thread->synch_cs);
382 mono_mutex_lock (thread->synch_cs);
383 MONO_FINISH_TRY_BLOCKING;
387 unlock_thread (MonoInternalThread *thread)
389 mono_mutex_unlock (thread->synch_cs);
393 * NOTE: this function can be called also for threads different from the current one:
394 * make sure no code called from it will ever assume it is run on the thread that is
395 * getting cleaned up.
397 static void thread_cleanup (MonoInternalThread *thread)
399 g_assert (thread != NULL);
401 if (thread->abort_state_handle) {
402 mono_gchandle_free (thread->abort_state_handle);
403 thread->abort_state_handle = 0;
405 thread->abort_exc = NULL;
406 thread->current_appcontext = NULL;
409 * This is necessary because otherwise we might have
410 * cross-domain references which will not get cleaned up when
411 * the target domain is unloaded.
413 if (thread->cached_culture_info) {
415 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
416 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
420 * thread->synch_cs can be NULL if this was called after
421 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
422 * This can happen only during shutdown.
423 * The shutting_down flag is not always set, so we can't assert on it.
425 if (thread->synch_cs)
426 LOCK_THREAD (thread);
428 thread->state |= ThreadState_Stopped;
429 thread->state &= ~ThreadState_Background;
431 if (thread->synch_cs)
432 UNLOCK_THREAD (thread);
435 An interruption request has leaked to cleanup. Adjust the global counter.
437 This can happen is the abort source thread finds the abortee (this) thread
438 in unmanaged code. If this thread never trips back to managed code or check
439 the local flag it will be left set and positively unbalance the global counter.
441 Leaving the counter unbalanced will cause a performance degradation since all threads
442 will now keep checking their local flags all the time.
444 if (InterlockedExchange (&thread->interruption_requested, 0))
445 InterlockedDecrement (&thread_interruption_requested);
447 /* if the thread is not in the hash it has been removed already */
448 if (!handle_remove (thread)) {
449 if (thread == mono_thread_internal_current ()) {
450 mono_domain_unset ();
451 mono_memory_barrier ();
453 /* This needs to be called even if handle_remove () fails */
454 if (mono_thread_cleanup_fn)
455 mono_thread_cleanup_fn (thread_get_tid (thread));
458 mono_release_type_locks (thread);
460 mono_profiler_thread_end (thread->tid);
462 if (thread == mono_thread_internal_current ()) {
464 * This will signal async signal handlers that the thread has exited.
465 * The profiler callback needs this to be set, so it cannot be done earlier.
467 mono_domain_unset ();
468 mono_memory_barrier ();
471 if (thread == mono_thread_internal_current ())
472 mono_thread_pop_appdomain_ref ();
474 thread->cached_culture_info = NULL;
476 mono_free_static_data (thread->static_data);
477 thread->static_data = NULL;
478 ref_stack_destroy (thread->appdomain_refs);
479 thread->appdomain_refs = NULL;
481 if (mono_thread_cleanup_fn)
482 mono_thread_cleanup_fn (thread_get_tid (thread));
484 if (mono_gc_is_moving ()) {
485 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
486 thread->thread_pinning_ref = NULL;
491 * A special static data offset (guint32) consists of 3 parts:
493 * [0] 6-bit index into the array of chunks.
494 * [6] 25-bit offset into the array.
495 * [31] Bit indicating thread or context static.
500 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
511 } SpecialStaticOffset;
513 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
514 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
516 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
517 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
518 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
519 (((SpecialStaticOffset *) &(x))->fields.f)
522 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
524 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
526 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
527 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
529 return ((char *) thread->static_data [idx]) + off;
533 get_context_static_data (MonoAppContext *ctx, guint32 offset)
535 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
537 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
538 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
540 return ((char *) ctx->static_data [idx]) + off;
544 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
546 static MonoClassField *current_thread_field = NULL;
550 if (!current_thread_field) {
551 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
552 g_assert (current_thread_field);
555 mono_class_vtable (domain, mono_defaults.thread_class);
556 mono_domain_lock (domain);
557 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
558 mono_domain_unlock (domain);
561 return get_thread_static_data (thread, offset);
565 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
567 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
569 g_assert (current->obj.vtable->domain == domain);
571 g_assert (!*current_thread_ptr);
572 *current_thread_ptr = current;
576 create_thread_object (MonoDomain *domain)
578 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
579 return (MonoThread*)mono_gc_alloc_mature (vt);
583 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
585 MonoThread *thread = create_thread_object (domain);
586 MONO_OBJECT_SETREF (thread, internal_thread, internal);
590 static MonoInternalThread*
591 create_internal_thread (void)
593 MonoInternalThread *thread;
596 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
597 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
599 thread->synch_cs = g_new0 (mono_mutex_t, 1);
600 mono_mutex_init_recursive (thread->synch_cs);
602 thread->apartment_state = ThreadApartmentState_Unknown;
603 thread->managed_id = get_next_managed_thread_id ();
604 if (mono_gc_is_moving ()) {
605 thread->thread_pinning_ref = thread;
606 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
613 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
615 MonoDomain *domain = mono_get_root_domain ();
617 if (!candidate || candidate->obj.vtable->domain != domain)
618 candidate = new_thread_with_internal (domain, thread);
619 set_current_thread_for_domain (domain, thread, candidate);
620 g_assert (!thread->root_domain_thread);
621 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
624 static guint32 WINAPI start_wrapper_internal(void *data)
626 MonoThreadInfo *info;
627 StartInfo *start_info = (StartInfo *)data;
628 guint32 (*start_func)(void *);
632 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
635 MonoInternalThread *internal = start_info->obj->internal_thread;
636 MonoObject *start_delegate = start_info->delegate;
637 MonoDomain *domain = start_info->obj->obj.vtable->domain;
639 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
641 /* We can be sure start_info->obj->tid and
642 * start_info->obj->handle have been set, because the thread
643 * was created suspended, and these values were set before the
647 info = mono_thread_info_current ();
649 internal->thread_info = info;
650 internal->small_id = info->small_id;
654 SET_CURRENT_OBJECT (internal);
656 /* Every thread references the appdomain which created it */
657 mono_thread_push_appdomain_ref (domain);
659 if (!mono_domain_set (domain, FALSE)) {
660 /* No point in raising an appdomain_unloaded exception here */
661 /* FIXME: Cleanup here */
662 mono_thread_pop_appdomain_ref ();
666 start_func = start_info->func;
667 start_arg = start_info->start_arg;
669 /* We have to do this here because mono_thread_new_init()
670 requires that root_domain_thread is set up. */
671 thread_adjust_static_data (internal);
672 init_root_domain_thread (internal, start_info->obj);
674 /* This MUST be called before any managed code can be
675 * executed, as it calls the callback function that (for the
676 * jit) sets the lmf marker.
678 mono_thread_new_init (tid, &tid, start_func);
679 internal->stack_ptr = &tid;
681 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
683 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
685 /* On 2.0 profile (and higher), set explicitly since state might have been
687 if (internal->apartment_state == ThreadApartmentState_Unknown)
688 internal->apartment_state = ThreadApartmentState_MTA;
690 mono_thread_init_apartment_state ();
692 if(internal->start_notify!=NULL) {
693 /* Let the thread that called Start() know we're
696 ReleaseSemaphore (internal->start_notify, 1, NULL);
699 mono_threads_lock ();
700 mono_g_hash_table_remove (thread_start_args, start_info->obj);
701 mono_threads_unlock ();
704 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
708 * Call this after calling start_notify, since the profiler callback might want
709 * to lock the thread, and the lock is held by thread_start () which waits for
712 mono_profiler_thread_start (tid);
714 /* if the name was set before starting, we didn't invoke the profiler callback */
715 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
716 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
717 mono_profiler_thread_name (internal->tid, tname);
720 /* start_func is set only for unmanaged start functions */
722 start_func (start_arg);
725 g_assert (start_delegate != NULL);
726 args [0] = start_arg;
727 /* we may want to handle the exception here. See comment below on unhandled exceptions */
728 mono_runtime_delegate_invoke (start_delegate, args, NULL);
731 /* If the thread calls ExitThread at all, this remaining code
732 * will not be executed, but the main thread will eventually
733 * call thread_cleanup() on this thread's behalf.
736 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
738 /* Do any cleanup needed for apartment state. This
739 * cannot be done in thread_cleanup since thread_cleanup could be
740 * called for a thread other than the current thread.
741 * mono_thread_cleanup_apartment_state cleans up apartment
742 * for the current thead */
743 mono_thread_cleanup_apartment_state ();
745 thread_cleanup (internal);
749 /* Remove the reference to the thread object in the TLS data,
750 * so the thread object can be finalized. This won't be
751 * reached if the thread threw an uncaught exception, so those
752 * thread handles will stay referenced :-( (This is due to
753 * missing support for scanning thread-specific data in the
754 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
757 SET_CURRENT_OBJECT (NULL);
762 static guint32 WINAPI start_wrapper(void *data)
766 /* Avoid scanning the frames above this frame during a GC */
767 mono_gc_set_stack_end ((void*)&dummy);
769 return start_wrapper_internal (data);
775 * Common thread creation code.
776 * LOCKING: Acquires the threads lock.
779 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
780 gboolean throw_on_failure)
782 HANDLE thread_handle;
783 MonoNativeThreadId tid;
784 guint32 create_flags;
787 * Join joinable threads to prevent running out of threads since the finalizer
788 * thread might be blocked/backlogged.
790 mono_threads_join_threads ();
792 mono_threads_lock ();
795 mono_threads_unlock ();
799 * The thread start argument may be an object reference, and there is
800 * no ref to keep it alive when the new thread is started but not yet
801 * registered with the collector. So we store it in a GC tracked hash
804 if (thread_start_args == NULL) {
805 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
806 thread_start_args = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_CONSERVATIVE_GC);
808 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
809 if (threads_starting_up == NULL) {
810 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
811 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
813 mono_g_hash_table_insert (threads_starting_up, thread, thread);
814 mono_threads_unlock ();
816 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
817 if (!internal->start_notify) {
818 mono_threads_lock ();
819 mono_g_hash_table_remove (threads_starting_up, thread);
820 mono_threads_unlock ();
821 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
827 stack_size = default_stacksize_for_thread (internal);
829 /* Create suspended, so we can do some housekeeping before the thread
832 create_flags = CREATE_SUSPENDED;
834 MONO_PREPARE_BLOCKING;
835 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
836 stack_size, create_flags, &tid);
837 MONO_FINISH_BLOCKING;
839 if (thread_handle == NULL) {
840 /* The thread couldn't be created, so throw an exception */
841 mono_threads_lock ();
842 mono_g_hash_table_remove (threads_starting_up, thread);
843 mono_threads_unlock ();
845 if (throw_on_failure)
846 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
848 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
851 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
853 internal->handle = thread_handle;
854 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
856 internal->threadpool_thread = threadpool_thread;
857 if (threadpool_thread)
858 mono_thread_set_state (internal, ThreadState_Background);
860 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
862 /* Only store the handle when the thread is about to be
863 * launched, to avoid the main thread deadlocking while trying
864 * to clean up a thread that will never be signalled.
866 if (!handle_store (thread, FALSE))
869 MONO_PREPARE_BLOCKING;
870 mono_thread_info_resume (tid);
871 MONO_FINISH_BLOCKING;
873 if (internal->start_notify) {
875 * Wait for the thread to set up its TLS data etc, so
876 * theres no potential race condition if someone tries
877 * to look up the data believing the thread has
880 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
882 MONO_PREPARE_BLOCKING;
883 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
884 MONO_FINISH_BLOCKING;
886 CloseHandle (internal->start_notify);
887 internal->start_notify = NULL;
890 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
895 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
897 if (mono_thread_start_cb) {
898 mono_thread_start_cb (tid, stack_start, func);
902 void mono_threads_set_default_stacksize (guint32 stacksize)
904 default_stacksize = stacksize;
907 guint32 mono_threads_get_default_stacksize (void)
909 return default_stacksize;
913 * mono_thread_create_internal:
917 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
920 MonoInternalThread *internal;
921 StartInfo *start_info;
924 thread = create_thread_object (domain);
925 internal = create_internal_thread ();
926 MONO_OBJECT_SETREF (thread, internal_thread, internal);
928 start_info = g_new0 (StartInfo, 1);
929 start_info->func = func;
930 start_info->obj = thread;
931 start_info->start_arg = arg;
933 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
937 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
938 if (mono_check_corlib_version () == NULL)
939 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
945 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
947 mono_thread_create_internal (domain, func, arg, FALSE, 0);
951 mono_thread_attach (MonoDomain *domain)
953 return mono_thread_attach_full (domain, FALSE);
957 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
959 MonoThreadInfo *info;
960 MonoInternalThread *thread;
961 MonoThread *current_thread;
962 HANDLE thread_handle;
965 if ((thread = mono_thread_internal_current ())) {
966 if (domain != mono_domain_get ())
967 mono_domain_set (domain, TRUE);
968 /* Already attached */
969 return mono_thread_current ();
972 if (!mono_gc_register_thread (&domain)) {
973 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 ());
976 thread = create_internal_thread ();
978 thread_handle = mono_thread_info_open_handle ();
979 g_assert (thread_handle);
981 tid=GetCurrentThreadId ();
983 thread->handle = thread_handle;
985 thread->stack_ptr = &tid;
987 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
989 info = mono_thread_info_current ();
991 thread->thread_info = info;
992 thread->small_id = info->small_id;
994 current_thread = new_thread_with_internal (domain, thread);
996 if (!handle_store (current_thread, force_attach)) {
997 /* Mono is shutting down, so just wait for the end */
1002 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
1004 SET_CURRENT_OBJECT (thread);
1005 mono_domain_set (domain, TRUE);
1007 thread_adjust_static_data (thread);
1009 init_root_domain_thread (thread, current_thread);
1010 if (domain != mono_get_root_domain ())
1011 set_current_thread_for_domain (domain, thread, current_thread);
1014 if (mono_thread_attach_cb) {
1018 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1021 mono_thread_attach_cb (tid, &tid);
1023 mono_thread_attach_cb (tid, staddr + stsize);
1026 // FIXME: Need a separate callback
1027 mono_profiler_thread_start (tid);
1029 return current_thread;
1033 mono_thread_detach_internal (MonoInternalThread *thread)
1035 g_return_if_fail (thread != NULL);
1037 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1039 thread_cleanup (thread);
1041 SET_CURRENT_OBJECT (NULL);
1042 mono_domain_unset ();
1044 /* Don't need to CloseHandle this thread, even though we took a
1045 * reference in mono_thread_attach (), because the GC will do it
1046 * when the Thread object is finalised.
1051 mono_thread_detach (MonoThread *thread)
1054 mono_thread_detach_internal (thread->internal_thread);
1058 * mono_thread_detach_if_exiting:
1060 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1061 * This should be used at the end of embedding code which calls into managed code, and which
1062 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1065 mono_thread_detach_if_exiting (void)
1067 if (mono_thread_info_is_exiting ()) {
1068 MonoInternalThread *thread;
1070 thread = mono_thread_internal_current ();
1072 mono_thread_detach_internal (thread);
1073 mono_thread_info_detach ();
1081 MonoInternalThread *thread = mono_thread_internal_current ();
1083 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1085 thread_cleanup (thread);
1086 SET_CURRENT_OBJECT (NULL);
1087 mono_domain_unset ();
1089 /* we could add a callback here for embedders to use. */
1090 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1091 exit (mono_environment_exitcode_get ());
1092 mono_thread_info_exit ();
1096 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1098 MonoInternalThread *internal = create_internal_thread ();
1100 internal->state = ThreadState_Unstarted;
1102 InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
1106 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1109 StartInfo *start_info;
1110 MonoInternalThread *internal;
1113 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1115 if (!this_obj->internal_thread)
1116 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1117 internal = this_obj->internal_thread;
1119 LOCK_THREAD (internal);
1121 if ((internal->state & ThreadState_Unstarted) == 0) {
1122 UNLOCK_THREAD (internal);
1123 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1127 if ((internal->state & ThreadState_Aborted) != 0) {
1128 UNLOCK_THREAD (internal);
1131 /* This is freed in start_wrapper */
1132 start_info = g_new0 (StartInfo, 1);
1133 start_info->func = NULL;
1134 start_info->start_arg = this_obj->start_obj; /* FIXME: GC object stored in unmanaged memory */
1135 start_info->delegate = start;
1136 start_info->obj = this_obj;
1137 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1139 res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
1141 UNLOCK_THREAD (internal);
1145 internal->state &= ~ThreadState_Unstarted;
1147 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1149 UNLOCK_THREAD (internal);
1150 return internal->handle;
1154 * This is called from the finalizer of the internal thread object.
1157 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1159 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1162 * Since threads keep a reference to their thread object while running, by the time this function is called,
1163 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1164 * when thread_cleanup () can be called after this.
1167 CloseHandle (thread);
1169 if (this_obj->synch_cs) {
1170 mono_mutex_t *synch_cs = this_obj->synch_cs;
1171 this_obj->synch_cs = NULL;
1172 mono_mutex_destroy (synch_cs);
1176 if (this_obj->name) {
1177 void *name = this_obj->name;
1178 this_obj->name = NULL;
1184 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1187 MonoInternalThread *thread = mono_thread_internal_current ();
1189 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1191 mono_thread_current_check_pending_interrupt ();
1194 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1196 MONO_PREPARE_BLOCKING;
1197 res = SleepEx(ms,TRUE);
1198 MONO_FINISH_BLOCKING;
1200 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1202 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1203 MonoException* exc = mono_thread_execute_interruption (thread);
1205 mono_raise_exception (exc);
1217 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1222 ves_icall_System_Threading_Thread_GetDomainID (void)
1224 return mono_domain_get()->domain_id;
1228 ves_icall_System_Threading_Thread_Yield (void)
1230 return mono_thread_info_yield ();
1234 * mono_thread_get_name:
1236 * Return the name of the thread. NAME_LEN is set to the length of the name.
1237 * Return NULL if the thread has no name. The returned memory is owned by the
1241 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1245 LOCK_THREAD (this_obj);
1247 if (!this_obj->name) {
1251 *name_len = this_obj->name_len;
1252 res = g_new (gunichar2, this_obj->name_len);
1253 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1256 UNLOCK_THREAD (this_obj);
1262 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1266 LOCK_THREAD (this_obj);
1268 if (!this_obj->name)
1271 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1273 UNLOCK_THREAD (this_obj);
1279 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1281 LOCK_THREAD (this_obj);
1283 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1284 UNLOCK_THREAD (this_obj);
1286 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1289 if (this_obj->name) {
1290 g_free (this_obj->name);
1291 this_obj->name_len = 0;
1294 this_obj->name = g_new (gunichar2, mono_string_length (name));
1295 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1296 this_obj->name_len = mono_string_length (name);
1299 this_obj->name = NULL;
1302 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1304 UNLOCK_THREAD (this_obj);
1306 if (this_obj->name && this_obj->tid) {
1307 char *tname = mono_string_to_utf8 (name);
1308 mono_profiler_thread_name (this_obj->tid, tname);
1309 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1315 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1317 mono_thread_set_name_internal (this_obj, name, TRUE);
1321 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this)
1323 return ThreadPriority_Lowest;
1327 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1331 /* If the array is already in the requested domain, we just return it,
1332 otherwise we return a copy in that domain. */
1334 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1341 if (mono_object_domain (arr) == domain)
1344 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1345 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1350 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1352 return byte_array_to_domain (arr, mono_get_root_domain ());
1356 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1358 return byte_array_to_domain (arr, mono_domain_get ());
1362 mono_thread_current (void)
1364 MonoDomain *domain = mono_domain_get ();
1365 MonoInternalThread *internal = mono_thread_internal_current ();
1366 MonoThread **current_thread_ptr;
1368 g_assert (internal);
1369 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1371 if (!*current_thread_ptr) {
1372 g_assert (domain != mono_get_root_domain ());
1373 *current_thread_ptr = new_thread_with_internal (domain, internal);
1375 return *current_thread_ptr;
1379 mono_thread_internal_current (void)
1381 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1382 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1387 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1389 MonoInternalThread *thread = this_obj->internal_thread;
1390 HANDLE handle = thread->handle;
1391 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1394 mono_thread_current_check_pending_interrupt ();
1396 LOCK_THREAD (thread);
1398 if ((thread->state & ThreadState_Unstarted) != 0) {
1399 UNLOCK_THREAD (thread);
1401 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1405 UNLOCK_THREAD (thread);
1410 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1412 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1414 MONO_PREPARE_BLOCKING;
1415 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1416 MONO_FINISH_BLOCKING;
1418 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1420 if(ret==WAIT_OBJECT_0) {
1421 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1426 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1432 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1440 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1442 MONO_PREPARE_BLOCKING;
1444 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1446 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1447 MONO_FINISH_BLOCKING;
1449 if (ret != WAIT_IO_COMPLETION)
1452 exc = mono_thread_execute_interruption (thread);
1454 mono_raise_exception (exc);
1459 /* Re-calculate ms according to the time passed */
1460 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1461 if (diff_ms >= ms) {
1465 wait = ms - diff_ms;
1471 /* FIXME: exitContext isnt documented */
1472 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1478 MonoObject *waitHandle;
1479 MonoInternalThread *thread = mono_thread_internal_current ();
1481 /* Do this WaitSleepJoin check before creating objects */
1482 mono_thread_current_check_pending_interrupt ();
1484 /* We fail in managed if the array has more than 64 elements */
1485 numhandles = (guint32)mono_array_length(mono_handles);
1486 handles = g_new0(HANDLE, numhandles);
1488 for(i = 0; i < numhandles; i++) {
1489 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1490 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1497 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1499 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1501 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1505 if(ret==WAIT_FAILED) {
1506 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1508 } else if(ret==WAIT_TIMEOUT) {
1509 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1516 /* FIXME: exitContext isnt documented */
1517 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1519 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1520 uintptr_t numhandles;
1523 MonoObject *waitHandle;
1524 MonoInternalThread *thread = mono_thread_internal_current ();
1526 /* Do this WaitSleepJoin check before creating objects */
1527 mono_thread_current_check_pending_interrupt ();
1529 numhandles = mono_array_length(mono_handles);
1530 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1533 for(i = 0; i < numhandles; i++) {
1534 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1535 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1542 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1544 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1546 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1548 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1551 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1553 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1554 return ret - WAIT_OBJECT_0;
1556 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1557 return ret - WAIT_ABANDONED_0;
1564 /* FIXME: exitContext isnt documented */
1565 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this_obj, HANDLE handle, gint32 ms, gboolean exitContext)
1568 MonoInternalThread *thread = mono_thread_internal_current ();
1570 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1576 mono_thread_current_check_pending_interrupt ();
1578 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1580 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1582 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1584 if(ret==WAIT_FAILED) {
1585 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1587 } else if(ret==WAIT_TIMEOUT) {
1588 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1596 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1599 MonoInternalThread *thread = mono_thread_internal_current ();
1604 mono_thread_current_check_pending_interrupt ();
1606 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1608 MONO_PREPARE_BLOCKING;
1609 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1610 MONO_FINISH_BLOCKING;
1612 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1614 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1617 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1624 mutex = CreateMutex (NULL, owned, NULL);
1626 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1628 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1636 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1637 return(ReleaseMutex (handle));
1640 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1646 *error = ERROR_SUCCESS;
1648 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1650 *error = GetLastError ();
1657 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1664 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1666 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1667 mono_string_chars (name));
1669 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1677 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1681 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1686 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1690 *error = ERROR_SUCCESS;
1692 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1694 *error = GetLastError ();
1700 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1707 event = CreateEvent (NULL, manual, initial, NULL);
1709 event = CreateEvent (NULL, manual, initial,
1710 mono_string_chars (name));
1712 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1720 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1721 return (SetEvent(handle));
1724 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1725 return (ResetEvent(handle));
1729 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1730 CloseHandle (handle);
1733 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1739 *error = ERROR_SUCCESS;
1741 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1743 *error = GetLastError ();
1749 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1751 return InterlockedIncrement (location);
1754 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1756 #if SIZEOF_VOID_P == 4
1757 if (G_UNLIKELY ((size_t)location & 0x7)) {
1759 mono_interlocked_lock ();
1762 mono_interlocked_unlock ();
1766 return InterlockedIncrement64 (location);
1769 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1771 return InterlockedDecrement(location);
1774 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1776 #if SIZEOF_VOID_P == 4
1777 if (G_UNLIKELY ((size_t)location & 0x7)) {
1779 mono_interlocked_lock ();
1782 mono_interlocked_unlock ();
1786 return InterlockedDecrement64 (location);
1789 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1791 return InterlockedExchange(location, value);
1794 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1797 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1798 mono_gc_wbarrier_generic_nostore (location);
1802 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1804 return InterlockedExchangePointer(location, value);
1807 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1809 IntFloatUnion val, ret;
1812 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1818 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1820 #if SIZEOF_VOID_P == 4
1821 if (G_UNLIKELY ((size_t)location & 0x7)) {
1823 mono_interlocked_lock ();
1826 mono_interlocked_unlock ();
1830 return InterlockedExchange64 (location, value);
1834 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1836 LongDoubleUnion val, ret;
1839 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1844 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1846 return InterlockedCompareExchange(location, value, comparand);
1849 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1851 gint32 r = InterlockedCompareExchange(location, value, comparand);
1852 *success = r == comparand;
1856 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1859 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1860 mono_gc_wbarrier_generic_nostore (location);
1864 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1866 return InterlockedCompareExchangePointer(location, value, comparand);
1869 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1871 IntFloatUnion val, ret, cmp;
1874 cmp.fval = comparand;
1875 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1881 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1883 #if SIZEOF_VOID_P == 8
1884 LongDoubleUnion val, comp, ret;
1887 comp.fval = comparand;
1888 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1894 mono_interlocked_lock ();
1896 if (old == comparand)
1898 mono_interlocked_unlock ();
1905 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1907 #if SIZEOF_VOID_P == 4
1908 if (G_UNLIKELY ((size_t)location & 0x7)) {
1910 mono_interlocked_lock ();
1912 if (old == comparand)
1914 mono_interlocked_unlock ();
1918 return InterlockedCompareExchange64 (location, value, comparand);
1922 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1925 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1926 mono_gc_wbarrier_generic_nostore (location);
1931 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1934 res = InterlockedExchangePointer ((gpointer *)location, value);
1935 mono_gc_wbarrier_generic_nostore (location);
1940 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1942 return InterlockedAdd (location, value);
1946 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1948 #if SIZEOF_VOID_P == 4
1949 if (G_UNLIKELY ((size_t)location & 0x7)) {
1951 mono_interlocked_lock ();
1954 mono_interlocked_unlock ();
1958 return InterlockedAdd64 (location, value);
1962 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1964 #if SIZEOF_VOID_P == 4
1965 if (G_UNLIKELY ((size_t)location & 0x7)) {
1967 mono_interlocked_lock ();
1969 mono_interlocked_unlock ();
1973 return InterlockedRead64 (location);
1977 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1979 mono_memory_barrier ();
1983 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1985 mono_thread_clr_state (this, state);
1987 if (state & ThreadState_Background) {
1988 /* If the thread changes the background mode, the main thread has to
1989 * be notified, since it has to rebuild the list of threads to
1992 SetEvent (background_change_event);
1997 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1999 mono_thread_set_state (this, state);
2001 if (state & ThreadState_Background) {
2002 /* If the thread changes the background mode, the main thread has to
2003 * be notified, since it has to rebuild the list of threads to
2006 SetEvent (background_change_event);
2011 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2017 state = this->state;
2019 UNLOCK_THREAD (this);
2024 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2026 MonoInternalThread *current;
2028 MonoInternalThread *thread = this_obj->internal_thread;
2030 LOCK_THREAD (thread);
2032 current = mono_thread_internal_current ();
2034 thread->thread_interrupt_requested = TRUE;
2035 throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2037 UNLOCK_THREAD (thread);
2040 abort_thread_internal (thread, TRUE, FALSE);
2044 void mono_thread_current_check_pending_interrupt ()
2046 MonoInternalThread *thread = mono_thread_internal_current ();
2047 gboolean throw = FALSE;
2049 LOCK_THREAD (thread);
2051 if (thread->thread_interrupt_requested) {
2053 thread->thread_interrupt_requested = FALSE;
2056 UNLOCK_THREAD (thread);
2059 mono_raise_exception (mono_get_exception_thread_interrupted ());
2064 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2066 LOCK_THREAD (thread);
2068 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2069 (thread->state & ThreadState_StopRequested) != 0 ||
2070 (thread->state & ThreadState_Stopped) != 0)
2072 UNLOCK_THREAD (thread);
2076 if ((thread->state & ThreadState_Unstarted) != 0) {
2077 thread->state |= ThreadState_Aborted;
2078 UNLOCK_THREAD (thread);
2082 thread->state |= ThreadState_AbortRequested;
2083 if (thread->abort_state_handle)
2084 mono_gchandle_free (thread->abort_state_handle);
2086 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2087 g_assert (thread->abort_state_handle);
2089 thread->abort_state_handle = 0;
2091 thread->abort_exc = NULL;
2093 UNLOCK_THREAD (thread);
2095 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2097 /* During shutdown, we can't wait for other threads */
2099 /* Make sure the thread is awake */
2100 mono_thread_resume (thread);
2102 abort_thread_internal (thread, TRUE, TRUE);
2106 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2108 MonoInternalThread *thread = mono_thread_internal_current ();
2109 gboolean was_aborting;
2111 LOCK_THREAD (thread);
2112 was_aborting = thread->state & ThreadState_AbortRequested;
2113 thread->state &= ~ThreadState_AbortRequested;
2114 UNLOCK_THREAD (thread);
2116 if (!was_aborting) {
2117 const char *msg = "Unable to reset abort because no abort was requested";
2118 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2121 thread->abort_exc = NULL;
2122 if (thread->abort_state_handle) {
2123 mono_gchandle_free (thread->abort_state_handle);
2124 /* This is actually not necessary - the handle
2125 only counts if the exception is set */
2126 thread->abort_state_handle = 0;
2131 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2133 LOCK_THREAD (thread);
2135 thread->state &= ~ThreadState_AbortRequested;
2137 if (thread->abort_exc) {
2138 thread->abort_exc = NULL;
2139 if (thread->abort_state_handle) {
2140 mono_gchandle_free (thread->abort_state_handle);
2141 /* This is actually not necessary - the handle
2142 only counts if the exception is set */
2143 thread->abort_state_handle = 0;
2147 UNLOCK_THREAD (thread);
2151 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2153 MonoInternalThread *thread = this_obj->internal_thread;
2154 MonoObject *state, *deserialized = NULL, *exc;
2157 if (!thread->abort_state_handle)
2160 state = mono_gchandle_get_target (thread->abort_state_handle);
2163 domain = mono_domain_get ();
2164 if (mono_object_domain (state) == domain)
2167 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2169 if (!deserialized) {
2170 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2172 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2173 mono_set_pending_exception (invalid_op_exc);
2177 return deserialized;
2181 mono_thread_suspend (MonoInternalThread *thread)
2183 LOCK_THREAD (thread);
2185 if ((thread->state & ThreadState_Unstarted) != 0 ||
2186 (thread->state & ThreadState_Aborted) != 0 ||
2187 (thread->state & ThreadState_Stopped) != 0)
2189 UNLOCK_THREAD (thread);
2193 if ((thread->state & ThreadState_Suspended) != 0 ||
2194 (thread->state & ThreadState_SuspendRequested) != 0 ||
2195 (thread->state & ThreadState_StopRequested) != 0)
2197 UNLOCK_THREAD (thread);
2201 thread->state |= ThreadState_SuspendRequested;
2203 UNLOCK_THREAD (thread);
2205 suspend_thread_internal (thread, FALSE);
2210 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2212 if (!mono_thread_suspend (this_obj->internal_thread)) {
2213 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2219 mono_thread_resume (MonoInternalThread *thread)
2221 LOCK_THREAD (thread);
2223 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2224 thread->state &= ~ThreadState_SuspendRequested;
2225 UNLOCK_THREAD (thread);
2229 if ((thread->state & ThreadState_Suspended) == 0 ||
2230 (thread->state & ThreadState_Unstarted) != 0 ||
2231 (thread->state & ThreadState_Aborted) != 0 ||
2232 (thread->state & ThreadState_Stopped) != 0)
2234 UNLOCK_THREAD (thread);
2238 return resume_thread_internal (thread);
2242 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2244 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2245 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2251 mono_threads_is_critical_method (MonoMethod *method)
2253 switch (method->wrapper_type) {
2254 case MONO_WRAPPER_RUNTIME_INVOKE:
2255 case MONO_WRAPPER_XDOMAIN_INVOKE:
2256 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2263 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2268 if (mono_threads_is_critical_method (m)) {
2269 *((gboolean*)data) = TRUE;
2276 is_running_protected_wrapper (void)
2278 gboolean found = FALSE;
2279 mono_stack_walk (find_wrapper, &found);
2283 void mono_thread_internal_stop (MonoInternalThread *thread)
2285 LOCK_THREAD (thread);
2287 if ((thread->state & ThreadState_StopRequested) != 0 ||
2288 (thread->state & ThreadState_Stopped) != 0)
2290 UNLOCK_THREAD (thread);
2294 /* Make sure the thread is awake */
2295 mono_thread_resume (thread);
2297 thread->state |= ThreadState_StopRequested;
2298 thread->state &= ~ThreadState_AbortRequested;
2300 UNLOCK_THREAD (thread);
2302 abort_thread_internal (thread, TRUE, TRUE);
2305 void mono_thread_stop (MonoThread *thread)
2307 mono_thread_internal_stop (thread->internal_thread);
2311 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2314 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2319 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2322 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2327 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2330 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2335 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2338 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2343 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2346 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2347 return (void *) tmp;
2351 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2353 volatile MonoObject *tmp;
2354 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2355 return (MonoObject *) tmp;
2359 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2362 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2367 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2370 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2375 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2377 return InterlockedRead8 (ptr);
2381 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2383 return InterlockedRead16 (ptr);
2387 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2389 return InterlockedRead (ptr);
2393 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2395 #if SIZEOF_VOID_P == 4
2396 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2398 mono_interlocked_lock ();
2399 val = *(gint64*)ptr;
2400 mono_interlocked_unlock ();
2404 return InterlockedRead64 (ptr);
2408 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2410 return InterlockedReadPointer (ptr);
2414 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2418 #if SIZEOF_VOID_P == 4
2419 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2421 mono_interlocked_lock ();
2422 val = *(double*)ptr;
2423 mono_interlocked_unlock ();
2428 u.ival = InterlockedRead64 (ptr);
2434 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2438 u.ival = InterlockedRead (ptr);
2444 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2446 return InterlockedReadPointer (ptr);
2450 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2452 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2456 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2458 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2462 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2464 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2468 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2470 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2474 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2476 mono_atomic_store_release ((volatile void **) ptr, value);
2480 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2482 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2486 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2488 mono_atomic_store_release ((volatile double *) ptr, value);
2492 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2494 mono_atomic_store_release ((volatile float *) ptr, value);
2498 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2500 InterlockedWrite8 (ptr, value);
2504 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2506 InterlockedWrite16 (ptr, value);
2510 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2512 InterlockedWrite (ptr, value);
2516 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2518 #if SIZEOF_VOID_P == 4
2519 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2520 mono_interlocked_lock ();
2521 *(gint64*)ptr = value;
2522 mono_interlocked_unlock ();
2527 InterlockedWrite64 (ptr, value);
2531 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2533 InterlockedWritePointer (ptr, value);
2537 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2541 #if SIZEOF_VOID_P == 4
2542 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2543 mono_interlocked_lock ();
2544 *(double*)ptr = value;
2545 mono_interlocked_unlock ();
2552 InterlockedWrite64 (ptr, u.ival);
2556 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2562 InterlockedWrite (ptr, u.ival);
2566 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2568 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2572 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2574 mono_threads_lock ();
2576 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2579 contexts = g_hash_table_new (NULL, NULL);
2581 context_adjust_static_data (ctx);
2582 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2583 g_hash_table_insert (contexts, gch, gch);
2585 mono_threads_unlock ();
2587 mono_profiler_context_loaded (ctx);
2591 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2594 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2595 * cleanup in exceptional circumstances, we don't actually do any
2596 * cleanup work here. We instead do this when we iterate the `contexts`
2597 * hash table. The only purpose of this finalizer, at the moment, is to
2598 * notify the profiler.
2601 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2603 mono_profiler_context_unloaded (ctx);
2607 mono_thread_init_tls (void)
2609 MONO_FAST_TLS_INIT (tls_current_object);
2610 mono_native_tls_alloc (¤t_object_key, NULL);
2613 void mono_thread_init (MonoThreadStartCB start_cb,
2614 MonoThreadAttachCB attach_cb)
2616 mono_mutex_init_recursive(&threads_mutex);
2617 mono_mutex_init_recursive(&interlocked_mutex);
2618 mono_mutex_init_recursive(&joinable_threads_mutex);
2620 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2621 g_assert(background_change_event != NULL);
2623 mono_init_static_data_info (&thread_static_info);
2624 mono_init_static_data_info (&context_static_info);
2626 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2628 mono_thread_start_cb = start_cb;
2629 mono_thread_attach_cb = attach_cb;
2631 /* Get a pseudo handle to the current process. This is just a
2632 * kludge so that wapi can build a process handle if needed.
2633 * As a pseudo handle is returned, we don't need to clean
2636 GetCurrentProcess ();
2639 void mono_thread_cleanup (void)
2641 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2642 MonoThreadInfo *info;
2644 /* The main thread must abandon any held mutexes (particularly
2645 * important for named mutexes as they are shared across
2646 * processes, see bug 74680.) This will happen when the
2647 * thread exits, but if it's not running in a subthread it
2648 * won't exit in time.
2650 info = mono_thread_info_current ();
2651 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2655 /* This stuff needs more testing, it seems one of these
2656 * critical sections can be locked when mono_thread_cleanup is
2659 mono_mutex_destroy (&threads_mutex);
2660 mono_mutex_destroy (&interlocked_mutex);
2661 mono_mutex_destroy (&delayed_free_table_mutex);
2662 mono_mutex_destroy (&small_id_mutex);
2663 CloseHandle (background_change_event);
2666 mono_native_tls_free (current_object_key);
2670 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2672 mono_thread_cleanup_fn = func;
2676 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2678 thread->internal_thread->manage_callback = func;
2681 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2683 mono_thread_notify_pending_exc_fn = func;
2687 static void print_tids (gpointer key, gpointer value, gpointer user)
2689 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2690 * sizeof(uint) and a cast to uint would overflow
2692 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2693 * print this as a pointer.
2695 g_message ("Waiting for: %p", key);
2700 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2701 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2705 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2709 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2711 MONO_PREPARE_BLOCKING;
2712 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2713 MONO_FINISH_BLOCKING;
2715 if(ret==WAIT_FAILED) {
2716 /* See the comment in build_wait_tids() */
2717 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2721 for(i=0; i<wait->num; i++)
2722 CloseHandle (wait->handles[i]);
2724 if (ret == WAIT_TIMEOUT)
2727 for(i=0; i<wait->num; i++) {
2728 gsize tid = wait->threads[i]->tid;
2731 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2732 * it can still run io-layer etc. code. So wait for it to really exit.
2733 * FIXME: This won't join threads which are not in the joinable_hash yet.
2735 mono_thread_join ((gpointer)tid);
2737 mono_threads_lock ();
2738 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2739 /* This thread must have been killed, because
2740 * it hasn't cleaned itself up. (It's just
2741 * possible that the thread exited before the
2742 * parent thread had a chance to store the
2743 * handle, and now there is another pointer to
2744 * the already-exited thread stored. In this
2745 * case, we'll just get two
2746 * mono_profiler_thread_end() calls for the
2750 mono_threads_unlock ();
2751 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2752 thread_cleanup (wait->threads[i]);
2754 mono_threads_unlock ();
2759 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2761 guint32 i, ret, count;
2763 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2765 /* Add the thread state change event, so it wakes up if a thread changes
2766 * to background mode.
2769 if (count < MAXIMUM_WAIT_OBJECTS) {
2770 wait->handles [count] = background_change_event;
2774 MONO_PREPARE_BLOCKING;
2775 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2776 MONO_FINISH_BLOCKING;
2778 if(ret==WAIT_FAILED) {
2779 /* See the comment in build_wait_tids() */
2780 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2784 for(i=0; i<wait->num; i++)
2785 CloseHandle (wait->handles[i]);
2787 if (ret == WAIT_TIMEOUT)
2790 if (ret < wait->num) {
2791 gsize tid = wait->threads[ret]->tid;
2792 mono_threads_lock ();
2793 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2794 /* See comment in wait_for_tids about thread cleanup */
2795 mono_threads_unlock ();
2796 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2797 thread_cleanup (wait->threads [ret]);
2799 mono_threads_unlock ();
2803 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2805 struct wait_data *wait=(struct wait_data *)user;
2807 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2809 MonoInternalThread *thread=(MonoInternalThread *)value;
2811 /* Ignore background threads, we abort them later */
2812 /* Do not lock here since it is not needed and the caller holds threads_lock */
2813 if (thread->state & ThreadState_Background) {
2814 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2815 return; /* just leave, ignore */
2818 if (mono_gc_is_finalizer_internal_thread (thread)) {
2819 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2823 if (thread == mono_thread_internal_current ()) {
2824 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2828 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2829 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2833 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2834 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2838 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2839 if (handle == NULL) {
2840 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2844 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2845 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2846 wait->handles[wait->num]=handle;
2847 wait->threads[wait->num]=thread;
2850 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2852 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2857 /* Just ignore the rest, we can't do anything with
2864 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2866 struct wait_data *wait=(struct wait_data *)user;
2867 gsize self = GetCurrentThreadId ();
2868 MonoInternalThread *thread = value;
2871 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2874 /* The finalizer thread is not a background thread */
2875 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2876 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2878 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
2882 /* printf ("A: %d\n", wait->num); */
2883 wait->handles[wait->num]=thread->handle;
2884 wait->threads[wait->num]=thread;
2887 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2888 mono_thread_internal_stop (thread);
2892 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2896 * mono_threads_set_shutting_down:
2898 * Is called by a thread that wants to shut down Mono. If the runtime is already
2899 * shutting down, the calling thread is suspended/stopped, and this function never
2903 mono_threads_set_shutting_down (void)
2905 MonoInternalThread *current_thread = mono_thread_internal_current ();
2907 mono_threads_lock ();
2909 if (shutting_down) {
2910 mono_threads_unlock ();
2912 /* Make sure we're properly suspended/stopped */
2914 LOCK_THREAD (current_thread);
2916 if ((current_thread->state & ThreadState_SuspendRequested) ||
2917 (current_thread->state & ThreadState_AbortRequested) ||
2918 (current_thread->state & ThreadState_StopRequested)) {
2919 UNLOCK_THREAD (current_thread);
2920 mono_thread_execute_interruption (current_thread);
2922 current_thread->state |= ThreadState_Stopped;
2923 UNLOCK_THREAD (current_thread);
2926 /*since we're killing the thread, unset the current domain.*/
2927 mono_domain_unset ();
2929 /* Wake up other threads potentially waiting for us */
2930 mono_thread_info_exit ();
2932 shutting_down = TRUE;
2934 /* Not really a background state change, but this will
2935 * interrupt the main thread if it is waiting for all
2936 * the other threads.
2938 SetEvent (background_change_event);
2940 mono_threads_unlock ();
2944 void mono_thread_manage (void)
2946 struct wait_data wait_data;
2947 struct wait_data *wait = &wait_data;
2949 memset (wait, 0, sizeof (struct wait_data));
2950 /* join each thread that's still running */
2951 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2953 mono_threads_lock ();
2955 THREAD_DEBUG (g_message("%s: No threads", __func__));
2956 mono_threads_unlock ();
2959 mono_threads_unlock ();
2962 mono_threads_lock ();
2963 if (shutting_down) {
2964 /* somebody else is shutting down */
2965 mono_threads_unlock ();
2968 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2969 mono_g_hash_table_foreach (threads, print_tids, NULL));
2971 ResetEvent (background_change_event);
2973 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2974 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2975 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2976 mono_threads_unlock ();
2978 /* Something to wait for */
2979 wait_for_tids_or_state_change (wait, INFINITE);
2981 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2982 } while(wait->num>0);
2984 /* Mono is shutting down, so just wait for the end */
2985 if (!mono_runtime_try_shutdown ()) {
2986 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2987 mono_thread_suspend (mono_thread_internal_current ());
2988 mono_thread_execute_interruption (mono_thread_internal_current ());
2992 * Remove everything but the finalizer thread and self.
2993 * Also abort all the background threads
2996 mono_threads_lock ();
2999 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3000 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3001 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3003 mono_threads_unlock ();
3005 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3007 /* Something to wait for */
3008 wait_for_tids (wait, INFINITE);
3010 } while (wait->num > 0);
3013 * give the subthreads a chance to really quit (this is mainly needed
3014 * to get correct user and system times from getrusage/wait/time(1)).
3015 * This could be removed if we avoid pthread_detach() and use pthread_join().
3017 mono_thread_info_yield ();
3020 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3022 MonoInternalThread *thread=(MonoInternalThread *)value;
3024 if(thread->tid != (gsize)user) {
3025 /*TerminateThread (thread->handle, -1);*/
3029 void mono_thread_abort_all_other_threads (void)
3031 gsize self = GetCurrentThreadId ();
3033 mono_threads_lock ();
3034 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3035 mono_g_hash_table_size (threads));
3036 mono_g_hash_table_foreach (threads, print_tids, NULL));
3038 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3040 mono_threads_unlock ();
3044 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3046 MonoInternalThread *thread = (MonoInternalThread*)value;
3047 struct wait_data *wait = (struct wait_data*)user_data;
3051 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3053 * This needs no locking.
3055 if ((thread->state & ThreadState_Suspended) != 0 ||
3056 (thread->state & ThreadState_Stopped) != 0)
3059 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3060 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3064 wait->handles [wait->num] = handle;
3065 wait->threads [wait->num] = thread;
3071 * mono_thread_suspend_all_other_threads:
3073 * Suspend all managed threads except the finalizer thread and this thread. It is
3074 * not possible to resume them later.
3076 void mono_thread_suspend_all_other_threads (void)
3078 struct wait_data wait_data;
3079 struct wait_data *wait = &wait_data;
3081 gsize self = GetCurrentThreadId ();
3082 guint32 eventidx = 0;
3083 gboolean starting, finished;
3085 memset (wait, 0, sizeof (struct wait_data));
3087 * The other threads could be in an arbitrary state at this point, i.e.
3088 * they could be starting up, shutting down etc. This means that there could be
3089 * threads which are not even in the threads hash table yet.
3093 * First we set a barrier which will be checked by all threads before they
3094 * are added to the threads hash table, and they will exit if the flag is set.
3095 * This ensures that no threads could be added to the hash later.
3096 * We will use shutting_down as the barrier for now.
3098 g_assert (shutting_down);
3101 * We make multiple calls to WaitForMultipleObjects since:
3102 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3103 * - some threads could exit without becoming suspended
3108 * Make a copy of the hashtable since we can't do anything with
3109 * threads while threads_mutex is held.
3112 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3113 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3114 mono_threads_lock ();
3115 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3116 mono_threads_unlock ();
3119 /* Get the suspended events that we'll be waiting for */
3120 for (i = 0; i < wait->num; ++i) {
3121 MonoInternalThread *thread = wait->threads [i];
3123 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3124 //CloseHandle (wait->handles [i]);
3125 wait->threads [i] = NULL; /* ignore this thread in next loop */
3129 LOCK_THREAD (thread);
3131 if ((thread->state & ThreadState_Suspended) != 0 ||
3132 (thread->state & ThreadState_StopRequested) != 0 ||
3133 (thread->state & ThreadState_Stopped) != 0) {
3134 UNLOCK_THREAD (thread);
3135 CloseHandle (wait->handles [i]);
3136 wait->threads [i] = NULL; /* ignore this thread in next loop */
3142 /* Convert abort requests into suspend requests */
3143 if ((thread->state & ThreadState_AbortRequested) != 0)
3144 thread->state &= ~ThreadState_AbortRequested;
3146 thread->state |= ThreadState_SuspendRequested;
3148 UNLOCK_THREAD (thread);
3150 /* Signal the thread to suspend */
3151 suspend_thread_internal (thread, TRUE);
3153 if (eventidx <= 0) {
3155 * If there are threads which are starting up, we wait until they
3156 * are suspended when they try to register in the threads hash.
3157 * This is guaranteed to finish, since the threads which can create new
3158 * threads get suspended after a while.
3159 * FIXME: The finalizer thread can still create new threads.
3161 mono_threads_lock ();
3162 if (threads_starting_up)
3163 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3166 mono_threads_unlock ();
3175 static gboolean thread_dump_requested;
3177 static G_GNUC_UNUSED gboolean
3178 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3180 GString *p = (GString*)data;
3181 MonoMethod *method = NULL;
3182 if (frame->type == FRAME_TYPE_MANAGED)
3183 method = mono_jit_info_get_method (frame->ji);
3186 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3187 g_string_append_printf (p, " %s\n", location);
3190 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3195 static SuspendThreadResult
3196 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3198 MonoInternalThread *thread = ud;
3199 GString* text = g_string_new (0);
3201 GError *error = NULL;
3204 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3206 g_string_append_printf (text, "\n\"%s\"", name);
3209 else if (thread->threadpool_thread)
3210 g_string_append (text, "\n\"<threadpool thread>\"");
3212 g_string_append (text, "\n\"<unnamed thread>\"");
3215 /* This no longer works with remote unwinding */
3217 wapi_desc = wapi_current_thread_desc ();
3218 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3223 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);
3225 fprintf (stdout, "%s", text->str);
3227 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3228 OutputDebugStringA(text->str);
3231 g_string_free (text, TRUE);
3233 return MonoResumeThread;
3237 dump_thread (gpointer key, gpointer value, gpointer user)
3239 MonoInternalThread *thread = (MonoInternalThread *)value;
3241 if (thread == mono_thread_internal_current ())
3245 FIXME This still can hang if we stop a thread during malloc.
3246 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3247 that takes a callback and runs it with the target suspended.
3248 We probably should loop a bit around trying to get it to either managed code
3251 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, print_thread_dump, thread);
3255 mono_threads_perform_thread_dump (void)
3257 if (!thread_dump_requested)
3260 printf ("Full thread dump:\n");
3262 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3263 something needs then in the process.
3265 mono_loader_lock ();
3266 mono_domain_lock (mono_get_root_domain ());
3268 mono_threads_lock ();
3269 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3270 mono_threads_unlock ();
3272 mono_domain_unlock (mono_get_root_domain ());
3273 mono_loader_unlock ();
3275 thread_dump_requested = FALSE;
3279 * mono_threads_request_thread_dump:
3281 * Ask all threads except the current to print their stacktrace to stdout.
3284 mono_threads_request_thread_dump (void)
3286 /*The new thread dump code runs out of the finalizer thread. */
3287 thread_dump_requested = TRUE;
3288 mono_gc_finalize_notify ();
3293 gint allocated; /* +1 so that refs [allocated] == NULL */
3297 typedef struct ref_stack RefStack;
3300 ref_stack_new (gint initial_size)
3304 initial_size = MAX (initial_size, 16) + 1;
3305 rs = g_new0 (RefStack, 1);
3306 rs->refs = g_new0 (gpointer, initial_size);
3307 rs->allocated = initial_size;
3312 ref_stack_destroy (gpointer ptr)
3323 ref_stack_push (RefStack *rs, gpointer ptr)
3325 g_assert (rs != NULL);
3327 if (rs->bottom >= rs->allocated) {
3328 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3329 rs->allocated <<= 1;
3330 rs->refs [rs->allocated] = NULL;
3332 rs->refs [rs->bottom++] = ptr;
3336 ref_stack_pop (RefStack *rs)
3338 if (rs == NULL || rs->bottom == 0)
3342 rs->refs [rs->bottom] = NULL;
3346 ref_stack_find (RefStack *rs, gpointer ptr)
3353 for (refs = rs->refs; refs && *refs; refs++) {
3361 * mono_thread_push_appdomain_ref:
3363 * Register that the current thread may have references to objects in domain
3364 * @domain on its stack. Each call to this function should be paired with a
3365 * call to pop_appdomain_ref.
3368 mono_thread_push_appdomain_ref (MonoDomain *domain)
3370 MonoInternalThread *thread = mono_thread_internal_current ();
3373 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3374 SPIN_LOCK (thread->lock_thread_id);
3375 if (thread->appdomain_refs == NULL)
3376 thread->appdomain_refs = ref_stack_new (16);
3377 ref_stack_push (thread->appdomain_refs, domain);
3378 SPIN_UNLOCK (thread->lock_thread_id);
3383 mono_thread_pop_appdomain_ref (void)
3385 MonoInternalThread *thread = mono_thread_internal_current ();
3388 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3389 SPIN_LOCK (thread->lock_thread_id);
3390 ref_stack_pop (thread->appdomain_refs);
3391 SPIN_UNLOCK (thread->lock_thread_id);
3396 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3399 SPIN_LOCK (thread->lock_thread_id);
3400 res = ref_stack_find (thread->appdomain_refs, domain);
3401 SPIN_UNLOCK (thread->lock_thread_id);
3406 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3408 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3411 typedef struct abort_appdomain_data {
3412 struct wait_data wait;
3414 } abort_appdomain_data;
3417 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3419 MonoInternalThread *thread = (MonoInternalThread*)value;
3420 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3421 MonoDomain *domain = data->domain;
3423 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3424 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3426 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3427 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3430 data->wait.handles [data->wait.num] = handle;
3431 data->wait.threads [data->wait.num] = thread;
3434 /* Just ignore the rest, we can't do anything with
3442 * mono_threads_abort_appdomain_threads:
3444 * Abort threads which has references to the given appdomain.
3447 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3449 #ifdef __native_client__
3453 abort_appdomain_data user_data;
3455 int orig_timeout = timeout;
3458 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3460 start_time = mono_msec_ticks ();
3462 mono_threads_lock ();
3464 user_data.domain = domain;
3465 user_data.wait.num = 0;
3466 /* This shouldn't take any locks */
3467 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3468 mono_threads_unlock ();
3470 if (user_data.wait.num > 0) {
3471 /* Abort the threads outside the threads lock */
3472 for (i = 0; i < user_data.wait.num; ++i)
3473 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3476 * We should wait for the threads either to abort, or to leave the
3477 * domain. We can't do the latter, so we wait with a timeout.
3479 wait_for_tids (&user_data.wait, 100);
3482 /* Update remaining time */
3483 timeout -= mono_msec_ticks () - start_time;
3484 start_time = mono_msec_ticks ();
3486 if (orig_timeout != -1 && timeout < 0)
3489 while (user_data.wait.num > 0);
3491 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3497 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3499 MonoInternalThread *thread = (MonoInternalThread*)value;
3500 MonoDomain *domain = (MonoDomain*)user_data;
3503 /* No locking needed here */
3504 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3506 if (thread->cached_culture_info) {
3507 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3508 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3509 if (obj && obj->vtable->domain == domain)
3510 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3516 * mono_threads_clear_cached_culture:
3518 * Clear the cached_current_culture from all threads if it is in the
3522 mono_threads_clear_cached_culture (MonoDomain *domain)
3524 mono_threads_lock ();
3525 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3526 mono_threads_unlock ();
3530 * mono_thread_get_undeniable_exception:
3532 * Return an exception which needs to be raised when leaving a catch clause.
3533 * This is used for undeniable exception propagation.
3536 mono_thread_get_undeniable_exception (void)
3538 MonoInternalThread *thread = mono_thread_internal_current ();
3540 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3542 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3543 * exception if the thread no longer references a dying appdomain.
3545 thread->abort_exc->trace_ips = NULL;
3546 thread->abort_exc->stack_trace = NULL;
3547 return thread->abort_exc;
3553 #if MONO_SMALL_CONFIG
3554 #define NUM_STATIC_DATA_IDX 4
3555 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3559 #define NUM_STATIC_DATA_IDX 8
3560 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3561 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3565 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3566 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3569 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3571 gpointer *static_data = addr;
3573 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3574 void **ptr = static_data [i];
3579 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3580 void **p = ptr + idx;
3583 mark_func ((MonoObject**)p, gc_data);
3589 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3591 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3595 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3597 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3601 * mono_alloc_static_data
3603 * Allocate memory blocks for storing threads or context static data
3606 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3608 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3611 gpointer* static_data = *static_data_ptr;
3613 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3614 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3616 if (mono_gc_user_markers_supported ()) {
3617 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3618 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3620 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3621 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3624 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc);
3625 *static_data_ptr = static_data;
3626 static_data [0] = static_data;
3629 for (i = 1; i <= idx; ++i) {
3630 if (static_data [i])
3633 if (mono_gc_user_markers_supported ())
3634 static_data [i] = g_malloc0 (static_data_size [i]);
3636 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL);
3641 mono_free_static_data (gpointer* static_data)
3644 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3645 gpointer p = static_data [i];
3649 * At this point, the static data pointer array is still registered with the
3650 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3651 * data. Freeing the individual arrays without first nulling their slots
3652 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3653 * such an already freed array. See bug #13813.
3655 static_data [i] = NULL;
3656 mono_memory_write_barrier ();
3657 if (mono_gc_user_markers_supported ())
3660 mono_gc_free_fixed (p);
3662 mono_gc_free_fixed (static_data);
3666 * mono_init_static_data_info
3668 * Initializes static data counters
3670 static void mono_init_static_data_info (StaticDataInfo *static_data)
3672 static_data->idx = 0;
3673 static_data->offset = 0;
3674 static_data->freelist = NULL;
3678 * mono_alloc_static_data_slot
3680 * Generates an offset for static data. static_data contains the counters
3681 * used to generate it.
3684 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3686 if (!static_data->idx && !static_data->offset) {
3688 * we use the first chunk of the first allocation also as
3689 * an array for the rest of the data
3691 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3693 static_data->offset += align - 1;
3694 static_data->offset &= ~(align - 1);
3695 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3696 static_data->idx ++;
3697 g_assert (size <= static_data_size [static_data->idx]);
3698 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3699 static_data->offset = 0;
3701 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3702 static_data->offset += size;
3707 * ensure thread static fields already allocated are valid for thread
3708 * This function is called when a thread is created or on thread attach.
3711 thread_adjust_static_data (MonoInternalThread *thread)
3713 mono_threads_lock ();
3714 if (thread_static_info.offset || thread_static_info.idx > 0) {
3715 /* get the current allocated size */
3716 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3717 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3719 mono_threads_unlock ();
3723 * LOCKING: requires that threads_mutex is held
3726 context_adjust_static_data (MonoAppContext *ctx)
3728 if (context_static_info.offset || context_static_info.idx > 0) {
3729 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3730 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3735 * LOCKING: requires that threads_mutex is held
3738 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3740 MonoInternalThread *thread = value;
3741 guint32 offset = GPOINTER_TO_UINT (user);
3743 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3747 * LOCKING: requires that threads_mutex is held
3750 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3752 uint32_t gch = GPOINTER_TO_INT (key);
3753 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3756 mono_gchandle_free (gch);
3757 return TRUE; // Remove this key/value pair
3760 guint32 offset = GPOINTER_TO_UINT (user);
3761 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3763 return FALSE; // Don't remove it
3766 static StaticDataFreeList*
3767 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3769 StaticDataFreeList* prev = NULL;
3770 StaticDataFreeList* tmp = static_data->freelist;
3772 if (tmp->size == size) {
3774 prev->next = tmp->next;
3776 static_data->freelist = tmp->next;
3785 #if SIZEOF_VOID_P == 4
3792 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3794 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3796 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3797 MonoBitSet *rb = sets [idx];
3798 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3799 offset /= sizeof (uintptr_t);
3800 /* offset is now the bitmap offset */
3801 for (int i = 0; i < numbits; ++i) {
3802 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3803 mono_bitset_set_fast (rb, offset + i);
3808 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3810 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3811 MonoBitSet *rb = sets [idx];
3812 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3813 offset /= sizeof (uintptr_t);
3814 /* offset is now the bitmap offset */
3815 for (int i = 0; i < size / sizeof (uintptr_t); i++)
3816 mono_bitset_clear_fast (rb, offset + i);
3820 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3822 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3824 StaticDataInfo *info;
3827 if (static_type == SPECIAL_STATIC_THREAD) {
3828 info = &thread_static_info;
3829 sets = thread_reference_bitmaps;
3831 info = &context_static_info;
3832 sets = context_reference_bitmaps;
3835 mono_threads_lock ();
3837 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3841 offset = item->offset;
3844 offset = mono_alloc_static_data_slot (info, size, align);
3847 update_reference_bitmap (sets, offset, bitmap, numbits);
3849 if (static_type == SPECIAL_STATIC_THREAD) {
3850 /* This can be called during startup */
3851 if (threads != NULL)
3852 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3854 if (contexts != NULL)
3855 g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3857 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3860 mono_threads_unlock ();
3866 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3868 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3870 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3871 return get_thread_static_data (thread, offset);
3873 return get_context_static_data (thread->current_appcontext, offset);
3878 mono_get_special_static_data (guint32 offset)
3880 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3889 * LOCKING: requires that threads_mutex is held
3892 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3894 MonoInternalThread *thread = value;
3895 OffsetSize *data = user;
3896 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3897 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3900 if (!thread->static_data || !thread->static_data [idx])
3902 ptr = ((char*) thread->static_data [idx]) + off;
3903 mono_gc_bzero_atomic (ptr, data->size);
3907 * LOCKING: requires that threads_mutex is held
3910 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3912 uint32_t gch = GPOINTER_TO_INT (key);
3913 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3916 mono_gchandle_free (gch);
3917 return TRUE; // Remove this key/value pair
3920 OffsetSize *data = user;
3921 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3922 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3925 if (!ctx->static_data || !ctx->static_data [idx])
3926 return FALSE; // Don't remove this key/value pair
3928 ptr = ((char*) ctx->static_data [idx]) + off;
3929 mono_gc_bzero_atomic (ptr, data->size);
3931 return FALSE; // Don't remove this key/value pair
3935 do_free_special_slot (guint32 offset, guint32 size)
3937 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3939 StaticDataInfo *info;
3941 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3942 info = &thread_static_info;
3943 sets = thread_reference_bitmaps;
3945 info = &context_static_info;
3946 sets = context_reference_bitmaps;
3949 guint32 data_offset = offset;
3950 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
3951 OffsetSize data = { data_offset, size };
3953 clear_reference_bitmap (sets, data.offset, data.size);
3955 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3956 if (threads != NULL)
3957 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3959 if (contexts != NULL)
3960 g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
3963 if (!mono_runtime_is_shutting_down ()) {
3964 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
3966 item->offset = offset;
3969 item->next = info->freelist;
3970 info->freelist = item;
3975 do_free_special (gpointer key, gpointer value, gpointer data)
3977 MonoClassField *field = key;
3978 guint32 offset = GPOINTER_TO_UINT (value);
3981 size = mono_type_size (field->type, &align);
3982 do_free_special_slot (offset, size);
3986 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3988 mono_threads_lock ();
3990 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3992 mono_threads_unlock ();
3996 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3998 /* Only ever called for ThreadLocal instances */
3999 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
4001 mono_threads_lock ();
4002 do_free_special_slot (offset, size);
4003 mono_threads_unlock ();
4007 static void CALLBACK dummy_apc (ULONG_PTR param)
4013 * mono_thread_execute_interruption
4015 * Performs the operation that the requested thread state requires (abort,
4018 static MonoException*
4019 mono_thread_execute_interruption (MonoInternalThread *thread)
4021 LOCK_THREAD (thread);
4023 /* MonoThread::interruption_requested can only be changed with atomics */
4024 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4025 /* this will consume pending APC calls */
4027 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4029 InterlockedDecrement (&thread_interruption_requested);
4031 /* Clear the interrupted flag of the thread so it can wait again */
4032 mono_thread_info_clear_self_interrupt ();
4035 if ((thread->state & ThreadState_AbortRequested) != 0) {
4036 UNLOCK_THREAD (thread);
4037 if (thread->abort_exc == NULL) {
4039 * This might be racy, but it has to be called outside the lock
4040 * since it calls managed code.
4042 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4044 return thread->abort_exc;
4046 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4047 self_suspend_internal (thread);
4050 else if ((thread->state & ThreadState_StopRequested) != 0) {
4051 /* FIXME: do this through the JIT? */
4053 UNLOCK_THREAD (thread);
4055 mono_thread_exit ();
4057 } else if (thread->pending_exception) {
4060 exc = thread->pending_exception;
4061 thread->pending_exception = NULL;
4063 UNLOCK_THREAD (thread);
4065 } else if (thread->thread_interrupt_requested) {
4067 thread->thread_interrupt_requested = FALSE;
4068 UNLOCK_THREAD (thread);
4070 return(mono_get_exception_thread_interrupted ());
4073 UNLOCK_THREAD (thread);
4079 * mono_thread_request_interruption
4081 * A signal handler can call this method to request the interruption of a
4082 * thread. The result of the interruption will depend on the current state of
4083 * the thread. If the result is an exception that needs to be throw, it is
4084 * provided as return value.
4087 mono_thread_request_interruption (gboolean running_managed)
4089 MonoInternalThread *thread = mono_thread_internal_current ();
4091 /* The thread may already be stopping */
4096 if (thread->interrupt_on_stop &&
4097 thread->state & ThreadState_StopRequested &&
4098 thread->state & ThreadState_Background)
4102 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4104 InterlockedIncrement (&thread_interruption_requested);
4106 if (!running_managed || is_running_protected_wrapper ()) {
4107 /* Can't stop while in unmanaged code. Increase the global interruption
4108 request count. When exiting the unmanaged method the count will be
4109 checked and the thread will be interrupted. */
4111 if (mono_thread_notify_pending_exc_fn && !running_managed)
4112 /* The JIT will notify the thread about the interruption */
4113 /* This shouldn't take any locks */
4114 mono_thread_notify_pending_exc_fn (NULL);
4116 /* this will awake the thread if it is in WaitForSingleObject
4118 /* Our implementation of this function ignores the func argument */
4120 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4122 mono_thread_info_self_interrupt ();
4127 return mono_thread_execute_interruption (thread);
4131 /*This function should be called by a thread after it has exited all of
4132 * its handle blocks at interruption time.*/
4134 mono_thread_resume_interruption (void)
4136 MonoInternalThread *thread = mono_thread_internal_current ();
4137 gboolean still_aborting;
4139 /* The thread may already be stopping */
4143 LOCK_THREAD (thread);
4144 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4145 UNLOCK_THREAD (thread);
4147 /*This can happen if the protected block called Thread::ResetAbort*/
4148 if (!still_aborting)
4151 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4153 InterlockedIncrement (&thread_interruption_requested);
4155 mono_thread_info_self_interrupt ();
4157 return mono_thread_execute_interruption (thread);
4160 gboolean mono_thread_interruption_requested ()
4162 if (thread_interruption_requested) {
4163 MonoInternalThread *thread = mono_thread_internal_current ();
4164 /* The thread may already be stopping */
4166 return (thread->interruption_requested);
4171 static MonoException*
4172 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4174 MonoInternalThread *thread = mono_thread_internal_current ();
4176 /* The thread may already be stopping */
4180 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4181 MonoException* exc = mono_thread_execute_interruption (thread);
4189 * Performs the interruption of the current thread, if one has been requested,
4190 * and the thread is not running a protected wrapper.
4191 * Return the exception which needs to be thrown, if any.
4194 mono_thread_interruption_checkpoint (void)
4196 return mono_thread_interruption_checkpoint_request (FALSE);
4200 * Performs the interruption of the current thread, if one has been requested.
4201 * Return the exception which needs to be thrown, if any.
4204 mono_thread_force_interruption_checkpoint_noraise (void)
4206 return mono_thread_interruption_checkpoint_request (TRUE);
4210 * Performs the interruption of the current thread, if one has been requested.
4211 * Throw the exception which needs to be thrown, if any.
4214 mono_thread_force_interruption_checkpoint (void)
4218 ex = mono_thread_interruption_checkpoint_request (TRUE);
4220 mono_raise_exception (ex);
4224 * mono_thread_get_and_clear_pending_exception:
4226 * Return any pending exceptions for the current thread and clear it as a side effect.
4229 mono_thread_get_and_clear_pending_exception (void)
4231 MonoInternalThread *thread = mono_thread_internal_current ();
4233 /* The thread may already be stopping */
4237 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4238 return mono_thread_execute_interruption (thread);
4241 if (thread->pending_exception) {
4242 MonoException *exc = thread->pending_exception;
4244 thread->pending_exception = NULL;
4252 * mono_set_pending_exception:
4254 * Set the pending exception of the current thread to EXC.
4255 * The exception will be thrown when execution returns to managed code.
4258 mono_set_pending_exception (MonoException *exc)
4260 MonoInternalThread *thread = mono_thread_internal_current ();
4262 /* The thread may already be stopping */
4266 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4268 mono_thread_request_interruption (FALSE);
4272 * mono_thread_interruption_request_flag:
4274 * Returns the address of a flag that will be non-zero if an interruption has
4275 * been requested for a thread. The thread to interrupt may not be the current
4276 * thread, so an additional call to mono_thread_interruption_requested() or
4277 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4280 gint32* mono_thread_interruption_request_flag ()
4282 return &thread_interruption_requested;
4286 mono_thread_init_apartment_state (void)
4289 MonoInternalThread* thread = mono_thread_internal_current ();
4291 /* Positive return value indicates success, either
4292 * S_OK if this is first CoInitialize call, or
4293 * S_FALSE if CoInitialize already called, but with same
4294 * threading model. A negative value indicates failure,
4295 * probably due to trying to change the threading model.
4297 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4298 ? COINIT_APARTMENTTHREADED
4299 : COINIT_MULTITHREADED) < 0) {
4300 thread->apartment_state = ThreadApartmentState_Unknown;
4306 mono_thread_cleanup_apartment_state (void)
4309 MonoInternalThread* thread = mono_thread_internal_current ();
4311 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4318 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4320 LOCK_THREAD (thread);
4321 thread->state |= state;
4322 UNLOCK_THREAD (thread);
4326 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4328 LOCK_THREAD (thread);
4329 thread->state &= ~state;
4330 UNLOCK_THREAD (thread);
4334 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4336 gboolean ret = FALSE;
4338 LOCK_THREAD (thread);
4340 if ((thread->state & test) != 0) {
4344 UNLOCK_THREAD (thread);
4349 static gboolean has_tls_get = FALSE;
4352 mono_runtime_set_has_tls_get (gboolean val)
4358 mono_runtime_has_tls_get (void)
4364 self_interrupt_thread (void *_unused)
4366 MonoThreadInfo *info = mono_thread_info_current ();
4367 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4368 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4369 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. */
4370 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4374 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4378 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4382 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4384 MonoJitInfo **dest = data;
4390 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4392 MonoJitInfo *ji = NULL;
4395 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4400 MonoInternalThread *thread;
4401 gboolean install_async_abort;
4402 MonoThreadInfoInterruptToken *interrupt_token;
4405 static SuspendThreadResult
4406 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4408 AbortThreadData *data = ud;
4409 MonoInternalThread *thread = data->thread;
4410 MonoJitInfo *ji = NULL;
4411 gboolean protected_wrapper;
4412 gboolean running_managed;
4414 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4415 return MonoResumeThread;
4417 /*someone is already interrupting it*/
4418 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4419 return MonoResumeThread;
4421 InterlockedIncrement (&thread_interruption_requested);
4423 ji = mono_thread_info_get_last_managed (info);
4424 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4425 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4427 if (!protected_wrapper && running_managed) {
4428 /*We are in managed code*/
4429 /*Set the thread to call */
4430 if (data->install_async_abort)
4431 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4432 return MonoResumeThread;
4434 if (mono_thread_notify_pending_exc_fn)
4435 /* The JIT will notify the thread about the interruption */
4436 mono_thread_notify_pending_exc_fn (info);
4439 * This will cause waits to be broken.
4440 * It will also prevent the thread from entering a wait, so if the thread returns
4441 * from the wait before it receives the abort signal, it will just spin in the wait
4442 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4445 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4447 return MonoResumeThread;
4452 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4454 AbortThreadData data = { 0 };
4455 data.thread = thread;
4456 data.install_async_abort = install_async_abort;
4459 FIXME this is insanely broken, it doesn't cause interruption to happen
4460 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4462 if (thread == mono_thread_internal_current ()) {
4463 /* Do it synchronously */
4464 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4466 mono_raise_exception (exc);
4468 mono_thread_info_self_interrupt ();
4473 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, abort_thread_critical, &data);
4474 if (data.interrupt_token)
4475 mono_thread_info_finish_interrupt (data.interrupt_token);
4476 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4480 MonoInternalThread *thread;
4482 MonoThreadInfoInterruptToken *interrupt_token;
4483 } SuspendThreadData;
4485 static SuspendThreadResult
4486 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4488 SuspendThreadData *data = ud;
4489 MonoInternalThread *thread = data->thread;
4490 MonoJitInfo *ji = NULL;
4491 gboolean protected_wrapper;
4492 gboolean running_managed;
4494 ji = mono_thread_info_get_last_managed (info);
4495 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4496 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4498 if (running_managed && !protected_wrapper) {
4499 thread->state &= ~ThreadState_SuspendRequested;
4500 thread->state |= ThreadState_Suspended;
4501 return KeepSuspended;
4503 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4504 InterlockedIncrement (&thread_interruption_requested);
4505 if (data->interrupt)
4506 data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
4508 if (mono_thread_notify_pending_exc_fn && !running_managed)
4509 /* The JIT will notify the thread about the interruption */
4510 mono_thread_notify_pending_exc_fn (info);
4511 return MonoResumeThread;
4516 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4518 LOCK_THREAD (thread);
4519 if (thread == mono_thread_internal_current ()) {
4520 mono_thread_info_begin_self_suspend ();
4521 //XXX replace this with better named functions
4522 thread->state &= ~ThreadState_SuspendRequested;
4523 thread->state |= ThreadState_Suspended;
4524 UNLOCK_THREAD (thread);
4525 mono_thread_info_end_self_suspend ();
4527 SuspendThreadData data = { 0 };
4528 data.thread = thread;
4529 data.interrupt = interrupt;
4531 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, suspend_thread_critical, &data);
4532 if (data.interrupt_token)
4533 mono_thread_info_finish_interrupt (data.interrupt_token);
4534 UNLOCK_THREAD (thread);
4538 /*This is called with @thread synch_cs held and it must release it*/
4540 self_suspend_internal (MonoInternalThread *thread)
4542 mono_thread_info_begin_self_suspend ();
4543 thread->state &= ~ThreadState_SuspendRequested;
4544 thread->state |= ThreadState_Suspended;
4545 UNLOCK_THREAD (thread);
4546 mono_thread_info_end_self_suspend ();
4549 /*This is called with @thread synch_cs held and it must release it*/
4551 resume_thread_internal (MonoInternalThread *thread)
4553 UNLOCK_THREAD (thread);
4554 /* Awake the thread */
4555 if (!mono_thread_info_resume (thread_get_tid (thread)))
4557 LOCK_THREAD (thread);
4558 thread->state &= ~ThreadState_Suspended;
4559 UNLOCK_THREAD (thread);
4565 * mono_thread_is_foreign:
4566 * @thread: the thread to query
4568 * This function allows one to determine if a thread was created by the mono runtime and has
4569 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4571 * Returns: true if @thread was not created by the runtime.
4574 mono_thread_is_foreign (MonoThread *thread)
4576 MonoThreadInfo *info = thread->internal_thread->thread_info;
4577 return info->runtime_thread == FALSE;
4581 * mono_add_joinable_thread:
4583 * Add TID to the list of joinable threads.
4584 * LOCKING: Acquires the threads lock.
4587 mono_threads_add_joinable_thread (gpointer tid)
4591 * We cannot detach from threads because it causes problems like
4592 * 2fd16f60/r114307. So we collect them and join them when
4593 * we have time (in he finalizer thread).
4595 joinable_threads_lock ();
4596 if (!joinable_threads)
4597 joinable_threads = g_hash_table_new (NULL, NULL);
4598 g_hash_table_insert (joinable_threads, tid, tid);
4599 joinable_thread_count ++;
4600 joinable_threads_unlock ();
4602 mono_gc_finalize_notify ();
4607 * mono_threads_join_threads:
4609 * Join all joinable threads. This is called from the finalizer thread.
4610 * LOCKING: Acquires the threads lock.
4613 mono_threads_join_threads (void)
4616 GHashTableIter iter;
4623 if (!joinable_thread_count)
4627 joinable_threads_lock ();
4629 if (g_hash_table_size (joinable_threads)) {
4630 g_hash_table_iter_init (&iter, joinable_threads);
4631 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4632 thread = (pthread_t)tid;
4633 g_hash_table_remove (joinable_threads, key);
4634 joinable_thread_count --;
4637 joinable_threads_unlock ();
4639 if (thread != pthread_self ())
4640 /* This shouldn't block */
4641 pthread_join (thread, NULL);
4652 * Wait for thread TID to exit.
4653 * LOCKING: Acquires the threads lock.
4656 mono_thread_join (gpointer tid)
4660 gboolean found = FALSE;
4662 joinable_threads_lock ();
4663 if (!joinable_threads)
4664 joinable_threads = g_hash_table_new (NULL, NULL);
4665 if (g_hash_table_lookup (joinable_threads, tid)) {
4666 g_hash_table_remove (joinable_threads, tid);
4667 joinable_thread_count --;
4670 joinable_threads_unlock ();
4673 thread = (pthread_t)tid;
4674 pthread_join (thread, NULL);
4679 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4681 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4682 mono_thread_interruption_checkpoint ();
4685 static inline gboolean
4686 is_appdomainunloaded_exception (MonoClass *klass)
4688 static MonoClass *app_domain_unloaded_exception_klass = NULL;
4690 if (!app_domain_unloaded_exception_klass)
4691 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4692 g_assert (app_domain_unloaded_exception_klass);
4694 return klass == app_domain_unloaded_exception_klass;
4697 static inline gboolean
4698 is_threadabort_exception (MonoClass *klass)
4700 return klass == mono_defaults.threadabortexception_class;
4704 mono_thread_internal_unhandled_exception (MonoObject* exc)
4706 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4707 MonoClass *klass = exc->vtable->klass;
4708 if (is_threadabort_exception (klass)) {
4709 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4710 } else if (!is_appdomainunloaded_exception (klass)) {
4711 mono_unhandled_exception (exc);
4712 if (mono_environment_exitcode_get () == 1)