[coop] Don't call unhandled exn hook for ThreadAbortException
[mono-project.git] / mono / metadata / threads.c
blob9b2a401567e5823aa95dc7f96e4fecf9af70db9c
1 /*
2 * threads.c: Thread support internal calls
4 * Author:
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)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <config.h>
17 #include <glib.h>
18 #include <string.h>
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/threads.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internals.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/mono-threads-coop.h>
41 #include <mono/utils/hazard-pointer.h>
42 #include <mono/utils/mono-tls.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/mono-threads-coop.h>
46 #include <mono/utils/mono-error-internals.h>
48 #include <mono/metadata/gc-internals.h>
49 #include <mono/metadata/reflection-internals.h>
51 #ifdef HAVE_SIGNAL_H
52 #include <signal.h>
53 #endif
55 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
56 #define USE_TKILL_ON_ANDROID 1
57 #endif
59 #ifdef PLATFORM_ANDROID
60 #include <errno.h>
62 #ifdef USE_TKILL_ON_ANDROID
63 extern int tkill (pid_t tid, int signal);
64 #endif
65 #endif
67 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
68 #define THREAD_DEBUG(a)
69 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
70 #define THREAD_WAIT_DEBUG(a)
71 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
72 #define LIBGC_DEBUG(a)
74 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
75 #define SPIN_LOCK(i) do { \
76 if (SPIN_TRYLOCK (i)) \
77 break; \
78 } while (1)
80 #define SPIN_UNLOCK(i) i = 0
82 #define LOCK_THREAD(thread) lock_thread((thread))
83 #define UNLOCK_THREAD(thread) unlock_thread((thread))
85 typedef struct
87 guint32 (*func)(void *);
88 MonoThread *obj;
89 MonoObject *delegate;
90 void *start_arg;
91 } StartInfo;
93 typedef union {
94 gint32 ival;
95 gfloat fval;
96 } IntFloatUnion;
98 typedef union {
99 gint64 ival;
100 gdouble fval;
101 } LongDoubleUnion;
103 typedef struct _StaticDataFreeList StaticDataFreeList;
104 struct _StaticDataFreeList {
105 StaticDataFreeList *next;
106 guint32 offset;
107 guint32 size;
110 typedef struct {
111 int idx;
112 int offset;
113 StaticDataFreeList *freelist;
114 } StaticDataInfo;
116 /* Number of cached culture objects in the MonoThread->cached_culture_info array
117 * (per-type): we use the first NUM entries for CultureInfo and the last for
118 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
120 #define NUM_CACHED_CULTURES 4
121 #define CULTURES_START_IDX 0
122 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
124 /* Controls access to the 'threads' hash table */
125 static void mono_threads_lock (void);
126 static void mono_threads_unlock (void);
127 static MonoCoopMutex threads_mutex;
129 /* Controls access to the 'joinable_threads' hash table */
130 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
131 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
132 static mono_mutex_t joinable_threads_mutex;
134 /* Holds current status of static data heap */
135 static StaticDataInfo thread_static_info;
136 static StaticDataInfo context_static_info;
138 /* The hash of existing threads (key is thread ID, value is
139 * MonoInternalThread*) that need joining before exit
141 static MonoGHashTable *threads=NULL;
143 /* List of app context GC handles.
144 * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
146 static GHashTable *contexts = NULL;
148 /* Cleanup queue for contexts. */
149 static MonoReferenceQueue *context_queue;
152 * Threads which are starting up and they are not in the 'threads' hash yet.
153 * When handle_store is called for a thread, it will be removed from this hash table.
154 * Protected by mono_threads_lock ().
156 static MonoGHashTable *threads_starting_up = NULL;
158 /* The TLS key that holds the MonoObject assigned to each thread */
159 static MonoNativeTlsKey current_object_key;
161 /* Contains tids */
162 /* Protected by the threads lock */
163 static GHashTable *joinable_threads;
164 static int joinable_thread_count;
166 #ifdef MONO_HAVE_FAST_TLS
167 /* we need to use both the Tls* functions and __thread because
168 * the gc needs to see all the threads
170 MONO_FAST_TLS_DECLARE(tls_current_object);
171 #define SET_CURRENT_OBJECT(x) do { \
172 MONO_FAST_TLS_SET (tls_current_object, x); \
173 mono_native_tls_set_value (current_object_key, x); \
174 } while (FALSE)
175 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
176 #else
177 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
178 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
179 #endif
181 /* function called at thread start */
182 static MonoThreadStartCB mono_thread_start_cb = NULL;
184 /* function called at thread attach */
185 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
187 /* function called at thread cleanup */
188 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
190 /* The default stack size for each thread */
191 static guint32 default_stacksize = 0;
192 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
194 static void thread_adjust_static_data (MonoInternalThread *thread);
195 static void context_adjust_static_data (MonoAppContext *ctx);
196 static void mono_free_static_data (gpointer* static_data);
197 static void mono_init_static_data_info (StaticDataInfo *static_data);
198 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
199 static gboolean mono_thread_resume (MonoInternalThread* thread);
200 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
201 static void self_abort_internal (MonoError *error);
202 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
203 static void self_suspend_internal (void);
205 static MonoException* mono_thread_execute_interruption (void);
206 static void ref_stack_destroy (gpointer rs);
208 /* Spin lock for InterlockedXXX 64 bit functions */
209 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
210 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
211 static mono_mutex_t interlocked_mutex;
213 /* global count of thread interruptions requested */
214 static gint32 thread_interruption_requested = 0;
216 /* Event signaled when a thread changes its background mode */
217 static HANDLE background_change_event;
219 static gboolean shutting_down = FALSE;
221 static gint32 managed_thread_id_counter = 0;
223 /* Class lazy loading functions */
224 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
226 static void
227 mono_threads_lock (void)
229 mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
232 static void
233 mono_threads_unlock (void)
235 mono_locks_coop_release (&threads_mutex, ThreadsLock);
239 static guint32
240 get_next_managed_thread_id (void)
242 return InterlockedIncrement (&managed_thread_id_counter);
245 MonoNativeTlsKey
246 mono_thread_get_tls_key (void)
248 return current_object_key;
251 gint32
252 mono_thread_get_tls_offset (void)
254 int offset = -1;
256 #ifdef HOST_WIN32
257 if (current_object_key)
258 offset = current_object_key;
259 #else
260 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
261 #endif
262 return offset;
265 static inline MonoNativeThreadId
266 thread_get_tid (MonoInternalThread *thread)
268 /* We store the tid as a guint64 to keep the object layout constant between platforms */
269 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
272 /* handle_store() and handle_remove() manage the array of threads that
273 * still need to be waited for when the main thread exits.
275 * If handle_store() returns FALSE the thread must not be started
276 * because Mono is shutting down.
278 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
280 mono_threads_lock ();
282 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
284 if (threads_starting_up)
285 mono_g_hash_table_remove (threads_starting_up, thread);
287 if (shutting_down && !force_attach) {
288 mono_threads_unlock ();
289 return FALSE;
292 if(threads==NULL) {
293 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
294 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
297 /* We don't need to duplicate thread->handle, because it is
298 * only closed when the thread object is finalized by the GC.
300 g_assert (thread->internal_thread);
301 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
302 thread->internal_thread);
304 mono_threads_unlock ();
306 return TRUE;
309 static gboolean handle_remove(MonoInternalThread *thread)
311 gboolean ret;
312 gsize tid = thread->tid;
314 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
316 mono_threads_lock ();
318 if (threads) {
319 /* We have to check whether the thread object for the
320 * tid is still the same in the table because the
321 * thread might have been destroyed and the tid reused
322 * in the meantime, in which case the tid would be in
323 * the table, but with another thread object.
325 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
326 mono_g_hash_table_remove (threads, (gpointer)tid);
327 ret = TRUE;
328 } else {
329 ret = FALSE;
332 else
333 ret = FALSE;
335 mono_threads_unlock ();
337 /* Don't close the handle here, wait for the object finalizer
338 * to do it. Otherwise, the following race condition applies:
340 * 1) Thread exits (and handle_remove() closes the handle)
342 * 2) Some other handle is reassigned the same slot
344 * 3) Another thread tries to join the first thread, and
345 * blocks waiting for the reassigned handle to be signalled
346 * (which might never happen). This is possible, because the
347 * thread calling Join() still has a reference to the first
348 * thread's object.
350 return ret;
353 static void ensure_synch_cs_set (MonoInternalThread *thread)
355 MonoCoopMutex *synch_cs;
357 if (thread->synch_cs != NULL) {
358 return;
361 synch_cs = g_new0 (MonoCoopMutex, 1);
362 mono_coop_mutex_init_recursive (synch_cs);
364 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
365 synch_cs, NULL) != NULL) {
366 /* Another thread must have installed this CS */
367 mono_coop_mutex_destroy (synch_cs);
368 g_free (synch_cs);
372 static inline void
373 lock_thread (MonoInternalThread *thread)
375 if (!thread->synch_cs)
376 ensure_synch_cs_set (thread);
378 g_assert (thread->synch_cs);
380 mono_coop_mutex_lock (thread->synch_cs);
383 static inline void
384 unlock_thread (MonoInternalThread *thread)
386 mono_coop_mutex_unlock (thread->synch_cs);
389 static inline gboolean
390 is_appdomainunloaded_exception (MonoClass *klass)
392 return klass == mono_class_get_appdomain_unloaded_exception_class ();
395 static inline gboolean
396 is_threadabort_exception (MonoClass *klass)
398 return klass == mono_defaults.threadabortexception_class;
402 * NOTE: this function can be called also for threads different from the current one:
403 * make sure no code called from it will ever assume it is run on the thread that is
404 * getting cleaned up.
406 static void thread_cleanup (MonoInternalThread *thread)
408 g_assert (thread != NULL);
410 if (thread->abort_state_handle) {
411 mono_gchandle_free (thread->abort_state_handle);
412 thread->abort_state_handle = 0;
414 thread->abort_exc = NULL;
415 thread->current_appcontext = NULL;
418 * This is necessary because otherwise we might have
419 * cross-domain references which will not get cleaned up when
420 * the target domain is unloaded.
422 if (thread->cached_culture_info) {
423 int i;
424 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
425 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
429 * thread->synch_cs can be NULL if this was called after
430 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
431 * This can happen only during shutdown.
432 * The shutting_down flag is not always set, so we can't assert on it.
434 if (thread->synch_cs)
435 LOCK_THREAD (thread);
437 thread->state |= ThreadState_Stopped;
438 thread->state &= ~ThreadState_Background;
440 if (thread->synch_cs)
441 UNLOCK_THREAD (thread);
444 An interruption request has leaked to cleanup. Adjust the global counter.
446 This can happen is the abort source thread finds the abortee (this) thread
447 in unmanaged code. If this thread never trips back to managed code or check
448 the local flag it will be left set and positively unbalance the global counter.
450 Leaving the counter unbalanced will cause a performance degradation since all threads
451 will now keep checking their local flags all the time.
453 if (InterlockedExchange (&thread->interruption_requested, 0))
454 InterlockedDecrement (&thread_interruption_requested);
456 /* if the thread is not in the hash it has been removed already */
457 if (!handle_remove (thread)) {
458 if (thread == mono_thread_internal_current ()) {
459 mono_domain_unset ();
460 mono_memory_barrier ();
462 /* This needs to be called even if handle_remove () fails */
463 if (mono_thread_cleanup_fn)
464 mono_thread_cleanup_fn (thread_get_tid (thread));
465 return;
467 mono_release_type_locks (thread);
469 /* Can happen when we attach the profiler helper thread in order to heapshot. */
470 if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
471 mono_profiler_thread_end (thread->tid);
473 mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
475 if (thread == mono_thread_internal_current ()) {
477 * This will signal async signal handlers that the thread has exited.
478 * The profiler callback needs this to be set, so it cannot be done earlier.
480 mono_domain_unset ();
481 mono_memory_barrier ();
484 if (thread == mono_thread_internal_current ())
485 mono_thread_pop_appdomain_ref ();
487 thread->cached_culture_info = NULL;
489 mono_free_static_data (thread->static_data);
490 thread->static_data = NULL;
491 ref_stack_destroy (thread->appdomain_refs);
492 thread->appdomain_refs = NULL;
494 if (mono_thread_cleanup_fn)
495 mono_thread_cleanup_fn (thread_get_tid (thread));
497 if (mono_gc_is_moving ()) {
498 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
499 thread->thread_pinning_ref = NULL;
505 * A special static data offset (guint32) consists of 3 parts:
507 * [0] 6-bit index into the array of chunks.
508 * [6] 25-bit offset into the array.
509 * [31] Bit indicating thread or context static.
512 typedef union {
513 struct {
514 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
515 guint32 type : 1;
516 guint32 offset : 25;
517 guint32 index : 6;
518 #else
519 guint32 index : 6;
520 guint32 offset : 25;
521 guint32 type : 1;
522 #endif
523 } fields;
524 guint32 raw;
525 } SpecialStaticOffset;
527 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
528 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
530 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
531 ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
532 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
533 (((SpecialStaticOffset *) &(x))->fields.f)
535 static gpointer
536 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
538 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
540 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
541 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
543 return ((char *) thread->static_data [idx]) + off;
546 static gpointer
547 get_context_static_data (MonoAppContext *ctx, guint32 offset)
549 g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
551 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
552 int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
554 return ((char *) ctx->static_data [idx]) + off;
557 static MonoThread**
558 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
560 static MonoClassField *current_thread_field = NULL;
562 guint32 offset;
564 if (!current_thread_field) {
565 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
566 g_assert (current_thread_field);
569 mono_class_vtable (domain, mono_defaults.thread_class);
570 mono_domain_lock (domain);
571 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
572 mono_domain_unlock (domain);
573 g_assert (offset);
575 return (MonoThread **)get_thread_static_data (thread, offset);
578 static void
579 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
581 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
583 g_assert (current->obj.vtable->domain == domain);
585 g_assert (!*current_thread_ptr);
586 *current_thread_ptr = current;
589 static MonoThread*
590 create_thread_object (MonoDomain *domain)
592 MonoError error;
593 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
594 MonoThread *t = (MonoThread*)mono_object_new_mature (vt, &error);
595 /* only possible failure mode is OOM, from which we don't expect to recover. */
596 mono_error_assert_ok (&error);
597 return t;
600 static MonoThread*
601 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
603 MonoThread *thread;
605 thread = create_thread_object (domain);
606 thread->priority = THREAD_PRIORITY_NORMAL;
608 MONO_OBJECT_SETREF (thread, internal_thread, internal);
610 return thread;
613 static MonoInternalThread*
614 create_internal_thread (void)
616 MonoError error;
617 MonoInternalThread *thread;
618 MonoVTable *vt;
620 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
621 thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
622 /* only possible failure mode is OOM, from which we don't exect to recover */
623 mono_error_assert_ok (&error);
625 thread->synch_cs = g_new0 (MonoCoopMutex, 1);
626 mono_coop_mutex_init_recursive (thread->synch_cs);
628 thread->apartment_state = ThreadApartmentState_Unknown;
629 thread->managed_id = get_next_managed_thread_id ();
630 if (mono_gc_is_moving ()) {
631 thread->thread_pinning_ref = thread;
632 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
635 return thread;
638 static gboolean
639 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
641 MonoDomain *domain = mono_get_root_domain ();
643 if (!candidate || candidate->obj.vtable->domain != domain) {
644 candidate = new_thread_with_internal (domain, thread);
646 set_current_thread_for_domain (domain, thread, candidate);
647 g_assert (!thread->root_domain_thread);
648 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
649 return TRUE;
652 static guint32 WINAPI start_wrapper_internal(void *data)
654 MonoError error;
655 MonoThreadInfo *info;
656 StartInfo *start_info = (StartInfo *)data;
657 guint32 (*start_func)(void *);
658 void *start_arg;
659 gsize tid;
661 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
662 * GC stack walk.
664 MonoInternalThread *internal = start_info->obj->internal_thread;
665 MonoObject *start_delegate = start_info->delegate;
666 MonoDomain *domain = start_info->obj->obj.vtable->domain;
668 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
670 /* We can be sure start_info->obj->tid and
671 * start_info->obj->handle have been set, because the thread
672 * was created suspended, and these values were set before the
673 * thread resumed
676 info = mono_thread_info_current ();
677 g_assert (info);
678 internal->thread_info = info;
679 internal->small_id = info->small_id;
681 tid = internal->tid;
683 SET_CURRENT_OBJECT (internal);
685 /* Every thread references the appdomain which created it */
686 mono_thread_push_appdomain_ref (domain);
688 if (!mono_domain_set (domain, FALSE)) {
689 /* No point in raising an appdomain_unloaded exception here */
690 /* FIXME: Cleanup here */
691 mono_thread_pop_appdomain_ref ();
692 return 0;
695 start_func = start_info->func;
696 start_arg = start_info->obj->start_obj;
697 if (!start_arg)
698 start_arg = start_info->start_arg;
700 /* We have to do this here because mono_thread_new_init()
701 requires that root_domain_thread is set up. */
702 thread_adjust_static_data (internal);
703 init_root_domain_thread (internal, start_info->obj);
705 /* This MUST be called before any managed code can be
706 * executed, as it calls the callback function that (for the
707 * jit) sets the lmf marker.
709 mono_thread_new_init (tid, &tid, start_func);
710 internal->stack_ptr = &tid;
711 if (domain != mono_get_root_domain ())
712 set_current_thread_for_domain (domain, internal, start_info->obj);
714 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, mono_native_thread_id_get (), getpid (), thread->stack_ptr));
716 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
718 /* On 2.0 profile (and higher), set explicitly since state might have been
719 Unknown */
720 if (internal->apartment_state == ThreadApartmentState_Unknown)
721 internal->apartment_state = ThreadApartmentState_MTA;
723 mono_thread_init_apartment_state ();
725 if(internal->start_notify!=NULL) {
726 /* Let the thread that called Start() know we're
727 * ready
729 ReleaseSemaphore (internal->start_notify, 1, NULL);
732 g_free (start_info);
733 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
734 internal->tid));
737 * Call this after calling start_notify, since the profiler callback might want
738 * to lock the thread, and the lock is held by thread_start () which waits for
739 * start_notify.
741 mono_profiler_thread_start (tid);
743 /* if the name was set before starting, we didn't invoke the profiler callback */
744 if (internal->name) {
745 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
746 mono_profiler_thread_name (internal->tid, tname);
747 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
748 g_free (tname);
751 /* start_func is set only for unmanaged start functions */
752 if (start_func) {
753 start_func (start_arg);
754 } else {
755 void *args [1];
756 g_assert (start_delegate != NULL);
757 args [0] = start_arg;
758 /* we may want to handle the exception here. See comment below on unhandled exceptions */
759 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
761 if (!mono_error_ok (&error)) {
762 MonoException *ex = mono_error_convert_to_exception (&error);
764 g_assert (ex != NULL);
765 MonoClass *klass = mono_object_get_class (&ex->object);
766 if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
767 !is_threadabort_exception (klass)) {
768 mono_unhandled_exception (&ex->object);
769 mono_invoke_unhandled_exception_hook (&ex->object);
770 g_assert_not_reached ();
772 } else {
773 mono_error_cleanup (&error);
777 /* If the thread calls ExitThread at all, this remaining code
778 * will not be executed, but the main thread will eventually
779 * call thread_cleanup() on this thread's behalf.
782 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
784 /* Do any cleanup needed for apartment state. This
785 * cannot be done in thread_cleanup since thread_cleanup could be
786 * called for a thread other than the current thread.
787 * mono_thread_cleanup_apartment_state cleans up apartment
788 * for the current thead */
789 mono_thread_cleanup_apartment_state ();
791 thread_cleanup (internal);
793 internal->tid = 0;
795 /* Remove the reference to the thread object in the TLS data,
796 * so the thread object can be finalized. This won't be
797 * reached if the thread threw an uncaught exception, so those
798 * thread handles will stay referenced :-( (This is due to
799 * missing support for scanning thread-specific data in the
800 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
801 * to TLS data.)
803 SET_CURRENT_OBJECT (NULL);
805 return(0);
808 static guint32 WINAPI start_wrapper(void *data)
810 volatile int dummy;
812 /* Avoid scanning the frames above this frame during a GC */
813 mono_gc_set_stack_end ((void*)&dummy);
815 return start_wrapper_internal (data);
819 * create_thread:
821 * Common thread creation code.
822 * LOCKING: Acquires the threads lock.
824 static gboolean
825 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
826 MonoError *error)
828 HANDLE thread_handle;
829 MonoNativeThreadId tid;
830 MonoThreadParm tp;
833 * Join joinable threads to prevent running out of threads since the finalizer
834 * thread might be blocked/backlogged.
836 mono_threads_join_threads ();
838 mono_error_init (error);
840 mono_threads_lock ();
841 if (shutting_down) {
842 g_free (start_info);
843 mono_threads_unlock ();
844 return FALSE;
846 if (threads_starting_up == NULL) {
847 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
848 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
850 mono_g_hash_table_insert (threads_starting_up, thread, thread);
851 mono_threads_unlock ();
853 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
854 if (!internal->start_notify) {
855 mono_threads_lock ();
856 mono_g_hash_table_remove (threads_starting_up, thread);
857 mono_threads_unlock ();
858 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
859 g_free (start_info);
860 return FALSE;
863 if (stack_size == 0)
864 stack_size = default_stacksize_for_thread (internal);
866 /* Create suspended, so we can do some housekeeping before the thread
867 * starts
869 tp.priority = thread->priority;
870 tp.stack_size = stack_size;
871 tp.creation_flags = CREATE_SUSPENDED;
873 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info, &tp, &tid);
875 if (thread_handle == NULL) {
876 /* The thread couldn't be created, so set an exception */
877 mono_threads_lock ();
878 mono_g_hash_table_remove (threads_starting_up, thread);
879 mono_threads_unlock ();
880 g_free (start_info);
881 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
882 return FALSE;
884 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
886 internal->handle = thread_handle;
887 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
889 internal->threadpool_thread = threadpool_thread;
890 if (threadpool_thread)
891 mono_thread_set_state (internal, ThreadState_Background);
893 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
895 /* Only store the handle when the thread is about to be
896 * launched, to avoid the main thread deadlocking while trying
897 * to clean up a thread that will never be signalled.
899 if (!handle_store (thread, FALSE))
900 return FALSE;
902 mono_thread_info_resume (tid);
904 if (internal->start_notify) {
906 * Wait for the thread to set up its TLS data etc, so
907 * theres no potential race condition if someone tries
908 * to look up the data believing the thread has
909 * started
911 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
913 MONO_ENTER_GC_SAFE;
914 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
915 MONO_EXIT_GC_SAFE;
917 CloseHandle (internal->start_notify);
918 internal->start_notify = NULL;
921 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
923 return TRUE;
926 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
928 if (mono_thread_start_cb) {
929 mono_thread_start_cb (tid, stack_start, func);
933 void mono_threads_set_default_stacksize (guint32 stacksize)
935 default_stacksize = stacksize;
938 guint32 mono_threads_get_default_stacksize (void)
940 return default_stacksize;
944 * mono_thread_create_internal:
946 * ARG should not be a GC reference.
948 MonoInternalThread*
949 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
951 MonoThread *thread;
952 MonoInternalThread *internal;
953 StartInfo *start_info;
954 gboolean res;
956 mono_error_init (error);
958 thread = create_thread_object (domain);
960 internal = create_internal_thread ();
962 MONO_OBJECT_SETREF (thread, internal_thread, internal);
964 start_info = g_new0 (StartInfo, 1);
965 start_info->func = (guint32 (*)(void *))func;
966 start_info->obj = thread;
967 start_info->start_arg = arg;
969 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, error);
970 return_val_if_nok (error, NULL);
972 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
973 #ifndef MONO_CROSS_COMPILE
974 if (mono_check_corlib_version () == NULL)
975 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
976 #endif
978 return internal;
981 void
982 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
984 MonoError error;
985 if (!mono_thread_create_checked (domain, func, arg, &error))
986 mono_error_cleanup (&error);
989 gboolean
990 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
992 return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
995 MonoThread *
996 mono_thread_attach (MonoDomain *domain)
998 MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1000 return thread;
1003 MonoThread *
1004 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1006 MonoThreadInfo *info;
1007 MonoInternalThread *thread;
1008 MonoThread *current_thread;
1009 HANDLE thread_handle;
1010 MonoNativeThreadId tid;
1012 if ((thread = mono_thread_internal_current ())) {
1013 if (domain != mono_domain_get ())
1014 mono_domain_set (domain, TRUE);
1015 /* Already attached */
1016 return mono_thread_current ();
1019 if (!mono_gc_register_thread (&domain)) {
1020 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", mono_native_thread_id_get ());
1023 thread = create_internal_thread ();
1025 thread_handle = mono_thread_info_open_handle ();
1026 g_assert (thread_handle);
1028 tid=mono_native_thread_id_get ();
1030 thread->handle = thread_handle;
1031 thread->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
1032 thread->stack_ptr = &tid;
1034 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
1036 info = mono_thread_info_current ();
1037 g_assert (info);
1038 thread->thread_info = info;
1039 thread->small_id = info->small_id;
1041 current_thread = new_thread_with_internal (domain, thread);
1043 if (!handle_store (current_thread, force_attach)) {
1044 /* Mono is shutting down, so just wait for the end */
1045 for (;;)
1046 mono_thread_info_sleep (10000, NULL);
1049 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), thread));
1051 SET_CURRENT_OBJECT (thread);
1052 mono_domain_set (domain, TRUE);
1054 thread_adjust_static_data (thread);
1056 init_root_domain_thread (thread, current_thread);
1058 if (domain != mono_get_root_domain ())
1059 set_current_thread_for_domain (domain, thread, current_thread);
1062 if (mono_thread_attach_cb) {
1063 guint8 *staddr;
1064 size_t stsize;
1066 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1068 if (staddr == NULL)
1069 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &tid);
1070 else
1071 mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1074 /* Can happen when we attach the profiler helper thread in order to heapshot. */
1075 if (!info->tools_thread)
1076 // FIXME: Need a separate callback
1077 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1079 return current_thread;
1082 void
1083 mono_thread_detach_internal (MonoInternalThread *thread)
1085 g_return_if_fail (thread != NULL);
1087 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1089 thread_cleanup (thread);
1091 SET_CURRENT_OBJECT (NULL);
1092 mono_domain_unset ();
1094 /* Don't need to CloseHandle this thread, even though we took a
1095 * reference in mono_thread_attach (), because the GC will do it
1096 * when the Thread object is finalised.
1100 void
1101 mono_thread_detach (MonoThread *thread)
1103 if (thread)
1104 mono_thread_detach_internal (thread->internal_thread);
1108 * mono_thread_detach_if_exiting:
1110 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1111 * This should be used at the end of embedding code which calls into managed code, and which
1112 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1114 mono_bool
1115 mono_thread_detach_if_exiting (void)
1117 if (mono_thread_info_is_exiting ()) {
1118 MonoInternalThread *thread;
1120 thread = mono_thread_internal_current ();
1121 if (thread) {
1122 mono_thread_detach_internal (thread);
1123 mono_thread_info_detach ();
1124 return TRUE;
1127 return FALSE;
1130 void
1131 mono_thread_exit (void)
1133 MonoInternalThread *thread = mono_thread_internal_current ();
1135 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1137 thread_cleanup (thread);
1138 SET_CURRENT_OBJECT (NULL);
1139 mono_domain_unset ();
1141 /* we could add a callback here for embedders to use. */
1142 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1143 exit (mono_environment_exitcode_get ());
1144 mono_thread_info_exit ();
1147 void
1148 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1150 MonoInternalThread *internal;
1152 internal = create_internal_thread ();
1154 internal->state = ThreadState_Unstarted;
1156 InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1159 HANDLE
1160 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1161 MonoObject *start)
1163 MonoError error;
1164 StartInfo *start_info;
1165 MonoInternalThread *internal;
1166 gboolean res;
1168 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1170 if (!this_obj->internal_thread)
1171 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1172 internal = this_obj->internal_thread;
1174 LOCK_THREAD (internal);
1176 if ((internal->state & ThreadState_Unstarted) == 0) {
1177 UNLOCK_THREAD (internal);
1178 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1179 return NULL;
1182 if ((internal->state & ThreadState_Aborted) != 0) {
1183 UNLOCK_THREAD (internal);
1184 return this_obj;
1186 /* This is freed in start_wrapper */
1187 start_info = g_new0 (StartInfo, 1);
1188 start_info->func = NULL;
1189 start_info->start_arg = NULL;
1190 start_info->delegate = start;
1191 start_info->obj = this_obj;
1192 g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1194 res = create_thread (this_obj, internal, start_info, FALSE, 0, &error);
1195 if (!res) {
1196 mono_error_cleanup (&error);
1197 UNLOCK_THREAD (internal);
1198 return NULL;
1201 internal->state &= ~ThreadState_Unstarted;
1203 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1205 UNLOCK_THREAD (internal);
1206 return internal->handle;
1210 * This is called from the finalizer of the internal thread object.
1212 void
1213 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1215 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1218 * Since threads keep a reference to their thread object while running, by the time this function is called,
1219 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1220 * when thread_cleanup () can be called after this.
1222 if (thread)
1223 CloseHandle (thread);
1225 if (this_obj->synch_cs) {
1226 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1227 this_obj->synch_cs = NULL;
1228 mono_coop_mutex_destroy (synch_cs);
1229 g_free (synch_cs);
1232 if (this_obj->name) {
1233 void *name = this_obj->name;
1234 this_obj->name = NULL;
1235 g_free (name);
1239 void
1240 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1242 guint32 res;
1243 MonoInternalThread *thread = mono_thread_internal_current ();
1245 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1247 if (mono_thread_current_check_pending_interrupt ())
1248 return;
1250 while (TRUE) {
1251 gboolean alerted = FALSE;
1253 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1255 res = mono_thread_info_sleep (ms, &alerted);
1257 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1259 if (alerted) {
1260 MonoException* exc = mono_thread_execute_interruption ();
1261 if (exc) {
1262 mono_raise_exception (exc);
1263 } else {
1264 // FIXME: !INFINITE
1265 if (ms != INFINITE)
1266 break;
1268 } else {
1269 break;
1274 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1278 gint32
1279 ves_icall_System_Threading_Thread_GetDomainID (void)
1281 return mono_domain_get()->domain_id;
1284 gboolean
1285 ves_icall_System_Threading_Thread_Yield (void)
1287 return mono_thread_info_yield ();
1291 * mono_thread_get_name:
1293 * Return the name of the thread. NAME_LEN is set to the length of the name.
1294 * Return NULL if the thread has no name. The returned memory is owned by the
1295 * caller.
1297 gunichar2*
1298 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1300 gunichar2 *res;
1302 LOCK_THREAD (this_obj);
1304 if (!this_obj->name) {
1305 *name_len = 0;
1306 res = NULL;
1307 } else {
1308 *name_len = this_obj->name_len;
1309 res = g_new (gunichar2, this_obj->name_len);
1310 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1313 UNLOCK_THREAD (this_obj);
1315 return res;
1319 * mono_thread_get_name_utf8:
1321 * Return the name of the thread in UTF-8.
1322 * Return NULL if the thread has no name.
1323 * The returned memory is owned by the caller.
1325 char *
1326 mono_thread_get_name_utf8 (MonoThread *thread)
1328 if (thread == NULL)
1329 return NULL;
1331 MonoInternalThread *internal = thread->internal_thread;
1332 if (internal == NULL)
1333 return NULL;
1335 LOCK_THREAD (internal);
1337 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1339 UNLOCK_THREAD (internal);
1341 return tname;
1345 * mono_thread_get_managed_id:
1347 * Return the Thread.ManagedThreadId value of `thread`.
1348 * Returns -1 if `thread` is NULL.
1350 int32_t
1351 mono_thread_get_managed_id (MonoThread *thread)
1353 if (thread == NULL)
1354 return -1;
1356 MonoInternalThread *internal = thread->internal_thread;
1357 if (internal == NULL)
1358 return -1;
1360 int32_t id = internal->managed_id;
1362 return id;
1365 MonoString*
1366 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1368 MonoError error;
1369 MonoString* str;
1371 mono_error_init (&error);
1373 LOCK_THREAD (this_obj);
1375 if (!this_obj->name)
1376 str = NULL;
1377 else
1378 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1380 UNLOCK_THREAD (this_obj);
1382 if (mono_error_set_pending_exception (&error))
1383 return NULL;
1385 return str;
1388 void
1389 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1391 LOCK_THREAD (this_obj);
1393 mono_error_init (error);
1395 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1396 UNLOCK_THREAD (this_obj);
1398 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1399 return;
1401 if (this_obj->name) {
1402 g_free (this_obj->name);
1403 this_obj->name_len = 0;
1405 if (name) {
1406 this_obj->name = g_new (gunichar2, mono_string_length (name));
1407 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1408 this_obj->name_len = mono_string_length (name);
1410 if (permanent)
1411 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1413 else
1414 this_obj->name = NULL;
1417 UNLOCK_THREAD (this_obj);
1419 if (this_obj->name && this_obj->tid) {
1420 char *tname = mono_string_to_utf8_checked (name, error);
1421 return_if_nok (error);
1422 mono_profiler_thread_name (this_obj->tid, tname);
1423 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1424 mono_free (tname);
1428 void
1429 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1431 MonoError error;
1432 mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1433 mono_error_set_pending_exception (&error);
1437 * ves_icall_System_Threading_Thread_GetPriority_internal:
1438 * @param this_obj: The MonoInternalThread on which to operate.
1440 * Gets the priority of the given thread.
1441 * @return: The priority of the given thread.
1444 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1446 gint32 priority;
1447 MonoInternalThread *internal = this_obj->internal_thread;
1449 LOCK_THREAD (internal);
1450 if (internal->handle != NULL)
1451 priority = GetThreadPriority (internal->handle) + 2;
1452 else
1453 priority = this_obj->priority + 2;
1454 UNLOCK_THREAD (internal);
1455 return priority;
1459 * ves_icall_System_Threading_Thread_SetPriority_internal:
1460 * @param this_obj: The MonoInternalThread on which to operate.
1461 * @param priority: The priority to set.
1463 * Sets the priority of the given thread.
1465 void
1466 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1468 MonoInternalThread *internal = this_obj->internal_thread;
1470 LOCK_THREAD (internal);
1471 this_obj->priority = priority - 2;
1472 if (internal->handle != NULL)
1473 SetThreadPriority (internal->handle, this_obj->priority);
1474 UNLOCK_THREAD (internal);
1477 /* If the array is already in the requested domain, we just return it,
1478 otherwise we return a copy in that domain. */
1479 static MonoArray*
1480 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1482 MonoArray *copy;
1484 mono_error_init (error);
1485 if (!arr)
1486 return NULL;
1488 if (mono_object_domain (arr) == domain)
1489 return arr;
1491 copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1492 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1493 return copy;
1496 MonoArray*
1497 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1499 MonoError error;
1500 MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1501 mono_error_set_pending_exception (&error);
1502 return result;
1505 MonoArray*
1506 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1508 MonoError error;
1509 MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1510 mono_error_set_pending_exception (&error);
1511 return result;
1514 MonoThread *
1515 mono_thread_current (void)
1517 MonoDomain *domain = mono_domain_get ();
1518 MonoInternalThread *internal = mono_thread_internal_current ();
1519 MonoThread **current_thread_ptr;
1521 g_assert (internal);
1522 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1524 if (!*current_thread_ptr) {
1525 g_assert (domain != mono_get_root_domain ());
1526 *current_thread_ptr = new_thread_with_internal (domain, internal);
1528 return *current_thread_ptr;
1531 /* Return the thread object belonging to INTERNAL in the current domain */
1532 static MonoThread *
1533 mono_thread_current_for_thread (MonoInternalThread *internal)
1535 MonoDomain *domain = mono_domain_get ();
1536 MonoThread **current_thread_ptr;
1538 g_assert (internal);
1539 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1541 if (!*current_thread_ptr) {
1542 g_assert (domain != mono_get_root_domain ());
1543 *current_thread_ptr = new_thread_with_internal (domain, internal);
1545 return *current_thread_ptr;
1548 MonoInternalThread*
1549 mono_thread_internal_current (void)
1551 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1552 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1553 return res;
1556 gboolean
1557 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1559 MonoInternalThread *thread = this_obj->internal_thread;
1560 HANDLE handle = thread->handle;
1561 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1562 gboolean ret;
1564 if (mono_thread_current_check_pending_interrupt ())
1565 return FALSE;
1567 LOCK_THREAD (thread);
1569 if ((thread->state & ThreadState_Unstarted) != 0) {
1570 UNLOCK_THREAD (thread);
1572 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1573 return FALSE;
1576 UNLOCK_THREAD (thread);
1578 if(ms== -1) {
1579 ms=INFINITE;
1581 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1583 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1585 MONO_ENTER_GC_SAFE;
1586 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1587 MONO_EXIT_GC_SAFE;
1589 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1591 if(ret==WAIT_OBJECT_0) {
1592 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1594 return(TRUE);
1597 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1599 return(FALSE);
1602 #define MANAGED_WAIT_FAILED 0x7fffffff
1604 static gint32
1605 map_native_wait_result_to_managed (gint32 val)
1607 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1608 return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1611 static gint32
1612 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1614 MonoException *exc;
1615 guint32 ret;
1616 gint64 start;
1617 gint32 diff_ms;
1618 gint32 wait = ms;
1620 mono_error_init (error);
1622 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1623 do {
1624 MONO_ENTER_GC_SAFE;
1625 if (numhandles != 1)
1626 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1627 else
1628 ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1629 MONO_EXIT_GC_SAFE;
1631 if (ret != WAIT_IO_COMPLETION)
1632 break;
1634 exc = mono_thread_execute_interruption ();
1635 if (exc) {
1636 mono_error_set_exception_instance (error, exc);
1637 break;
1640 if (ms == -1)
1641 continue;
1643 /* Re-calculate ms according to the time passed */
1644 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1645 if (diff_ms >= ms) {
1646 ret = WAIT_TIMEOUT;
1647 break;
1649 wait = ms - diff_ms;
1650 } while (TRUE);
1652 return ret;
1655 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1657 MonoError error;
1658 HANDLE *handles;
1659 guint32 numhandles;
1660 guint32 ret;
1661 guint32 i;
1662 MonoObject *waitHandle;
1663 MonoInternalThread *thread = mono_thread_internal_current ();
1665 /* Do this WaitSleepJoin check before creating objects */
1666 if (mono_thread_current_check_pending_interrupt ())
1667 return map_native_wait_result_to_managed (WAIT_FAILED);
1669 /* We fail in managed if the array has more than 64 elements */
1670 numhandles = (guint32)mono_array_length(mono_handles);
1671 handles = g_new0(HANDLE, numhandles);
1673 for(i = 0; i < numhandles; i++) {
1674 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1675 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1678 if(ms== -1) {
1679 ms=INFINITE;
1682 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1684 ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1686 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1688 g_free(handles);
1690 mono_error_set_pending_exception (&error);
1692 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1693 return map_native_wait_result_to_managed (ret);
1696 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1698 MonoError error;
1699 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1700 uintptr_t numhandles;
1701 guint32 ret;
1702 guint32 i;
1703 MonoObject *waitHandle;
1704 MonoInternalThread *thread = mono_thread_internal_current ();
1706 /* Do this WaitSleepJoin check before creating objects */
1707 if (mono_thread_current_check_pending_interrupt ())
1708 return map_native_wait_result_to_managed (WAIT_FAILED);
1710 numhandles = mono_array_length(mono_handles);
1711 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1712 return map_native_wait_result_to_managed (WAIT_FAILED);
1714 for(i = 0; i < numhandles; i++) {
1715 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1716 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1719 if(ms== -1) {
1720 ms=INFINITE;
1723 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1725 ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1727 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1729 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1731 mono_error_set_pending_exception (&error);
1733 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1735 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1736 return map_native_wait_result_to_managed (ret - WAIT_OBJECT_0);
1738 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1739 return map_native_wait_result_to_managed (ret - WAIT_ABANDONED_0);
1741 else {
1742 /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1743 return map_native_wait_result_to_managed (ret);
1747 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1749 MonoError error;
1750 guint32 ret;
1751 MonoInternalThread *thread = mono_thread_internal_current ();
1753 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1755 if(ms== -1) {
1756 ms=INFINITE;
1759 if (mono_thread_current_check_pending_interrupt ())
1760 return map_native_wait_result_to_managed (WAIT_FAILED);
1762 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1764 ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1766 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1768 mono_error_set_pending_exception (&error);
1769 return map_native_wait_result_to_managed (ret);
1772 gint32
1773 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1775 guint32 ret;
1776 MonoInternalThread *thread = mono_thread_internal_current ();
1778 if (ms == -1)
1779 ms = INFINITE;
1781 if (mono_thread_current_check_pending_interrupt ())
1782 return map_native_wait_result_to_managed (WAIT_FAILED);
1784 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1786 MONO_ENTER_GC_SAFE;
1787 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1788 MONO_EXIT_GC_SAFE;
1790 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1792 return map_native_wait_result_to_managed (ret);
1795 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1797 HANDLE mutex;
1799 *created = TRUE;
1801 if (name == NULL) {
1802 mutex = CreateMutex (NULL, owned, NULL);
1803 } else {
1804 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1806 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1807 *created = FALSE;
1811 return(mutex);
1814 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1815 return(ReleaseMutex (handle));
1818 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1819 gint32 rights,
1820 gint32 *error)
1822 HANDLE ret;
1824 *error = ERROR_SUCCESS;
1826 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1827 if (ret == NULL) {
1828 *error = GetLastError ();
1831 return(ret);
1835 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, gint32 *error)
1837 HANDLE sem;
1839 if (name == NULL) {
1840 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1841 } else {
1842 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1843 mono_string_chars (name));
1846 *error = GetLastError ();
1847 return(sem);
1850 MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, gint32 *prevcount)
1852 return ReleaseSemaphore (handle, releaseCount, prevcount);
1855 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1857 HANDLE sem;
1859 sem = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1860 *error = GetLastError ();
1862 return(sem);
1865 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1867 HANDLE event;
1869 *created = TRUE;
1871 if (name == NULL) {
1872 event = CreateEvent (NULL, manual, initial, NULL);
1873 } else {
1874 event = CreateEvent (NULL, manual, initial,
1875 mono_string_chars (name));
1877 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1878 *created = FALSE;
1882 return(event);
1885 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1886 return (SetEvent(handle));
1889 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1890 return (ResetEvent(handle));
1893 void
1894 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1895 CloseHandle (handle);
1898 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1899 gint32 rights,
1900 gint32 *error)
1902 HANDLE ret;
1904 *error = ERROR_SUCCESS;
1906 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1907 if (ret == NULL) {
1908 *error = GetLastError ();
1911 return(ret);
1914 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1916 return InterlockedIncrement (location);
1919 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1921 #if SIZEOF_VOID_P == 4
1922 if (G_UNLIKELY ((size_t)location & 0x7)) {
1923 gint64 ret;
1924 mono_interlocked_lock ();
1925 (*location)++;
1926 ret = *location;
1927 mono_interlocked_unlock ();
1928 return ret;
1930 #endif
1931 return InterlockedIncrement64 (location);
1934 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1936 return InterlockedDecrement(location);
1939 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1941 #if SIZEOF_VOID_P == 4
1942 if (G_UNLIKELY ((size_t)location & 0x7)) {
1943 gint64 ret;
1944 mono_interlocked_lock ();
1945 (*location)--;
1946 ret = *location;
1947 mono_interlocked_unlock ();
1948 return ret;
1950 #endif
1951 return InterlockedDecrement64 (location);
1954 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1956 return InterlockedExchange(location, value);
1959 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1961 MonoObject *res;
1962 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1963 mono_gc_wbarrier_generic_nostore (location);
1964 return res;
1967 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1969 return InterlockedExchangePointer(location, value);
1972 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1974 IntFloatUnion val, ret;
1976 val.fval = value;
1977 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1979 return ret.fval;
1982 gint64
1983 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1985 #if SIZEOF_VOID_P == 4
1986 if (G_UNLIKELY ((size_t)location & 0x7)) {
1987 gint64 ret;
1988 mono_interlocked_lock ();
1989 ret = *location;
1990 *location = value;
1991 mono_interlocked_unlock ();
1992 return ret;
1994 #endif
1995 return InterlockedExchange64 (location, value);
1998 gdouble
1999 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
2001 LongDoubleUnion val, ret;
2003 val.fval = value;
2004 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
2006 return ret.fval;
2009 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
2011 return InterlockedCompareExchange(location, value, comparand);
2014 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
2016 gint32 r = InterlockedCompareExchange(location, value, comparand);
2017 *success = r == comparand;
2018 return r;
2021 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
2023 MonoObject *res;
2024 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
2025 mono_gc_wbarrier_generic_nostore (location);
2026 return res;
2029 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
2031 return InterlockedCompareExchangePointer(location, value, comparand);
2034 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
2036 IntFloatUnion val, ret, cmp;
2038 val.fval = value;
2039 cmp.fval = comparand;
2040 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
2042 return ret.fval;
2045 gdouble
2046 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
2048 #if SIZEOF_VOID_P == 8
2049 LongDoubleUnion val, comp, ret;
2051 val.fval = value;
2052 comp.fval = comparand;
2053 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
2055 return ret.fval;
2056 #else
2057 gdouble old;
2059 mono_interlocked_lock ();
2060 old = *location;
2061 if (old == comparand)
2062 *location = value;
2063 mono_interlocked_unlock ();
2065 return old;
2066 #endif
2069 gint64
2070 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
2072 #if SIZEOF_VOID_P == 4
2073 if (G_UNLIKELY ((size_t)location & 0x7)) {
2074 gint64 old;
2075 mono_interlocked_lock ();
2076 old = *location;
2077 if (old == comparand)
2078 *location = value;
2079 mono_interlocked_unlock ();
2080 return old;
2082 #endif
2083 return InterlockedCompareExchange64 (location, value, comparand);
2086 MonoObject*
2087 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
2089 MonoObject *res;
2090 res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
2091 mono_gc_wbarrier_generic_nostore (location);
2092 return res;
2095 MonoObject*
2096 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2098 MonoObject *res;
2099 MONO_CHECK_NULL (location, NULL);
2100 res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2101 mono_gc_wbarrier_generic_nostore (location);
2102 return res;
2105 gint32
2106 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2108 return InterlockedAdd (location, value);
2111 gint64
2112 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2114 #if SIZEOF_VOID_P == 4
2115 if (G_UNLIKELY ((size_t)location & 0x7)) {
2116 gint64 ret;
2117 mono_interlocked_lock ();
2118 *location += value;
2119 ret = *location;
2120 mono_interlocked_unlock ();
2121 return ret;
2123 #endif
2124 return InterlockedAdd64 (location, value);
2127 gint64
2128 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2130 #if SIZEOF_VOID_P == 4
2131 if (G_UNLIKELY ((size_t)location & 0x7)) {
2132 gint64 ret;
2133 mono_interlocked_lock ();
2134 ret = *location;
2135 mono_interlocked_unlock ();
2136 return ret;
2138 #endif
2139 return InterlockedRead64 (location);
2142 void
2143 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2145 mono_memory_barrier ();
2148 void
2149 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2151 mono_thread_clr_state (this_obj, (MonoThreadState)state);
2153 if (state & ThreadState_Background) {
2154 /* If the thread changes the background mode, the main thread has to
2155 * be notified, since it has to rebuild the list of threads to
2156 * wait for.
2158 SetEvent (background_change_event);
2162 void
2163 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2165 mono_thread_set_state (this_obj, (MonoThreadState)state);
2167 if (state & ThreadState_Background) {
2168 /* If the thread changes the background mode, the main thread has to
2169 * be notified, since it has to rebuild the list of threads to
2170 * wait for.
2172 SetEvent (background_change_event);
2176 guint32
2177 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2179 guint32 state;
2181 LOCK_THREAD (this_obj);
2183 state = this_obj->state;
2185 UNLOCK_THREAD (this_obj);
2187 return state;
2190 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2192 MonoInternalThread *current;
2193 gboolean throw_;
2194 MonoInternalThread *thread = this_obj->internal_thread;
2196 LOCK_THREAD (thread);
2198 current = mono_thread_internal_current ();
2200 thread->thread_interrupt_requested = TRUE;
2201 throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2203 UNLOCK_THREAD (thread);
2205 if (throw_) {
2206 async_abort_internal (thread, FALSE);
2211 * mono_thread_current_check_pending_interrupt:
2213 * Checks if there's a interruption request and set the pending exception if so.
2215 * @returns true if a pending exception was set
2217 gboolean
2218 mono_thread_current_check_pending_interrupt (void)
2220 MonoInternalThread *thread = mono_thread_internal_current ();
2221 gboolean throw_ = FALSE;
2223 LOCK_THREAD (thread);
2225 if (thread->thread_interrupt_requested) {
2226 throw_ = TRUE;
2227 thread->thread_interrupt_requested = FALSE;
2230 UNLOCK_THREAD (thread);
2232 if (throw_)
2233 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2234 return throw_;
2237 static gboolean
2238 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2240 LOCK_THREAD (thread);
2242 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2243 (thread->state & ThreadState_StopRequested) != 0 ||
2244 (thread->state & ThreadState_Stopped) != 0)
2246 UNLOCK_THREAD (thread);
2247 return FALSE;
2250 if ((thread->state & ThreadState_Unstarted) != 0) {
2251 thread->state |= ThreadState_Aborted;
2252 UNLOCK_THREAD (thread);
2253 return FALSE;
2256 thread->state |= ThreadState_AbortRequested;
2257 if (thread->abort_state_handle)
2258 mono_gchandle_free (thread->abort_state_handle);
2259 if (state) {
2260 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2261 g_assert (thread->abort_state_handle);
2262 } else {
2263 thread->abort_state_handle = 0;
2265 thread->abort_exc = NULL;
2267 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), thread, (gsize)thread->tid));
2269 /* During shutdown, we can't wait for other threads */
2270 if (!shutting_down)
2271 /* Make sure the thread is awake */
2272 mono_thread_resume (thread);
2274 UNLOCK_THREAD (thread);
2275 return TRUE;
2278 void
2279 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2281 if (!request_thread_abort (thread, state))
2282 return;
2284 if (thread == mono_thread_internal_current ()) {
2285 MonoError error;
2286 self_abort_internal (&error);
2287 mono_error_set_pending_exception (&error);
2288 } else {
2289 async_abort_internal (thread, TRUE);
2294 * mono_thread_internal_abort:
2296 * Request thread @thread to be aborted.
2298 * @thread MUST NOT be the current thread.
2300 void
2301 mono_thread_internal_abort (MonoInternalThread *thread)
2303 g_assert (thread != mono_thread_internal_current ());
2305 if (!request_thread_abort (thread, NULL))
2306 return;
2307 async_abort_internal (thread, TRUE);
2310 void
2311 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2313 MonoInternalThread *thread = mono_thread_internal_current ();
2314 gboolean was_aborting;
2316 LOCK_THREAD (thread);
2317 was_aborting = thread->state & ThreadState_AbortRequested;
2318 thread->state &= ~ThreadState_AbortRequested;
2319 UNLOCK_THREAD (thread);
2321 if (!was_aborting) {
2322 const char *msg = "Unable to reset abort because no abort was requested";
2323 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2324 return;
2326 thread->abort_exc = NULL;
2327 if (thread->abort_state_handle) {
2328 mono_gchandle_free (thread->abort_state_handle);
2329 /* This is actually not necessary - the handle
2330 only counts if the exception is set */
2331 thread->abort_state_handle = 0;
2335 void
2336 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2338 LOCK_THREAD (thread);
2340 thread->state &= ~ThreadState_AbortRequested;
2342 if (thread->abort_exc) {
2343 thread->abort_exc = NULL;
2344 if (thread->abort_state_handle) {
2345 mono_gchandle_free (thread->abort_state_handle);
2346 /* This is actually not necessary - the handle
2347 only counts if the exception is set */
2348 thread->abort_state_handle = 0;
2352 UNLOCK_THREAD (thread);
2355 MonoObject*
2356 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2358 MonoError error;
2359 MonoInternalThread *thread = this_obj->internal_thread;
2360 MonoObject *state, *deserialized = NULL;
2361 MonoDomain *domain;
2363 if (!thread->abort_state_handle)
2364 return NULL;
2366 state = mono_gchandle_get_target (thread->abort_state_handle);
2367 g_assert (state);
2369 domain = mono_domain_get ();
2370 if (mono_object_domain (state) == domain)
2371 return state;
2373 deserialized = mono_object_xdomain_representation (state, domain, &error);
2375 if (!deserialized) {
2376 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2377 if (!is_ok (&error)) {
2378 MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2379 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2381 mono_set_pending_exception (invalid_op_exc);
2382 return NULL;
2385 return deserialized;
2388 static gboolean
2389 mono_thread_suspend (MonoInternalThread *thread)
2391 LOCK_THREAD (thread);
2393 if ((thread->state & ThreadState_Unstarted) != 0 ||
2394 (thread->state & ThreadState_Aborted) != 0 ||
2395 (thread->state & ThreadState_Stopped) != 0)
2397 UNLOCK_THREAD (thread);
2398 return FALSE;
2401 if ((thread->state & ThreadState_Suspended) != 0 ||
2402 (thread->state & ThreadState_SuspendRequested) != 0 ||
2403 (thread->state & ThreadState_StopRequested) != 0)
2405 UNLOCK_THREAD (thread);
2406 return TRUE;
2409 thread->state |= ThreadState_SuspendRequested;
2411 if (thread == mono_thread_internal_current ()) {
2412 /* calls UNLOCK_THREAD (thread) */
2413 self_suspend_internal ();
2414 } else {
2415 /* calls UNLOCK_THREAD (thread) */
2416 async_suspend_internal (thread, FALSE);
2419 return TRUE;
2422 void
2423 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2425 if (!mono_thread_suspend (this_obj->internal_thread)) {
2426 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2427 return;
2431 /* LOCKING: LOCK_THREAD(thread) must be held */
2432 static gboolean
2433 mono_thread_resume (MonoInternalThread *thread)
2435 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2436 thread->state &= ~ThreadState_SuspendRequested;
2437 return TRUE;
2440 if ((thread->state & ThreadState_Suspended) == 0 ||
2441 (thread->state & ThreadState_Unstarted) != 0 ||
2442 (thread->state & ThreadState_Aborted) != 0 ||
2443 (thread->state & ThreadState_Stopped) != 0)
2445 return FALSE;
2448 UNLOCK_THREAD (thread);
2450 /* Awake the thread */
2451 if (!mono_thread_info_resume (thread_get_tid (thread)))
2452 return FALSE;
2454 LOCK_THREAD (thread);
2456 thread->state &= ~ThreadState_Suspended;
2458 return TRUE;
2461 void
2462 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2464 if (!thread->internal_thread) {
2465 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2466 } else {
2467 LOCK_THREAD (thread->internal_thread);
2468 if (!mono_thread_resume (thread->internal_thread))
2469 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2470 UNLOCK_THREAD (thread->internal_thread);
2474 static gboolean
2475 mono_threads_is_critical_method (MonoMethod *method)
2477 switch (method->wrapper_type) {
2478 case MONO_WRAPPER_RUNTIME_INVOKE:
2479 case MONO_WRAPPER_XDOMAIN_INVOKE:
2480 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2481 return TRUE;
2483 return FALSE;
2486 static gboolean
2487 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2489 if (managed)
2490 return TRUE;
2492 if (mono_threads_is_critical_method (m)) {
2493 *((gboolean*)data) = TRUE;
2494 return TRUE;
2496 return FALSE;
2499 static gboolean
2500 is_running_protected_wrapper (void)
2502 gboolean found = FALSE;
2503 mono_stack_walk (find_wrapper, &found);
2504 return found;
2507 static gboolean
2508 request_thread_stop (MonoInternalThread *thread)
2510 LOCK_THREAD (thread);
2512 if ((thread->state & ThreadState_StopRequested) != 0 ||
2513 (thread->state & ThreadState_Stopped) != 0)
2515 UNLOCK_THREAD (thread);
2516 return FALSE;
2519 /* Make sure the thread is awake */
2520 mono_thread_resume (thread);
2522 thread->state |= ThreadState_StopRequested;
2523 thread->state &= ~ThreadState_AbortRequested;
2525 UNLOCK_THREAD (thread);
2526 return TRUE;
2530 * mono_thread_internal_stop:
2532 * Request thread @thread to stop.
2534 * @thread MUST NOT be the current thread.
2536 void
2537 mono_thread_internal_stop (MonoInternalThread *thread)
2539 g_assert (thread != mono_thread_internal_current ());
2541 if (!request_thread_stop (thread))
2542 return;
2544 async_abort_internal (thread, TRUE);
2547 void mono_thread_stop (MonoThread *thread)
2549 MonoInternalThread *internal = thread->internal_thread;
2551 if (!request_thread_stop (internal))
2552 return;
2554 if (internal == mono_thread_internal_current ()) {
2555 MonoError error;
2556 self_abort_internal (&error);
2558 This function is part of the embeding API and has no way to return the exception
2559 to be thrown. So what we do is keep the old behavior and raise the exception.
2561 mono_error_raise_exception (&error); /* OK to throw, see note */
2562 } else {
2563 async_abort_internal (internal, TRUE);
2567 gint8
2568 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2570 gint8 tmp = *(volatile gint8 *)ptr;
2571 mono_memory_barrier ();
2572 return tmp;
2575 gint16
2576 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2578 gint16 tmp = *(volatile gint16 *)ptr;
2579 mono_memory_barrier ();
2580 return tmp;
2583 gint32
2584 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2586 gint32 tmp = *(volatile gint32 *)ptr;
2587 mono_memory_barrier ();
2588 return tmp;
2591 gint64
2592 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2594 gint64 tmp = *(volatile gint64 *)ptr;
2595 mono_memory_barrier ();
2596 return tmp;
2599 void *
2600 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2602 volatile void *tmp = *(volatile void **)ptr;
2603 mono_memory_barrier ();
2604 return (void *) tmp;
2607 void *
2608 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2610 volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2611 mono_memory_barrier ();
2612 return (MonoObject *) tmp;
2615 double
2616 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2618 double tmp = *(volatile double *)ptr;
2619 mono_memory_barrier ();
2620 return tmp;
2623 float
2624 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2626 float tmp = *(volatile float *)ptr;
2627 mono_memory_barrier ();
2628 return tmp;
2631 gint8
2632 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2634 return InterlockedRead8 ((volatile gint8 *)ptr);
2637 gint16
2638 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2640 return InterlockedRead16 ((volatile gint16 *)ptr);
2643 gint32
2644 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2646 return InterlockedRead ((volatile gint32 *)ptr);
2649 gint64
2650 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2652 #if SIZEOF_VOID_P == 4
2653 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2654 gint64 val;
2655 mono_interlocked_lock ();
2656 val = *(gint64*)ptr;
2657 mono_interlocked_unlock ();
2658 return val;
2660 #endif
2661 return InterlockedRead64 ((volatile gint64 *)ptr);
2664 void *
2665 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2667 return InterlockedReadPointer ((volatile gpointer *)ptr);
2670 double
2671 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2673 LongDoubleUnion u;
2675 #if SIZEOF_VOID_P == 4
2676 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2677 double val;
2678 mono_interlocked_lock ();
2679 val = *(double*)ptr;
2680 mono_interlocked_unlock ();
2681 return val;
2683 #endif
2685 u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2687 return u.fval;
2690 float
2691 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2693 IntFloatUnion u;
2695 u.ival = InterlockedRead ((volatile gint32 *)ptr);
2697 return u.fval;
2700 MonoObject*
2701 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2703 return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2706 void
2707 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2709 mono_memory_barrier ();
2710 *(volatile gint8 *)ptr = value;
2713 void
2714 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2716 mono_memory_barrier ();
2717 *(volatile gint16 *)ptr = value;
2720 void
2721 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2723 mono_memory_barrier ();
2724 *(volatile gint32 *)ptr = value;
2727 void
2728 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2730 mono_memory_barrier ();
2731 *(volatile gint64 *)ptr = value;
2734 void
2735 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2737 mono_memory_barrier ();
2738 *(volatile void **)ptr = value;
2741 void
2742 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2744 mono_memory_barrier ();
2745 mono_gc_wbarrier_generic_store (ptr, value);
2748 void
2749 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2751 mono_memory_barrier ();
2752 *(volatile double *)ptr = value;
2755 void
2756 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2758 mono_memory_barrier ();
2759 *(volatile float *)ptr = value;
2762 void
2763 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2765 InterlockedWrite8 ((volatile gint8 *)ptr, value);
2768 void
2769 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2771 InterlockedWrite16 ((volatile gint16 *)ptr, value);
2774 void
2775 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2777 InterlockedWrite ((volatile gint32 *)ptr, value);
2780 void
2781 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2783 #if SIZEOF_VOID_P == 4
2784 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2785 mono_interlocked_lock ();
2786 *(gint64*)ptr = value;
2787 mono_interlocked_unlock ();
2788 return;
2790 #endif
2792 InterlockedWrite64 ((volatile gint64 *)ptr, value);
2795 void
2796 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2798 InterlockedWritePointer ((volatile gpointer *)ptr, value);
2801 void
2802 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2804 LongDoubleUnion u;
2806 #if SIZEOF_VOID_P == 4
2807 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2808 mono_interlocked_lock ();
2809 *(double*)ptr = value;
2810 mono_interlocked_unlock ();
2811 return;
2813 #endif
2815 u.fval = value;
2817 InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2820 void
2821 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2823 IntFloatUnion u;
2825 u.fval = value;
2827 InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2830 void
2831 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2833 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2836 static void
2837 free_context (void *user_data)
2839 ContextStaticData *data = user_data;
2841 mono_threads_lock ();
2844 * There is no guarantee that, by the point this reference queue callback
2845 * has been invoked, the GC handle associated with the object will fail to
2846 * resolve as one might expect. So if we don't free and remove the GC
2847 * handle here, free_context_static_data_helper () could end up resolving
2848 * a GC handle to an actually-dead context which would contain a pointer
2849 * to an already-freed static data segment, resulting in a crash when
2850 * accessing it.
2852 g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2854 mono_threads_unlock ();
2856 mono_gchandle_free (data->gc_handle);
2857 mono_free_static_data (data->static_data);
2858 g_free (data);
2861 void
2862 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2864 mono_threads_lock ();
2866 //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2868 if (!contexts)
2869 contexts = g_hash_table_new (NULL, NULL);
2871 if (!context_queue)
2872 context_queue = mono_gc_reference_queue_new (free_context);
2874 gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2875 g_hash_table_insert (contexts, gch, gch);
2878 * We use this intermediate structure to contain a duplicate pointer to
2879 * the static data because we can't rely on being able to resolve the GC
2880 * handle in the reference queue callback.
2882 ContextStaticData *data = g_new0 (ContextStaticData, 1);
2883 data->gc_handle = GPOINTER_TO_UINT (gch);
2884 ctx->data = data;
2886 context_adjust_static_data (ctx);
2887 mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2889 mono_threads_unlock ();
2891 mono_profiler_context_loaded (ctx);
2894 void
2895 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2898 * NOTE: Since finalizers are unreliable for the purposes of ensuring
2899 * cleanup in exceptional circumstances, we don't actually do any
2900 * cleanup work here. We instead do this via a reference queue.
2903 //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2905 mono_profiler_context_unloaded (ctx);
2908 void
2909 mono_thread_init_tls (void)
2911 MONO_FAST_TLS_INIT (tls_current_object);
2912 mono_native_tls_alloc (&current_object_key, NULL);
2915 void mono_thread_init (MonoThreadStartCB start_cb,
2916 MonoThreadAttachCB attach_cb)
2918 mono_coop_mutex_init_recursive (&threads_mutex);
2920 mono_os_mutex_init_recursive(&interlocked_mutex);
2921 mono_os_mutex_init_recursive(&joinable_threads_mutex);
2923 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2924 g_assert(background_change_event != NULL);
2926 mono_init_static_data_info (&thread_static_info);
2927 mono_init_static_data_info (&context_static_info);
2929 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2931 mono_thread_start_cb = start_cb;
2932 mono_thread_attach_cb = attach_cb;
2934 /* Get a pseudo handle to the current process. This is just a
2935 * kludge so that wapi can build a process handle if needed.
2936 * As a pseudo handle is returned, we don't need to clean
2937 * anything up.
2939 GetCurrentProcess ();
2942 void mono_thread_cleanup (void)
2944 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2945 MonoThreadInfo *info;
2947 /* The main thread must abandon any held mutexes (particularly
2948 * important for named mutexes as they are shared across
2949 * processes, see bug 74680.) This will happen when the
2950 * thread exits, but if it's not running in a subthread it
2951 * won't exit in time.
2953 info = mono_thread_info_current ();
2954 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2955 #endif
2957 #if 0
2958 /* This stuff needs more testing, it seems one of these
2959 * critical sections can be locked when mono_thread_cleanup is
2960 * called.
2962 mono_coop_mutex_destroy (&threads_mutex);
2963 mono_os_mutex_destroy (&interlocked_mutex);
2964 mono_os_mutex_destroy (&delayed_free_table_mutex);
2965 mono_os_mutex_destroy (&small_id_mutex);
2966 CloseHandle (background_change_event);
2967 #endif
2969 mono_native_tls_free (current_object_key);
2972 void
2973 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2975 mono_thread_cleanup_fn = func;
2978 void
2979 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2981 thread->internal_thread->manage_callback = func;
2984 G_GNUC_UNUSED
2985 static void print_tids (gpointer key, gpointer value, gpointer user)
2987 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2988 * sizeof(uint) and a cast to uint would overflow
2990 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2991 * print this as a pointer.
2993 g_message ("Waiting for: %p", key);
2996 struct wait_data
2998 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2999 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
3000 guint32 num;
3003 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
3005 guint32 i, ret;
3007 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3009 MONO_ENTER_GC_SAFE;
3010 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
3011 MONO_EXIT_GC_SAFE;
3013 if(ret==WAIT_FAILED) {
3014 /* See the comment in build_wait_tids() */
3015 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3016 return;
3019 for(i=0; i<wait->num; i++)
3020 CloseHandle (wait->handles[i]);
3022 if (ret == WAIT_TIMEOUT)
3023 return;
3025 for(i=0; i<wait->num; i++) {
3026 gsize tid = wait->threads[i]->tid;
3029 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
3030 * it can still run io-layer etc. code. So wait for it to really exit.
3031 * FIXME: This won't join threads which are not in the joinable_hash yet.
3033 mono_thread_join ((gpointer)tid);
3035 mono_threads_lock ();
3036 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3037 /* This thread must have been killed, because
3038 * it hasn't cleaned itself up. (It's just
3039 * possible that the thread exited before the
3040 * parent thread had a chance to store the
3041 * handle, and now there is another pointer to
3042 * the already-exited thread stored. In this
3043 * case, we'll just get two
3044 * mono_profiler_thread_end() calls for the
3045 * same thread.)
3048 mono_threads_unlock ();
3049 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
3050 thread_cleanup (wait->threads[i]);
3051 } else {
3052 mono_threads_unlock ();
3057 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
3059 guint32 i, ret, count;
3061 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
3063 /* Add the thread state change event, so it wakes up if a thread changes
3064 * to background mode.
3066 count = wait->num;
3067 if (count < MAXIMUM_WAIT_OBJECTS) {
3068 wait->handles [count] = background_change_event;
3069 count++;
3072 MONO_ENTER_GC_SAFE;
3073 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
3074 MONO_EXIT_GC_SAFE;
3076 if(ret==WAIT_FAILED) {
3077 /* See the comment in build_wait_tids() */
3078 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
3079 return;
3082 for(i=0; i<wait->num; i++)
3083 CloseHandle (wait->handles[i]);
3085 if (ret == WAIT_TIMEOUT)
3086 return;
3088 if (ret < wait->num) {
3089 gsize tid = wait->threads[ret]->tid;
3090 mono_threads_lock ();
3091 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3092 /* See comment in wait_for_tids about thread cleanup */
3093 mono_threads_unlock ();
3094 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3095 thread_cleanup (wait->threads [ret]);
3096 } else
3097 mono_threads_unlock ();
3101 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3103 struct wait_data *wait=(struct wait_data *)user;
3105 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
3106 HANDLE handle;
3107 MonoInternalThread *thread=(MonoInternalThread *)value;
3109 /* Ignore background threads, we abort them later */
3110 /* Do not lock here since it is not needed and the caller holds threads_lock */
3111 if (thread->state & ThreadState_Background) {
3112 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3113 return; /* just leave, ignore */
3116 if (mono_gc_is_finalizer_internal_thread (thread)) {
3117 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3118 return;
3121 if (thread == mono_thread_internal_current ()) {
3122 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3123 return;
3126 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3127 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3128 return;
3131 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3132 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3133 return;
3136 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3137 if (handle == NULL) {
3138 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3139 return;
3142 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3143 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3144 wait->handles[wait->num]=handle;
3145 wait->threads[wait->num]=thread;
3146 wait->num++;
3148 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3149 } else {
3150 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3154 } else {
3155 /* Just ignore the rest, we can't do anything with
3156 * them yet
3161 static gboolean
3162 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3164 struct wait_data *wait=(struct wait_data *)user;
3165 MonoNativeThreadId self = mono_native_thread_id_get ();
3166 MonoInternalThread *thread = (MonoInternalThread *)value;
3167 HANDLE handle;
3169 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
3170 return FALSE;
3172 /* The finalizer thread is not a background thread */
3173 if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3174 && (thread->state & ThreadState_Background) != 0
3175 && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3177 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3178 if (handle == NULL)
3179 return FALSE;
3181 wait->handles[wait->num] = handle;
3182 wait->threads[wait->num] = thread;
3183 wait->num++;
3185 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3186 mono_thread_internal_abort (thread);
3187 return TRUE;
3190 return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3191 && !mono_gc_is_finalizer_internal_thread (thread);
3194 /**
3195 * mono_threads_set_shutting_down:
3197 * Is called by a thread that wants to shut down Mono. If the runtime is already
3198 * shutting down, the calling thread is suspended/stopped, and this function never
3199 * returns.
3201 void
3202 mono_threads_set_shutting_down (void)
3204 MonoInternalThread *current_thread = mono_thread_internal_current ();
3206 mono_threads_lock ();
3208 if (shutting_down) {
3209 mono_threads_unlock ();
3211 /* Make sure we're properly suspended/stopped */
3213 LOCK_THREAD (current_thread);
3215 if ((current_thread->state & ThreadState_SuspendRequested) ||
3216 (current_thread->state & ThreadState_AbortRequested) ||
3217 (current_thread->state & ThreadState_StopRequested)) {
3218 UNLOCK_THREAD (current_thread);
3219 mono_thread_execute_interruption ();
3220 } else {
3221 current_thread->state |= ThreadState_Stopped;
3222 UNLOCK_THREAD (current_thread);
3225 /*since we're killing the thread, unset the current domain.*/
3226 mono_domain_unset ();
3228 /* Wake up other threads potentially waiting for us */
3229 mono_thread_info_exit ();
3230 } else {
3231 shutting_down = TRUE;
3233 /* Not really a background state change, but this will
3234 * interrupt the main thread if it is waiting for all
3235 * the other threads.
3237 SetEvent (background_change_event);
3239 mono_threads_unlock ();
3243 void mono_thread_manage (void)
3245 struct wait_data wait_data;
3246 struct wait_data *wait = &wait_data;
3248 memset (wait, 0, sizeof (struct wait_data));
3249 /* join each thread that's still running */
3250 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3252 mono_threads_lock ();
3253 if(threads==NULL) {
3254 THREAD_DEBUG (g_message("%s: No threads", __func__));
3255 mono_threads_unlock ();
3256 return;
3258 mono_threads_unlock ();
3260 do {
3261 mono_threads_lock ();
3262 if (shutting_down) {
3263 /* somebody else is shutting down */
3264 mono_threads_unlock ();
3265 break;
3267 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3268 mono_g_hash_table_foreach (threads, print_tids, NULL));
3270 ResetEvent (background_change_event);
3271 wait->num=0;
3272 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3273 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3274 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3275 mono_threads_unlock ();
3276 if(wait->num>0) {
3277 /* Something to wait for */
3278 wait_for_tids_or_state_change (wait, INFINITE);
3280 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3281 } while(wait->num>0);
3283 /* Mono is shutting down, so just wait for the end */
3284 if (!mono_runtime_try_shutdown ()) {
3285 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3286 mono_thread_suspend (mono_thread_internal_current ());
3287 mono_thread_execute_interruption ();
3291 * Remove everything but the finalizer thread and self.
3292 * Also abort all the background threads
3293 * */
3294 do {
3295 mono_threads_lock ();
3297 wait->num = 0;
3298 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3299 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3300 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3302 mono_threads_unlock ();
3304 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3305 if(wait->num>0) {
3306 /* Something to wait for */
3307 wait_for_tids (wait, INFINITE);
3309 } while (wait->num > 0);
3312 * give the subthreads a chance to really quit (this is mainly needed
3313 * to get correct user and system times from getrusage/wait/time(1)).
3314 * This could be removed if we avoid pthread_detach() and use pthread_join().
3316 mono_thread_info_yield ();
3319 static void
3320 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3322 MonoInternalThread *thread = (MonoInternalThread*)value;
3323 struct wait_data *wait = (struct wait_data*)user_data;
3324 HANDLE handle;
3327 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3328 * limitation.
3329 * This needs no locking.
3331 if ((thread->state & ThreadState_Suspended) != 0 ||
3332 (thread->state & ThreadState_Stopped) != 0)
3333 return;
3335 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3336 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3337 if (handle == NULL)
3338 return;
3340 wait->handles [wait->num] = handle;
3341 wait->threads [wait->num] = thread;
3342 wait->num++;
3347 * mono_thread_suspend_all_other_threads:
3349 * Suspend all managed threads except the finalizer thread and this thread. It is
3350 * not possible to resume them later.
3352 void mono_thread_suspend_all_other_threads (void)
3354 struct wait_data wait_data;
3355 struct wait_data *wait = &wait_data;
3356 int i;
3357 MonoNativeThreadId self = mono_native_thread_id_get ();
3358 guint32 eventidx = 0;
3359 gboolean starting, finished;
3361 memset (wait, 0, sizeof (struct wait_data));
3363 * The other threads could be in an arbitrary state at this point, i.e.
3364 * they could be starting up, shutting down etc. This means that there could be
3365 * threads which are not even in the threads hash table yet.
3369 * First we set a barrier which will be checked by all threads before they
3370 * are added to the threads hash table, and they will exit if the flag is set.
3371 * This ensures that no threads could be added to the hash later.
3372 * We will use shutting_down as the barrier for now.
3374 g_assert (shutting_down);
3377 * We make multiple calls to WaitForMultipleObjects since:
3378 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3379 * - some threads could exit without becoming suspended
3381 finished = FALSE;
3382 while (!finished) {
3384 * Make a copy of the hashtable since we can't do anything with
3385 * threads while threads_mutex is held.
3387 wait->num = 0;
3388 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3389 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3390 mono_threads_lock ();
3391 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3392 mono_threads_unlock ();
3394 eventidx = 0;
3395 /* Get the suspended events that we'll be waiting for */
3396 for (i = 0; i < wait->num; ++i) {
3397 MonoInternalThread *thread = wait->threads [i];
3399 if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3400 || mono_gc_is_finalizer_internal_thread (thread)
3401 || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3403 //CloseHandle (wait->handles [i]);
3404 wait->threads [i] = NULL; /* ignore this thread in next loop */
3405 continue;
3408 LOCK_THREAD (thread);
3410 if ((thread->state & ThreadState_Suspended) != 0 ||
3411 (thread->state & ThreadState_StopRequested) != 0 ||
3412 (thread->state & ThreadState_Stopped) != 0) {
3413 UNLOCK_THREAD (thread);
3414 CloseHandle (wait->handles [i]);
3415 wait->threads [i] = NULL; /* ignore this thread in next loop */
3416 continue;
3419 ++eventidx;
3421 /* Convert abort requests into suspend requests */
3422 if ((thread->state & ThreadState_AbortRequested) != 0)
3423 thread->state &= ~ThreadState_AbortRequested;
3425 thread->state |= ThreadState_SuspendRequested;
3427 /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3428 async_suspend_internal (thread, TRUE);
3430 if (eventidx <= 0) {
3432 * If there are threads which are starting up, we wait until they
3433 * are suspended when they try to register in the threads hash.
3434 * This is guaranteed to finish, since the threads which can create new
3435 * threads get suspended after a while.
3436 * FIXME: The finalizer thread can still create new threads.
3438 mono_threads_lock ();
3439 if (threads_starting_up)
3440 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3441 else
3442 starting = FALSE;
3443 mono_threads_unlock ();
3444 if (starting)
3445 mono_thread_info_sleep (100, NULL);
3446 else
3447 finished = TRUE;
3452 typedef struct {
3453 MonoInternalThread *thread;
3454 MonoStackFrameInfo *frames;
3455 int nframes, max_frames;
3456 int nthreads, max_threads;
3457 MonoInternalThread **threads;
3458 } ThreadDumpUserData;
3460 static gboolean thread_dump_requested;
3462 /* This needs to be async safe */
3463 static gboolean
3464 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3466 ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3468 if (ud->nframes < ud->max_frames) {
3469 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3470 ud->nframes ++;
3473 return FALSE;
3476 /* This needs to be async safe */
3477 static SuspendThreadResult
3478 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3480 ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3481 MonoInternalThread *thread = user_data->thread;
3483 #if 0
3484 /* This no longer works with remote unwinding */
3485 #ifndef HOST_WIN32
3486 wapi_desc = wapi_current_thread_desc ();
3487 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3488 free (wapi_desc);
3489 #endif
3490 #endif
3492 if (thread == mono_thread_internal_current ())
3493 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3494 else
3495 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3497 return MonoResumeThread;
3500 typedef struct {
3501 int nthreads, max_threads;
3502 MonoInternalThread **threads;
3503 } CollectThreadsUserData;
3505 static void
3506 collect_thread (gpointer key, gpointer value, gpointer user)
3508 CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3509 MonoInternalThread *thread = (MonoInternalThread *)value;
3511 if (ud->nthreads < ud->max_threads)
3512 ud->threads [ud->nthreads ++] = thread;
3516 * Collect running threads into the THREADS array.
3517 * THREADS should be an array allocated on the stack.
3519 static int
3520 collect_threads (MonoInternalThread **thread_array, int max_threads)
3522 CollectThreadsUserData ud;
3524 memset (&ud, 0, sizeof (ud));
3525 /* This array contains refs, but its on the stack, so its ok */
3526 ud.threads = thread_array;
3527 ud.max_threads = max_threads;
3529 mono_threads_lock ();
3530 mono_g_hash_table_foreach (threads, collect_thread, &ud);
3531 mono_threads_unlock ();
3533 return ud.nthreads;
3536 static void
3537 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3539 GString* text = g_string_new (0);
3540 char *name;
3541 GError *error = NULL;
3542 int i;
3544 ud->thread = thread;
3545 ud->nframes = 0;
3547 /* Collect frames for the thread */
3548 if (thread == mono_thread_internal_current ()) {
3549 get_thread_dump (mono_thread_info_current (), ud);
3550 } else {
3551 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3555 * Do all the non async-safe work outside of get_thread_dump.
3557 if (thread->name) {
3558 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3559 g_assert (!error);
3560 g_string_append_printf (text, "\n\"%s\"", name);
3561 g_free (name);
3563 else if (thread->threadpool_thread) {
3564 g_string_append (text, "\n\"<threadpool thread>\"");
3565 } else {
3566 g_string_append (text, "\n\"<unnamed thread>\"");
3569 for (i = 0; i < ud->nframes; ++i) {
3570 MonoStackFrameInfo *frame = &ud->frames [i];
3571 MonoMethod *method = NULL;
3573 if (frame->type == FRAME_TYPE_MANAGED)
3574 method = mono_jit_info_get_method (frame->ji);
3576 if (method) {
3577 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3578 g_string_append_printf (text, " %s\n", location);
3579 g_free (location);
3580 } else {
3581 g_string_append_printf (text, " at <unknown> <0x%05x>\n", frame->native_offset);
3585 fprintf (stdout, "%s", text->str);
3587 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3588 OutputDebugStringA(text->str);
3589 #endif
3591 g_string_free (text, TRUE);
3592 fflush (stdout);
3595 void
3596 mono_threads_perform_thread_dump (void)
3598 ThreadDumpUserData ud;
3599 MonoInternalThread *thread_array [128];
3600 int tindex, nthreads;
3602 if (!thread_dump_requested)
3603 return;
3605 printf ("Full thread dump:\n");
3607 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3608 nthreads = collect_threads (thread_array, 128);
3610 memset (&ud, 0, sizeof (ud));
3611 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3612 ud.max_frames = 256;
3614 for (tindex = 0; tindex < nthreads; ++tindex)
3615 dump_thread (thread_array [tindex], &ud);
3617 g_free (ud.frames);
3619 thread_dump_requested = FALSE;
3622 /* Obtain the thread dump of all threads */
3623 static gboolean
3624 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3627 ThreadDumpUserData ud;
3628 MonoInternalThread *thread_array [128];
3629 MonoDomain *domain = mono_domain_get ();
3630 MonoDebugSourceLocation *location;
3631 int tindex, nthreads;
3633 mono_error_init (error);
3635 *out_threads = NULL;
3636 *out_stack_frames = NULL;
3638 /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3639 nthreads = collect_threads (thread_array, 128);
3641 memset (&ud, 0, sizeof (ud));
3642 ud.frames = g_new0 (MonoStackFrameInfo, 256);
3643 ud.max_frames = 256;
3645 *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3646 if (!is_ok (error))
3647 goto leave;
3648 *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3649 if (!is_ok (error))
3650 goto leave;
3652 for (tindex = 0; tindex < nthreads; ++tindex) {
3653 MonoInternalThread *thread = thread_array [tindex];
3654 MonoArray *thread_frames;
3655 int i;
3657 ud.thread = thread;
3658 ud.nframes = 0;
3660 /* Collect frames for the thread */
3661 if (thread == mono_thread_internal_current ()) {
3662 get_thread_dump (mono_thread_info_current (), &ud);
3663 } else {
3664 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3667 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3669 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3670 if (!is_ok (error))
3671 goto leave;
3672 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3674 for (i = 0; i < ud.nframes; ++i) {
3675 MonoStackFrameInfo *frame = &ud.frames [i];
3676 MonoMethod *method = NULL;
3677 MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3678 if (!is_ok (error))
3679 goto leave;
3681 sf->native_offset = frame->native_offset;
3683 if (frame->type == FRAME_TYPE_MANAGED)
3684 method = mono_jit_info_get_method (frame->ji);
3686 if (method) {
3687 sf->method_address = (gsize) frame->ji->code_start;
3689 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3690 if (!is_ok (error))
3691 goto leave;
3692 MONO_OBJECT_SETREF (sf, method, rm);
3694 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3695 if (location) {
3696 sf->il_offset = location->il_offset;
3698 if (location && location->source_file) {
3699 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3700 sf->line = location->row;
3701 sf->column = location->column;
3703 mono_debug_free_source_location (location);
3704 } else {
3705 sf->il_offset = -1;
3708 mono_array_setref (thread_frames, i, sf);
3712 leave:
3713 g_free (ud.frames);
3714 return is_ok (error);
3718 * mono_threads_request_thread_dump:
3720 * Ask all threads except the current to print their stacktrace to stdout.
3722 void
3723 mono_threads_request_thread_dump (void)
3725 /*The new thread dump code runs out of the finalizer thread. */
3726 thread_dump_requested = TRUE;
3727 mono_gc_finalize_notify ();
3730 struct ref_stack {
3731 gpointer *refs;
3732 gint allocated; /* +1 so that refs [allocated] == NULL */
3733 gint bottom;
3736 typedef struct ref_stack RefStack;
3738 static RefStack *
3739 ref_stack_new (gint initial_size)
3741 RefStack *rs;
3743 initial_size = MAX (initial_size, 16) + 1;
3744 rs = g_new0 (RefStack, 1);
3745 rs->refs = g_new0 (gpointer, initial_size);
3746 rs->allocated = initial_size;
3747 return rs;
3750 static void
3751 ref_stack_destroy (gpointer ptr)
3753 RefStack *rs = (RefStack *)ptr;
3755 if (rs != NULL) {
3756 g_free (rs->refs);
3757 g_free (rs);
3761 static void
3762 ref_stack_push (RefStack *rs, gpointer ptr)
3764 g_assert (rs != NULL);
3766 if (rs->bottom >= rs->allocated) {
3767 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3768 rs->allocated <<= 1;
3769 rs->refs [rs->allocated] = NULL;
3771 rs->refs [rs->bottom++] = ptr;
3774 static void
3775 ref_stack_pop (RefStack *rs)
3777 if (rs == NULL || rs->bottom == 0)
3778 return;
3780 rs->bottom--;
3781 rs->refs [rs->bottom] = NULL;
3784 static gboolean
3785 ref_stack_find (RefStack *rs, gpointer ptr)
3787 gpointer *refs;
3789 if (rs == NULL)
3790 return FALSE;
3792 for (refs = rs->refs; refs && *refs; refs++) {
3793 if (*refs == ptr)
3794 return TRUE;
3796 return FALSE;
3800 * mono_thread_push_appdomain_ref:
3802 * Register that the current thread may have references to objects in domain
3803 * @domain on its stack. Each call to this function should be paired with a
3804 * call to pop_appdomain_ref.
3806 void
3807 mono_thread_push_appdomain_ref (MonoDomain *domain)
3809 MonoInternalThread *thread = mono_thread_internal_current ();
3811 if (thread) {
3812 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3813 SPIN_LOCK (thread->lock_thread_id);
3814 if (thread->appdomain_refs == NULL)
3815 thread->appdomain_refs = ref_stack_new (16);
3816 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3817 SPIN_UNLOCK (thread->lock_thread_id);
3821 void
3822 mono_thread_pop_appdomain_ref (void)
3824 MonoInternalThread *thread = mono_thread_internal_current ();
3826 if (thread) {
3827 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3828 SPIN_LOCK (thread->lock_thread_id);
3829 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3830 SPIN_UNLOCK (thread->lock_thread_id);
3834 gboolean
3835 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3837 gboolean res;
3838 SPIN_LOCK (thread->lock_thread_id);
3839 res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3840 SPIN_UNLOCK (thread->lock_thread_id);
3841 return res;
3844 gboolean
3845 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3847 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3850 typedef struct abort_appdomain_data {
3851 struct wait_data wait;
3852 MonoDomain *domain;
3853 } abort_appdomain_data;
3855 static void
3856 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3858 MonoInternalThread *thread = (MonoInternalThread*)value;
3859 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3860 MonoDomain *domain = data->domain;
3862 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3863 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3865 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3866 HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3867 if (handle == NULL)
3868 return;
3869 data->wait.handles [data->wait.num] = handle;
3870 data->wait.threads [data->wait.num] = thread;
3871 data->wait.num++;
3872 } else {
3873 /* Just ignore the rest, we can't do anything with
3874 * them yet
3881 * mono_threads_abort_appdomain_threads:
3883 * Abort threads which has references to the given appdomain.
3885 gboolean
3886 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3888 #ifdef __native_client__
3889 return FALSE;
3890 #endif
3892 abort_appdomain_data user_data;
3893 gint64 start_time;
3894 int orig_timeout = timeout;
3895 int i;
3897 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3899 start_time = mono_msec_ticks ();
3900 do {
3901 mono_threads_lock ();
3903 user_data.domain = domain;
3904 user_data.wait.num = 0;
3905 /* This shouldn't take any locks */
3906 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3907 mono_threads_unlock ();
3909 if (user_data.wait.num > 0) {
3910 /* Abort the threads outside the threads lock */
3911 for (i = 0; i < user_data.wait.num; ++i)
3912 mono_thread_internal_abort (user_data.wait.threads [i]);
3915 * We should wait for the threads either to abort, or to leave the
3916 * domain. We can't do the latter, so we wait with a timeout.
3918 wait_for_tids (&user_data.wait, 100);
3921 /* Update remaining time */
3922 timeout -= mono_msec_ticks () - start_time;
3923 start_time = mono_msec_ticks ();
3925 if (orig_timeout != -1 && timeout < 0)
3926 return FALSE;
3928 while (user_data.wait.num > 0);
3930 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3932 return TRUE;
3935 static void
3936 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3938 MonoInternalThread *thread = (MonoInternalThread*)value;
3939 MonoDomain *domain = (MonoDomain*)user_data;
3940 int i;
3942 /* No locking needed here */
3943 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3945 if (thread->cached_culture_info) {
3946 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3947 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3948 if (obj && obj->vtable->domain == domain)
3949 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3955 * mono_threads_clear_cached_culture:
3957 * Clear the cached_current_culture from all threads if it is in the
3958 * given appdomain.
3960 void
3961 mono_threads_clear_cached_culture (MonoDomain *domain)
3963 mono_threads_lock ();
3964 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3965 mono_threads_unlock ();
3969 * mono_thread_get_undeniable_exception:
3971 * Return an exception which needs to be raised when leaving a catch clause.
3972 * This is used for undeniable exception propagation.
3974 MonoException*
3975 mono_thread_get_undeniable_exception (void)
3977 MonoInternalThread *thread = mono_thread_internal_current ();
3979 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3981 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3982 * exception if the thread no longer references a dying appdomain.
3984 thread->abort_exc->trace_ips = NULL;
3985 thread->abort_exc->stack_trace = NULL;
3986 return thread->abort_exc;
3989 return NULL;
3992 #if MONO_SMALL_CONFIG
3993 #define NUM_STATIC_DATA_IDX 4
3994 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3995 64, 256, 1024, 4096
3997 #else
3998 #define NUM_STATIC_DATA_IDX 8
3999 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
4000 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
4002 #endif
4004 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
4005 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
4007 static void
4008 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
4010 gpointer *static_data = (gpointer *)addr;
4012 for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
4013 void **ptr = (void **)static_data [i];
4015 if (!ptr)
4016 continue;
4018 MONO_BITSET_FOREACH (bitmaps [i], idx, {
4019 void **p = ptr + idx;
4021 if (*p)
4022 mark_func ((MonoObject**)p, gc_data);
4027 static void
4028 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4030 mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
4033 static void
4034 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4036 mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
4040 * mono_alloc_static_data
4042 * Allocate memory blocks for storing threads or context static data
4044 static void
4045 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4047 guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4048 int i;
4050 gpointer* static_data = *static_data_ptr;
4051 if (!static_data) {
4052 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4053 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4055 if (mono_gc_user_markers_supported ()) {
4056 if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4057 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4059 if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4060 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4063 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4064 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4065 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4066 *static_data_ptr = static_data;
4067 static_data [0] = static_data;
4070 for (i = 1; i <= idx; ++i) {
4071 if (static_data [i])
4072 continue;
4074 if (mono_gc_user_markers_supported ())
4075 static_data [i] = g_malloc0 (static_data_size [i]);
4076 else
4077 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4078 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4079 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4083 static void
4084 mono_free_static_data (gpointer* static_data)
4086 int i;
4087 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4088 gpointer p = static_data [i];
4089 if (!p)
4090 continue;
4092 * At this point, the static data pointer array is still registered with the
4093 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4094 * data. Freeing the individual arrays without first nulling their slots
4095 * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4096 * such an already freed array. See bug #13813.
4098 static_data [i] = NULL;
4099 mono_memory_write_barrier ();
4100 if (mono_gc_user_markers_supported ())
4101 g_free (p);
4102 else
4103 mono_gc_free_fixed (p);
4105 mono_gc_free_fixed (static_data);
4109 * mono_init_static_data_info
4111 * Initializes static data counters
4113 static void mono_init_static_data_info (StaticDataInfo *static_data)
4115 static_data->idx = 0;
4116 static_data->offset = 0;
4117 static_data->freelist = NULL;
4121 * mono_alloc_static_data_slot
4123 * Generates an offset for static data. static_data contains the counters
4124 * used to generate it.
4126 static guint32
4127 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4129 if (!static_data->idx && !static_data->offset) {
4131 * we use the first chunk of the first allocation also as
4132 * an array for the rest of the data
4134 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4136 static_data->offset += align - 1;
4137 static_data->offset &= ~(align - 1);
4138 if (static_data->offset + size >= static_data_size [static_data->idx]) {
4139 static_data->idx ++;
4140 g_assert (size <= static_data_size [static_data->idx]);
4141 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4142 static_data->offset = 0;
4144 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4145 static_data->offset += size;
4146 return offset;
4150 * ensure thread static fields already allocated are valid for thread
4151 * This function is called when a thread is created or on thread attach.
4153 static void
4154 thread_adjust_static_data (MonoInternalThread *thread)
4156 mono_threads_lock ();
4157 if (thread_static_info.offset || thread_static_info.idx > 0) {
4158 /* get the current allocated size */
4159 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
4160 mono_alloc_static_data (&thread->static_data, offset, TRUE);
4162 mono_threads_unlock ();
4166 * LOCKING: requires that threads_mutex is held
4168 static void
4169 context_adjust_static_data (MonoAppContext *ctx)
4171 if (context_static_info.offset || context_static_info.idx > 0) {
4172 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4173 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4174 ctx->data->static_data = ctx->static_data;
4179 * LOCKING: requires that threads_mutex is held
4181 static void
4182 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4184 MonoInternalThread *thread = (MonoInternalThread *)value;
4185 guint32 offset = GPOINTER_TO_UINT (user);
4187 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4191 * LOCKING: requires that threads_mutex is held
4193 static void
4194 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4196 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4198 if (!ctx)
4199 return;
4201 guint32 offset = GPOINTER_TO_UINT (user);
4202 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4203 ctx->data->static_data = ctx->static_data;
4206 static StaticDataFreeList*
4207 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4209 StaticDataFreeList* prev = NULL;
4210 StaticDataFreeList* tmp = static_data->freelist;
4211 while (tmp) {
4212 if (tmp->size == size) {
4213 if (prev)
4214 prev->next = tmp->next;
4215 else
4216 static_data->freelist = tmp->next;
4217 return tmp;
4219 prev = tmp;
4220 tmp = tmp->next;
4222 return NULL;
4225 #if SIZEOF_VOID_P == 4
4226 #define ONE_P 1
4227 #else
4228 #define ONE_P 1ll
4229 #endif
4231 static void
4232 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4234 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4235 if (!sets [idx])
4236 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4237 MonoBitSet *rb = sets [idx];
4238 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4239 offset /= sizeof (uintptr_t);
4240 /* offset is now the bitmap offset */
4241 for (int i = 0; i < numbits; ++i) {
4242 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4243 mono_bitset_set_fast (rb, offset + i);
4247 static void
4248 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4250 int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4251 MonoBitSet *rb = sets [idx];
4252 offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4253 offset /= sizeof (uintptr_t);
4254 /* offset is now the bitmap offset */
4255 for (int i = 0; i < size / sizeof (uintptr_t); i++)
4256 mono_bitset_clear_fast (rb, offset + i);
4259 guint32
4260 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4262 g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4264 StaticDataInfo *info;
4265 MonoBitSet **sets;
4267 if (static_type == SPECIAL_STATIC_THREAD) {
4268 info = &thread_static_info;
4269 sets = thread_reference_bitmaps;
4270 } else {
4271 info = &context_static_info;
4272 sets = context_reference_bitmaps;
4275 mono_threads_lock ();
4277 StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4278 guint32 offset;
4280 if (item) {
4281 offset = item->offset;
4282 g_free (item);
4283 } else {
4284 offset = mono_alloc_static_data_slot (info, size, align);
4287 update_reference_bitmap (sets, offset, bitmap, numbits);
4289 if (static_type == SPECIAL_STATIC_THREAD) {
4290 /* This can be called during startup */
4291 if (threads != NULL)
4292 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4293 } else {
4294 if (contexts != NULL)
4295 g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4297 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4300 mono_threads_unlock ();
4302 return offset;
4305 gpointer
4306 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4308 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4310 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4311 return get_thread_static_data (thread, offset);
4312 } else {
4313 return get_context_static_data (thread->current_appcontext, offset);
4317 gpointer
4318 mono_get_special_static_data (guint32 offset)
4320 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4323 typedef struct {
4324 guint32 offset;
4325 guint32 size;
4326 } OffsetSize;
4329 * LOCKING: requires that threads_mutex is held
4331 static void
4332 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4334 MonoInternalThread *thread = (MonoInternalThread *)value;
4335 OffsetSize *data = (OffsetSize *)user;
4336 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4337 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4338 char *ptr;
4340 if (!thread->static_data || !thread->static_data [idx])
4341 return;
4342 ptr = ((char*) thread->static_data [idx]) + off;
4343 mono_gc_bzero_atomic (ptr, data->size);
4347 * LOCKING: requires that threads_mutex is held
4349 static void
4350 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4352 MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4354 if (!ctx)
4355 return;
4357 OffsetSize *data = (OffsetSize *)user;
4358 int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4359 int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4360 char *ptr;
4362 if (!ctx->static_data || !ctx->static_data [idx])
4363 return;
4365 ptr = ((char*) ctx->static_data [idx]) + off;
4366 mono_gc_bzero_atomic (ptr, data->size);
4369 static void
4370 do_free_special_slot (guint32 offset, guint32 size)
4372 guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4373 MonoBitSet **sets;
4374 StaticDataInfo *info;
4376 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4377 info = &thread_static_info;
4378 sets = thread_reference_bitmaps;
4379 } else {
4380 info = &context_static_info;
4381 sets = context_reference_bitmaps;
4384 guint32 data_offset = offset;
4385 ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4386 OffsetSize data = { data_offset, size };
4388 clear_reference_bitmap (sets, data.offset, data.size);
4390 if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4391 if (threads != NULL)
4392 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4393 } else {
4394 if (contexts != NULL)
4395 g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4398 if (!mono_runtime_is_shutting_down ()) {
4399 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4401 item->offset = offset;
4402 item->size = size;
4404 item->next = info->freelist;
4405 info->freelist = item;
4409 static void
4410 do_free_special (gpointer key, gpointer value, gpointer data)
4412 MonoClassField *field = (MonoClassField *)key;
4413 guint32 offset = GPOINTER_TO_UINT (value);
4414 gint32 align;
4415 guint32 size;
4416 size = mono_type_size (field->type, &align);
4417 do_free_special_slot (offset, size);
4420 void
4421 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4423 mono_threads_lock ();
4425 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4427 mono_threads_unlock ();
4430 #ifdef HOST_WIN32
4431 static void CALLBACK dummy_apc (ULONG_PTR param)
4434 #endif
4437 * mono_thread_execute_interruption
4439 * Performs the operation that the requested thread state requires (abort,
4440 * suspend or stop)
4442 static MonoException*
4443 mono_thread_execute_interruption (void)
4445 MonoInternalThread *thread = mono_thread_internal_current ();
4446 MonoThread *sys_thread = mono_thread_current ();
4448 LOCK_THREAD (thread);
4450 /* MonoThread::interruption_requested can only be changed with atomics */
4451 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4452 /* this will consume pending APC calls */
4453 #ifdef HOST_WIN32
4454 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4455 #endif
4456 InterlockedDecrement (&thread_interruption_requested);
4458 /* Clear the interrupted flag of the thread so it can wait again */
4459 mono_thread_info_clear_self_interrupt ();
4462 /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4463 if (sys_thread->pending_exception) {
4464 MonoException *exc;
4466 exc = sys_thread->pending_exception;
4467 sys_thread->pending_exception = NULL;
4469 UNLOCK_THREAD (thread);
4470 return exc;
4471 } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4472 UNLOCK_THREAD (thread);
4473 g_assert (sys_thread->pending_exception == NULL);
4474 if (thread->abort_exc == NULL) {
4476 * This might be racy, but it has to be called outside the lock
4477 * since it calls managed code.
4479 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4481 return thread->abort_exc;
4483 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4484 /* calls UNLOCK_THREAD (thread) */
4485 self_suspend_internal ();
4486 return NULL;
4488 else if ((thread->state & ThreadState_StopRequested) != 0) {
4489 /* FIXME: do this through the JIT? */
4491 UNLOCK_THREAD (thread);
4493 mono_thread_exit ();
4494 return NULL;
4495 } else if (thread->thread_interrupt_requested) {
4497 thread->thread_interrupt_requested = FALSE;
4498 UNLOCK_THREAD (thread);
4500 return(mono_get_exception_thread_interrupted ());
4503 UNLOCK_THREAD (thread);
4505 return NULL;
4509 * mono_thread_request_interruption
4511 * A signal handler can call this method to request the interruption of a
4512 * thread. The result of the interruption will depend on the current state of
4513 * the thread. If the result is an exception that needs to be throw, it is
4514 * provided as return value.
4516 MonoException*
4517 mono_thread_request_interruption (gboolean running_managed)
4519 MonoInternalThread *thread = mono_thread_internal_current ();
4521 /* The thread may already be stopping */
4522 if (thread == NULL)
4523 return NULL;
4525 #ifdef HOST_WIN32
4526 if (thread->interrupt_on_stop &&
4527 thread->state & ThreadState_StopRequested &&
4528 thread->state & ThreadState_Background)
4529 ExitThread (1);
4530 #endif
4532 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4533 return NULL;
4534 InterlockedIncrement (&thread_interruption_requested);
4536 if (!running_managed || is_running_protected_wrapper ()) {
4537 /* Can't stop while in unmanaged code. Increase the global interruption
4538 request count. When exiting the unmanaged method the count will be
4539 checked and the thread will be interrupted. */
4541 /* this will awake the thread if it is in WaitForSingleObject
4542 or similar */
4543 /* Our implementation of this function ignores the func argument */
4544 #ifdef HOST_WIN32
4545 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4546 #else
4547 mono_thread_info_self_interrupt ();
4548 #endif
4549 return NULL;
4551 else {
4552 return mono_thread_execute_interruption ();
4556 /*This function should be called by a thread after it has exited all of
4557 * its handle blocks at interruption time.*/
4558 MonoException*
4559 mono_thread_resume_interruption (void)
4561 MonoInternalThread *thread = mono_thread_internal_current ();
4562 gboolean still_aborting;
4564 /* The thread may already be stopping */
4565 if (thread == NULL)
4566 return NULL;
4568 LOCK_THREAD (thread);
4569 still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4570 UNLOCK_THREAD (thread);
4572 /*This can happen if the protected block called Thread::ResetAbort*/
4573 if (!still_aborting)
4574 return FALSE;
4576 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4577 return NULL;
4578 InterlockedIncrement (&thread_interruption_requested);
4580 mono_thread_info_self_interrupt ();
4582 return mono_thread_execute_interruption ();
4585 gboolean mono_thread_interruption_requested ()
4587 if (thread_interruption_requested) {
4588 MonoInternalThread *thread = mono_thread_internal_current ();
4589 /* The thread may already be stopping */
4590 if (thread != NULL)
4591 return (thread->interruption_requested);
4593 return FALSE;
4596 static MonoException*
4597 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4599 MonoInternalThread *thread = mono_thread_internal_current ();
4601 /* The thread may already be stopping */
4602 if (thread == NULL)
4603 return NULL;
4605 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4606 MonoException* exc = mono_thread_execute_interruption ();
4607 if (exc)
4608 return exc;
4610 return NULL;
4614 * Performs the interruption of the current thread, if one has been requested,
4615 * and the thread is not running a protected wrapper.
4616 * Return the exception which needs to be thrown, if any.
4618 MonoException*
4619 mono_thread_interruption_checkpoint (void)
4621 return mono_thread_interruption_checkpoint_request (FALSE);
4625 * Performs the interruption of the current thread, if one has been requested.
4626 * Return the exception which needs to be thrown, if any.
4628 MonoException*
4629 mono_thread_force_interruption_checkpoint_noraise (void)
4631 return mono_thread_interruption_checkpoint_request (TRUE);
4635 * mono_set_pending_exception:
4637 * Set the pending exception of the current thread to EXC.
4638 * The exception will be thrown when execution returns to managed code.
4640 void
4641 mono_set_pending_exception (MonoException *exc)
4643 MonoThread *thread = mono_thread_current ();
4645 /* The thread may already be stopping */
4646 if (thread == NULL)
4647 return;
4649 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4651 mono_thread_request_interruption (FALSE);
4655 * mono_thread_interruption_request_flag:
4657 * Returns the address of a flag that will be non-zero if an interruption has
4658 * been requested for a thread. The thread to interrupt may not be the current
4659 * thread, so an additional call to mono_thread_interruption_requested() or
4660 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4661 * zero.
4663 gint32* mono_thread_interruption_request_flag ()
4665 return &thread_interruption_requested;
4668 void
4669 mono_thread_init_apartment_state (void)
4671 #ifdef HOST_WIN32
4672 MonoInternalThread* thread = mono_thread_internal_current ();
4674 /* Positive return value indicates success, either
4675 * S_OK if this is first CoInitialize call, or
4676 * S_FALSE if CoInitialize already called, but with same
4677 * threading model. A negative value indicates failure,
4678 * probably due to trying to change the threading model.
4680 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4681 ? COINIT_APARTMENTTHREADED
4682 : COINIT_MULTITHREADED) < 0) {
4683 thread->apartment_state = ThreadApartmentState_Unknown;
4685 #endif
4688 void
4689 mono_thread_cleanup_apartment_state (void)
4691 #ifdef HOST_WIN32
4692 MonoInternalThread* thread = mono_thread_internal_current ();
4694 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4695 CoUninitialize ();
4697 #endif
4700 void
4701 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4703 LOCK_THREAD (thread);
4704 thread->state |= state;
4705 UNLOCK_THREAD (thread);
4708 void
4709 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4711 LOCK_THREAD (thread);
4712 thread->state &= ~state;
4713 UNLOCK_THREAD (thread);
4716 gboolean
4717 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4719 gboolean ret = FALSE;
4721 LOCK_THREAD (thread);
4723 if ((thread->state & test) != 0) {
4724 ret = TRUE;
4727 UNLOCK_THREAD (thread);
4729 return ret;
4732 static gboolean has_tls_get = FALSE;
4734 void
4735 mono_runtime_set_has_tls_get (gboolean val)
4737 has_tls_get = val;
4740 gboolean
4741 mono_runtime_has_tls_get (void)
4743 return has_tls_get;
4746 static void
4747 self_interrupt_thread (void *_unused)
4749 MonoThreadInfo *info = mono_thread_info_current ();
4750 MonoException *exc = mono_thread_execute_interruption ();
4751 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4752 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. */
4753 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4756 static gboolean
4757 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4759 if (!ji)
4760 return FALSE;
4761 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4764 static gboolean
4765 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4767 MonoJitInfo **dest = (MonoJitInfo **)data;
4768 *dest = frame->ji;
4769 return TRUE;
4772 static MonoJitInfo*
4773 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4775 MonoJitInfo *ji = NULL;
4776 if (!info)
4777 return NULL;
4780 * The suspended thread might be holding runtime locks. Make sure we don't try taking
4781 * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4782 * where we hold runtime locks.
4784 if (!mono_threads_is_coop_enabled ())
4785 mono_thread_info_set_is_async_context (TRUE);
4786 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4787 if (!mono_threads_is_coop_enabled ())
4788 mono_thread_info_set_is_async_context (FALSE);
4789 return ji;
4792 typedef struct {
4793 MonoInternalThread *thread;
4794 gboolean install_async_abort;
4795 MonoThreadInfoInterruptToken *interrupt_token;
4796 } AbortThreadData;
4798 static SuspendThreadResult
4799 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4801 AbortThreadData *data = (AbortThreadData *)ud;
4802 MonoInternalThread *thread = data->thread;
4803 MonoJitInfo *ji = NULL;
4804 gboolean protected_wrapper;
4805 gboolean running_managed;
4807 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4808 return MonoResumeThread;
4810 /*someone is already interrupting it*/
4811 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4812 return MonoResumeThread;
4814 InterlockedIncrement (&thread_interruption_requested);
4816 ji = mono_thread_info_get_last_managed (info);
4817 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4818 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4820 if (!protected_wrapper && running_managed) {
4821 /*We are in managed code*/
4822 /*Set the thread to call */
4823 if (data->install_async_abort)
4824 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4825 return MonoResumeThread;
4826 } else {
4828 * This will cause waits to be broken.
4829 * It will also prevent the thread from entering a wait, so if the thread returns
4830 * from the wait before it receives the abort signal, it will just spin in the wait
4831 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4832 * make it return.
4834 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4836 return MonoResumeThread;
4840 static void
4841 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4843 AbortThreadData data;
4845 g_assert (thread != mono_thread_internal_current ());
4847 data.thread = thread;
4848 data.install_async_abort = install_async_abort;
4849 data.interrupt_token = NULL;
4851 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4852 if (data.interrupt_token)
4853 mono_thread_info_finish_interrupt (data.interrupt_token);
4854 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4857 static void
4858 self_abort_internal (MonoError *error)
4860 MonoException *exc;
4862 mono_error_init (error);
4864 /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4865 * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4867 exc = mono_thread_request_interruption (TRUE);
4868 if (exc)
4869 mono_error_set_exception_instance (error, exc);
4870 else
4871 mono_thread_info_self_interrupt ();
4874 typedef struct {
4875 MonoInternalThread *thread;
4876 gboolean interrupt;
4877 MonoThreadInfoInterruptToken *interrupt_token;
4878 } SuspendThreadData;
4880 static SuspendThreadResult
4881 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4883 SuspendThreadData *data = (SuspendThreadData *)ud;
4884 MonoInternalThread *thread = data->thread;
4885 MonoJitInfo *ji = NULL;
4886 gboolean protected_wrapper;
4887 gboolean running_managed;
4889 ji = mono_thread_info_get_last_managed (info);
4890 protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4891 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4893 if (running_managed && !protected_wrapper) {
4894 thread->state &= ~ThreadState_SuspendRequested;
4895 thread->state |= ThreadState_Suspended;
4896 return KeepSuspended;
4897 } else {
4898 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4899 InterlockedIncrement (&thread_interruption_requested);
4900 if (data->interrupt)
4901 data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4903 return MonoResumeThread;
4907 /* LOCKING: called with @thread synch_cs held, and releases it */
4908 static void
4909 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4911 SuspendThreadData data;
4913 g_assert (thread != mono_thread_internal_current ());
4915 data.thread = thread;
4916 data.interrupt = interrupt;
4917 data.interrupt_token = NULL;
4919 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4920 if (data.interrupt_token)
4921 mono_thread_info_finish_interrupt (data.interrupt_token);
4923 UNLOCK_THREAD (thread);
4926 /* LOCKING: called with @thread synch_cs held, and releases it */
4927 static void
4928 self_suspend_internal (void)
4930 MonoInternalThread *thread;
4932 thread = mono_thread_internal_current ();
4934 mono_thread_info_begin_self_suspend ();
4935 thread->state &= ~ThreadState_SuspendRequested;
4936 thread->state |= ThreadState_Suspended;
4938 UNLOCK_THREAD (thread);
4940 mono_thread_info_end_self_suspend ();
4944 * mono_thread_is_foreign:
4945 * @thread: the thread to query
4947 * This function allows one to determine if a thread was created by the mono runtime and has
4948 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4950 * Returns: TRUE if @thread was not created by the runtime.
4952 mono_bool
4953 mono_thread_is_foreign (MonoThread *thread)
4955 MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4956 return info->runtime_thread == FALSE;
4960 * mono_add_joinable_thread:
4962 * Add TID to the list of joinable threads.
4963 * LOCKING: Acquires the threads lock.
4965 void
4966 mono_threads_add_joinable_thread (gpointer tid)
4968 #ifndef HOST_WIN32
4970 * We cannot detach from threads because it causes problems like
4971 * 2fd16f60/r114307. So we collect them and join them when
4972 * we have time (in he finalizer thread).
4974 joinable_threads_lock ();
4975 if (!joinable_threads)
4976 joinable_threads = g_hash_table_new (NULL, NULL);
4977 g_hash_table_insert (joinable_threads, tid, tid);
4978 joinable_thread_count ++;
4979 joinable_threads_unlock ();
4981 mono_gc_finalize_notify ();
4982 #endif
4986 * mono_threads_join_threads:
4988 * Join all joinable threads. This is called from the finalizer thread.
4989 * LOCKING: Acquires the threads lock.
4991 void
4992 mono_threads_join_threads (void)
4994 #ifndef HOST_WIN32
4995 GHashTableIter iter;
4996 gpointer key;
4997 gpointer tid;
4998 pthread_t thread;
4999 gboolean found;
5001 /* Fastpath */
5002 if (!joinable_thread_count)
5003 return;
5005 while (TRUE) {
5006 joinable_threads_lock ();
5007 found = FALSE;
5008 if (g_hash_table_size (joinable_threads)) {
5009 g_hash_table_iter_init (&iter, joinable_threads);
5010 g_hash_table_iter_next (&iter, &key, (void**)&tid);
5011 thread = (pthread_t)tid;
5012 g_hash_table_remove (joinable_threads, key);
5013 joinable_thread_count --;
5014 found = TRUE;
5016 joinable_threads_unlock ();
5017 if (found) {
5018 if (thread != pthread_self ()) {
5019 MONO_ENTER_GC_SAFE;
5020 /* This shouldn't block */
5021 pthread_join (thread, NULL);
5022 MONO_EXIT_GC_SAFE;
5024 } else {
5025 break;
5028 #endif
5032 * mono_thread_join:
5034 * Wait for thread TID to exit.
5035 * LOCKING: Acquires the threads lock.
5037 void
5038 mono_thread_join (gpointer tid)
5040 #ifndef HOST_WIN32
5041 pthread_t thread;
5042 gboolean found = FALSE;
5044 joinable_threads_lock ();
5045 if (!joinable_threads)
5046 joinable_threads = g_hash_table_new (NULL, NULL);
5047 if (g_hash_table_lookup (joinable_threads, tid)) {
5048 g_hash_table_remove (joinable_threads, tid);
5049 joinable_thread_count --;
5050 found = TRUE;
5052 joinable_threads_unlock ();
5053 if (!found)
5054 return;
5055 thread = (pthread_t)tid;
5056 MONO_ENTER_GC_SAFE;
5057 pthread_join (thread, NULL);
5058 MONO_EXIT_GC_SAFE;
5059 #endif
5062 void
5063 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
5065 if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
5066 mono_thread_interruption_checkpoint ();
5069 void
5070 mono_thread_internal_unhandled_exception (MonoObject* exc)
5072 if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5073 MonoClass *klass = exc->vtable->klass;
5074 if (is_threadabort_exception (klass)) {
5075 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5076 } else if (!is_appdomainunloaded_exception (klass)) {
5077 mono_unhandled_exception (exc);
5078 if (mono_environment_exitcode_get () == 1) {
5079 mono_environment_exitcode_set (255);
5080 mono_invoke_unhandled_exception_hook (exc);
5081 g_assert_not_reached ();
5087 void
5088 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5090 MonoError error;
5091 mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5092 mono_error_set_pending_exception (&error);
5096 * mono_threads_attach_coop: called by native->managed wrappers
5098 * In non-coop mode:
5099 * - @dummy: is NULL
5100 * - @return: the original domain which needs to be restored, or NULL.
5102 * In coop mode:
5103 * - @dummy: contains the original domain
5104 * - @return: a cookie containing current MonoThreadInfo*.
5106 gpointer
5107 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5109 MonoDomain *orig;
5110 gboolean fresh_thread = FALSE;
5112 if (!domain) {
5113 /* Happens when called from AOTed code which is only used in the root domain. */
5114 domain = mono_get_root_domain ();
5117 g_assert (domain);
5119 /* On coop, when we detached, we moved the thread from RUNNING->BLOCKING.
5120 * If we try to reattach we do a BLOCKING->RUNNING transition. If the thread
5121 * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5122 * we're only responsible for making the cookie. */
5123 if (mono_threads_is_coop_enabled ()) {
5124 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5125 fresh_thread = !info || !mono_thread_info_is_live (info);
5128 if (!mono_thread_internal_current ()) {
5129 mono_thread_attach_full (domain, FALSE);
5131 // #678164
5132 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5135 orig = mono_domain_get ();
5136 if (orig != domain)
5137 mono_domain_set (domain, TRUE);
5139 if (!mono_threads_is_coop_enabled ())
5140 return orig != domain ? orig : NULL;
5142 if (fresh_thread) {
5143 *dummy = NULL;
5144 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5145 * return the right cookie. */
5146 return mono_threads_enter_gc_unsafe_region_cookie ();
5147 } else {
5148 *dummy = orig;
5149 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5150 return mono_threads_enter_gc_unsafe_region (dummy);
5155 * mono_threads_detach_coop: called by native->managed wrappers
5157 * In non-coop mode:
5158 * - @cookie: the original domain which needs to be restored, or NULL.
5159 * - @dummy: is NULL
5161 * In coop mode:
5162 * - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5163 * - @dummy: contains the original domain
5165 void
5166 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5168 MonoDomain *domain, *orig;
5170 if (!mono_threads_is_coop_enabled ()) {
5171 orig = (MonoDomain*) cookie;
5172 if (orig)
5173 mono_domain_set (orig, TRUE);
5174 } else {
5175 orig = (MonoDomain*) *dummy;
5177 domain = mono_domain_get ();
5178 g_assert (domain);
5180 /* it won't do anything if cookie is NULL
5181 * thread state RUNNING -> (RUNNING|BLOCKING) */
5182 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5184 if (orig != domain) {
5185 if (!orig)
5186 mono_domain_unset ();
5187 else
5188 mono_domain_set (orig, TRUE);