2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
20 #if defined(__OpenBSD__) || defined(__FreeBSD__)
22 #include <pthread_np.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/domain-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/threads.h>
29 #include <mono/metadata/threadpool.h>
30 #include <mono/metadata/threads-types.h>
31 #include <mono/metadata/exception.h>
32 #include <mono/metadata/environment.h>
33 #include <mono/metadata/monitor.h>
34 #include <mono/metadata/gc-internal.h>
35 #include <mono/metadata/marshal.h>
36 #include <mono/io-layer/io-layer.h>
38 #include <mono/io-layer/threads.h>
40 #include <mono/metadata/object-internals.h>
41 #include <mono/metadata/mono-debug-debugger.h>
42 #include <mono/utils/mono-compiler.h>
43 #include <mono/utils/mono-mmap.h>
44 #include <mono/utils/mono-membar.h>
45 #include <mono/utils/mono-time.h>
46 #include <mono/utils/mono-threads.h>
47 #include <mono/utils/hazard-pointer.h>
48 #include <mono/utils/mono-tls.h>
50 #include <mono/metadata/gc-internal.h>
52 #ifdef PLATFORM_ANDROID
55 extern int tkill (pid_t tid, int signal);
58 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
59 void *pthread_get_stackaddr_np(pthread_t);
60 size_t pthread_get_stacksize_np(pthread_t);
63 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
64 #define THREAD_DEBUG(a)
65 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
66 #define THREAD_WAIT_DEBUG(a)
67 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
68 #define LIBGC_DEBUG(a)
70 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
71 #define SPIN_LOCK(i) do { \
72 if (SPIN_TRYLOCK (i)) \
76 #define SPIN_UNLOCK(i) i = 0
78 /* Provide this for systems with glib < 2.6 */
79 #ifndef G_GSIZE_FORMAT
80 # if GLIB_SIZEOF_LONG == 8
81 # define G_GSIZE_FORMAT "lu"
83 # define G_GSIZE_FORMAT "u"
89 guint32 (*func)(void *);
105 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
106 struct _MonoThreadDomainTls {
107 MonoThreadDomainTls *next;
115 MonoThreadDomainTls *freelist;
118 /* Number of cached culture objects in the MonoThread->cached_culture_info array
119 * (per-type): we use the first NUM entries for CultureInfo and the last for
120 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
122 #define NUM_CACHED_CULTURES 4
123 #define CULTURES_START_IDX 0
124 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
126 /* Controls access to the 'threads' hash table */
127 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
128 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
129 static CRITICAL_SECTION threads_mutex;
131 /* Controls access to context static data */
132 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
133 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
134 static CRITICAL_SECTION contexts_mutex;
136 /* Holds current status of static data heap */
137 static StaticDataInfo thread_static_info;
138 static StaticDataInfo context_static_info;
140 /* The hash of existing threads (key is thread ID, value is
141 * MonoInternalThread*) that need joining before exit
143 static MonoGHashTable *threads=NULL;
146 * Threads which are starting up and they are not in the 'threads' hash yet.
147 * When handle_store is called for a thread, it will be removed from this hash table.
148 * Protected by mono_threads_lock ().
150 static MonoGHashTable *threads_starting_up = NULL;
152 /* Maps a MonoThread to its start argument */
153 /* Protected by mono_threads_lock () */
154 static MonoGHashTable *thread_start_args = NULL;
156 /* The TLS key that holds the MonoObject assigned to each thread */
157 static MonoNativeTlsKey current_object_key;
159 #ifdef MONO_HAVE_FAST_TLS
160 /* we need to use both the Tls* functions and __thread because
161 * the gc needs to see all the threads
163 MONO_FAST_TLS_DECLARE(tls_current_object);
164 #define SET_CURRENT_OBJECT(x) do { \
165 MONO_FAST_TLS_SET (tls_current_object, x); \
166 mono_native_tls_set_value (current_object_key, x); \
168 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
170 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
171 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
174 /* function called at thread start */
175 static MonoThreadStartCB mono_thread_start_cb = NULL;
177 /* function called at thread attach */
178 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
180 /* function called at thread cleanup */
181 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
183 /* function called to notify the runtime about a pending exception on the current thread */
184 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
186 /* The default stack size for each thread */
187 static guint32 default_stacksize = 0;
188 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
190 static void thread_adjust_static_data (MonoInternalThread *thread);
191 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
192 static void mono_init_static_data_info (StaticDataInfo *static_data);
193 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
194 static gboolean mono_thread_resume (MonoInternalThread* thread);
195 static void mono_thread_start (MonoThread *thread);
196 static void signal_thread_state_change (MonoInternalThread *thread);
197 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
198 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
199 static void self_suspend_internal (MonoInternalThread *thread);
200 static gboolean resume_thread_internal (MonoInternalThread *thread);
202 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
203 static void ref_stack_destroy (gpointer rs);
205 /* Spin lock for InterlockedXXX 64 bit functions */
206 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
207 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
208 static CRITICAL_SECTION interlocked_mutex;
210 /* global count of thread interruptions requested */
211 static gint32 thread_interruption_requested = 0;
213 /* Event signaled when a thread changes its background mode */
214 static HANDLE background_change_event;
216 static gboolean shutting_down = FALSE;
218 static gint32 managed_thread_id_counter = 0;
221 get_next_managed_thread_id (void)
223 return InterlockedIncrement (&managed_thread_id_counter);
227 mono_thread_get_tls_key (void)
229 return current_object_key;
233 mono_thread_get_tls_offset (void)
236 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
240 /* handle_store() and handle_remove() manage the array of threads that
241 * still need to be waited for when the main thread exits.
243 * If handle_store() returns FALSE the thread must not be started
244 * because Mono is shutting down.
246 static gboolean handle_store(MonoThread *thread)
248 mono_threads_lock ();
250 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
252 if (threads_starting_up)
253 mono_g_hash_table_remove (threads_starting_up, thread);
256 mono_threads_unlock ();
261 MONO_GC_REGISTER_ROOT_FIXED (threads);
262 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
265 /* We don't need to duplicate thread->handle, because it is
266 * only closed when the thread object is finalized by the GC.
268 g_assert (thread->internal_thread);
269 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
270 thread->internal_thread);
272 mono_threads_unlock ();
277 static gboolean handle_remove(MonoInternalThread *thread)
280 gsize tid = thread->tid;
282 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
284 mono_threads_lock ();
287 /* We have to check whether the thread object for the
288 * tid is still the same in the table because the
289 * thread might have been destroyed and the tid reused
290 * in the meantime, in which case the tid would be in
291 * the table, but with another thread object.
293 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
294 mono_g_hash_table_remove (threads, (gpointer)tid);
303 mono_threads_unlock ();
305 /* Don't close the handle here, wait for the object finalizer
306 * to do it. Otherwise, the following race condition applies:
308 * 1) Thread exits (and handle_remove() closes the handle)
310 * 2) Some other handle is reassigned the same slot
312 * 3) Another thread tries to join the first thread, and
313 * blocks waiting for the reassigned handle to be signalled
314 * (which might never happen). This is possible, because the
315 * thread calling Join() still has a reference to the first
321 static void ensure_synch_cs_set (MonoInternalThread *thread)
323 CRITICAL_SECTION *synch_cs;
325 if (thread->synch_cs != NULL) {
329 synch_cs = g_new0 (CRITICAL_SECTION, 1);
330 InitializeCriticalSection (synch_cs);
332 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
333 synch_cs, NULL) != NULL) {
334 /* Another thread must have installed this CS */
335 DeleteCriticalSection (synch_cs);
341 * NOTE: this function can be called also for threads different from the current one:
342 * make sure no code called from it will ever assume it is run on the thread that is
343 * getting cleaned up.
345 static void thread_cleanup (MonoInternalThread *thread)
347 g_assert (thread != NULL);
349 if (thread->abort_state_handle) {
350 mono_gchandle_free (thread->abort_state_handle);
351 thread->abort_state_handle = 0;
353 thread->abort_exc = NULL;
354 thread->current_appcontext = NULL;
357 * This is necessary because otherwise we might have
358 * cross-domain references which will not get cleaned up when
359 * the target domain is unloaded.
361 if (thread->cached_culture_info) {
363 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
364 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
367 ensure_synch_cs_set (thread);
369 EnterCriticalSection (thread->synch_cs);
371 thread->state |= ThreadState_Stopped;
372 thread->state &= ~ThreadState_Background;
374 LeaveCriticalSection (thread->synch_cs);
377 An interruption request has leaked to cleanup. Adjust the global counter.
379 This can happen is the abort source thread finds the abortee (this) thread
380 in unmanaged code. If this thread never trips back to managed code or check
381 the local flag it will be left set and positively unbalance the global counter.
383 Leaving the counter unbalanced will cause a performance degradation since all threads
384 will now keep checking their local flags all the time.
386 if (InterlockedExchange (&thread->interruption_requested, 0))
387 InterlockedDecrement (&thread_interruption_requested);
389 /* if the thread is not in the hash it has been removed already */
390 if (!handle_remove (thread)) {
391 /* This needs to be called even if handle_remove () fails */
392 if (mono_thread_cleanup_fn)
393 mono_thread_cleanup_fn (thread);
396 mono_release_type_locks (thread);
398 mono_profiler_thread_end (thread->tid);
400 if (thread == mono_thread_internal_current ())
401 mono_thread_pop_appdomain_ref ();
403 thread->cached_culture_info = NULL;
405 mono_free_static_data (thread->static_data, TRUE);
406 thread->static_data = NULL;
407 ref_stack_destroy (thread->appdomain_refs);
408 thread->appdomain_refs = NULL;
410 if (mono_thread_cleanup_fn)
411 mono_thread_cleanup_fn (thread);
413 if (mono_gc_is_moving ()) {
414 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
415 thread->thread_pinning_ref = NULL;
421 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
424 g_assert ((offset & 0x80000000) == 0);
425 offset &= 0x7fffffff;
426 idx = (offset >> 24) - 1;
427 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
431 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
433 static MonoClassField *current_thread_field = NULL;
437 if (!current_thread_field) {
438 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
439 g_assert (current_thread_field);
442 mono_class_vtable (domain, mono_defaults.thread_class);
443 mono_domain_lock (domain);
444 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
445 mono_domain_unlock (domain);
448 return get_thread_static_data (thread, offset);
452 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
454 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
456 g_assert (current->obj.vtable->domain == domain);
458 g_assert (!*current_thread_ptr);
459 *current_thread_ptr = current;
462 static MonoInternalThread*
463 create_internal_thread_object (void)
465 MonoVTable *vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
466 return (MonoInternalThread*)mono_gc_alloc_mature (vt);
470 create_thread_object (MonoDomain *domain)
472 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
473 return (MonoThread*)mono_gc_alloc_mature (vt);
477 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
479 MonoThread *thread = create_thread_object (domain);
480 MONO_OBJECT_SETREF (thread, internal_thread, internal);
485 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
487 MonoDomain *domain = mono_get_root_domain ();
489 if (!candidate || candidate->obj.vtable->domain != domain)
490 candidate = new_thread_with_internal (domain, thread);
491 set_current_thread_for_domain (domain, thread, candidate);
492 g_assert (!thread->root_domain_thread);
493 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
496 static guint32 WINAPI start_wrapper_internal(void *data)
498 MonoThreadInfo *info;
499 struct StartInfo *start_info=(struct StartInfo *)data;
500 guint32 (*start_func)(void *);
504 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
507 MonoInternalThread *internal = start_info->obj->internal_thread;
508 MonoObject *start_delegate = start_info->delegate;
509 MonoDomain *domain = start_info->obj->obj.vtable->domain;
511 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
513 /* We can be sure start_info->obj->tid and
514 * start_info->obj->handle have been set, because the thread
515 * was created suspended, and these values were set before the
519 info = mono_thread_info_current ();
521 internal->thread_info = info;
526 SET_CURRENT_OBJECT (internal);
528 mono_monitor_init_tls ();
530 /* Every thread references the appdomain which created it */
531 mono_thread_push_appdomain_ref (domain);
533 if (!mono_domain_set (domain, FALSE)) {
534 /* No point in raising an appdomain_unloaded exception here */
535 /* FIXME: Cleanup here */
536 mono_thread_pop_appdomain_ref ();
540 start_func = start_info->func;
541 start_arg = start_info->start_arg;
543 /* We have to do this here because mono_thread_new_init()
544 requires that root_domain_thread is set up. */
545 thread_adjust_static_data (internal);
546 init_root_domain_thread (internal, start_info->obj);
548 /* This MUST be called before any managed code can be
549 * executed, as it calls the callback function that (for the
550 * jit) sets the lmf marker.
552 mono_thread_new_init (tid, &tid, start_func);
553 internal->stack_ptr = &tid;
555 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
557 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
559 /* On 2.0 profile (and higher), set explicitly since state might have been
561 if (internal->apartment_state == ThreadApartmentState_Unknown)
562 internal->apartment_state = ThreadApartmentState_MTA;
564 mono_thread_init_apartment_state ();
566 if(internal->start_notify!=NULL) {
567 /* Let the thread that called Start() know we're
570 ReleaseSemaphore (internal->start_notify, 1, NULL);
573 mono_threads_lock ();
574 mono_g_hash_table_remove (thread_start_args, start_info->obj);
575 mono_threads_unlock ();
577 mono_thread_set_execution_context (start_info->obj->ec_to_set);
578 start_info->obj->ec_to_set = NULL;
581 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
585 * Call this after calling start_notify, since the profiler callback might want
586 * to lock the thread, and the lock is held by thread_start () which waits for
589 mono_profiler_thread_start (tid);
591 /* start_func is set only for unmanaged start functions */
593 start_func (start_arg);
596 g_assert (start_delegate != NULL);
597 args [0] = start_arg;
598 /* we may want to handle the exception here. See comment below on unhandled exceptions */
599 mono_runtime_delegate_invoke (start_delegate, args, NULL);
602 /* If the thread calls ExitThread at all, this remaining code
603 * will not be executed, but the main thread will eventually
604 * call thread_cleanup() on this thread's behalf.
607 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
609 thread_cleanup (internal);
611 /* Do any cleanup needed for apartment state. This
612 * cannot be done in thread_cleanup since thread_cleanup could be
613 * called for a thread other than the current thread.
614 * mono_thread_cleanup_apartment_state cleans up apartment
615 * for the current thead */
616 mono_thread_cleanup_apartment_state ();
618 /* Remove the reference to the thread object in the TLS data,
619 * so the thread object can be finalized. This won't be
620 * reached if the thread threw an uncaught exception, so those
621 * thread handles will stay referenced :-( (This is due to
622 * missing support for scanning thread-specific data in the
623 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
626 SET_CURRENT_OBJECT (NULL);
627 mono_domain_unset ();
632 static guint32 WINAPI start_wrapper(void *data)
636 /* Avoid scanning the frames above this frame during a GC */
637 mono_gc_set_stack_end ((void*)&dummy);
639 return start_wrapper_internal (data);
642 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
644 if (mono_thread_start_cb) {
645 mono_thread_start_cb (tid, stack_start, func);
649 void mono_threads_set_default_stacksize (guint32 stacksize)
651 default_stacksize = stacksize;
654 guint32 mono_threads_get_default_stacksize (void)
656 return default_stacksize;
660 * mono_create_thread:
662 * This is a wrapper around CreateThread which handles differences in the type of
663 * the the 'tid' argument.
665 gpointer mono_create_thread (WapiSecurityAttributes *security,
666 guint32 stacksize, WapiThreadStart start,
667 gpointer param, guint32 create, gsize *tid)
674 res = mono_threads_CreateThread (security, stacksize, start, param, create, &real_tid);
678 res = CreateThread (security, stacksize, start, param, create, tid);
685 * The thread start argument may be an object reference, and there is
686 * no ref to keep it alive when the new thread is started but not yet
687 * registered with the collector. So we store it in a GC tracked hash
690 * LOCKING: Assumes the threads lock is held.
693 register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info)
695 if (thread_start_args == NULL) {
696 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
697 thread_start_args = mono_g_hash_table_new (NULL, NULL);
699 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
703 * mono_thread_create_internal:
705 * If NO_DETACH is TRUE, then the thread is not detached using pthread_detach (). This is needed to fix the race condition where waiting for a thred to exit only waits for its exit event to be
706 * signalled, which can cause shutdown crashes if the thread shutdown code accesses data already freed by the runtime shutdown.
707 * Currently, this is only used for the finalizer thread.
710 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size)
713 MonoInternalThread *internal;
714 HANDLE thread_handle;
715 struct StartInfo *start_info;
717 guint32 create_flags;
719 thread = create_thread_object (domain);
720 internal = create_internal_thread_object ();
721 MONO_OBJECT_SETREF (thread, internal_thread, internal);
723 start_info=g_new0 (struct StartInfo, 1);
724 start_info->func = func;
725 start_info->obj = thread;
726 start_info->start_arg = arg;
728 mono_threads_lock ();
730 mono_threads_unlock ();
734 if (threads_starting_up == NULL) {
735 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
736 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
739 register_thread_start_argument (thread, start_info);
740 mono_g_hash_table_insert (threads_starting_up, thread, thread);
741 mono_threads_unlock ();
744 stack_size = default_stacksize_for_thread (internal);
746 /* Create suspended, so we can do some housekeeping before the thread
749 create_flags = CREATE_SUSPENDED;
752 create_flags |= CREATE_NO_DETACH;
754 thread_handle = mono_create_thread (NULL, stack_size, (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
756 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
757 if (thread_handle == NULL) {
758 /* The thread couldn't be created, so throw an exception */
759 mono_threads_lock ();
760 mono_g_hash_table_remove (threads_starting_up, thread);
761 mono_threads_unlock ();
763 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
767 internal->handle=thread_handle;
769 internal->apartment_state=ThreadApartmentState_Unknown;
770 internal->managed_id = get_next_managed_thread_id ();
771 if (mono_gc_is_moving ()) {
772 internal->thread_pinning_ref = internal;
773 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
776 internal->synch_cs = g_new0 (CRITICAL_SECTION, 1);
777 InitializeCriticalSection (internal->synch_cs);
779 internal->threadpool_thread = threadpool_thread;
780 if (threadpool_thread)
781 mono_thread_set_state (internal, ThreadState_Background);
783 if (handle_store (thread))
784 ResumeThread (thread_handle);
786 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
787 if (mono_check_corlib_version () == NULL)
788 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
794 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
796 mono_thread_create_internal (domain, func, arg, FALSE, FALSE, 0);
800 * mono_thread_get_stack_bounds:
802 * Return the address and size of the current threads stack. Return NULL as the
803 * stack address if the stack address cannot be determined.
806 mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
808 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
809 *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self ());
810 *stsize = pthread_get_stacksize_np (pthread_self ());
812 /* staddr points to the start of the stack, not the end */
814 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
816 /* FIXME: simplify the mess below */
817 #elif !defined(HOST_WIN32)
819 guint8 *current = (guint8*)&attr;
821 pthread_attr_init (&attr);
822 # ifdef HAVE_PTHREAD_GETATTR_NP
823 pthread_getattr_np (pthread_self(), &attr);
825 # ifdef HAVE_PTHREAD_ATTR_GET_NP
826 pthread_attr_get_np (pthread_self(), &attr);
829 pthread_attr_getstacksize (&attr, &stsize);
830 # elif defined(__OpenBSD__)
834 rslt = pthread_stackseg_np(pthread_self(), &ss);
835 g_assert (rslt == 0);
837 *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
838 *stsize = ss.ss_size;
847 # if !defined(__OpenBSD__)
848 pthread_attr_getstack (&attr, (void**)staddr, stsize);
851 g_assert ((current > *staddr) && (current < *staddr + *stsize));
854 pthread_attr_destroy (&attr);
857 *stsize = (size_t)-1;
860 /* When running under emacs, sometimes staddr is not aligned to a page size */
861 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
865 mono_thread_attach (MonoDomain *domain)
867 MonoInternalThread *thread;
868 MonoThread *current_thread;
869 HANDLE thread_handle;
872 if ((thread = mono_thread_internal_current ())) {
873 if (domain != mono_domain_get ())
874 mono_domain_set (domain, TRUE);
875 /* Already attached */
876 return mono_thread_current ();
879 if (!mono_gc_register_thread (&domain)) {
880 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ());
883 thread = create_internal_thread_object ();
885 thread_handle = GetCurrentThread ();
886 g_assert (thread_handle);
888 tid=GetCurrentThreadId ();
891 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
892 * refer to the thread from other threads for things like aborting.
894 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
895 THREAD_ALL_ACCESS, TRUE, 0);
897 thread->handle=thread_handle;
899 #ifdef PLATFORM_ANDROID
900 thread->android_tid = (gpointer) gettid ();
902 thread->apartment_state=ThreadApartmentState_Unknown;
903 thread->managed_id = get_next_managed_thread_id ();
904 if (mono_gc_is_moving ()) {
905 thread->thread_pinning_ref = thread;
906 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
909 thread->stack_ptr = &tid;
911 thread->synch_cs = g_new0 (CRITICAL_SECTION, 1);
912 InitializeCriticalSection (thread->synch_cs);
914 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
916 current_thread = new_thread_with_internal (domain, thread);
918 if (!handle_store (current_thread)) {
919 /* Mono is shutting down, so just wait for the end */
924 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
926 SET_CURRENT_OBJECT (thread);
927 mono_domain_set (domain, TRUE);
929 mono_monitor_init_tls ();
931 thread_adjust_static_data (thread);
933 init_root_domain_thread (thread, current_thread);
934 if (domain != mono_get_root_domain ())
935 set_current_thread_for_domain (domain, thread, current_thread);
938 if (mono_thread_attach_cb) {
942 mono_thread_get_stack_bounds (&staddr, &stsize);
945 mono_thread_attach_cb (tid, &tid);
947 mono_thread_attach_cb (tid, staddr + stsize);
950 // FIXME: Need a separate callback
951 mono_profiler_thread_start (tid);
953 return current_thread;
957 mono_thread_detach (MonoThread *thread)
959 g_return_if_fail (thread != NULL);
961 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
963 mono_profiler_thread_end (thread->internal_thread->tid);
965 thread_cleanup (thread->internal_thread);
967 SET_CURRENT_OBJECT (NULL);
968 mono_domain_unset ();
970 /* Don't need to CloseHandle this thread, even though we took a
971 * reference in mono_thread_attach (), because the GC will do it
972 * when the Thread object is finalised.
979 MonoInternalThread *thread = mono_thread_internal_current ();
981 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
983 thread_cleanup (thread);
984 SET_CURRENT_OBJECT (NULL);
985 mono_domain_unset ();
987 /* we could add a callback here for embedders to use. */
988 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
989 exit (mono_environment_exitcode_get ());
994 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
996 MonoInternalThread *internal = create_internal_thread_object ();
998 internal->state = ThreadState_Unstarted;
999 internal->apartment_state = ThreadApartmentState_Unknown;
1000 internal->managed_id = get_next_managed_thread_id ();
1002 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1005 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
1008 guint32 (*start_func)(void *);
1009 struct StartInfo *start_info;
1012 MonoInternalThread *internal;
1014 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1016 if (!this->internal_thread)
1017 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1018 internal = this->internal_thread;
1020 ensure_synch_cs_set (internal);
1022 EnterCriticalSection (internal->synch_cs);
1024 if ((internal->state & ThreadState_Unstarted) == 0) {
1025 LeaveCriticalSection (internal->synch_cs);
1026 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1030 if ((internal->state & ThreadState_Aborted) != 0) {
1031 LeaveCriticalSection (internal->synch_cs);
1036 /* This is freed in start_wrapper */
1037 start_info = g_new0 (struct StartInfo, 1);
1038 start_info->func = start_func;
1039 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1040 start_info->delegate = start;
1041 start_info->obj = this;
1042 g_assert (this->obj.vtable->domain == mono_domain_get ());
1044 internal->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
1045 if (internal->start_notify==NULL) {
1046 LeaveCriticalSection (internal->synch_cs);
1047 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
1048 g_free (start_info);
1052 mono_threads_lock ();
1053 register_thread_start_argument (this, start_info);
1054 if (threads_starting_up == NULL) {
1055 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
1056 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
1058 mono_g_hash_table_insert (threads_starting_up, this, this);
1059 mono_threads_unlock ();
1061 thread=mono_create_thread(NULL, default_stacksize_for_thread (internal), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
1062 CREATE_SUSPENDED, &tid);
1064 LeaveCriticalSection (internal->synch_cs);
1065 mono_threads_lock ();
1066 mono_g_hash_table_remove (threads_starting_up, this);
1067 mono_threads_unlock ();
1068 g_warning("%s: CreateThread error 0x%x", __func__, GetLastError());
1072 internal->handle=thread;
1074 if (mono_gc_is_moving ()) {
1075 internal->thread_pinning_ref = internal;
1076 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
1080 /* Don't call handle_store() here, delay it to Start.
1081 * We can't join a thread (trying to will just block
1082 * forever) until it actually starts running, so don't
1083 * store the handle till then.
1086 mono_thread_start (this);
1088 internal->state &= ~ThreadState_Unstarted;
1090 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1092 LeaveCriticalSection (internal->synch_cs);
1097 void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1099 MONO_ARCH_SAVE_REGS;
1101 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1104 CloseHandle (thread);
1106 if (this->synch_cs) {
1107 CRITICAL_SECTION *synch_cs = this->synch_cs;
1108 this->synch_cs = NULL;
1109 DeleteCriticalSection (synch_cs);
1114 void *name = this->name;
1120 static void mono_thread_start (MonoThread *thread)
1122 MonoInternalThread *internal = thread->internal_thread;
1124 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1126 /* Only store the handle when the thread is about to be
1127 * launched, to avoid the main thread deadlocking while trying
1128 * to clean up a thread that will never be signalled.
1130 if (!handle_store (thread))
1133 ResumeThread (internal->handle);
1135 if(internal->start_notify!=NULL) {
1136 /* Wait for the thread to set up its TLS data etc, so
1137 * theres no potential race condition if someone tries
1138 * to look up the data believing the thread has
1142 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1144 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
1145 CloseHandle (internal->start_notify);
1146 internal->start_notify = NULL;
1149 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1152 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1155 MonoInternalThread *thread = mono_thread_internal_current ();
1157 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1159 mono_thread_current_check_pending_interrupt ();
1162 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1164 res = SleepEx(ms,TRUE);
1166 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1168 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1169 MonoException* exc = mono_thread_execute_interruption (thread);
1171 mono_raise_exception (exc);
1183 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1188 ves_icall_System_Threading_Thread_GetDomainID (void)
1190 MONO_ARCH_SAVE_REGS;
1192 return mono_domain_get()->domain_id;
1196 ves_icall_System_Threading_Thread_Yield (void)
1199 return SwitchToThread ();
1201 return sched_yield () == 0;
1206 * mono_thread_get_name:
1208 * Return the name of the thread. NAME_LEN is set to the length of the name.
1209 * Return NULL if the thread has no name. The returned memory is owned by the
1213 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1217 ensure_synch_cs_set (this_obj);
1219 EnterCriticalSection (this_obj->synch_cs);
1221 if (!this_obj->name) {
1225 *name_len = this_obj->name_len;
1226 res = g_new (gunichar2, this_obj->name_len);
1227 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1230 LeaveCriticalSection (this_obj->synch_cs);
1236 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1240 ensure_synch_cs_set (this_obj);
1242 EnterCriticalSection (this_obj->synch_cs);
1244 if (!this_obj->name)
1247 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1249 LeaveCriticalSection (this_obj->synch_cs);
1255 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1257 ensure_synch_cs_set (this_obj);
1259 EnterCriticalSection (this_obj->synch_cs);
1261 if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1262 LeaveCriticalSection (this_obj->synch_cs);
1264 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1268 this_obj->name = g_new (gunichar2, mono_string_length (name));
1269 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1270 this_obj->name_len = mono_string_length (name);
1273 this_obj->name = NULL;
1276 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1278 LeaveCriticalSection (this_obj->synch_cs);
1279 if (this_obj->name) {
1280 char *tname = mono_string_to_utf8 (name);
1281 mono_profiler_thread_name (this_obj->tid, tname);
1287 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1289 mono_thread_set_name_internal (this_obj, name, TRUE);
1292 /* If the array is already in the requested domain, we just return it,
1293 otherwise we return a copy in that domain. */
1295 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1302 if (mono_object_domain (arr) == domain)
1305 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1306 mono_gc_memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1311 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1313 return byte_array_to_domain (arr, mono_get_root_domain ());
1317 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1319 return byte_array_to_domain (arr, mono_domain_get ());
1323 mono_thread_current (void)
1325 MonoDomain *domain = mono_domain_get ();
1326 MonoInternalThread *internal = mono_thread_internal_current ();
1327 MonoThread **current_thread_ptr;
1329 g_assert (internal);
1330 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1332 if (!*current_thread_ptr) {
1333 g_assert (domain != mono_get_root_domain ());
1334 *current_thread_ptr = new_thread_with_internal (domain, internal);
1336 return *current_thread_ptr;
1340 mono_thread_internal_current (void)
1342 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1343 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1347 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1348 int ms, HANDLE thread)
1350 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1353 mono_thread_current_check_pending_interrupt ();
1355 ensure_synch_cs_set (this);
1357 EnterCriticalSection (this->synch_cs);
1359 if ((this->state & ThreadState_Unstarted) != 0) {
1360 LeaveCriticalSection (this->synch_cs);
1362 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1366 LeaveCriticalSection (this->synch_cs);
1371 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1373 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1375 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1377 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1379 if(ret==WAIT_OBJECT_0) {
1380 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1385 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1391 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1399 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1402 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1404 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1406 if (ret != WAIT_IO_COMPLETION)
1409 exc = mono_thread_execute_interruption (thread);
1411 mono_raise_exception (exc);
1416 /* Re-calculate ms according to the time passed */
1417 diff_ms = (mono_100ns_ticks () - start) / 10000;
1418 if (diff_ms >= ms) {
1422 wait = ms - diff_ms;
1428 /* FIXME: exitContext isnt documented */
1429 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1435 MonoObject *waitHandle;
1436 MonoInternalThread *thread = mono_thread_internal_current ();
1438 /* Do this WaitSleepJoin check before creating objects */
1439 mono_thread_current_check_pending_interrupt ();
1441 numhandles = mono_array_length(mono_handles);
1442 handles = g_new0(HANDLE, numhandles);
1444 for(i = 0; i < numhandles; i++) {
1445 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1446 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1453 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1455 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1457 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1461 if(ret==WAIT_FAILED) {
1462 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1464 } else if(ret==WAIT_TIMEOUT) {
1465 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1472 /* FIXME: exitContext isnt documented */
1473 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1475 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1479 MonoObject *waitHandle;
1480 MonoInternalThread *thread = mono_thread_internal_current ();
1482 /* Do this WaitSleepJoin check before creating objects */
1483 mono_thread_current_check_pending_interrupt ();
1485 numhandles = mono_array_length(mono_handles);
1486 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1489 for(i = 0; i < numhandles; i++) {
1490 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1491 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1498 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1500 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1502 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1504 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1507 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1509 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1510 return ret - WAIT_OBJECT_0;
1512 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1513 return ret - WAIT_ABANDONED_0;
1520 /* FIXME: exitContext isnt documented */
1521 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1524 MonoInternalThread *thread = mono_thread_internal_current ();
1526 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1532 mono_thread_current_check_pending_interrupt ();
1534 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1536 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1538 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1540 if(ret==WAIT_FAILED) {
1541 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1543 } else if(ret==WAIT_TIMEOUT) {
1544 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1552 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1555 MonoInternalThread *thread = mono_thread_internal_current ();
1557 MONO_ARCH_SAVE_REGS;
1562 mono_thread_current_check_pending_interrupt ();
1564 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1566 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1568 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1570 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1573 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1577 MONO_ARCH_SAVE_REGS;
1582 mutex = CreateMutex (NULL, owned, NULL);
1584 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1586 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1594 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1595 MONO_ARCH_SAVE_REGS;
1597 return(ReleaseMutex (handle));
1600 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1606 MONO_ARCH_SAVE_REGS;
1608 *error = ERROR_SUCCESS;
1610 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1612 *error = GetLastError ();
1619 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1623 MONO_ARCH_SAVE_REGS;
1628 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1630 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1631 mono_string_chars (name));
1633 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1641 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1645 MONO_ARCH_SAVE_REGS;
1647 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1652 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1656 MONO_ARCH_SAVE_REGS;
1658 *error = ERROR_SUCCESS;
1660 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1662 *error = GetLastError ();
1668 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1672 MONO_ARCH_SAVE_REGS;
1677 event = CreateEvent (NULL, manual, initial, NULL);
1679 event = CreateEvent (NULL, manual, initial,
1680 mono_string_chars (name));
1682 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1690 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1691 MONO_ARCH_SAVE_REGS;
1693 return (SetEvent(handle));
1696 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1697 MONO_ARCH_SAVE_REGS;
1699 return (ResetEvent(handle));
1703 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1704 MONO_ARCH_SAVE_REGS;
1706 CloseHandle (handle);
1709 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1715 MONO_ARCH_SAVE_REGS;
1717 *error = ERROR_SUCCESS;
1719 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1721 *error = GetLastError ();
1727 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1729 MONO_ARCH_SAVE_REGS;
1731 return InterlockedIncrement (location);
1734 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1738 MONO_ARCH_SAVE_REGS;
1740 mono_interlocked_lock ();
1744 mono_interlocked_unlock ();
1750 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1752 MONO_ARCH_SAVE_REGS;
1754 return InterlockedDecrement(location);
1757 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1761 MONO_ARCH_SAVE_REGS;
1763 mono_interlocked_lock ();
1767 mono_interlocked_unlock ();
1772 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1774 MONO_ARCH_SAVE_REGS;
1776 return InterlockedExchange(location, value);
1779 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1782 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1783 mono_gc_wbarrier_generic_nostore (location);
1787 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1789 return InterlockedExchangePointer(location, value);
1792 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1794 IntFloatUnion val, ret;
1796 MONO_ARCH_SAVE_REGS;
1799 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1805 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1807 #if SIZEOF_VOID_P == 8
1808 return (gint64) InterlockedExchangePointer((gpointer *) location, (gpointer)value);
1813 * According to MSDN, this function is only atomic with regards to the
1814 * other Interlocked functions on 32 bit platforms.
1816 mono_interlocked_lock ();
1819 mono_interlocked_unlock ();
1826 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1828 #if SIZEOF_VOID_P == 8
1829 LongDoubleUnion val, ret;
1832 ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location, (gpointer)val.ival);
1839 * According to MSDN, this function is only atomic with regards to the
1840 * other Interlocked functions on 32 bit platforms.
1842 mono_interlocked_lock ();
1845 mono_interlocked_unlock ();
1851 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1853 MONO_ARCH_SAVE_REGS;
1855 return InterlockedCompareExchange(location, value, comparand);
1858 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1861 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1862 mono_gc_wbarrier_generic_nostore (location);
1866 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1868 return InterlockedCompareExchangePointer(location, value, comparand);
1871 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1873 IntFloatUnion val, ret, cmp;
1875 MONO_ARCH_SAVE_REGS;
1878 cmp.fval = comparand;
1879 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1885 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1887 #if SIZEOF_VOID_P == 8
1888 LongDoubleUnion val, comp, ret;
1891 comp.fval = comparand;
1892 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1898 mono_interlocked_lock ();
1900 if (old == comparand)
1902 mono_interlocked_unlock ();
1909 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1911 #if SIZEOF_VOID_P == 8
1912 return (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)value, (gpointer)comparand);
1916 mono_interlocked_lock ();
1918 if (old == comparand)
1920 mono_interlocked_unlock ();
1927 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1930 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1931 mono_gc_wbarrier_generic_nostore (location);
1936 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1939 res = InterlockedExchangePointer ((gpointer *)location, value);
1940 mono_gc_wbarrier_generic_nostore (location);
1945 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1947 #if SIZEOF_VOID_P == 8
1948 /* Should be implemented as a JIT intrinsic */
1949 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1954 mono_interlocked_lock ();
1956 *location = orig + value;
1957 mono_interlocked_unlock ();
1959 return orig + value;
1964 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1966 #if SIZEOF_VOID_P == 8
1967 /* Should be implemented as a JIT intrinsic */
1968 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1973 mono_interlocked_lock ();
1975 *location = orig + value;
1976 mono_interlocked_unlock ();
1978 return orig + value;
1983 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1985 #if SIZEOF_VOID_P == 8
1986 /* 64 bit reads are already atomic */
1991 mono_interlocked_lock ();
1993 mono_interlocked_unlock ();
2000 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2002 mono_threads_lock ();
2003 mono_threads_unlock ();
2007 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
2009 mono_thread_clr_state (this, state);
2011 if (state & ThreadState_Background) {
2012 /* If the thread changes the background mode, the main thread has to
2013 * be notified, since it has to rebuild the list of threads to
2016 SetEvent (background_change_event);
2021 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
2023 mono_thread_set_state (this, state);
2025 if (state & ThreadState_Background) {
2026 /* If the thread changes the background mode, the main thread has to
2027 * be notified, since it has to rebuild the list of threads to
2030 SetEvent (background_change_event);
2035 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2039 ensure_synch_cs_set (this);
2041 EnterCriticalSection (this->synch_cs);
2043 state = this->state;
2045 LeaveCriticalSection (this->synch_cs);
2050 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
2052 MonoInternalThread *current;
2055 ensure_synch_cs_set (this);
2057 current = mono_thread_internal_current ();
2059 EnterCriticalSection (this->synch_cs);
2061 this->thread_interrupt_requested = TRUE;
2062 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
2064 LeaveCriticalSection (this->synch_cs);
2067 abort_thread_internal (this, TRUE, FALSE);
2071 void mono_thread_current_check_pending_interrupt ()
2073 MonoInternalThread *thread = mono_thread_internal_current ();
2074 gboolean throw = FALSE;
2076 mono_debugger_check_interruption ();
2078 ensure_synch_cs_set (thread);
2080 EnterCriticalSection (thread->synch_cs);
2082 if (thread->thread_interrupt_requested) {
2084 thread->thread_interrupt_requested = FALSE;
2087 LeaveCriticalSection (thread->synch_cs);
2090 mono_raise_exception (mono_get_exception_thread_interrupted ());
2095 mono_thread_get_abort_signal (void)
2099 #elif defined(PLATFORM_ANDROID)
2101 #elif !defined (SIGRTMIN)
2106 #endif /* SIGUSR1 */
2108 static int abort_signum = -1;
2110 if (abort_signum != -1)
2111 return abort_signum;
2112 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2113 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2114 struct sigaction sinfo;
2115 sigaction (i, NULL, &sinfo);
2116 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2121 /* fallback to the old way */
2123 #endif /* HOST_WIN32 */
2127 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2129 MonoException* exc = mono_thread_request_interruption (FALSE);
2130 if (exc) mono_raise_exception (exc);
2132 #endif /* HOST_WIN32 */
2135 * signal_thread_state_change
2137 * Tells the thread that his state has changed and it has to enter the new
2138 * state as soon as possible.
2140 static void signal_thread_state_change (MonoInternalThread *thread)
2142 if (thread == mono_thread_internal_current ()) {
2143 /* Do it synchronously */
2144 MonoException *exc = mono_thread_request_interruption (FALSE);
2146 mono_raise_exception (exc);
2150 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
2152 /* fixme: store the state somewhere */
2153 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2156 * This will cause waits to be broken.
2157 * It will also prevent the thread from entering a wait, so if the thread returns
2158 * from the wait before it receives the abort signal, it will just spin in the wait
2159 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2162 wapi_interrupt_thread (thread->handle);
2163 #endif /* HOST_WIN32 */
2167 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2169 ensure_synch_cs_set (thread);
2171 EnterCriticalSection (thread->synch_cs);
2173 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2174 (thread->state & ThreadState_StopRequested) != 0 ||
2175 (thread->state & ThreadState_Stopped) != 0)
2177 LeaveCriticalSection (thread->synch_cs);
2181 if ((thread->state & ThreadState_Unstarted) != 0) {
2182 thread->state |= ThreadState_Aborted;
2183 LeaveCriticalSection (thread->synch_cs);
2187 thread->state |= ThreadState_AbortRequested;
2188 if (thread->abort_state_handle)
2189 mono_gchandle_free (thread->abort_state_handle);
2191 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2192 g_assert (thread->abort_state_handle);
2194 thread->abort_state_handle = 0;
2196 thread->abort_exc = NULL;
2199 * abort_exc is set in mono_thread_execute_interruption(),
2200 * triggered by the call to signal_thread_state_change(),
2201 * below. There's a point between where we have
2202 * abort_state_handle set, but abort_exc NULL, but that's not
2206 LeaveCriticalSection (thread->synch_cs);
2208 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2210 /* During shutdown, we can't wait for other threads */
2212 /* Make sure the thread is awake */
2213 mono_thread_resume (thread);
2215 abort_thread_internal (thread, TRUE, TRUE);
2219 ves_icall_System_Threading_Thread_ResetAbort (void)
2221 MonoInternalThread *thread = mono_thread_internal_current ();
2222 gboolean was_aborting;
2224 ensure_synch_cs_set (thread);
2226 EnterCriticalSection (thread->synch_cs);
2227 was_aborting = thread->state & ThreadState_AbortRequested;
2228 thread->state &= ~ThreadState_AbortRequested;
2229 LeaveCriticalSection (thread->synch_cs);
2231 if (!was_aborting) {
2232 const char *msg = "Unable to reset abort because no abort was requested";
2233 mono_raise_exception (mono_get_exception_thread_state (msg));
2235 thread->abort_exc = NULL;
2236 if (thread->abort_state_handle) {
2237 mono_gchandle_free (thread->abort_state_handle);
2238 /* This is actually not necessary - the handle
2239 only counts if the exception is set */
2240 thread->abort_state_handle = 0;
2245 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2247 ensure_synch_cs_set (thread);
2249 EnterCriticalSection (thread->synch_cs);
2251 thread->state &= ~ThreadState_AbortRequested;
2253 if (thread->abort_exc) {
2254 thread->abort_exc = NULL;
2255 if (thread->abort_state_handle) {
2256 mono_gchandle_free (thread->abort_state_handle);
2257 /* This is actually not necessary - the handle
2258 only counts if the exception is set */
2259 thread->abort_state_handle = 0;
2263 LeaveCriticalSection (thread->synch_cs);
2267 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2269 MonoInternalThread *thread = this->internal_thread;
2270 MonoObject *state, *deserialized = NULL, *exc;
2273 if (!thread->abort_state_handle)
2276 state = mono_gchandle_get_target (thread->abort_state_handle);
2279 domain = mono_domain_get ();
2280 if (mono_object_domain (state) == domain)
2283 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2285 if (!deserialized) {
2286 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2288 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2289 mono_raise_exception (invalid_op_exc);
2292 return deserialized;
2296 mono_thread_suspend (MonoInternalThread *thread)
2298 ensure_synch_cs_set (thread);
2300 EnterCriticalSection (thread->synch_cs);
2302 if ((thread->state & ThreadState_Unstarted) != 0 ||
2303 (thread->state & ThreadState_Aborted) != 0 ||
2304 (thread->state & ThreadState_Stopped) != 0)
2306 LeaveCriticalSection (thread->synch_cs);
2310 if ((thread->state & ThreadState_Suspended) != 0 ||
2311 (thread->state & ThreadState_SuspendRequested) != 0 ||
2312 (thread->state & ThreadState_StopRequested) != 0)
2314 LeaveCriticalSection (thread->synch_cs);
2318 thread->state |= ThreadState_SuspendRequested;
2320 LeaveCriticalSection (thread->synch_cs);
2322 suspend_thread_internal (thread, FALSE);
2327 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2329 if (!mono_thread_suspend (thread))
2330 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2334 mono_thread_resume (MonoInternalThread *thread)
2336 ensure_synch_cs_set (thread);
2338 EnterCriticalSection (thread->synch_cs);
2340 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2341 thread->state &= ~ThreadState_SuspendRequested;
2342 LeaveCriticalSection (thread->synch_cs);
2346 if ((thread->state & ThreadState_Suspended) == 0 ||
2347 (thread->state & ThreadState_Unstarted) != 0 ||
2348 (thread->state & ThreadState_Aborted) != 0 ||
2349 (thread->state & ThreadState_Stopped) != 0)
2351 LeaveCriticalSection (thread->synch_cs);
2355 return resume_thread_internal (thread);
2359 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2361 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2362 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2366 mono_threads_is_critical_method (MonoMethod *method)
2368 switch (method->wrapper_type) {
2369 case MONO_WRAPPER_RUNTIME_INVOKE:
2370 case MONO_WRAPPER_XDOMAIN_INVOKE:
2371 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2378 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2383 if (mono_threads_is_critical_method (m)) {
2384 *((gboolean*)data) = TRUE;
2391 is_running_protected_wrapper (void)
2393 gboolean found = FALSE;
2394 mono_stack_walk (find_wrapper, &found);
2398 void mono_thread_internal_stop (MonoInternalThread *thread)
2400 ensure_synch_cs_set (thread);
2402 EnterCriticalSection (thread->synch_cs);
2404 if ((thread->state & ThreadState_StopRequested) != 0 ||
2405 (thread->state & ThreadState_Stopped) != 0)
2407 LeaveCriticalSection (thread->synch_cs);
2411 /* Make sure the thread is awake */
2412 mono_thread_resume (thread);
2414 thread->state |= ThreadState_StopRequested;
2415 thread->state &= ~ThreadState_AbortRequested;
2417 LeaveCriticalSection (thread->synch_cs);
2419 abort_thread_internal (thread, TRUE, TRUE);
2422 void mono_thread_stop (MonoThread *thread)
2424 mono_thread_internal_stop (thread->internal_thread);
2428 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2430 return *((volatile gint8 *) (ptr));
2434 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2436 return *((volatile gint16 *) (ptr));
2440 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2442 return *((volatile gint32 *) (ptr));
2446 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2448 return *((volatile gint64 *) (ptr));
2452 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2454 return (void *) *((volatile void **) ptr);
2458 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2460 return *((volatile double *) (ptr));
2464 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2466 return *((volatile float *) (ptr));
2470 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2472 return (MonoObject*)*((volatile MonoObject**)ptr);
2476 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2478 *((volatile gint8 *) ptr) = value;
2482 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2484 *((volatile gint16 *) ptr) = value;
2488 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2490 *((volatile gint32 *) ptr) = value;
2494 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2496 *((volatile gint64 *) ptr) = value;
2500 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2502 *((volatile void **) ptr) = value;
2506 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, void *value)
2508 mono_gc_wbarrier_generic_store (ptr, value);
2512 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2514 *((volatile double *) ptr) = value;
2518 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2520 *((volatile float *) ptr) = value;
2524 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2526 *((volatile MonoObject **) ptr) = value;
2527 mono_gc_wbarrier_generic_nostore (ptr);
2530 void mono_thread_init (MonoThreadStartCB start_cb,
2531 MonoThreadAttachCB attach_cb)
2533 InitializeCriticalSection(&threads_mutex);
2534 InitializeCriticalSection(&interlocked_mutex);
2535 InitializeCriticalSection(&contexts_mutex);
2537 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2538 g_assert(background_change_event != NULL);
2540 mono_init_static_data_info (&thread_static_info);
2541 mono_init_static_data_info (&context_static_info);
2543 MONO_FAST_TLS_INIT (tls_current_object);
2544 mono_native_tls_alloc (¤t_object_key, NULL);
2545 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2547 mono_thread_start_cb = start_cb;
2548 mono_thread_attach_cb = attach_cb;
2550 /* Get a pseudo handle to the current process. This is just a
2551 * kludge so that wapi can build a process handle if needed.
2552 * As a pseudo handle is returned, we don't need to clean
2555 GetCurrentProcess ();
2558 void mono_thread_cleanup (void)
2560 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2561 /* The main thread must abandon any held mutexes (particularly
2562 * important for named mutexes as they are shared across
2563 * processes, see bug 74680.) This will happen when the
2564 * thread exits, but if it's not running in a subthread it
2565 * won't exit in time.
2567 /* Using non-w32 API is a nasty kludge, but I couldn't find
2568 * anything in the documentation that would let me do this
2569 * here yet still be safe to call on windows.
2571 _wapi_thread_signal_self (mono_environment_exitcode_get ());
2575 /* This stuff needs more testing, it seems one of these
2576 * critical sections can be locked when mono_thread_cleanup is
2579 DeleteCriticalSection (&threads_mutex);
2580 DeleteCriticalSection (&interlocked_mutex);
2581 DeleteCriticalSection (&contexts_mutex);
2582 DeleteCriticalSection (&delayed_free_table_mutex);
2583 DeleteCriticalSection (&small_id_mutex);
2584 CloseHandle (background_change_event);
2587 mono_native_tls_free (current_object_key);
2591 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2593 mono_thread_cleanup_fn = func;
2597 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2599 thread->internal_thread->manage_callback = func;
2602 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2604 mono_thread_notify_pending_exc_fn = func;
2608 static void print_tids (gpointer key, gpointer value, gpointer user)
2610 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2611 * sizeof(uint) and a cast to uint would overflow
2613 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2614 * print this as a pointer.
2616 g_message ("Waiting for: %p", key);
2621 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2622 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2626 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2630 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2632 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2634 if(ret==WAIT_FAILED) {
2635 /* See the comment in build_wait_tids() */
2636 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2640 for(i=0; i<wait->num; i++)
2641 CloseHandle (wait->handles[i]);
2643 if (ret == WAIT_TIMEOUT)
2646 for(i=0; i<wait->num; i++) {
2647 gsize tid = wait->threads[i]->tid;
2649 mono_threads_lock ();
2650 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2651 /* This thread must have been killed, because
2652 * it hasn't cleaned itself up. (It's just
2653 * possible that the thread exited before the
2654 * parent thread had a chance to store the
2655 * handle, and now there is another pointer to
2656 * the already-exited thread stored. In this
2657 * case, we'll just get two
2658 * mono_profiler_thread_end() calls for the
2662 mono_threads_unlock ();
2663 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2664 thread_cleanup (wait->threads[i]);
2666 mono_threads_unlock ();
2671 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2673 guint32 i, ret, count;
2675 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2677 /* Add the thread state change event, so it wakes up if a thread changes
2678 * to background mode.
2681 if (count < MAXIMUM_WAIT_OBJECTS) {
2682 wait->handles [count] = background_change_event;
2686 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2688 if(ret==WAIT_FAILED) {
2689 /* See the comment in build_wait_tids() */
2690 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2694 for(i=0; i<wait->num; i++)
2695 CloseHandle (wait->handles[i]);
2697 if (ret == WAIT_TIMEOUT)
2700 if (ret < wait->num) {
2701 gsize tid = wait->threads[ret]->tid;
2702 mono_threads_lock ();
2703 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2704 /* See comment in wait_for_tids about thread cleanup */
2705 mono_threads_unlock ();
2706 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2707 thread_cleanup (wait->threads [ret]);
2709 mono_threads_unlock ();
2713 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2715 struct wait_data *wait=(struct wait_data *)user;
2717 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2719 MonoInternalThread *thread=(MonoInternalThread *)value;
2721 /* Ignore background threads, we abort them later */
2722 /* Do not lock here since it is not needed and the caller holds threads_lock */
2723 if (thread->state & ThreadState_Background) {
2724 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2725 return; /* just leave, ignore */
2728 if (mono_gc_is_finalizer_internal_thread (thread)) {
2729 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2733 if (thread == mono_thread_internal_current ()) {
2734 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2738 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2739 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2743 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2744 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2748 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2749 if (handle == NULL) {
2750 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2754 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2755 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2756 wait->handles[wait->num]=handle;
2757 wait->threads[wait->num]=thread;
2760 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2762 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2767 /* Just ignore the rest, we can't do anything with
2774 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2776 struct wait_data *wait=(struct wait_data *)user;
2777 gsize self = GetCurrentThreadId ();
2778 MonoInternalThread *thread = value;
2781 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2784 /* The finalizer thread is not a background thread */
2785 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2786 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2788 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2792 /* printf ("A: %d\n", wait->num); */
2793 wait->handles[wait->num]=thread->handle;
2794 wait->threads[wait->num]=thread;
2797 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2798 mono_thread_internal_stop (thread);
2802 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2806 * mono_threads_set_shutting_down:
2808 * Is called by a thread that wants to shut down Mono. If the runtime is already
2809 * shutting down, the calling thread is suspended/stopped, and this function never
2813 mono_threads_set_shutting_down (void)
2815 MonoInternalThread *current_thread = mono_thread_internal_current ();
2817 mono_threads_lock ();
2819 if (shutting_down) {
2820 mono_threads_unlock ();
2822 /* Make sure we're properly suspended/stopped */
2824 EnterCriticalSection (current_thread->synch_cs);
2826 if ((current_thread->state & ThreadState_SuspendRequested) ||
2827 (current_thread->state & ThreadState_AbortRequested) ||
2828 (current_thread->state & ThreadState_StopRequested)) {
2829 LeaveCriticalSection (current_thread->synch_cs);
2830 mono_thread_execute_interruption (current_thread);
2832 current_thread->state |= ThreadState_Stopped;
2833 LeaveCriticalSection (current_thread->synch_cs);
2836 /*since we're killing the thread, unset the current domain.*/
2837 mono_domain_unset ();
2839 /* Wake up other threads potentially waiting for us */
2842 shutting_down = TRUE;
2844 /* Not really a background state change, but this will
2845 * interrupt the main thread if it is waiting for all
2846 * the other threads.
2848 SetEvent (background_change_event);
2850 mono_threads_unlock ();
2855 * mono_threads_is_shutting_down:
2857 * Returns whether a thread has commenced shutdown of Mono. Note that
2858 * if the function returns FALSE the caller must not assume that
2859 * shutdown is not in progress, because the situation might have
2860 * changed since the function returned. For that reason this function
2861 * is of very limited utility.
2864 mono_threads_is_shutting_down (void)
2866 return shutting_down;
2869 void mono_thread_manage (void)
2871 struct wait_data wait_data;
2872 struct wait_data *wait = &wait_data;
2874 memset (wait, 0, sizeof (struct wait_data));
2875 /* join each thread that's still running */
2876 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2878 mono_threads_lock ();
2880 THREAD_DEBUG (g_message("%s: No threads", __func__));
2881 mono_threads_unlock ();
2884 mono_threads_unlock ();
2887 mono_threads_lock ();
2888 if (shutting_down) {
2889 /* somebody else is shutting down */
2890 mono_threads_unlock ();
2893 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2894 mono_g_hash_table_foreach (threads, print_tids, NULL));
2896 ResetEvent (background_change_event);
2898 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2899 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2900 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2901 mono_threads_unlock ();
2903 /* Something to wait for */
2904 wait_for_tids_or_state_change (wait, INFINITE);
2906 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2907 } while(wait->num>0);
2909 mono_threads_set_shutting_down ();
2911 /* No new threads will be created after this point */
2913 mono_runtime_set_shutting_down ();
2915 THREAD_DEBUG (g_message ("%s: threadpool cleanup", __func__));
2916 mono_thread_pool_cleanup ();
2919 * Remove everything but the finalizer thread and self.
2920 * Also abort all the background threads
2923 mono_threads_lock ();
2926 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2927 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2928 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2930 mono_threads_unlock ();
2932 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2934 /* Something to wait for */
2935 wait_for_tids (wait, INFINITE);
2937 } while (wait->num > 0);
2940 * give the subthreads a chance to really quit (this is mainly needed
2941 * to get correct user and system times from getrusage/wait/time(1)).
2942 * This could be removed if we avoid pthread_detach() and use pthread_join().
2949 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2951 MonoInternalThread *thread=(MonoInternalThread *)value;
2953 if(thread->tid != (gsize)user) {
2954 /*TerminateThread (thread->handle, -1);*/
2958 void mono_thread_abort_all_other_threads (void)
2960 gsize self = GetCurrentThreadId ();
2962 mono_threads_lock ();
2963 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2964 mono_g_hash_table_size (threads));
2965 mono_g_hash_table_foreach (threads, print_tids, NULL));
2967 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2969 mono_threads_unlock ();
2973 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2975 MonoInternalThread *thread = (MonoInternalThread*)value;
2976 struct wait_data *wait = (struct wait_data*)user_data;
2980 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
2982 * This needs no locking.
2984 if ((thread->state & ThreadState_Suspended) != 0 ||
2985 (thread->state & ThreadState_Stopped) != 0)
2988 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2989 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2993 wait->handles [wait->num] = handle;
2994 wait->threads [wait->num] = thread;
3000 * mono_thread_suspend_all_other_threads:
3002 * Suspend all managed threads except the finalizer thread and this thread. It is
3003 * not possible to resume them later.
3005 void mono_thread_suspend_all_other_threads (void)
3007 struct wait_data wait_data;
3008 struct wait_data *wait = &wait_data;
3010 gsize self = GetCurrentThreadId ();
3012 guint32 eventidx = 0;
3013 gboolean starting, finished;
3015 memset (wait, 0, sizeof (struct wait_data));
3017 * The other threads could be in an arbitrary state at this point, i.e.
3018 * they could be starting up, shutting down etc. This means that there could be
3019 * threads which are not even in the threads hash table yet.
3023 * First we set a barrier which will be checked by all threads before they
3024 * are added to the threads hash table, and they will exit if the flag is set.
3025 * This ensures that no threads could be added to the hash later.
3026 * We will use shutting_down as the barrier for now.
3028 g_assert (shutting_down);
3031 * We make multiple calls to WaitForMultipleObjects since:
3032 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3033 * - some threads could exit without becoming suspended
3038 * Make a copy of the hashtable since we can't do anything with
3039 * threads while threads_mutex is held.
3042 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3043 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3044 mono_threads_lock ();
3045 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3046 mono_threads_unlock ();
3048 events = g_new0 (gpointer, wait->num);
3050 /* Get the suspended events that we'll be waiting for */
3051 for (i = 0; i < wait->num; ++i) {
3052 MonoInternalThread *thread = wait->threads [i];
3053 gboolean signal_suspend = FALSE;
3055 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3056 //CloseHandle (wait->handles [i]);
3057 wait->threads [i] = NULL; /* ignore this thread in next loop */
3061 ensure_synch_cs_set (thread);
3063 EnterCriticalSection (thread->synch_cs);
3065 if (thread->suspended_event == NULL) {
3066 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3067 if (thread->suspended_event == NULL) {
3068 /* Forget this one and go on to the next */
3069 LeaveCriticalSection (thread->synch_cs);
3074 if ((thread->state & ThreadState_Suspended) != 0 ||
3075 (thread->state & ThreadState_StopRequested) != 0 ||
3076 (thread->state & ThreadState_Stopped) != 0) {
3077 LeaveCriticalSection (thread->synch_cs);
3078 CloseHandle (wait->handles [i]);
3079 wait->threads [i] = NULL; /* ignore this thread in next loop */
3083 if ((thread->state & ThreadState_SuspendRequested) == 0)
3084 signal_suspend = TRUE;
3086 events [eventidx++] = thread->suspended_event;
3088 /* Convert abort requests into suspend requests */
3089 if ((thread->state & ThreadState_AbortRequested) != 0)
3090 thread->state &= ~ThreadState_AbortRequested;
3092 thread->state |= ThreadState_SuspendRequested;
3094 LeaveCriticalSection (thread->synch_cs);
3096 /* Signal the thread to suspend */
3097 if (mono_thread_info_new_interrupt_enabled ())
3098 suspend_thread_internal (thread, TRUE);
3099 else if (signal_suspend)
3100 signal_thread_state_change (thread);
3103 /*Only wait on the suspend event if we are using the old path */
3104 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3105 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3106 for (i = 0; i < wait->num; ++i) {
3107 MonoInternalThread *thread = wait->threads [i];
3112 ensure_synch_cs_set (thread);
3114 EnterCriticalSection (thread->synch_cs);
3115 if ((thread->state & ThreadState_Suspended) != 0) {
3116 CloseHandle (thread->suspended_event);
3117 thread->suspended_event = NULL;
3119 LeaveCriticalSection (thread->synch_cs);
3123 if (eventidx <= 0) {
3125 * If there are threads which are starting up, we wait until they
3126 * are suspended when they try to register in the threads hash.
3127 * This is guaranteed to finish, since the threads which can create new
3128 * threads get suspended after a while.
3129 * FIXME: The finalizer thread can still create new threads.
3131 mono_threads_lock ();
3132 if (threads_starting_up)
3133 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3136 mono_threads_unlock ();
3148 collect_threads (gpointer key, gpointer value, gpointer user_data)
3150 MonoInternalThread *thread = (MonoInternalThread*)value;
3151 struct wait_data *wait = (struct wait_data*)user_data;
3154 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3155 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3159 wait->handles [wait->num] = handle;
3160 wait->threads [wait->num] = thread;
3165 static gboolean thread_dump_requested;
3167 static G_GNUC_UNUSED gboolean
3168 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3170 GString *p = (GString*)data;
3171 MonoMethod *method = NULL;
3173 method = frame->ji->method;
3176 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3177 g_string_append_printf (p, " %s\n", location);
3180 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3186 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3188 GString* text = g_string_new (0);
3190 GError *error = NULL;
3193 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3195 g_string_append_printf (text, "\n\"%s\"", name);
3198 else if (thread->threadpool_thread)
3199 g_string_append (text, "\n\"<threadpool thread>\"");
3201 g_string_append (text, "\n\"<unnamed thread>\"");
3204 /* This no longer works with remote unwinding */
3206 wapi_desc = wapi_current_thread_desc ();
3207 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3212 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3213 mono_thread_info_resume (mono_thread_info_get_tid (info));
3215 fprintf (stdout, "%s", text->str);
3217 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3218 OutputDebugStringA(text->str);
3221 g_string_free (text, TRUE);
3226 dump_thread (gpointer key, gpointer value, gpointer user)
3228 MonoInternalThread *thread = (MonoInternalThread *)value;
3229 MonoThreadInfo *info;
3231 if (thread == mono_thread_internal_current ())
3235 FIXME This still can hang if we stop a thread during malloc.
3236 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3237 that takes a callback and runs it with the target suspended.
3238 We probably should loop a bit around trying to get it to either managed code
3241 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3246 print_thread_dump (thread, info);
3250 mono_threads_perform_thread_dump (void)
3252 if (!thread_dump_requested)
3255 printf ("Full thread dump:\n");
3258 * Make a copy of the hashtable since we can't do anything with
3259 * threads while threads_mutex is held.
3261 mono_threads_lock ();
3262 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3263 mono_threads_unlock ();
3265 thread_dump_requested = FALSE;
3269 * mono_threads_request_thread_dump:
3271 * Ask all threads except the current to print their stacktrace to stdout.
3274 mono_threads_request_thread_dump (void)
3276 struct wait_data wait_data;
3277 struct wait_data *wait = &wait_data;
3280 /*The new thread dump code runs out of the finalizer thread. */
3281 if (mono_thread_info_new_interrupt_enabled ()) {
3282 thread_dump_requested = TRUE;
3283 mono_gc_finalize_notify ();
3288 memset (wait, 0, sizeof (struct wait_data));
3291 * Make a copy of the hashtable since we can't do anything with
3292 * threads while threads_mutex is held.
3294 mono_threads_lock ();
3295 mono_g_hash_table_foreach (threads, collect_threads, wait);
3296 mono_threads_unlock ();
3298 for (i = 0; i < wait->num; ++i) {
3299 MonoInternalThread *thread = wait->threads [i];
3301 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3302 (thread != mono_thread_internal_current ()) &&
3303 !thread->thread_dump_requested) {
3304 thread->thread_dump_requested = TRUE;
3306 signal_thread_state_change (thread);
3309 CloseHandle (wait->handles [i]);
3315 gint allocated; /* +1 so that refs [allocated] == NULL */
3319 typedef struct ref_stack RefStack;
3322 ref_stack_new (gint initial_size)
3326 initial_size = MAX (initial_size, 16) + 1;
3327 rs = g_new0 (RefStack, 1);
3328 rs->refs = g_new0 (gpointer, initial_size);
3329 rs->allocated = initial_size;
3334 ref_stack_destroy (gpointer ptr)
3345 ref_stack_push (RefStack *rs, gpointer ptr)
3347 g_assert (rs != NULL);
3349 if (rs->bottom >= rs->allocated) {
3350 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3351 rs->allocated <<= 1;
3352 rs->refs [rs->allocated] = NULL;
3354 rs->refs [rs->bottom++] = ptr;
3358 ref_stack_pop (RefStack *rs)
3360 if (rs == NULL || rs->bottom == 0)
3364 rs->refs [rs->bottom] = NULL;
3368 ref_stack_find (RefStack *rs, gpointer ptr)
3375 for (refs = rs->refs; refs && *refs; refs++) {
3383 * mono_thread_push_appdomain_ref:
3385 * Register that the current thread may have references to objects in domain
3386 * @domain on its stack. Each call to this function should be paired with a
3387 * call to pop_appdomain_ref.
3390 mono_thread_push_appdomain_ref (MonoDomain *domain)
3392 MonoInternalThread *thread = mono_thread_internal_current ();
3395 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3396 SPIN_LOCK (thread->lock_thread_id);
3397 if (thread->appdomain_refs == NULL)
3398 thread->appdomain_refs = ref_stack_new (16);
3399 ref_stack_push (thread->appdomain_refs, domain);
3400 SPIN_UNLOCK (thread->lock_thread_id);
3405 mono_thread_pop_appdomain_ref (void)
3407 MonoInternalThread *thread = mono_thread_internal_current ();
3410 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3411 SPIN_LOCK (thread->lock_thread_id);
3412 ref_stack_pop (thread->appdomain_refs);
3413 SPIN_UNLOCK (thread->lock_thread_id);
3418 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3421 SPIN_LOCK (thread->lock_thread_id);
3422 res = ref_stack_find (thread->appdomain_refs, domain);
3423 SPIN_UNLOCK (thread->lock_thread_id);
3428 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3430 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3433 typedef struct abort_appdomain_data {
3434 struct wait_data wait;
3436 } abort_appdomain_data;
3439 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3441 MonoInternalThread *thread = (MonoInternalThread*)value;
3442 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3443 MonoDomain *domain = data->domain;
3445 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3446 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3448 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3449 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3452 data->wait.handles [data->wait.num] = handle;
3453 data->wait.threads [data->wait.num] = thread;
3456 /* Just ignore the rest, we can't do anything with
3464 * mono_threads_abort_appdomain_threads:
3466 * Abort threads which has references to the given appdomain.
3469 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3471 abort_appdomain_data user_data;
3473 int orig_timeout = timeout;
3476 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3478 start_time = mono_msec_ticks ();
3480 mono_threads_lock ();
3482 user_data.domain = domain;
3483 user_data.wait.num = 0;
3484 /* This shouldn't take any locks */
3485 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3486 mono_threads_unlock ();
3488 if (user_data.wait.num > 0) {
3489 /* Abort the threads outside the threads lock */
3490 for (i = 0; i < user_data.wait.num; ++i)
3491 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3494 * We should wait for the threads either to abort, or to leave the
3495 * domain. We can't do the latter, so we wait with a timeout.
3497 wait_for_tids (&user_data.wait, 100);
3500 /* Update remaining time */
3501 timeout -= mono_msec_ticks () - start_time;
3502 start_time = mono_msec_ticks ();
3504 if (orig_timeout != -1 && timeout < 0)
3507 while (user_data.wait.num > 0);
3509 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3515 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3517 MonoInternalThread *thread = (MonoInternalThread*)value;
3518 MonoDomain *domain = (MonoDomain*)user_data;
3521 /* No locking needed here */
3522 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3524 if (thread->cached_culture_info) {
3525 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3526 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3527 if (obj && obj->vtable->domain == domain)
3528 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3534 * mono_threads_clear_cached_culture:
3536 * Clear the cached_current_culture from all threads if it is in the
3540 mono_threads_clear_cached_culture (MonoDomain *domain)
3542 mono_threads_lock ();
3543 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3544 mono_threads_unlock ();
3548 * mono_thread_get_undeniable_exception:
3550 * Return an exception which needs to be raised when leaving a catch clause.
3551 * This is used for undeniable exception propagation.
3554 mono_thread_get_undeniable_exception (void)
3556 MonoInternalThread *thread = mono_thread_internal_current ();
3558 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3560 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3561 * exception if the thread no longer references a dying appdomain.
3563 thread->abort_exc->trace_ips = NULL;
3564 thread->abort_exc->stack_trace = NULL;
3565 return thread->abort_exc;
3571 #if MONO_SMALL_CONFIG
3572 #define NUM_STATIC_DATA_IDX 4
3573 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3577 #define NUM_STATIC_DATA_IDX 8
3578 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3579 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3583 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3586 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
3589 gpointer *static_data = addr;
3590 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3593 if (!static_data [i])
3595 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3596 ptr = static_data [i];
3597 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3598 uintptr_t bmap = static_reference_bitmaps [i][j];
3601 if ((bmap & 1) && *p) {
3612 * mono_alloc_static_data
3614 * Allocate memory blocks for storing threads or context static data
3617 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3619 guint idx = (offset >> 24) - 1;
3622 gpointer* static_data = *static_data_ptr;
3624 static void* tls_desc = NULL;
3625 if (mono_gc_user_markers_supported () && !tls_desc)
3626 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3627 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3628 *static_data_ptr = static_data;
3629 static_data [0] = static_data;
3632 for (i = 1; i <= idx; ++i) {
3633 if (static_data [i])
3635 if (mono_gc_user_markers_supported () && threadlocal)
3636 static_data [i] = g_malloc0 (static_data_size [i]);
3638 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3643 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3646 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3647 if (!static_data [i])
3649 if (mono_gc_user_markers_supported () && threadlocal)
3650 g_free (static_data [i]);
3652 mono_gc_free_fixed (static_data [i]);
3654 mono_gc_free_fixed (static_data);
3658 * mono_init_static_data_info
3660 * Initializes static data counters
3662 static void mono_init_static_data_info (StaticDataInfo *static_data)
3664 static_data->idx = 0;
3665 static_data->offset = 0;
3666 static_data->freelist = NULL;
3670 * mono_alloc_static_data_slot
3672 * Generates an offset for static data. static_data contains the counters
3673 * used to generate it.
3676 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3680 if (!static_data->idx && !static_data->offset) {
3682 * we use the first chunk of the first allocation also as
3683 * an array for the rest of the data
3685 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3687 static_data->offset += align - 1;
3688 static_data->offset &= ~(align - 1);
3689 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3690 static_data->idx ++;
3691 g_assert (size <= static_data_size [static_data->idx]);
3692 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3693 static_data->offset = 0;
3695 offset = static_data->offset | ((static_data->idx + 1) << 24);
3696 static_data->offset += size;
3701 * ensure thread static fields already allocated are valid for thread
3702 * This function is called when a thread is created or on thread attach.
3705 thread_adjust_static_data (MonoInternalThread *thread)
3709 mono_threads_lock ();
3710 if (thread_static_info.offset || thread_static_info.idx > 0) {
3711 /* get the current allocated size */
3712 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3713 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3715 mono_threads_unlock ();
3719 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3721 MonoInternalThread *thread = value;
3722 guint32 offset = GPOINTER_TO_UINT (user);
3724 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3727 static MonoThreadDomainTls*
3728 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3730 MonoThreadDomainTls* prev = NULL;
3731 MonoThreadDomainTls* tmp = static_data->freelist;
3733 if (tmp->size == size) {
3735 prev->next = tmp->next;
3737 static_data->freelist = tmp->next;
3746 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3749 int idx = (offset >> 24) - 1;
3751 if (!static_reference_bitmaps [idx])
3752 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3753 rb = static_reference_bitmaps [idx];
3755 offset /= sizeof (gpointer);
3756 /* offset is now the bitmap offset */
3757 for (i = 0; i < numbits; ++i) {
3758 if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
3759 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3764 clear_reference_bitmap (guint32 offset, guint32 size)
3766 int idx = (offset >> 24) - 1;
3768 rb = static_reference_bitmaps [idx];
3770 offset /= sizeof (gpointer);
3771 size /= sizeof (gpointer);
3773 /* offset is now the bitmap offset */
3774 for (; offset < size; ++offset)
3775 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3779 * The offset for a special static variable is composed of three parts:
3780 * a bit that indicates the type of static data (0:thread, 1:context),
3781 * an index in the array of chunks of memory for the thread (thread->static_data)
3782 * and an offset in that chunk of mem. This allows allocating less memory in the
3787 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3790 if (static_type == SPECIAL_STATIC_THREAD) {
3791 MonoThreadDomainTls *item;
3792 mono_threads_lock ();
3793 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3794 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3796 offset = item->offset;
3799 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3801 update_tls_reference_bitmap (offset, bitmap, numbits);
3802 /* This can be called during startup */
3803 if (threads != NULL)
3804 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3805 mono_threads_unlock ();
3807 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3808 mono_contexts_lock ();
3809 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3810 mono_contexts_unlock ();
3811 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3817 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3819 /* The high bit means either thread (0) or static (1) data. */
3821 guint32 static_type = (offset & 0x80000000);
3824 offset &= 0x7fffffff;
3825 idx = (offset >> 24) - 1;
3827 if (static_type == 0) {
3828 return get_thread_static_data (thread, offset);
3830 /* Allocate static data block under demand, since we don't have a list
3833 MonoAppContext *context = mono_context_get ();
3834 if (!context->static_data || !context->static_data [idx]) {
3835 mono_contexts_lock ();
3836 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3837 mono_contexts_unlock ();
3839 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3844 mono_get_special_static_data (guint32 offset)
3846 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3855 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3857 MonoInternalThread *thread = value;
3858 TlsOffsetSize *data = user;
3859 int idx = (data->offset >> 24) - 1;
3862 if (!thread->static_data || !thread->static_data [idx])
3864 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3865 mono_gc_bzero (ptr, data->size);
3869 do_free_special_slot (guint32 offset, guint32 size)
3871 guint32 static_type = (offset & 0x80000000);
3872 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3873 if (static_type == 0) {
3875 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3876 data.offset = offset & 0x7fffffff;
3878 clear_reference_bitmap (data.offset, data.size);
3879 if (threads != NULL)
3880 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3881 item->offset = offset;
3884 if (!mono_runtime_is_shutting_down ()) {
3885 item->next = thread_static_info.freelist;
3886 thread_static_info.freelist = item;
3888 /* We could be called during shutdown after mono_thread_cleanup () is called */
3892 /* FIXME: free context static data as well */
3897 do_free_special (gpointer key, gpointer value, gpointer data)
3899 MonoClassField *field = key;
3900 guint32 offset = GPOINTER_TO_UINT (value);
3903 size = mono_type_size (field->type, &align);
3904 do_free_special_slot (offset, size);
3908 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3910 mono_threads_lock ();
3911 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3912 mono_threads_unlock ();
3916 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3918 mono_threads_lock ();
3919 do_free_special_slot (offset, size);
3920 mono_threads_unlock ();
3924 * allocates room in the thread local area for storing an instance of the struct type
3925 * the allocation is kept track of in domain->tlsrec_list.
3928 mono_thread_alloc_tls (MonoReflectionType *type)
3930 MonoDomain *domain = mono_domain_get ();
3932 MonoTlsDataRecord *tlsrec;
3935 gsize default_bitmap [4] = {0};
3936 uint32_t tls_offset;
3940 klass = mono_class_from_mono_type (type->type);
3941 /* TlsDatum is a struct, so we subtract the object header size offset */
3942 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3943 size = mono_type_size (type->type, &align);
3944 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3945 if (bitmap != default_bitmap)
3947 tlsrec = g_new0 (MonoTlsDataRecord, 1);
3948 tlsrec->tls_offset = tls_offset;
3949 tlsrec->size = size;
3950 mono_domain_lock (domain);
3951 tlsrec->next = domain->tlsrec_list;
3952 domain->tlsrec_list = tlsrec;
3953 mono_domain_unlock (domain);
3958 mono_thread_destroy_tls (uint32_t tls_offset)
3960 MonoTlsDataRecord *prev = NULL;
3961 MonoTlsDataRecord *cur;
3963 MonoDomain *domain = mono_domain_get ();
3964 mono_domain_lock (domain);
3965 cur = domain->tlsrec_list;
3967 if (cur->tls_offset == tls_offset) {
3969 prev->next = cur->next;
3971 domain->tlsrec_list = cur->next;
3979 mono_domain_unlock (domain);
3981 mono_special_static_data_free_slot (tls_offset, size);
3985 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
3988 mono_thread_destroy_domain_tls (MonoDomain *domain)
3990 while (domain->tlsrec_list)
3991 mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
3994 static MonoClassField *local_slots = NULL;
3997 /* local tls data to get locals_slot from a thread */
4000 /* index in the locals_slot array */
4005 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4007 LocalSlotID *sid = user_data;
4008 MonoInternalThread *thread = (MonoInternalThread*)value;
4009 MonoArray *slots_array;
4011 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4012 * it is for the right domain, so we need to check if it is allocated an initialized
4013 * for the current thread.
4015 /*g_print ("handling thread %p\n", thread);*/
4016 if (!thread->static_data || !thread->static_data [sid->idx])
4018 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4019 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4021 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4025 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4033 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4035 g_warning ("local_slots field not found in Thread class");
4039 domain = mono_domain_get ();
4040 mono_domain_lock (domain);
4041 if (domain->special_static_fields)
4042 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4043 mono_domain_unlock (domain);
4046 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4047 sid.offset = GPOINTER_TO_UINT (addr);
4048 sid.offset &= 0x7fffffff;
4049 sid.idx = (sid.offset >> 24) - 1;
4050 mono_threads_lock ();
4051 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4052 mono_threads_unlock ();
4054 /* FIXME: clear the slot for MonoAppContexts, too */
4059 static void CALLBACK dummy_apc (ULONG_PTR param)
4063 static guint32 dummy_apc (gpointer param)
4070 * mono_thread_execute_interruption
4072 * Performs the operation that the requested thread state requires (abort,
4075 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4077 ensure_synch_cs_set (thread);
4079 EnterCriticalSection (thread->synch_cs);
4081 /* MonoThread::interruption_requested can only be changed with atomics */
4082 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4083 /* this will consume pending APC calls */
4084 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4085 InterlockedDecrement (&thread_interruption_requested);
4087 /* Clear the interrupted flag of the thread so it can wait again */
4088 wapi_clear_interruption ();
4092 if ((thread->state & ThreadState_AbortRequested) != 0) {
4093 LeaveCriticalSection (thread->synch_cs);
4094 if (thread->abort_exc == NULL) {
4096 * This might be racy, but it has to be called outside the lock
4097 * since it calls managed code.
4099 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4101 return thread->abort_exc;
4103 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4104 self_suspend_internal (thread);
4107 else if ((thread->state & ThreadState_StopRequested) != 0) {
4108 /* FIXME: do this through the JIT? */
4110 LeaveCriticalSection (thread->synch_cs);
4112 mono_thread_exit ();
4114 } else if (thread->pending_exception) {
4117 exc = thread->pending_exception;
4118 thread->pending_exception = NULL;
4120 LeaveCriticalSection (thread->synch_cs);
4122 } else if (thread->thread_interrupt_requested) {
4124 thread->thread_interrupt_requested = FALSE;
4125 LeaveCriticalSection (thread->synch_cs);
4127 return(mono_get_exception_thread_interrupted ());
4130 LeaveCriticalSection (thread->synch_cs);
4136 * mono_thread_request_interruption
4138 * A signal handler can call this method to request the interruption of a
4139 * thread. The result of the interruption will depend on the current state of
4140 * the thread. If the result is an exception that needs to be throw, it is
4141 * provided as return value.
4144 mono_thread_request_interruption (gboolean running_managed)
4146 MonoInternalThread *thread = mono_thread_internal_current ();
4148 /* The thread may already be stopping */
4153 if (thread->interrupt_on_stop &&
4154 thread->state & ThreadState_StopRequested &&
4155 thread->state & ThreadState_Background)
4159 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4161 InterlockedIncrement (&thread_interruption_requested);
4163 if (!running_managed || is_running_protected_wrapper ()) {
4164 /* Can't stop while in unmanaged code. Increase the global interruption
4165 request count. When exiting the unmanaged method the count will be
4166 checked and the thread will be interrupted. */
4169 if (mono_thread_notify_pending_exc_fn && !running_managed)
4170 /* The JIT will notify the thread about the interruption */
4171 /* This shouldn't take any locks */
4172 mono_thread_notify_pending_exc_fn ();
4174 /* this will awake the thread if it is in WaitForSingleObject
4176 /* Our implementation of this function ignores the func argument */
4177 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
4181 return mono_thread_execute_interruption (thread);
4185 /*This function should be called by a thread after it has exited all of
4186 * its handle blocks at interruption time.*/
4188 mono_thread_resume_interruption (void)
4190 MonoInternalThread *thread = mono_thread_internal_current ();
4191 gboolean still_aborting;
4193 /* The thread may already be stopping */
4197 ensure_synch_cs_set (thread);
4198 EnterCriticalSection (thread->synch_cs);
4199 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4200 LeaveCriticalSection (thread->synch_cs);
4202 /*This can happen if the protected block called Thread::ResetAbort*/
4203 if (!still_aborting)
4206 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4208 InterlockedIncrement (&thread_interruption_requested);
4211 wapi_self_interrupt ();
4213 return mono_thread_execute_interruption (thread);
4216 gboolean mono_thread_interruption_requested ()
4218 if (thread_interruption_requested) {
4219 MonoInternalThread *thread = mono_thread_internal_current ();
4220 /* The thread may already be stopping */
4222 return (thread->interruption_requested);
4227 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4229 MonoInternalThread *thread = mono_thread_internal_current ();
4231 /* The thread may already be stopping */
4235 mono_debugger_check_interruption ();
4237 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4238 MonoException* exc = mono_thread_execute_interruption (thread);
4239 if (exc) mono_raise_exception (exc);
4244 * Performs the interruption of the current thread, if one has been requested,
4245 * and the thread is not running a protected wrapper.
4247 void mono_thread_interruption_checkpoint ()
4249 mono_thread_interruption_checkpoint_request (FALSE);
4253 * Performs the interruption of the current thread, if one has been requested.
4255 void mono_thread_force_interruption_checkpoint ()
4257 mono_thread_interruption_checkpoint_request (TRUE);
4261 * mono_thread_get_and_clear_pending_exception:
4263 * Return any pending exceptions for the current thread and clear it as a side effect.
4266 mono_thread_get_and_clear_pending_exception (void)
4268 MonoInternalThread *thread = mono_thread_internal_current ();
4270 /* The thread may already be stopping */
4274 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4275 return mono_thread_execute_interruption (thread);
4278 if (thread->pending_exception) {
4279 MonoException *exc = thread->pending_exception;
4281 thread->pending_exception = NULL;
4289 * mono_set_pending_exception:
4291 * Set the pending exception of the current thread to EXC.
4292 * The exception will be thrown when execution returns to managed code.
4295 mono_set_pending_exception (MonoException *exc)
4297 MonoInternalThread *thread = mono_thread_internal_current ();
4299 /* The thread may already be stopping */
4303 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4305 mono_thread_request_interruption (FALSE);
4309 * mono_thread_interruption_request_flag:
4311 * Returns the address of a flag that will be non-zero if an interruption has
4312 * been requested for a thread. The thread to interrupt may not be the current
4313 * thread, so an additional call to mono_thread_interruption_requested() or
4314 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4317 gint32* mono_thread_interruption_request_flag ()
4319 return &thread_interruption_requested;
4323 mono_thread_init_apartment_state (void)
4326 MonoInternalThread* thread = mono_thread_internal_current ();
4328 /* Positive return value indicates success, either
4329 * S_OK if this is first CoInitialize call, or
4330 * S_FALSE if CoInitialize already called, but with same
4331 * threading model. A negative value indicates failure,
4332 * probably due to trying to change the threading model.
4334 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4335 ? COINIT_APARTMENTTHREADED
4336 : COINIT_MULTITHREADED) < 0) {
4337 thread->apartment_state = ThreadApartmentState_Unknown;
4343 mono_thread_cleanup_apartment_state (void)
4346 MonoInternalThread* thread = mono_thread_internal_current ();
4348 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4355 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4357 ensure_synch_cs_set (thread);
4359 EnterCriticalSection (thread->synch_cs);
4360 thread->state |= state;
4361 LeaveCriticalSection (thread->synch_cs);
4365 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4367 ensure_synch_cs_set (thread);
4369 EnterCriticalSection (thread->synch_cs);
4370 thread->state &= ~state;
4371 LeaveCriticalSection (thread->synch_cs);
4375 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4377 gboolean ret = FALSE;
4379 ensure_synch_cs_set (thread);
4381 EnterCriticalSection (thread->synch_cs);
4383 if ((thread->state & test) != 0) {
4387 LeaveCriticalSection (thread->synch_cs);
4392 //static MonoClassField *execution_context_field;
4395 get_execution_context_addr (void)
4397 MonoDomain *domain = mono_domain_get ();
4398 guint32 offset = domain->execution_context_field_offset;
4401 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4404 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4406 mono_domain_lock (domain);
4407 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4408 mono_domain_unlock (domain);
4411 domain->execution_context_field_offset = offset;
4414 return (MonoObject**) mono_get_special_static_data (offset);
4418 mono_thread_get_execution_context (void)
4420 return *get_execution_context_addr ();
4424 mono_thread_set_execution_context (MonoObject *ec)
4426 *get_execution_context_addr () = ec;
4429 static gboolean has_tls_get = FALSE;
4432 mono_runtime_set_has_tls_get (gboolean val)
4438 mono_runtime_has_tls_get (void)
4444 mono_thread_kill (MonoInternalThread *thread, int signal)
4447 /* Win32 uses QueueUserAPC and callers of this are guarded */
4448 g_assert_not_reached ();
4450 # ifdef PTHREAD_POINTER_ID
4451 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4453 # ifdef PLATFORM_ANDROID
4454 if (thread->android_tid != 0) {
4456 int old_errno = errno;
4458 ret = tkill ((pid_t) thread->android_tid, signal);
4467 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4469 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4476 self_interrupt_thread (void *_unused)
4478 MonoThreadInfo *info = mono_thread_info_current ();
4479 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4480 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4481 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4482 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4486 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4490 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4494 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4496 MonoJitInfo **dest = data;
4502 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4504 MonoJitInfo *ji = NULL;
4507 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4512 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4515 MonoThreadInfo *info = NULL;
4516 gboolean protected_wrapper;
4517 gboolean running_managed;
4519 if (!mono_thread_info_new_interrupt_enabled ()) {
4520 signal_thread_state_change (thread);
4525 FIXME this is insanely broken, it doesn't cause interruption to happen
4526 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4528 if (thread == mono_thread_internal_current ()) {
4529 /* Do it synchronously */
4530 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4532 mono_raise_exception (exc);
4534 wapi_interrupt_thread (thread->handle);
4539 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4540 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4544 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4545 mono_thread_info_resume (mono_thread_info_get_tid (info));
4549 /*someone is already interrupting it*/
4550 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4551 mono_thread_info_resume (mono_thread_info_get_tid (info));
4554 InterlockedIncrement (&thread_interruption_requested);
4556 ji = mono_thread_info_get_last_managed (info);
4557 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4558 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4560 if (!protected_wrapper && running_managed) {
4561 /*We are in managed code*/
4562 /*Set the thread to call */
4563 if (install_async_abort)
4564 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4565 mono_thread_info_resume (mono_thread_info_get_tid (info));
4567 gpointer interrupt_handle;
4569 * This will cause waits to be broken.
4570 * It will also prevent the thread from entering a wait, so if the thread returns
4571 * from the wait before it receives the abort signal, it will just spin in the wait
4572 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4576 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4578 mono_thread_info_resume (mono_thread_info_get_tid (info));
4580 wapi_finish_interrupt_thread (interrupt_handle);
4583 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4587 transition_to_suspended (MonoInternalThread *thread)
4589 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4590 g_assert (0); /*FIXME we should not reach this */
4591 /*Make sure we balance the suspend count.*/
4592 mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
4594 thread->state &= ~ThreadState_SuspendRequested;
4595 thread->state |= ThreadState_Suspended;
4597 LeaveCriticalSection (thread->synch_cs);
4601 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4603 if (!mono_thread_info_new_interrupt_enabled ()) {
4604 signal_thread_state_change (thread);
4608 EnterCriticalSection (thread->synch_cs);
4609 if (thread == mono_thread_internal_current ()) {
4610 transition_to_suspended (thread);
4611 mono_thread_info_self_suspend ();
4613 MonoThreadInfo *info;
4615 gboolean protected_wrapper;
4616 gboolean running_managed;
4618 /*A null info usually means the thread is already dead. */
4619 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
4620 LeaveCriticalSection (thread->synch_cs);
4624 ji = mono_thread_info_get_last_managed (info);
4625 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4626 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4628 if (running_managed && !protected_wrapper) {
4629 transition_to_suspended (thread);
4631 gpointer interrupt_handle;
4633 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4634 InterlockedIncrement (&thread_interruption_requested);
4637 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4639 mono_thread_info_resume (mono_thread_info_get_tid (info));
4642 wapi_finish_interrupt_thread (interrupt_handle);
4644 LeaveCriticalSection (thread->synch_cs);
4649 /*This is called with @thread synch_cs held and it must release it*/
4651 self_suspend_internal (MonoInternalThread *thread)
4653 if (!mono_thread_info_new_interrupt_enabled ()) {
4654 thread->state &= ~ThreadState_SuspendRequested;
4655 thread->state |= ThreadState_Suspended;
4656 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4657 if (thread->suspend_event == NULL) {
4658 LeaveCriticalSection (thread->synch_cs);
4661 if (thread->suspended_event)
4662 SetEvent (thread->suspended_event);
4664 LeaveCriticalSection (thread->synch_cs);
4666 if (shutting_down) {
4667 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4672 WaitForSingleObject (thread->suspend_event, INFINITE);
4674 EnterCriticalSection (thread->synch_cs);
4676 CloseHandle (thread->suspend_event);
4677 thread->suspend_event = NULL;
4678 thread->state &= ~ThreadState_Suspended;
4680 /* The thread that requested the resume will have replaced this event
4681 * and will be waiting for it
4683 SetEvent (thread->resume_event);
4685 LeaveCriticalSection (thread->synch_cs);
4689 transition_to_suspended (thread);
4690 mono_thread_info_self_suspend ();
4693 /*This is called with @thread synch_cs held and it must release it*/
4695 resume_thread_internal (MonoInternalThread *thread)
4697 if (!mono_thread_info_new_interrupt_enabled ()) {
4698 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4699 if (thread->resume_event == NULL) {
4700 LeaveCriticalSection (thread->synch_cs);
4704 /* Awake the thread */
4705 SetEvent (thread->suspend_event);
4707 LeaveCriticalSection (thread->synch_cs);
4709 /* Wait for the thread to awake */
4710 WaitForSingleObject (thread->resume_event, INFINITE);
4711 CloseHandle (thread->resume_event);
4712 thread->resume_event = NULL;
4716 LeaveCriticalSection (thread->synch_cs);
4717 /* Awake the thread */
4718 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4720 EnterCriticalSection (thread->synch_cs);
4721 thread->state &= ~ThreadState_Suspended;
4722 LeaveCriticalSection (thread->synch_cs);