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/metadata/runtime.h>
37 #include <mono/io-layer/io-layer.h>
39 #include <mono/io-layer/threads.h>
41 #include <mono/metadata/object-internals.h>
42 #include <mono/metadata/mono-debug-debugger.h>
43 #include <mono/utils/mono-compiler.h>
44 #include <mono/utils/mono-mmap.h>
45 #include <mono/utils/mono-membar.h>
46 #include <mono/utils/mono-time.h>
47 #include <mono/utils/mono-threads.h>
48 #include <mono/utils/hazard-pointer.h>
49 #include <mono/utils/mono-tls.h>
50 #include <mono/utils/atomic.h>
52 #include <mono/metadata/gc-internal.h>
54 #ifdef PLATFORM_ANDROID
57 extern int tkill (pid_t tid, int signal);
60 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
61 void *pthread_get_stackaddr_np(pthread_t);
62 size_t pthread_get_stacksize_np(pthread_t);
65 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
66 #define THREAD_DEBUG(a)
67 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
68 #define THREAD_WAIT_DEBUG(a)
69 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
70 #define LIBGC_DEBUG(a)
72 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
73 #define SPIN_LOCK(i) do { \
74 if (SPIN_TRYLOCK (i)) \
78 #define SPIN_UNLOCK(i) i = 0
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func)(void *);
107 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
108 struct _MonoThreadDomainTls {
109 MonoThreadDomainTls *next;
117 MonoThreadDomainTls *freelist;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
130 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
131 static CRITICAL_SECTION threads_mutex;
133 /* Controls access to context static data */
134 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
135 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
136 static CRITICAL_SECTION contexts_mutex;
138 /* Holds current status of static data heap */
139 static StaticDataInfo thread_static_info;
140 static StaticDataInfo context_static_info;
142 /* The hash of existing threads (key is thread ID, value is
143 * MonoInternalThread*) that need joining before exit
145 static MonoGHashTable *threads=NULL;
148 * Threads which are starting up and they are not in the 'threads' hash yet.
149 * When handle_store is called for a thread, it will be removed from this hash table.
150 * Protected by mono_threads_lock ().
152 static MonoGHashTable *threads_starting_up = NULL;
154 /* Maps a MonoThread to its start argument */
155 /* Protected by mono_threads_lock () */
156 static MonoGHashTable *thread_start_args = NULL;
158 /* The TLS key that holds the MonoObject assigned to each thread */
159 static MonoNativeTlsKey current_object_key;
161 #ifdef MONO_HAVE_FAST_TLS
162 /* we need to use both the Tls* functions and __thread because
163 * the gc needs to see all the threads
165 MONO_FAST_TLS_DECLARE(tls_current_object);
166 #define SET_CURRENT_OBJECT(x) do { \
167 MONO_FAST_TLS_SET (tls_current_object, x); \
168 mono_native_tls_set_value (current_object_key, x); \
170 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
172 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
173 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
176 /* function called at thread start */
177 static MonoThreadStartCB mono_thread_start_cb = NULL;
179 /* function called at thread attach */
180 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
182 /* function called at thread cleanup */
183 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
185 /* function called to notify the runtime about a pending exception on the current thread */
186 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
188 /* The default stack size for each thread */
189 static guint32 default_stacksize = 0;
190 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
192 static void thread_adjust_static_data (MonoInternalThread *thread);
193 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
194 static void mono_init_static_data_info (StaticDataInfo *static_data);
195 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
196 static gboolean mono_thread_resume (MonoInternalThread* thread);
197 static void mono_thread_start (MonoThread *thread);
198 static void signal_thread_state_change (MonoInternalThread *thread);
199 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
200 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
201 static void self_suspend_internal (MonoInternalThread *thread);
202 static gboolean resume_thread_internal (MonoInternalThread *thread);
204 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
205 static void ref_stack_destroy (gpointer rs);
207 /* Spin lock for InterlockedXXX 64 bit functions */
208 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
209 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
210 static CRITICAL_SECTION interlocked_mutex;
212 /* global count of thread interruptions requested */
213 static gint32 thread_interruption_requested = 0;
215 /* Event signaled when a thread changes its background mode */
216 static HANDLE background_change_event;
218 static gboolean shutting_down = FALSE;
220 static gint32 managed_thread_id_counter = 0;
223 get_next_managed_thread_id (void)
225 return InterlockedIncrement (&managed_thread_id_counter);
229 mono_thread_get_tls_key (void)
231 return current_object_key;
235 mono_thread_get_tls_offset (void)
238 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
242 /* handle_store() and handle_remove() manage the array of threads that
243 * still need to be waited for when the main thread exits.
245 * If handle_store() returns FALSE the thread must not be started
246 * because Mono is shutting down.
248 static gboolean handle_store(MonoThread *thread)
250 mono_threads_lock ();
252 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
254 if (threads_starting_up)
255 mono_g_hash_table_remove (threads_starting_up, thread);
258 mono_threads_unlock ();
263 MONO_GC_REGISTER_ROOT_FIXED (threads);
264 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
267 /* We don't need to duplicate thread->handle, because it is
268 * only closed when the thread object is finalized by the GC.
270 g_assert (thread->internal_thread);
271 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
272 thread->internal_thread);
274 mono_threads_unlock ();
279 static gboolean handle_remove(MonoInternalThread *thread)
282 gsize tid = thread->tid;
284 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
286 mono_threads_lock ();
289 /* We have to check whether the thread object for the
290 * tid is still the same in the table because the
291 * thread might have been destroyed and the tid reused
292 * in the meantime, in which case the tid would be in
293 * the table, but with another thread object.
295 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
296 mono_g_hash_table_remove (threads, (gpointer)tid);
305 mono_threads_unlock ();
307 /* Don't close the handle here, wait for the object finalizer
308 * to do it. Otherwise, the following race condition applies:
310 * 1) Thread exits (and handle_remove() closes the handle)
312 * 2) Some other handle is reassigned the same slot
314 * 3) Another thread tries to join the first thread, and
315 * blocks waiting for the reassigned handle to be signalled
316 * (which might never happen). This is possible, because the
317 * thread calling Join() still has a reference to the first
323 static void ensure_synch_cs_set (MonoInternalThread *thread)
325 CRITICAL_SECTION *synch_cs;
327 if (thread->synch_cs != NULL) {
331 synch_cs = g_new0 (CRITICAL_SECTION, 1);
332 InitializeCriticalSection (synch_cs);
334 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
335 synch_cs, NULL) != NULL) {
336 /* Another thread must have installed this CS */
337 DeleteCriticalSection (synch_cs);
343 * NOTE: this function can be called also for threads different from the current one:
344 * make sure no code called from it will ever assume it is run on the thread that is
345 * getting cleaned up.
347 static void thread_cleanup (MonoInternalThread *thread)
349 g_assert (thread != NULL);
351 if (thread->abort_state_handle) {
352 mono_gchandle_free (thread->abort_state_handle);
353 thread->abort_state_handle = 0;
355 thread->abort_exc = NULL;
356 thread->current_appcontext = NULL;
359 * This is necessary because otherwise we might have
360 * cross-domain references which will not get cleaned up when
361 * the target domain is unloaded.
363 if (thread->cached_culture_info) {
365 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
366 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
369 ensure_synch_cs_set (thread);
371 EnterCriticalSection (thread->synch_cs);
373 thread->state |= ThreadState_Stopped;
374 thread->state &= ~ThreadState_Background;
376 LeaveCriticalSection (thread->synch_cs);
379 An interruption request has leaked to cleanup. Adjust the global counter.
381 This can happen is the abort source thread finds the abortee (this) thread
382 in unmanaged code. If this thread never trips back to managed code or check
383 the local flag it will be left set and positively unbalance the global counter.
385 Leaving the counter unbalanced will cause a performance degradation since all threads
386 will now keep checking their local flags all the time.
388 if (InterlockedExchange (&thread->interruption_requested, 0))
389 InterlockedDecrement (&thread_interruption_requested);
391 /* if the thread is not in the hash it has been removed already */
392 if (!handle_remove (thread)) {
393 /* This needs to be called even if handle_remove () fails */
394 if (mono_thread_cleanup_fn)
395 mono_thread_cleanup_fn (thread);
398 mono_release_type_locks (thread);
400 mono_profiler_thread_end (thread->tid);
402 if (thread == mono_thread_internal_current ())
403 mono_thread_pop_appdomain_ref ();
405 thread->cached_culture_info = NULL;
407 mono_free_static_data (thread->static_data, TRUE);
408 thread->static_data = NULL;
409 ref_stack_destroy (thread->appdomain_refs);
410 thread->appdomain_refs = NULL;
412 if (mono_thread_cleanup_fn)
413 mono_thread_cleanup_fn (thread);
415 if (mono_gc_is_moving ()) {
416 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
417 thread->thread_pinning_ref = NULL;
423 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
426 g_assert ((offset & 0x80000000) == 0);
427 offset &= 0x7fffffff;
428 idx = (offset >> 24) - 1;
429 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
433 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
435 static MonoClassField *current_thread_field = NULL;
439 if (!current_thread_field) {
440 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
441 g_assert (current_thread_field);
444 mono_class_vtable (domain, mono_defaults.thread_class);
445 mono_domain_lock (domain);
446 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
447 mono_domain_unlock (domain);
450 return get_thread_static_data (thread, offset);
454 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
456 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
458 g_assert (current->obj.vtable->domain == domain);
460 g_assert (!*current_thread_ptr);
461 *current_thread_ptr = current;
464 static MonoInternalThread*
465 create_internal_thread_object (void)
467 MonoVTable *vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
468 return (MonoInternalThread*)mono_gc_alloc_mature (vt);
472 create_thread_object (MonoDomain *domain)
474 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
475 return (MonoThread*)mono_gc_alloc_mature (vt);
479 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
481 MonoThread *thread = create_thread_object (domain);
482 MONO_OBJECT_SETREF (thread, internal_thread, internal);
487 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
489 MonoDomain *domain = mono_get_root_domain ();
491 if (!candidate || candidate->obj.vtable->domain != domain)
492 candidate = new_thread_with_internal (domain, thread);
493 set_current_thread_for_domain (domain, thread, candidate);
494 g_assert (!thread->root_domain_thread);
495 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
498 static guint32 WINAPI start_wrapper_internal(void *data)
500 MonoThreadInfo *info;
501 struct StartInfo *start_info=(struct StartInfo *)data;
502 guint32 (*start_func)(void *);
506 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
509 MonoInternalThread *internal = start_info->obj->internal_thread;
510 MonoObject *start_delegate = start_info->delegate;
511 MonoDomain *domain = start_info->obj->obj.vtable->domain;
513 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
515 /* We can be sure start_info->obj->tid and
516 * start_info->obj->handle have been set, because the thread
517 * was created suspended, and these values were set before the
521 info = mono_thread_info_current ();
523 internal->thread_info = info;
528 SET_CURRENT_OBJECT (internal);
530 mono_monitor_init_tls ();
532 /* Every thread references the appdomain which created it */
533 mono_thread_push_appdomain_ref (domain);
535 if (!mono_domain_set (domain, FALSE)) {
536 /* No point in raising an appdomain_unloaded exception here */
537 /* FIXME: Cleanup here */
538 mono_thread_pop_appdomain_ref ();
542 start_func = start_info->func;
543 start_arg = start_info->start_arg;
545 /* We have to do this here because mono_thread_new_init()
546 requires that root_domain_thread is set up. */
547 thread_adjust_static_data (internal);
548 init_root_domain_thread (internal, start_info->obj);
550 /* This MUST be called before any managed code can be
551 * executed, as it calls the callback function that (for the
552 * jit) sets the lmf marker.
554 mono_thread_new_init (tid, &tid, start_func);
555 internal->stack_ptr = &tid;
557 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
559 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
561 /* On 2.0 profile (and higher), set explicitly since state might have been
563 if (internal->apartment_state == ThreadApartmentState_Unknown)
564 internal->apartment_state = ThreadApartmentState_MTA;
566 mono_thread_init_apartment_state ();
568 if(internal->start_notify!=NULL) {
569 /* Let the thread that called Start() know we're
572 ReleaseSemaphore (internal->start_notify, 1, NULL);
575 mono_threads_lock ();
576 mono_g_hash_table_remove (thread_start_args, start_info->obj);
577 mono_threads_unlock ();
579 mono_thread_set_execution_context (start_info->obj->ec_to_set);
580 start_info->obj->ec_to_set = NULL;
583 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
587 * Call this after calling start_notify, since the profiler callback might want
588 * to lock the thread, and the lock is held by thread_start () which waits for
591 mono_profiler_thread_start (tid);
593 /* start_func is set only for unmanaged start functions */
595 start_func (start_arg);
598 g_assert (start_delegate != NULL);
599 args [0] = start_arg;
600 /* we may want to handle the exception here. See comment below on unhandled exceptions */
601 mono_runtime_delegate_invoke (start_delegate, args, NULL);
604 /* If the thread calls ExitThread at all, this remaining code
605 * will not be executed, but the main thread will eventually
606 * call thread_cleanup() on this thread's behalf.
609 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
611 thread_cleanup (internal);
613 /* Do any cleanup needed for apartment state. This
614 * cannot be done in thread_cleanup since thread_cleanup could be
615 * called for a thread other than the current thread.
616 * mono_thread_cleanup_apartment_state cleans up apartment
617 * for the current thead */
618 mono_thread_cleanup_apartment_state ();
620 /* Remove the reference to the thread object in the TLS data,
621 * so the thread object can be finalized. This won't be
622 * reached if the thread threw an uncaught exception, so those
623 * thread handles will stay referenced :-( (This is due to
624 * missing support for scanning thread-specific data in the
625 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
628 SET_CURRENT_OBJECT (NULL);
629 mono_domain_unset ();
634 static guint32 WINAPI start_wrapper(void *data)
638 /* Avoid scanning the frames above this frame during a GC */
639 mono_gc_set_stack_end ((void*)&dummy);
641 return start_wrapper_internal (data);
644 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
646 if (mono_thread_start_cb) {
647 mono_thread_start_cb (tid, stack_start, func);
651 void mono_threads_set_default_stacksize (guint32 stacksize)
653 default_stacksize = stacksize;
656 guint32 mono_threads_get_default_stacksize (void)
658 return default_stacksize;
662 * mono_create_thread:
664 * This is a wrapper around CreateThread which handles differences in the type of
665 * the the 'tid' argument.
667 gpointer mono_create_thread (WapiSecurityAttributes *security,
668 guint32 stacksize, WapiThreadStart start,
669 gpointer param, guint32 create, gsize *tid)
676 res = mono_threads_CreateThread (security, stacksize, start, param, create, &real_tid);
680 res = CreateThread (security, stacksize, start, param, create, tid);
687 * The thread start argument may be an object reference, and there is
688 * no ref to keep it alive when the new thread is started but not yet
689 * registered with the collector. So we store it in a GC tracked hash
692 * LOCKING: Assumes the threads lock is held.
695 register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info)
697 if (thread_start_args == NULL) {
698 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
699 thread_start_args = mono_g_hash_table_new (NULL, NULL);
701 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
705 * mono_thread_create_internal:
707 * 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
708 * signalled, which can cause shutdown crashes if the thread shutdown code accesses data already freed by the runtime shutdown.
709 * Currently, this is only used for the finalizer thread.
712 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size)
715 MonoInternalThread *internal;
716 HANDLE thread_handle;
717 struct StartInfo *start_info;
719 guint32 create_flags;
721 thread = create_thread_object (domain);
722 internal = create_internal_thread_object ();
723 MONO_OBJECT_SETREF (thread, internal_thread, internal);
725 start_info=g_new0 (struct StartInfo, 1);
726 start_info->func = func;
727 start_info->obj = thread;
728 start_info->start_arg = arg;
730 mono_threads_lock ();
732 mono_threads_unlock ();
736 if (threads_starting_up == NULL) {
737 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
738 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
741 register_thread_start_argument (thread, start_info);
742 mono_g_hash_table_insert (threads_starting_up, thread, thread);
743 mono_threads_unlock ();
746 stack_size = default_stacksize_for_thread (internal);
748 /* Create suspended, so we can do some housekeeping before the thread
751 create_flags = CREATE_SUSPENDED;
754 create_flags |= CREATE_NO_DETACH;
756 thread_handle = mono_create_thread (NULL, stack_size, (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
758 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
759 if (thread_handle == NULL) {
760 /* The thread couldn't be created, so throw an exception */
761 mono_threads_lock ();
762 mono_g_hash_table_remove (threads_starting_up, thread);
763 mono_threads_unlock ();
765 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
769 internal->handle=thread_handle;
771 internal->apartment_state=ThreadApartmentState_Unknown;
772 internal->managed_id = get_next_managed_thread_id ();
773 if (mono_gc_is_moving ()) {
774 internal->thread_pinning_ref = internal;
775 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
778 internal->synch_cs = g_new0 (CRITICAL_SECTION, 1);
779 InitializeCriticalSection (internal->synch_cs);
781 internal->threadpool_thread = threadpool_thread;
782 if (threadpool_thread)
783 mono_thread_set_state (internal, ThreadState_Background);
785 if (handle_store (thread))
786 ResumeThread (thread_handle);
788 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
789 if (mono_check_corlib_version () == NULL)
790 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
796 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
798 mono_thread_create_internal (domain, func, arg, FALSE, FALSE, 0);
802 * mono_thread_get_stack_bounds:
804 * Return the address and size of the current threads stack. Return NULL as the
805 * stack address if the stack address cannot be determined.
808 mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
810 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
811 *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self ());
812 *stsize = pthread_get_stacksize_np (pthread_self ());
814 /* staddr points to the start of the stack, not the end */
816 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
818 /* FIXME: simplify the mess below */
819 #elif defined(HOST_WIN32)
820 /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */
821 void* tib = (void*)__readfsdword(0x18);
822 guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4);
823 guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8);
825 *staddr = stackBottom;
826 *stsize = stackTop - stackBottom;
830 guint8 *current = (guint8*)&attr;
833 *stsize = (size_t)-1;
835 pthread_attr_init (&attr);
836 # ifdef HAVE_PTHREAD_GETATTR_NP
837 pthread_getattr_np (pthread_self(), &attr);
839 # ifdef HAVE_PTHREAD_ATTR_GET_NP
840 pthread_attr_get_np (pthread_self(), &attr);
843 pthread_attr_getstacksize (&attr, &stsize);
844 # elif defined(__OpenBSD__)
848 rslt = pthread_stackseg_np(pthread_self(), &ss);
849 g_assert (rslt == 0);
851 *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
852 *stsize = ss.ss_size;
861 # if !defined(__OpenBSD__)
862 pthread_attr_getstack (&attr, (void**)staddr, stsize);
865 g_assert ((current > *staddr) && (current < *staddr + *stsize));
868 pthread_attr_destroy (&attr);
871 /* When running under emacs, sometimes staddr is not aligned to a page size */
872 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
876 mono_thread_attach (MonoDomain *domain)
878 MonoInternalThread *thread;
879 MonoThread *current_thread;
880 HANDLE thread_handle;
883 if ((thread = mono_thread_internal_current ())) {
884 if (domain != mono_domain_get ())
885 mono_domain_set (domain, TRUE);
886 /* Already attached */
887 return mono_thread_current ();
890 if (!mono_gc_register_thread (&domain)) {
891 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 ());
894 thread = create_internal_thread_object ();
896 thread_handle = GetCurrentThread ();
897 g_assert (thread_handle);
899 tid=GetCurrentThreadId ();
902 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
903 * refer to the thread from other threads for things like aborting.
905 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
906 THREAD_ALL_ACCESS, TRUE, 0);
908 thread->handle=thread_handle;
910 #ifdef PLATFORM_ANDROID
911 thread->android_tid = (gpointer) gettid ();
913 thread->apartment_state=ThreadApartmentState_Unknown;
914 thread->managed_id = get_next_managed_thread_id ();
915 if (mono_gc_is_moving ()) {
916 thread->thread_pinning_ref = thread;
917 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
920 thread->stack_ptr = &tid;
922 thread->synch_cs = g_new0 (CRITICAL_SECTION, 1);
923 InitializeCriticalSection (thread->synch_cs);
925 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
927 current_thread = new_thread_with_internal (domain, thread);
929 if (!handle_store (current_thread)) {
930 /* Mono is shutting down, so just wait for the end */
935 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
937 SET_CURRENT_OBJECT (thread);
938 mono_domain_set (domain, TRUE);
940 mono_monitor_init_tls ();
942 thread_adjust_static_data (thread);
944 init_root_domain_thread (thread, current_thread);
945 if (domain != mono_get_root_domain ())
946 set_current_thread_for_domain (domain, thread, current_thread);
949 if (mono_thread_attach_cb) {
953 mono_thread_get_stack_bounds (&staddr, &stsize);
956 mono_thread_attach_cb (tid, &tid);
958 mono_thread_attach_cb (tid, staddr + stsize);
961 // FIXME: Need a separate callback
962 mono_profiler_thread_start (tid);
964 return current_thread;
968 mono_thread_detach (MonoThread *thread)
970 g_return_if_fail (thread != NULL);
972 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
974 mono_profiler_thread_end (thread->internal_thread->tid);
976 thread_cleanup (thread->internal_thread);
978 SET_CURRENT_OBJECT (NULL);
979 mono_domain_unset ();
981 /* Don't need to CloseHandle this thread, even though we took a
982 * reference in mono_thread_attach (), because the GC will do it
983 * when the Thread object is finalised.
990 MonoInternalThread *thread = mono_thread_internal_current ();
992 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
994 thread_cleanup (thread);
995 SET_CURRENT_OBJECT (NULL);
996 mono_domain_unset ();
998 /* we could add a callback here for embedders to use. */
999 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1000 exit (mono_environment_exitcode_get ());
1005 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1007 MonoInternalThread *internal = create_internal_thread_object ();
1009 internal->state = ThreadState_Unstarted;
1010 internal->apartment_state = ThreadApartmentState_Unknown;
1011 internal->managed_id = get_next_managed_thread_id ();
1013 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1016 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
1019 guint32 (*start_func)(void *);
1020 struct StartInfo *start_info;
1023 MonoInternalThread *internal;
1025 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1027 if (!this->internal_thread)
1028 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1029 internal = this->internal_thread;
1031 ensure_synch_cs_set (internal);
1033 EnterCriticalSection (internal->synch_cs);
1035 if ((internal->state & ThreadState_Unstarted) == 0) {
1036 LeaveCriticalSection (internal->synch_cs);
1037 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1041 if ((internal->state & ThreadState_Aborted) != 0) {
1042 LeaveCriticalSection (internal->synch_cs);
1047 /* This is freed in start_wrapper */
1048 start_info = g_new0 (struct StartInfo, 1);
1049 start_info->func = start_func;
1050 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1051 start_info->delegate = start;
1052 start_info->obj = this;
1053 g_assert (this->obj.vtable->domain == mono_domain_get ());
1055 internal->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
1056 if (internal->start_notify==NULL) {
1057 LeaveCriticalSection (internal->synch_cs);
1058 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
1059 g_free (start_info);
1063 mono_threads_lock ();
1064 register_thread_start_argument (this, start_info);
1065 if (threads_starting_up == NULL) {
1066 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
1067 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
1069 mono_g_hash_table_insert (threads_starting_up, this, this);
1070 mono_threads_unlock ();
1072 thread=mono_create_thread(NULL, default_stacksize_for_thread (internal), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
1073 CREATE_SUSPENDED, &tid);
1075 LeaveCriticalSection (internal->synch_cs);
1076 mono_threads_lock ();
1077 mono_g_hash_table_remove (threads_starting_up, this);
1078 mono_threads_unlock ();
1079 g_warning("%s: CreateThread error 0x%x", __func__, GetLastError());
1083 internal->handle=thread;
1085 if (mono_gc_is_moving ()) {
1086 internal->thread_pinning_ref = internal;
1087 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
1091 /* Don't call handle_store() here, delay it to Start.
1092 * We can't join a thread (trying to will just block
1093 * forever) until it actually starts running, so don't
1094 * store the handle till then.
1097 mono_thread_start (this);
1099 internal->state &= ~ThreadState_Unstarted;
1101 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1103 LeaveCriticalSection (internal->synch_cs);
1108 void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1110 MONO_ARCH_SAVE_REGS;
1112 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1115 CloseHandle (thread);
1117 if (this->synch_cs) {
1118 CRITICAL_SECTION *synch_cs = this->synch_cs;
1119 this->synch_cs = NULL;
1120 DeleteCriticalSection (synch_cs);
1125 void *name = this->name;
1131 static void mono_thread_start (MonoThread *thread)
1133 MonoInternalThread *internal = thread->internal_thread;
1135 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1137 /* Only store the handle when the thread is about to be
1138 * launched, to avoid the main thread deadlocking while trying
1139 * to clean up a thread that will never be signalled.
1141 if (!handle_store (thread))
1144 ResumeThread (internal->handle);
1146 if(internal->start_notify!=NULL) {
1147 /* Wait for the thread to set up its TLS data etc, so
1148 * theres no potential race condition if someone tries
1149 * to look up the data believing the thread has
1153 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1155 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
1156 CloseHandle (internal->start_notify);
1157 internal->start_notify = NULL;
1160 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1163 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1166 MonoInternalThread *thread = mono_thread_internal_current ();
1168 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1170 mono_thread_current_check_pending_interrupt ();
1173 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1175 res = SleepEx(ms,TRUE);
1177 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1179 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1180 MonoException* exc = mono_thread_execute_interruption (thread);
1182 mono_raise_exception (exc);
1194 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1199 ves_icall_System_Threading_Thread_GetDomainID (void)
1201 MONO_ARCH_SAVE_REGS;
1203 return mono_domain_get()->domain_id;
1207 ves_icall_System_Threading_Thread_Yield (void)
1210 return SwitchToThread ();
1212 return sched_yield () == 0;
1217 * mono_thread_get_name:
1219 * Return the name of the thread. NAME_LEN is set to the length of the name.
1220 * Return NULL if the thread has no name. The returned memory is owned by the
1224 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1228 ensure_synch_cs_set (this_obj);
1230 EnterCriticalSection (this_obj->synch_cs);
1232 if (!this_obj->name) {
1236 *name_len = this_obj->name_len;
1237 res = g_new (gunichar2, this_obj->name_len);
1238 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1241 LeaveCriticalSection (this_obj->synch_cs);
1247 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1251 ensure_synch_cs_set (this_obj);
1253 EnterCriticalSection (this_obj->synch_cs);
1255 if (!this_obj->name)
1258 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1260 LeaveCriticalSection (this_obj->synch_cs);
1266 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1268 ensure_synch_cs_set (this_obj);
1270 EnterCriticalSection (this_obj->synch_cs);
1272 if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1273 LeaveCriticalSection (this_obj->synch_cs);
1275 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1279 this_obj->name = g_new (gunichar2, mono_string_length (name));
1280 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1281 this_obj->name_len = mono_string_length (name);
1284 this_obj->name = NULL;
1287 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1289 LeaveCriticalSection (this_obj->synch_cs);
1290 if (this_obj->name) {
1291 char *tname = mono_string_to_utf8 (name);
1292 mono_profiler_thread_name (this_obj->tid, tname);
1298 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1300 mono_thread_set_name_internal (this_obj, name, TRUE);
1303 /* If the array is already in the requested domain, we just return it,
1304 otherwise we return a copy in that domain. */
1306 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1313 if (mono_object_domain (arr) == domain)
1316 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1317 mono_gc_memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1322 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1324 return byte_array_to_domain (arr, mono_get_root_domain ());
1328 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1330 return byte_array_to_domain (arr, mono_domain_get ());
1334 mono_thread_current (void)
1336 MonoDomain *domain = mono_domain_get ();
1337 MonoInternalThread *internal = mono_thread_internal_current ();
1338 MonoThread **current_thread_ptr;
1340 g_assert (internal);
1341 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1343 if (!*current_thread_ptr) {
1344 g_assert (domain != mono_get_root_domain ());
1345 *current_thread_ptr = new_thread_with_internal (domain, internal);
1347 return *current_thread_ptr;
1351 mono_thread_internal_current (void)
1353 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1354 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1358 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1359 int ms, HANDLE thread)
1361 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1364 mono_thread_current_check_pending_interrupt ();
1366 ensure_synch_cs_set (this);
1368 EnterCriticalSection (this->synch_cs);
1370 if ((this->state & ThreadState_Unstarted) != 0) {
1371 LeaveCriticalSection (this->synch_cs);
1373 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1377 LeaveCriticalSection (this->synch_cs);
1382 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1384 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1386 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1388 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1390 if(ret==WAIT_OBJECT_0) {
1391 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1396 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1402 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1410 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1413 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1415 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1417 if (ret != WAIT_IO_COMPLETION)
1420 exc = mono_thread_execute_interruption (thread);
1422 mono_raise_exception (exc);
1427 /* Re-calculate ms according to the time passed */
1428 diff_ms = (mono_100ns_ticks () - start) / 10000;
1429 if (diff_ms >= ms) {
1433 wait = ms - diff_ms;
1439 /* FIXME: exitContext isnt documented */
1440 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1446 MonoObject *waitHandle;
1447 MonoInternalThread *thread = mono_thread_internal_current ();
1449 /* Do this WaitSleepJoin check before creating objects */
1450 mono_thread_current_check_pending_interrupt ();
1452 numhandles = mono_array_length(mono_handles);
1453 handles = g_new0(HANDLE, numhandles);
1455 for(i = 0; i < numhandles; i++) {
1456 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1457 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1464 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1466 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1468 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1472 if(ret==WAIT_FAILED) {
1473 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1475 } else if(ret==WAIT_TIMEOUT) {
1476 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1483 /* FIXME: exitContext isnt documented */
1484 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1486 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1490 MonoObject *waitHandle;
1491 MonoInternalThread *thread = mono_thread_internal_current ();
1493 /* Do this WaitSleepJoin check before creating objects */
1494 mono_thread_current_check_pending_interrupt ();
1496 numhandles = mono_array_length(mono_handles);
1497 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1500 for(i = 0; i < numhandles; i++) {
1501 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1502 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1509 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1511 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1513 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1515 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1518 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1520 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1521 return ret - WAIT_OBJECT_0;
1523 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1524 return ret - WAIT_ABANDONED_0;
1531 /* FIXME: exitContext isnt documented */
1532 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1535 MonoInternalThread *thread = mono_thread_internal_current ();
1537 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1543 mono_thread_current_check_pending_interrupt ();
1545 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1547 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1549 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1551 if(ret==WAIT_FAILED) {
1552 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1554 } else if(ret==WAIT_TIMEOUT) {
1555 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1563 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1566 MonoInternalThread *thread = mono_thread_internal_current ();
1568 MONO_ARCH_SAVE_REGS;
1573 mono_thread_current_check_pending_interrupt ();
1575 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1577 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1579 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1581 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1584 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1588 MONO_ARCH_SAVE_REGS;
1593 mutex = CreateMutex (NULL, owned, NULL);
1595 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1597 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1605 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1606 MONO_ARCH_SAVE_REGS;
1608 return(ReleaseMutex (handle));
1611 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1617 MONO_ARCH_SAVE_REGS;
1619 *error = ERROR_SUCCESS;
1621 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1623 *error = GetLastError ();
1630 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1634 MONO_ARCH_SAVE_REGS;
1639 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1641 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1642 mono_string_chars (name));
1644 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1652 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1656 MONO_ARCH_SAVE_REGS;
1658 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1663 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1667 MONO_ARCH_SAVE_REGS;
1669 *error = ERROR_SUCCESS;
1671 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1673 *error = GetLastError ();
1679 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1683 MONO_ARCH_SAVE_REGS;
1688 event = CreateEvent (NULL, manual, initial, NULL);
1690 event = CreateEvent (NULL, manual, initial,
1691 mono_string_chars (name));
1693 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1701 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1702 MONO_ARCH_SAVE_REGS;
1704 return (SetEvent(handle));
1707 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1708 MONO_ARCH_SAVE_REGS;
1710 return (ResetEvent(handle));
1714 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1715 MONO_ARCH_SAVE_REGS;
1717 CloseHandle (handle);
1720 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1726 MONO_ARCH_SAVE_REGS;
1728 *error = ERROR_SUCCESS;
1730 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1732 *error = GetLastError ();
1738 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1740 MONO_ARCH_SAVE_REGS;
1742 return InterlockedIncrement (location);
1745 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1749 MONO_ARCH_SAVE_REGS;
1751 mono_interlocked_lock ();
1755 mono_interlocked_unlock ();
1761 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1763 MONO_ARCH_SAVE_REGS;
1765 return InterlockedDecrement(location);
1768 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1772 MONO_ARCH_SAVE_REGS;
1774 mono_interlocked_lock ();
1778 mono_interlocked_unlock ();
1783 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1785 MONO_ARCH_SAVE_REGS;
1787 return InterlockedExchange(location, value);
1790 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1793 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1794 mono_gc_wbarrier_generic_nostore (location);
1798 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1800 return InterlockedExchangePointer(location, value);
1803 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1805 IntFloatUnion val, ret;
1807 MONO_ARCH_SAVE_REGS;
1810 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1816 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1818 #if SIZEOF_VOID_P == 8
1819 return (gint64) InterlockedExchangePointer((gpointer *) location, (gpointer)value);
1824 * According to MSDN, this function is only atomic with regards to the
1825 * other Interlocked functions on 32 bit platforms.
1827 mono_interlocked_lock ();
1830 mono_interlocked_unlock ();
1837 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1839 #if SIZEOF_VOID_P == 8
1840 LongDoubleUnion val, ret;
1843 ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location, (gpointer)val.ival);
1850 * According to MSDN, this function is only atomic with regards to the
1851 * other Interlocked functions on 32 bit platforms.
1853 mono_interlocked_lock ();
1856 mono_interlocked_unlock ();
1862 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1864 MONO_ARCH_SAVE_REGS;
1866 return InterlockedCompareExchange(location, value, comparand);
1869 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1872 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1873 mono_gc_wbarrier_generic_nostore (location);
1877 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1879 return InterlockedCompareExchangePointer(location, value, comparand);
1882 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1884 IntFloatUnion val, ret, cmp;
1886 MONO_ARCH_SAVE_REGS;
1889 cmp.fval = comparand;
1890 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1896 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1898 #if SIZEOF_VOID_P == 8
1899 LongDoubleUnion val, comp, ret;
1902 comp.fval = comparand;
1903 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1909 mono_interlocked_lock ();
1911 if (old == comparand)
1913 mono_interlocked_unlock ();
1920 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1922 #if SIZEOF_VOID_P == 8
1923 return (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)value, (gpointer)comparand);
1927 mono_interlocked_lock ();
1929 if (old == comparand)
1931 mono_interlocked_unlock ();
1938 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1941 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1942 mono_gc_wbarrier_generic_nostore (location);
1947 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1950 res = InterlockedExchangePointer ((gpointer *)location, value);
1951 mono_gc_wbarrier_generic_nostore (location);
1956 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1958 #if SIZEOF_VOID_P == 8
1959 /* Should be implemented as a JIT intrinsic */
1960 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1965 mono_interlocked_lock ();
1967 *location = orig + value;
1968 mono_interlocked_unlock ();
1970 return orig + value;
1975 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1977 #if SIZEOF_VOID_P == 8
1978 /* Should be implemented as a JIT intrinsic */
1979 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1984 mono_interlocked_lock ();
1986 *location = orig + value;
1987 mono_interlocked_unlock ();
1989 return orig + value;
1994 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1996 #if SIZEOF_VOID_P == 8
1997 /* 64 bit reads are already atomic */
2002 mono_interlocked_lock ();
2004 mono_interlocked_unlock ();
2011 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2013 mono_threads_lock ();
2014 mono_threads_unlock ();
2018 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
2020 mono_thread_clr_state (this, state);
2022 if (state & ThreadState_Background) {
2023 /* If the thread changes the background mode, the main thread has to
2024 * be notified, since it has to rebuild the list of threads to
2027 SetEvent (background_change_event);
2032 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
2034 mono_thread_set_state (this, state);
2036 if (state & ThreadState_Background) {
2037 /* If the thread changes the background mode, the main thread has to
2038 * be notified, since it has to rebuild the list of threads to
2041 SetEvent (background_change_event);
2046 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2050 ensure_synch_cs_set (this);
2052 EnterCriticalSection (this->synch_cs);
2054 state = this->state;
2056 LeaveCriticalSection (this->synch_cs);
2061 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
2063 MonoInternalThread *current;
2066 ensure_synch_cs_set (this);
2068 current = mono_thread_internal_current ();
2070 EnterCriticalSection (this->synch_cs);
2072 this->thread_interrupt_requested = TRUE;
2073 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
2075 LeaveCriticalSection (this->synch_cs);
2078 abort_thread_internal (this, TRUE, FALSE);
2082 void mono_thread_current_check_pending_interrupt ()
2084 MonoInternalThread *thread = mono_thread_internal_current ();
2085 gboolean throw = FALSE;
2087 mono_debugger_check_interruption ();
2089 ensure_synch_cs_set (thread);
2091 EnterCriticalSection (thread->synch_cs);
2093 if (thread->thread_interrupt_requested) {
2095 thread->thread_interrupt_requested = FALSE;
2098 LeaveCriticalSection (thread->synch_cs);
2101 mono_raise_exception (mono_get_exception_thread_interrupted ());
2106 mono_thread_get_abort_signal (void)
2110 #elif defined(PLATFORM_ANDROID)
2112 #elif !defined (SIGRTMIN)
2117 #endif /* SIGUSR1 */
2119 static int abort_signum = -1;
2121 if (abort_signum != -1)
2122 return abort_signum;
2123 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2124 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2125 struct sigaction sinfo;
2126 sigaction (i, NULL, &sinfo);
2127 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2132 /* fallback to the old way */
2134 #endif /* HOST_WIN32 */
2138 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2140 MonoException* exc = mono_thread_request_interruption (FALSE);
2141 if (exc) mono_raise_exception (exc);
2143 #endif /* HOST_WIN32 */
2146 * signal_thread_state_change
2148 * Tells the thread that his state has changed and it has to enter the new
2149 * state as soon as possible.
2151 static void signal_thread_state_change (MonoInternalThread *thread)
2153 if (thread == mono_thread_internal_current ()) {
2154 /* Do it synchronously */
2155 MonoException *exc = mono_thread_request_interruption (FALSE);
2157 mono_raise_exception (exc);
2161 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
2163 /* fixme: store the state somewhere */
2164 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2167 * This will cause waits to be broken.
2168 * It will also prevent the thread from entering a wait, so if the thread returns
2169 * from the wait before it receives the abort signal, it will just spin in the wait
2170 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2173 wapi_interrupt_thread (thread->handle);
2174 #endif /* HOST_WIN32 */
2178 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2180 ensure_synch_cs_set (thread);
2182 EnterCriticalSection (thread->synch_cs);
2184 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2185 (thread->state & ThreadState_StopRequested) != 0 ||
2186 (thread->state & ThreadState_Stopped) != 0)
2188 LeaveCriticalSection (thread->synch_cs);
2192 if ((thread->state & ThreadState_Unstarted) != 0) {
2193 thread->state |= ThreadState_Aborted;
2194 LeaveCriticalSection (thread->synch_cs);
2198 thread->state |= ThreadState_AbortRequested;
2199 if (thread->abort_state_handle)
2200 mono_gchandle_free (thread->abort_state_handle);
2202 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2203 g_assert (thread->abort_state_handle);
2205 thread->abort_state_handle = 0;
2207 thread->abort_exc = NULL;
2210 * abort_exc is set in mono_thread_execute_interruption(),
2211 * triggered by the call to signal_thread_state_change(),
2212 * below. There's a point between where we have
2213 * abort_state_handle set, but abort_exc NULL, but that's not
2217 LeaveCriticalSection (thread->synch_cs);
2219 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2221 /* During shutdown, we can't wait for other threads */
2223 /* Make sure the thread is awake */
2224 mono_thread_resume (thread);
2226 abort_thread_internal (thread, TRUE, TRUE);
2230 ves_icall_System_Threading_Thread_ResetAbort (void)
2232 MonoInternalThread *thread = mono_thread_internal_current ();
2233 gboolean was_aborting;
2235 ensure_synch_cs_set (thread);
2237 EnterCriticalSection (thread->synch_cs);
2238 was_aborting = thread->state & ThreadState_AbortRequested;
2239 thread->state &= ~ThreadState_AbortRequested;
2240 LeaveCriticalSection (thread->synch_cs);
2242 if (!was_aborting) {
2243 const char *msg = "Unable to reset abort because no abort was requested";
2244 mono_raise_exception (mono_get_exception_thread_state (msg));
2246 thread->abort_exc = NULL;
2247 if (thread->abort_state_handle) {
2248 mono_gchandle_free (thread->abort_state_handle);
2249 /* This is actually not necessary - the handle
2250 only counts if the exception is set */
2251 thread->abort_state_handle = 0;
2256 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2258 ensure_synch_cs_set (thread);
2260 EnterCriticalSection (thread->synch_cs);
2262 thread->state &= ~ThreadState_AbortRequested;
2264 if (thread->abort_exc) {
2265 thread->abort_exc = NULL;
2266 if (thread->abort_state_handle) {
2267 mono_gchandle_free (thread->abort_state_handle);
2268 /* This is actually not necessary - the handle
2269 only counts if the exception is set */
2270 thread->abort_state_handle = 0;
2274 LeaveCriticalSection (thread->synch_cs);
2278 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2280 MonoInternalThread *thread = this->internal_thread;
2281 MonoObject *state, *deserialized = NULL, *exc;
2284 if (!thread->abort_state_handle)
2287 state = mono_gchandle_get_target (thread->abort_state_handle);
2290 domain = mono_domain_get ();
2291 if (mono_object_domain (state) == domain)
2294 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2296 if (!deserialized) {
2297 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2299 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2300 mono_raise_exception (invalid_op_exc);
2303 return deserialized;
2307 mono_thread_suspend (MonoInternalThread *thread)
2309 ensure_synch_cs_set (thread);
2311 EnterCriticalSection (thread->synch_cs);
2313 if ((thread->state & ThreadState_Unstarted) != 0 ||
2314 (thread->state & ThreadState_Aborted) != 0 ||
2315 (thread->state & ThreadState_Stopped) != 0)
2317 LeaveCriticalSection (thread->synch_cs);
2321 if ((thread->state & ThreadState_Suspended) != 0 ||
2322 (thread->state & ThreadState_SuspendRequested) != 0 ||
2323 (thread->state & ThreadState_StopRequested) != 0)
2325 LeaveCriticalSection (thread->synch_cs);
2329 thread->state |= ThreadState_SuspendRequested;
2331 LeaveCriticalSection (thread->synch_cs);
2333 suspend_thread_internal (thread, FALSE);
2338 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2340 if (!mono_thread_suspend (thread))
2341 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2345 mono_thread_resume (MonoInternalThread *thread)
2347 ensure_synch_cs_set (thread);
2349 EnterCriticalSection (thread->synch_cs);
2351 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2352 thread->state &= ~ThreadState_SuspendRequested;
2353 LeaveCriticalSection (thread->synch_cs);
2357 if ((thread->state & ThreadState_Suspended) == 0 ||
2358 (thread->state & ThreadState_Unstarted) != 0 ||
2359 (thread->state & ThreadState_Aborted) != 0 ||
2360 (thread->state & ThreadState_Stopped) != 0)
2362 LeaveCriticalSection (thread->synch_cs);
2366 return resume_thread_internal (thread);
2370 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2372 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2373 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2377 mono_threads_is_critical_method (MonoMethod *method)
2379 switch (method->wrapper_type) {
2380 case MONO_WRAPPER_RUNTIME_INVOKE:
2381 case MONO_WRAPPER_XDOMAIN_INVOKE:
2382 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2389 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2394 if (mono_threads_is_critical_method (m)) {
2395 *((gboolean*)data) = TRUE;
2402 is_running_protected_wrapper (void)
2404 gboolean found = FALSE;
2405 mono_stack_walk (find_wrapper, &found);
2409 void mono_thread_internal_stop (MonoInternalThread *thread)
2411 ensure_synch_cs_set (thread);
2413 EnterCriticalSection (thread->synch_cs);
2415 if ((thread->state & ThreadState_StopRequested) != 0 ||
2416 (thread->state & ThreadState_Stopped) != 0)
2418 LeaveCriticalSection (thread->synch_cs);
2422 /* Make sure the thread is awake */
2423 mono_thread_resume (thread);
2425 thread->state |= ThreadState_StopRequested;
2426 thread->state &= ~ThreadState_AbortRequested;
2428 LeaveCriticalSection (thread->synch_cs);
2430 abort_thread_internal (thread, TRUE, TRUE);
2433 void mono_thread_stop (MonoThread *thread)
2435 mono_thread_internal_stop (thread->internal_thread);
2439 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2441 return *((volatile gint8 *) (ptr));
2445 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2447 return *((volatile gint16 *) (ptr));
2451 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2453 return *((volatile gint32 *) (ptr));
2457 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2459 return *((volatile gint64 *) (ptr));
2463 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2465 return (void *) *((volatile void **) ptr);
2469 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2471 return *((volatile double *) (ptr));
2475 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2477 return *((volatile float *) (ptr));
2481 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2483 return (MonoObject*)*((volatile MonoObject**)ptr);
2487 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2489 *((volatile gint8 *) ptr) = value;
2493 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2495 *((volatile gint16 *) ptr) = value;
2499 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2501 *((volatile gint32 *) ptr) = value;
2505 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2507 *((volatile gint64 *) ptr) = value;
2511 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2513 *((volatile void **) ptr) = value;
2517 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, void *value)
2519 mono_gc_wbarrier_generic_store (ptr, value);
2523 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2525 *((volatile double *) ptr) = value;
2529 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2531 *((volatile float *) ptr) = value;
2535 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2537 *((volatile MonoObject **) ptr) = value;
2538 mono_gc_wbarrier_generic_nostore (ptr);
2541 void mono_thread_init (MonoThreadStartCB start_cb,
2542 MonoThreadAttachCB attach_cb)
2544 InitializeCriticalSection(&threads_mutex);
2545 InitializeCriticalSection(&interlocked_mutex);
2546 InitializeCriticalSection(&contexts_mutex);
2548 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2549 g_assert(background_change_event != NULL);
2551 mono_init_static_data_info (&thread_static_info);
2552 mono_init_static_data_info (&context_static_info);
2554 MONO_FAST_TLS_INIT (tls_current_object);
2555 mono_native_tls_alloc (¤t_object_key, NULL);
2556 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2558 mono_thread_start_cb = start_cb;
2559 mono_thread_attach_cb = attach_cb;
2561 /* Get a pseudo handle to the current process. This is just a
2562 * kludge so that wapi can build a process handle if needed.
2563 * As a pseudo handle is returned, we don't need to clean
2566 GetCurrentProcess ();
2569 void mono_thread_cleanup (void)
2571 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2572 /* The main thread must abandon any held mutexes (particularly
2573 * important for named mutexes as they are shared across
2574 * processes, see bug 74680.) This will happen when the
2575 * thread exits, but if it's not running in a subthread it
2576 * won't exit in time.
2578 /* Using non-w32 API is a nasty kludge, but I couldn't find
2579 * anything in the documentation that would let me do this
2580 * here yet still be safe to call on windows.
2582 _wapi_thread_signal_self (mono_environment_exitcode_get ());
2586 /* This stuff needs more testing, it seems one of these
2587 * critical sections can be locked when mono_thread_cleanup is
2590 DeleteCriticalSection (&threads_mutex);
2591 DeleteCriticalSection (&interlocked_mutex);
2592 DeleteCriticalSection (&contexts_mutex);
2593 DeleteCriticalSection (&delayed_free_table_mutex);
2594 DeleteCriticalSection (&small_id_mutex);
2595 CloseHandle (background_change_event);
2598 mono_native_tls_free (current_object_key);
2602 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2604 mono_thread_cleanup_fn = func;
2608 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2610 thread->internal_thread->manage_callback = func;
2613 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2615 mono_thread_notify_pending_exc_fn = func;
2619 static void print_tids (gpointer key, gpointer value, gpointer user)
2621 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2622 * sizeof(uint) and a cast to uint would overflow
2624 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2625 * print this as a pointer.
2627 g_message ("Waiting for: %p", key);
2632 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2633 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2637 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2641 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2643 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2645 if(ret==WAIT_FAILED) {
2646 /* See the comment in build_wait_tids() */
2647 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2651 for(i=0; i<wait->num; i++)
2652 CloseHandle (wait->handles[i]);
2654 if (ret == WAIT_TIMEOUT)
2657 for(i=0; i<wait->num; i++) {
2658 gsize tid = wait->threads[i]->tid;
2660 mono_threads_lock ();
2661 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2662 /* This thread must have been killed, because
2663 * it hasn't cleaned itself up. (It's just
2664 * possible that the thread exited before the
2665 * parent thread had a chance to store the
2666 * handle, and now there is another pointer to
2667 * the already-exited thread stored. In this
2668 * case, we'll just get two
2669 * mono_profiler_thread_end() calls for the
2673 mono_threads_unlock ();
2674 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2675 thread_cleanup (wait->threads[i]);
2677 mono_threads_unlock ();
2682 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2684 guint32 i, ret, count;
2686 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2688 /* Add the thread state change event, so it wakes up if a thread changes
2689 * to background mode.
2692 if (count < MAXIMUM_WAIT_OBJECTS) {
2693 wait->handles [count] = background_change_event;
2697 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2699 if(ret==WAIT_FAILED) {
2700 /* See the comment in build_wait_tids() */
2701 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2705 for(i=0; i<wait->num; i++)
2706 CloseHandle (wait->handles[i]);
2708 if (ret == WAIT_TIMEOUT)
2711 if (ret < wait->num) {
2712 gsize tid = wait->threads[ret]->tid;
2713 mono_threads_lock ();
2714 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2715 /* See comment in wait_for_tids about thread cleanup */
2716 mono_threads_unlock ();
2717 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2718 thread_cleanup (wait->threads [ret]);
2720 mono_threads_unlock ();
2724 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2726 struct wait_data *wait=(struct wait_data *)user;
2728 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2730 MonoInternalThread *thread=(MonoInternalThread *)value;
2732 /* Ignore background threads, we abort them later */
2733 /* Do not lock here since it is not needed and the caller holds threads_lock */
2734 if (thread->state & ThreadState_Background) {
2735 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2736 return; /* just leave, ignore */
2739 if (mono_gc_is_finalizer_internal_thread (thread)) {
2740 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2744 if (thread == mono_thread_internal_current ()) {
2745 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2749 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2750 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2754 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2755 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2759 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2760 if (handle == NULL) {
2761 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2765 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2766 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2767 wait->handles[wait->num]=handle;
2768 wait->threads[wait->num]=thread;
2771 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2773 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2778 /* Just ignore the rest, we can't do anything with
2785 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2787 struct wait_data *wait=(struct wait_data *)user;
2788 gsize self = GetCurrentThreadId ();
2789 MonoInternalThread *thread = value;
2792 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2795 /* The finalizer thread is not a background thread */
2796 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2797 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2799 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2803 /* printf ("A: %d\n", wait->num); */
2804 wait->handles[wait->num]=thread->handle;
2805 wait->threads[wait->num]=thread;
2808 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2809 mono_thread_internal_stop (thread);
2813 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2817 * mono_threads_set_shutting_down:
2819 * Is called by a thread that wants to shut down Mono. If the runtime is already
2820 * shutting down, the calling thread is suspended/stopped, and this function never
2824 mono_threads_set_shutting_down (void)
2826 MonoInternalThread *current_thread = mono_thread_internal_current ();
2828 mono_threads_lock ();
2830 if (shutting_down) {
2831 mono_threads_unlock ();
2833 /* Make sure we're properly suspended/stopped */
2835 EnterCriticalSection (current_thread->synch_cs);
2837 if ((current_thread->state & ThreadState_SuspendRequested) ||
2838 (current_thread->state & ThreadState_AbortRequested) ||
2839 (current_thread->state & ThreadState_StopRequested)) {
2840 LeaveCriticalSection (current_thread->synch_cs);
2841 mono_thread_execute_interruption (current_thread);
2843 current_thread->state |= ThreadState_Stopped;
2844 LeaveCriticalSection (current_thread->synch_cs);
2847 /*since we're killing the thread, unset the current domain.*/
2848 mono_domain_unset ();
2850 /* Wake up other threads potentially waiting for us */
2853 shutting_down = TRUE;
2855 /* Not really a background state change, but this will
2856 * interrupt the main thread if it is waiting for all
2857 * the other threads.
2859 SetEvent (background_change_event);
2861 mono_threads_unlock ();
2866 * mono_threads_is_shutting_down:
2868 * Returns whether a thread has commenced shutdown of Mono. Note that
2869 * if the function returns FALSE the caller must not assume that
2870 * shutdown is not in progress, because the situation might have
2871 * changed since the function returned. For that reason this function
2872 * is of very limited utility.
2875 mono_threads_is_shutting_down (void)
2877 return shutting_down;
2880 void mono_thread_manage (void)
2882 struct wait_data wait_data;
2883 struct wait_data *wait = &wait_data;
2885 memset (wait, 0, sizeof (struct wait_data));
2886 /* join each thread that's still running */
2887 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2889 mono_threads_lock ();
2891 THREAD_DEBUG (g_message("%s: No threads", __func__));
2892 mono_threads_unlock ();
2895 mono_threads_unlock ();
2898 mono_threads_lock ();
2899 if (shutting_down) {
2900 /* somebody else is shutting down */
2901 mono_threads_unlock ();
2904 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2905 mono_g_hash_table_foreach (threads, print_tids, NULL));
2907 ResetEvent (background_change_event);
2909 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2910 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2911 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2912 mono_threads_unlock ();
2914 /* Something to wait for */
2915 wait_for_tids_or_state_change (wait, INFINITE);
2917 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2918 } while(wait->num>0);
2920 mono_runtime_shutdown ();
2922 THREAD_DEBUG (g_message ("%s: threadpool cleanup", __func__));
2923 mono_thread_pool_cleanup ();
2926 * Remove everything but the finalizer thread and self.
2927 * Also abort all the background threads
2930 mono_threads_lock ();
2933 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2934 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2935 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2937 mono_threads_unlock ();
2939 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2941 /* Something to wait for */
2942 wait_for_tids (wait, INFINITE);
2944 } while (wait->num > 0);
2947 * give the subthreads a chance to really quit (this is mainly needed
2948 * to get correct user and system times from getrusage/wait/time(1)).
2949 * This could be removed if we avoid pthread_detach() and use pthread_join().
2956 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2958 MonoInternalThread *thread=(MonoInternalThread *)value;
2960 if(thread->tid != (gsize)user) {
2961 /*TerminateThread (thread->handle, -1);*/
2965 void mono_thread_abort_all_other_threads (void)
2967 gsize self = GetCurrentThreadId ();
2969 mono_threads_lock ();
2970 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2971 mono_g_hash_table_size (threads));
2972 mono_g_hash_table_foreach (threads, print_tids, NULL));
2974 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2976 mono_threads_unlock ();
2980 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2982 MonoInternalThread *thread = (MonoInternalThread*)value;
2983 struct wait_data *wait = (struct wait_data*)user_data;
2987 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
2989 * This needs no locking.
2991 if ((thread->state & ThreadState_Suspended) != 0 ||
2992 (thread->state & ThreadState_Stopped) != 0)
2995 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2996 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3000 wait->handles [wait->num] = handle;
3001 wait->threads [wait->num] = thread;
3007 * mono_thread_suspend_all_other_threads:
3009 * Suspend all managed threads except the finalizer thread and this thread. It is
3010 * not possible to resume them later.
3012 void mono_thread_suspend_all_other_threads (void)
3014 struct wait_data wait_data;
3015 struct wait_data *wait = &wait_data;
3017 gsize self = GetCurrentThreadId ();
3019 guint32 eventidx = 0;
3020 gboolean starting, finished;
3022 memset (wait, 0, sizeof (struct wait_data));
3024 * The other threads could be in an arbitrary state at this point, i.e.
3025 * they could be starting up, shutting down etc. This means that there could be
3026 * threads which are not even in the threads hash table yet.
3030 * First we set a barrier which will be checked by all threads before they
3031 * are added to the threads hash table, and they will exit if the flag is set.
3032 * This ensures that no threads could be added to the hash later.
3033 * We will use shutting_down as the barrier for now.
3035 g_assert (shutting_down);
3038 * We make multiple calls to WaitForMultipleObjects since:
3039 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3040 * - some threads could exit without becoming suspended
3045 * Make a copy of the hashtable since we can't do anything with
3046 * threads while threads_mutex is held.
3049 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3050 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3051 mono_threads_lock ();
3052 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3053 mono_threads_unlock ();
3055 events = g_new0 (gpointer, wait->num);
3057 /* Get the suspended events that we'll be waiting for */
3058 for (i = 0; i < wait->num; ++i) {
3059 MonoInternalThread *thread = wait->threads [i];
3060 gboolean signal_suspend = FALSE;
3062 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3063 //CloseHandle (wait->handles [i]);
3064 wait->threads [i] = NULL; /* ignore this thread in next loop */
3068 ensure_synch_cs_set (thread);
3070 EnterCriticalSection (thread->synch_cs);
3072 if (thread->suspended_event == NULL) {
3073 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3074 if (thread->suspended_event == NULL) {
3075 /* Forget this one and go on to the next */
3076 LeaveCriticalSection (thread->synch_cs);
3081 if ((thread->state & ThreadState_Suspended) != 0 ||
3082 (thread->state & ThreadState_StopRequested) != 0 ||
3083 (thread->state & ThreadState_Stopped) != 0) {
3084 LeaveCriticalSection (thread->synch_cs);
3085 CloseHandle (wait->handles [i]);
3086 wait->threads [i] = NULL; /* ignore this thread in next loop */
3090 if ((thread->state & ThreadState_SuspendRequested) == 0)
3091 signal_suspend = TRUE;
3093 events [eventidx++] = thread->suspended_event;
3095 /* Convert abort requests into suspend requests */
3096 if ((thread->state & ThreadState_AbortRequested) != 0)
3097 thread->state &= ~ThreadState_AbortRequested;
3099 thread->state |= ThreadState_SuspendRequested;
3101 LeaveCriticalSection (thread->synch_cs);
3103 /* Signal the thread to suspend */
3104 if (mono_thread_info_new_interrupt_enabled ())
3105 suspend_thread_internal (thread, TRUE);
3106 else if (signal_suspend)
3107 signal_thread_state_change (thread);
3110 /*Only wait on the suspend event if we are using the old path */
3111 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3112 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3113 for (i = 0; i < wait->num; ++i) {
3114 MonoInternalThread *thread = wait->threads [i];
3119 ensure_synch_cs_set (thread);
3121 EnterCriticalSection (thread->synch_cs);
3122 if ((thread->state & ThreadState_Suspended) != 0) {
3123 CloseHandle (thread->suspended_event);
3124 thread->suspended_event = NULL;
3126 LeaveCriticalSection (thread->synch_cs);
3130 if (eventidx <= 0) {
3132 * If there are threads which are starting up, we wait until they
3133 * are suspended when they try to register in the threads hash.
3134 * This is guaranteed to finish, since the threads which can create new
3135 * threads get suspended after a while.
3136 * FIXME: The finalizer thread can still create new threads.
3138 mono_threads_lock ();
3139 if (threads_starting_up)
3140 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3143 mono_threads_unlock ();
3155 collect_threads (gpointer key, gpointer value, gpointer user_data)
3157 MonoInternalThread *thread = (MonoInternalThread*)value;
3158 struct wait_data *wait = (struct wait_data*)user_data;
3161 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3162 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3166 wait->handles [wait->num] = handle;
3167 wait->threads [wait->num] = thread;
3172 static gboolean thread_dump_requested;
3174 static G_GNUC_UNUSED gboolean
3175 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3177 GString *p = (GString*)data;
3178 MonoMethod *method = NULL;
3180 method = frame->ji->method;
3183 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3184 g_string_append_printf (p, " %s\n", location);
3187 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3193 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3195 GString* text = g_string_new (0);
3197 GError *error = NULL;
3200 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3202 g_string_append_printf (text, "\n\"%s\"", name);
3205 else if (thread->threadpool_thread)
3206 g_string_append (text, "\n\"<threadpool thread>\"");
3208 g_string_append (text, "\n\"<unnamed thread>\"");
3211 /* This no longer works with remote unwinding */
3213 wapi_desc = wapi_current_thread_desc ();
3214 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3219 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3220 mono_thread_info_resume (mono_thread_info_get_tid (info));
3222 fprintf (stdout, "%s", text->str);
3224 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3225 OutputDebugStringA(text->str);
3228 g_string_free (text, TRUE);
3233 dump_thread (gpointer key, gpointer value, gpointer user)
3235 MonoInternalThread *thread = (MonoInternalThread *)value;
3236 MonoThreadInfo *info;
3238 if (thread == mono_thread_internal_current ())
3242 FIXME This still can hang if we stop a thread during malloc.
3243 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3244 that takes a callback and runs it with the target suspended.
3245 We probably should loop a bit around trying to get it to either managed code
3248 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3253 print_thread_dump (thread, info);
3257 mono_threads_perform_thread_dump (void)
3259 if (!thread_dump_requested)
3262 printf ("Full thread dump:\n");
3265 * Make a copy of the hashtable since we can't do anything with
3266 * threads while threads_mutex is held.
3268 mono_threads_lock ();
3269 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3270 mono_threads_unlock ();
3272 thread_dump_requested = FALSE;
3276 * mono_threads_request_thread_dump:
3278 * Ask all threads except the current to print their stacktrace to stdout.
3281 mono_threads_request_thread_dump (void)
3283 struct wait_data wait_data;
3284 struct wait_data *wait = &wait_data;
3287 /*The new thread dump code runs out of the finalizer thread. */
3288 if (mono_thread_info_new_interrupt_enabled ()) {
3289 thread_dump_requested = TRUE;
3290 mono_gc_finalize_notify ();
3295 memset (wait, 0, sizeof (struct wait_data));
3298 * Make a copy of the hashtable since we can't do anything with
3299 * threads while threads_mutex is held.
3301 mono_threads_lock ();
3302 mono_g_hash_table_foreach (threads, collect_threads, wait);
3303 mono_threads_unlock ();
3305 for (i = 0; i < wait->num; ++i) {
3306 MonoInternalThread *thread = wait->threads [i];
3308 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3309 (thread != mono_thread_internal_current ()) &&
3310 !thread->thread_dump_requested) {
3311 thread->thread_dump_requested = TRUE;
3313 signal_thread_state_change (thread);
3316 CloseHandle (wait->handles [i]);
3322 gint allocated; /* +1 so that refs [allocated] == NULL */
3326 typedef struct ref_stack RefStack;
3329 ref_stack_new (gint initial_size)
3333 initial_size = MAX (initial_size, 16) + 1;
3334 rs = g_new0 (RefStack, 1);
3335 rs->refs = g_new0 (gpointer, initial_size);
3336 rs->allocated = initial_size;
3341 ref_stack_destroy (gpointer ptr)
3352 ref_stack_push (RefStack *rs, gpointer ptr)
3354 g_assert (rs != NULL);
3356 if (rs->bottom >= rs->allocated) {
3357 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3358 rs->allocated <<= 1;
3359 rs->refs [rs->allocated] = NULL;
3361 rs->refs [rs->bottom++] = ptr;
3365 ref_stack_pop (RefStack *rs)
3367 if (rs == NULL || rs->bottom == 0)
3371 rs->refs [rs->bottom] = NULL;
3375 ref_stack_find (RefStack *rs, gpointer ptr)
3382 for (refs = rs->refs; refs && *refs; refs++) {
3390 * mono_thread_push_appdomain_ref:
3392 * Register that the current thread may have references to objects in domain
3393 * @domain on its stack. Each call to this function should be paired with a
3394 * call to pop_appdomain_ref.
3397 mono_thread_push_appdomain_ref (MonoDomain *domain)
3399 MonoInternalThread *thread = mono_thread_internal_current ();
3402 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3403 SPIN_LOCK (thread->lock_thread_id);
3404 if (thread->appdomain_refs == NULL)
3405 thread->appdomain_refs = ref_stack_new (16);
3406 ref_stack_push (thread->appdomain_refs, domain);
3407 SPIN_UNLOCK (thread->lock_thread_id);
3412 mono_thread_pop_appdomain_ref (void)
3414 MonoInternalThread *thread = mono_thread_internal_current ();
3417 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3418 SPIN_LOCK (thread->lock_thread_id);
3419 ref_stack_pop (thread->appdomain_refs);
3420 SPIN_UNLOCK (thread->lock_thread_id);
3425 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3428 SPIN_LOCK (thread->lock_thread_id);
3429 res = ref_stack_find (thread->appdomain_refs, domain);
3430 SPIN_UNLOCK (thread->lock_thread_id);
3435 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3437 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3440 typedef struct abort_appdomain_data {
3441 struct wait_data wait;
3443 } abort_appdomain_data;
3446 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3448 MonoInternalThread *thread = (MonoInternalThread*)value;
3449 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3450 MonoDomain *domain = data->domain;
3452 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3453 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3455 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3456 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3459 data->wait.handles [data->wait.num] = handle;
3460 data->wait.threads [data->wait.num] = thread;
3463 /* Just ignore the rest, we can't do anything with
3471 * mono_threads_abort_appdomain_threads:
3473 * Abort threads which has references to the given appdomain.
3476 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3478 abort_appdomain_data user_data;
3480 int orig_timeout = timeout;
3483 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3485 start_time = mono_msec_ticks ();
3487 mono_threads_lock ();
3489 user_data.domain = domain;
3490 user_data.wait.num = 0;
3491 /* This shouldn't take any locks */
3492 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3493 mono_threads_unlock ();
3495 if (user_data.wait.num > 0) {
3496 /* Abort the threads outside the threads lock */
3497 for (i = 0; i < user_data.wait.num; ++i)
3498 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3501 * We should wait for the threads either to abort, or to leave the
3502 * domain. We can't do the latter, so we wait with a timeout.
3504 wait_for_tids (&user_data.wait, 100);
3507 /* Update remaining time */
3508 timeout -= mono_msec_ticks () - start_time;
3509 start_time = mono_msec_ticks ();
3511 if (orig_timeout != -1 && timeout < 0)
3514 while (user_data.wait.num > 0);
3516 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3522 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3524 MonoInternalThread *thread = (MonoInternalThread*)value;
3525 MonoDomain *domain = (MonoDomain*)user_data;
3528 /* No locking needed here */
3529 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3531 if (thread->cached_culture_info) {
3532 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3533 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3534 if (obj && obj->vtable->domain == domain)
3535 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3541 * mono_threads_clear_cached_culture:
3543 * Clear the cached_current_culture from all threads if it is in the
3547 mono_threads_clear_cached_culture (MonoDomain *domain)
3549 mono_threads_lock ();
3550 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3551 mono_threads_unlock ();
3555 * mono_thread_get_undeniable_exception:
3557 * Return an exception which needs to be raised when leaving a catch clause.
3558 * This is used for undeniable exception propagation.
3561 mono_thread_get_undeniable_exception (void)
3563 MonoInternalThread *thread = mono_thread_internal_current ();
3565 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3567 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3568 * exception if the thread no longer references a dying appdomain.
3570 thread->abort_exc->trace_ips = NULL;
3571 thread->abort_exc->stack_trace = NULL;
3572 return thread->abort_exc;
3578 #if MONO_SMALL_CONFIG
3579 #define NUM_STATIC_DATA_IDX 4
3580 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3584 #define NUM_STATIC_DATA_IDX 8
3585 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3586 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3590 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3593 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
3596 gpointer *static_data = addr;
3597 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3600 if (!static_data [i])
3602 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3603 ptr = static_data [i];
3604 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3605 uintptr_t bmap = static_reference_bitmaps [i][j];
3608 if ((bmap & 1) && *p) {
3619 * mono_alloc_static_data
3621 * Allocate memory blocks for storing threads or context static data
3624 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3626 guint idx = (offset >> 24) - 1;
3629 gpointer* static_data = *static_data_ptr;
3631 static void* tls_desc = NULL;
3632 if (mono_gc_user_markers_supported () && !tls_desc)
3633 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3634 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3635 *static_data_ptr = static_data;
3636 static_data [0] = static_data;
3639 for (i = 1; i <= idx; ++i) {
3640 if (static_data [i])
3642 if (mono_gc_user_markers_supported () && threadlocal)
3643 static_data [i] = g_malloc0 (static_data_size [i]);
3645 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3650 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3653 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3654 if (!static_data [i])
3656 if (mono_gc_user_markers_supported () && threadlocal)
3657 g_free (static_data [i]);
3659 mono_gc_free_fixed (static_data [i]);
3661 mono_gc_free_fixed (static_data);
3665 * mono_init_static_data_info
3667 * Initializes static data counters
3669 static void mono_init_static_data_info (StaticDataInfo *static_data)
3671 static_data->idx = 0;
3672 static_data->offset = 0;
3673 static_data->freelist = NULL;
3677 * mono_alloc_static_data_slot
3679 * Generates an offset for static data. static_data contains the counters
3680 * used to generate it.
3683 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3687 if (!static_data->idx && !static_data->offset) {
3689 * we use the first chunk of the first allocation also as
3690 * an array for the rest of the data
3692 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3694 static_data->offset += align - 1;
3695 static_data->offset &= ~(align - 1);
3696 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3697 static_data->idx ++;
3698 g_assert (size <= static_data_size [static_data->idx]);
3699 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3700 static_data->offset = 0;
3702 offset = static_data->offset | ((static_data->idx + 1) << 24);
3703 static_data->offset += size;
3708 * ensure thread static fields already allocated are valid for thread
3709 * This function is called when a thread is created or on thread attach.
3712 thread_adjust_static_data (MonoInternalThread *thread)
3716 mono_threads_lock ();
3717 if (thread_static_info.offset || thread_static_info.idx > 0) {
3718 /* get the current allocated size */
3719 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3720 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3722 mono_threads_unlock ();
3726 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3728 MonoInternalThread *thread = value;
3729 guint32 offset = GPOINTER_TO_UINT (user);
3731 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3734 static MonoThreadDomainTls*
3735 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3737 MonoThreadDomainTls* prev = NULL;
3738 MonoThreadDomainTls* tmp = static_data->freelist;
3740 if (tmp->size == size) {
3742 prev->next = tmp->next;
3744 static_data->freelist = tmp->next;
3753 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3756 int idx = (offset >> 24) - 1;
3758 if (!static_reference_bitmaps [idx])
3759 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3760 rb = static_reference_bitmaps [idx];
3762 offset /= sizeof (gpointer);
3763 /* offset is now the bitmap offset */
3764 for (i = 0; i < numbits; ++i) {
3765 if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
3766 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3771 clear_reference_bitmap (guint32 offset, guint32 size)
3773 int idx = (offset >> 24) - 1;
3775 rb = static_reference_bitmaps [idx];
3777 offset /= sizeof (gpointer);
3778 size /= sizeof (gpointer);
3780 /* offset is now the bitmap offset */
3781 for (; offset < size; ++offset)
3782 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3786 * The offset for a special static variable is composed of three parts:
3787 * a bit that indicates the type of static data (0:thread, 1:context),
3788 * an index in the array of chunks of memory for the thread (thread->static_data)
3789 * and an offset in that chunk of mem. This allows allocating less memory in the
3794 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3797 if (static_type == SPECIAL_STATIC_THREAD) {
3798 MonoThreadDomainTls *item;
3799 mono_threads_lock ();
3800 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3801 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3803 offset = item->offset;
3806 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3808 update_tls_reference_bitmap (offset, bitmap, numbits);
3809 /* This can be called during startup */
3810 if (threads != NULL)
3811 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3812 mono_threads_unlock ();
3814 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3815 mono_contexts_lock ();
3816 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3817 mono_contexts_unlock ();
3818 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3824 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3826 /* The high bit means either thread (0) or static (1) data. */
3828 guint32 static_type = (offset & 0x80000000);
3831 offset &= 0x7fffffff;
3832 idx = (offset >> 24) - 1;
3834 if (static_type == 0) {
3835 return get_thread_static_data (thread, offset);
3837 /* Allocate static data block under demand, since we don't have a list
3840 MonoAppContext *context = mono_context_get ();
3841 if (!context->static_data || !context->static_data [idx]) {
3842 mono_contexts_lock ();
3843 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3844 mono_contexts_unlock ();
3846 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3851 mono_get_special_static_data (guint32 offset)
3853 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3862 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3864 MonoInternalThread *thread = value;
3865 TlsOffsetSize *data = user;
3866 int idx = (data->offset >> 24) - 1;
3869 if (!thread->static_data || !thread->static_data [idx])
3871 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3872 mono_gc_bzero (ptr, data->size);
3876 do_free_special_slot (guint32 offset, guint32 size)
3878 guint32 static_type = (offset & 0x80000000);
3879 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3880 if (static_type == 0) {
3882 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3883 data.offset = offset & 0x7fffffff;
3885 clear_reference_bitmap (data.offset, data.size);
3886 if (threads != NULL)
3887 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3888 item->offset = offset;
3891 if (!mono_runtime_is_shutting_down ()) {
3892 item->next = thread_static_info.freelist;
3893 thread_static_info.freelist = item;
3895 /* We could be called during shutdown after mono_thread_cleanup () is called */
3899 /* FIXME: free context static data as well */
3904 do_free_special (gpointer key, gpointer value, gpointer data)
3906 MonoClassField *field = key;
3907 guint32 offset = GPOINTER_TO_UINT (value);
3910 size = mono_type_size (field->type, &align);
3911 do_free_special_slot (offset, size);
3915 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3917 mono_threads_lock ();
3918 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3919 mono_threads_unlock ();
3923 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3925 mono_threads_lock ();
3926 do_free_special_slot (offset, size);
3927 mono_threads_unlock ();
3931 * allocates room in the thread local area for storing an instance of the struct type
3932 * the allocation is kept track of in domain->tlsrec_list.
3935 mono_thread_alloc_tls (MonoReflectionType *type)
3937 MonoDomain *domain = mono_domain_get ();
3939 MonoTlsDataRecord *tlsrec;
3942 gsize default_bitmap [4] = {0};
3943 uint32_t tls_offset;
3947 klass = mono_class_from_mono_type (type->type);
3948 /* TlsDatum is a struct, so we subtract the object header size offset */
3949 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3950 size = mono_type_size (type->type, &align);
3951 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3952 if (bitmap != default_bitmap)
3954 tlsrec = g_new0 (MonoTlsDataRecord, 1);
3955 tlsrec->tls_offset = tls_offset;
3956 tlsrec->size = size;
3957 mono_domain_lock (domain);
3958 tlsrec->next = domain->tlsrec_list;
3959 domain->tlsrec_list = tlsrec;
3960 mono_domain_unlock (domain);
3965 mono_thread_destroy_tls (uint32_t tls_offset)
3967 MonoTlsDataRecord *prev = NULL;
3968 MonoTlsDataRecord *cur;
3970 MonoDomain *domain = mono_domain_get ();
3971 mono_domain_lock (domain);
3972 cur = domain->tlsrec_list;
3974 if (cur->tls_offset == tls_offset) {
3976 prev->next = cur->next;
3978 domain->tlsrec_list = cur->next;
3986 mono_domain_unlock (domain);
3988 mono_special_static_data_free_slot (tls_offset, size);
3992 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
3995 mono_thread_destroy_domain_tls (MonoDomain *domain)
3997 while (domain->tlsrec_list)
3998 mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
4001 static MonoClassField *local_slots = NULL;
4004 /* local tls data to get locals_slot from a thread */
4007 /* index in the locals_slot array */
4012 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4014 LocalSlotID *sid = user_data;
4015 MonoInternalThread *thread = (MonoInternalThread*)value;
4016 MonoArray *slots_array;
4018 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4019 * it is for the right domain, so we need to check if it is allocated an initialized
4020 * for the current thread.
4022 /*g_print ("handling thread %p\n", thread);*/
4023 if (!thread->static_data || !thread->static_data [sid->idx])
4025 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4026 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4028 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4032 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4040 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4042 g_warning ("local_slots field not found in Thread class");
4046 domain = mono_domain_get ();
4047 mono_domain_lock (domain);
4048 if (domain->special_static_fields)
4049 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4050 mono_domain_unlock (domain);
4053 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4054 sid.offset = GPOINTER_TO_UINT (addr);
4055 sid.offset &= 0x7fffffff;
4056 sid.idx = (sid.offset >> 24) - 1;
4057 mono_threads_lock ();
4058 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4059 mono_threads_unlock ();
4061 /* FIXME: clear the slot for MonoAppContexts, too */
4066 static void CALLBACK dummy_apc (ULONG_PTR param)
4070 static guint32 dummy_apc (gpointer param)
4077 * mono_thread_execute_interruption
4079 * Performs the operation that the requested thread state requires (abort,
4082 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4084 ensure_synch_cs_set (thread);
4086 EnterCriticalSection (thread->synch_cs);
4088 /* MonoThread::interruption_requested can only be changed with atomics */
4089 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4090 /* this will consume pending APC calls */
4091 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4092 InterlockedDecrement (&thread_interruption_requested);
4094 /* Clear the interrupted flag of the thread so it can wait again */
4095 wapi_clear_interruption ();
4099 if ((thread->state & ThreadState_AbortRequested) != 0) {
4100 LeaveCriticalSection (thread->synch_cs);
4101 if (thread->abort_exc == NULL) {
4103 * This might be racy, but it has to be called outside the lock
4104 * since it calls managed code.
4106 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4108 return thread->abort_exc;
4110 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4111 self_suspend_internal (thread);
4114 else if ((thread->state & ThreadState_StopRequested) != 0) {
4115 /* FIXME: do this through the JIT? */
4117 LeaveCriticalSection (thread->synch_cs);
4119 mono_thread_exit ();
4121 } else if (thread->pending_exception) {
4124 exc = thread->pending_exception;
4125 thread->pending_exception = NULL;
4127 LeaveCriticalSection (thread->synch_cs);
4129 } else if (thread->thread_interrupt_requested) {
4131 thread->thread_interrupt_requested = FALSE;
4132 LeaveCriticalSection (thread->synch_cs);
4134 return(mono_get_exception_thread_interrupted ());
4137 LeaveCriticalSection (thread->synch_cs);
4143 * mono_thread_request_interruption
4145 * A signal handler can call this method to request the interruption of a
4146 * thread. The result of the interruption will depend on the current state of
4147 * the thread. If the result is an exception that needs to be throw, it is
4148 * provided as return value.
4151 mono_thread_request_interruption (gboolean running_managed)
4153 MonoInternalThread *thread = mono_thread_internal_current ();
4155 /* The thread may already be stopping */
4160 if (thread->interrupt_on_stop &&
4161 thread->state & ThreadState_StopRequested &&
4162 thread->state & ThreadState_Background)
4166 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4168 InterlockedIncrement (&thread_interruption_requested);
4170 if (!running_managed || is_running_protected_wrapper ()) {
4171 /* Can't stop while in unmanaged code. Increase the global interruption
4172 request count. When exiting the unmanaged method the count will be
4173 checked and the thread will be interrupted. */
4176 if (mono_thread_notify_pending_exc_fn && !running_managed)
4177 /* The JIT will notify the thread about the interruption */
4178 /* This shouldn't take any locks */
4179 mono_thread_notify_pending_exc_fn ();
4181 /* this will awake the thread if it is in WaitForSingleObject
4183 /* Our implementation of this function ignores the func argument */
4184 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
4188 return mono_thread_execute_interruption (thread);
4192 /*This function should be called by a thread after it has exited all of
4193 * its handle blocks at interruption time.*/
4195 mono_thread_resume_interruption (void)
4197 MonoInternalThread *thread = mono_thread_internal_current ();
4198 gboolean still_aborting;
4200 /* The thread may already be stopping */
4204 ensure_synch_cs_set (thread);
4205 EnterCriticalSection (thread->synch_cs);
4206 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4207 LeaveCriticalSection (thread->synch_cs);
4209 /*This can happen if the protected block called Thread::ResetAbort*/
4210 if (!still_aborting)
4213 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4215 InterlockedIncrement (&thread_interruption_requested);
4218 wapi_self_interrupt ();
4220 return mono_thread_execute_interruption (thread);
4223 gboolean mono_thread_interruption_requested ()
4225 if (thread_interruption_requested) {
4226 MonoInternalThread *thread = mono_thread_internal_current ();
4227 /* The thread may already be stopping */
4229 return (thread->interruption_requested);
4234 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4236 MonoInternalThread *thread = mono_thread_internal_current ();
4238 /* The thread may already be stopping */
4242 mono_debugger_check_interruption ();
4244 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4245 MonoException* exc = mono_thread_execute_interruption (thread);
4246 if (exc) mono_raise_exception (exc);
4251 * Performs the interruption of the current thread, if one has been requested,
4252 * and the thread is not running a protected wrapper.
4254 void mono_thread_interruption_checkpoint ()
4256 mono_thread_interruption_checkpoint_request (FALSE);
4260 * Performs the interruption of the current thread, if one has been requested.
4262 void mono_thread_force_interruption_checkpoint ()
4264 mono_thread_interruption_checkpoint_request (TRUE);
4268 * mono_thread_get_and_clear_pending_exception:
4270 * Return any pending exceptions for the current thread and clear it as a side effect.
4273 mono_thread_get_and_clear_pending_exception (void)
4275 MonoInternalThread *thread = mono_thread_internal_current ();
4277 /* The thread may already be stopping */
4281 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4282 return mono_thread_execute_interruption (thread);
4285 if (thread->pending_exception) {
4286 MonoException *exc = thread->pending_exception;
4288 thread->pending_exception = NULL;
4296 * mono_set_pending_exception:
4298 * Set the pending exception of the current thread to EXC.
4299 * The exception will be thrown when execution returns to managed code.
4302 mono_set_pending_exception (MonoException *exc)
4304 MonoInternalThread *thread = mono_thread_internal_current ();
4306 /* The thread may already be stopping */
4310 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4312 mono_thread_request_interruption (FALSE);
4316 * mono_thread_interruption_request_flag:
4318 * Returns the address of a flag that will be non-zero if an interruption has
4319 * been requested for a thread. The thread to interrupt may not be the current
4320 * thread, so an additional call to mono_thread_interruption_requested() or
4321 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4324 gint32* mono_thread_interruption_request_flag ()
4326 return &thread_interruption_requested;
4330 mono_thread_init_apartment_state (void)
4333 MonoInternalThread* thread = mono_thread_internal_current ();
4335 /* Positive return value indicates success, either
4336 * S_OK if this is first CoInitialize call, or
4337 * S_FALSE if CoInitialize already called, but with same
4338 * threading model. A negative value indicates failure,
4339 * probably due to trying to change the threading model.
4341 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4342 ? COINIT_APARTMENTTHREADED
4343 : COINIT_MULTITHREADED) < 0) {
4344 thread->apartment_state = ThreadApartmentState_Unknown;
4350 mono_thread_cleanup_apartment_state (void)
4353 MonoInternalThread* thread = mono_thread_internal_current ();
4355 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4362 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4364 ensure_synch_cs_set (thread);
4366 EnterCriticalSection (thread->synch_cs);
4367 thread->state |= state;
4368 LeaveCriticalSection (thread->synch_cs);
4372 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4374 ensure_synch_cs_set (thread);
4376 EnterCriticalSection (thread->synch_cs);
4377 thread->state &= ~state;
4378 LeaveCriticalSection (thread->synch_cs);
4382 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4384 gboolean ret = FALSE;
4386 ensure_synch_cs_set (thread);
4388 EnterCriticalSection (thread->synch_cs);
4390 if ((thread->state & test) != 0) {
4394 LeaveCriticalSection (thread->synch_cs);
4399 //static MonoClassField *execution_context_field;
4402 get_execution_context_addr (void)
4404 MonoDomain *domain = mono_domain_get ();
4405 guint32 offset = domain->execution_context_field_offset;
4408 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4411 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4413 mono_domain_lock (domain);
4414 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4415 mono_domain_unlock (domain);
4418 domain->execution_context_field_offset = offset;
4421 return (MonoObject**) mono_get_special_static_data (offset);
4425 mono_thread_get_execution_context (void)
4427 return *get_execution_context_addr ();
4431 mono_thread_set_execution_context (MonoObject *ec)
4433 *get_execution_context_addr () = ec;
4436 static gboolean has_tls_get = FALSE;
4439 mono_runtime_set_has_tls_get (gboolean val)
4445 mono_runtime_has_tls_get (void)
4451 mono_thread_kill (MonoInternalThread *thread, int signal)
4454 /* Win32 uses QueueUserAPC and callers of this are guarded */
4455 g_assert_not_reached ();
4457 # ifdef PTHREAD_POINTER_ID
4458 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4460 # ifdef PLATFORM_ANDROID
4461 if (thread->android_tid != 0) {
4463 int old_errno = errno;
4465 ret = tkill ((pid_t) thread->android_tid, signal);
4474 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4476 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4483 self_interrupt_thread (void *_unused)
4485 MonoThreadInfo *info = mono_thread_info_current ();
4486 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4487 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4488 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4489 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4493 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4497 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4501 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4503 MonoJitInfo **dest = data;
4509 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4511 MonoJitInfo *ji = NULL;
4514 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4519 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4522 MonoThreadInfo *info = NULL;
4523 gboolean protected_wrapper;
4524 gboolean running_managed;
4526 if (!mono_thread_info_new_interrupt_enabled ()) {
4527 signal_thread_state_change (thread);
4532 FIXME this is insanely broken, it doesn't cause interruption to happen
4533 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4535 if (thread == mono_thread_internal_current ()) {
4536 /* Do it synchronously */
4537 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4539 mono_raise_exception (exc);
4541 wapi_interrupt_thread (thread->handle);
4546 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4547 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4551 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4552 mono_thread_info_resume (mono_thread_info_get_tid (info));
4556 /*someone is already interrupting it*/
4557 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4558 mono_thread_info_resume (mono_thread_info_get_tid (info));
4561 InterlockedIncrement (&thread_interruption_requested);
4563 ji = mono_thread_info_get_last_managed (info);
4564 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4565 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4567 if (!protected_wrapper && running_managed) {
4568 /*We are in managed code*/
4569 /*Set the thread to call */
4570 if (install_async_abort)
4571 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4572 mono_thread_info_resume (mono_thread_info_get_tid (info));
4574 gpointer interrupt_handle;
4576 * This will cause waits to be broken.
4577 * It will also prevent the thread from entering a wait, so if the thread returns
4578 * from the wait before it receives the abort signal, it will just spin in the wait
4579 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4583 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4585 mono_thread_info_resume (mono_thread_info_get_tid (info));
4587 wapi_finish_interrupt_thread (interrupt_handle);
4590 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4594 transition_to_suspended (MonoInternalThread *thread)
4596 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4597 g_assert (0); /*FIXME we should not reach this */
4598 /*Make sure we balance the suspend count.*/
4599 mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
4601 thread->state &= ~ThreadState_SuspendRequested;
4602 thread->state |= ThreadState_Suspended;
4604 LeaveCriticalSection (thread->synch_cs);
4608 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4610 if (!mono_thread_info_new_interrupt_enabled ()) {
4611 signal_thread_state_change (thread);
4615 EnterCriticalSection (thread->synch_cs);
4616 if (thread == mono_thread_internal_current ()) {
4617 transition_to_suspended (thread);
4618 mono_thread_info_self_suspend ();
4620 MonoThreadInfo *info;
4622 gboolean protected_wrapper;
4623 gboolean running_managed;
4625 /*A null info usually means the thread is already dead. */
4626 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
4627 LeaveCriticalSection (thread->synch_cs);
4631 ji = mono_thread_info_get_last_managed (info);
4632 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4633 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4635 if (running_managed && !protected_wrapper) {
4636 transition_to_suspended (thread);
4638 gpointer interrupt_handle;
4640 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4641 InterlockedIncrement (&thread_interruption_requested);
4644 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4646 mono_thread_info_resume (mono_thread_info_get_tid (info));
4649 wapi_finish_interrupt_thread (interrupt_handle);
4651 LeaveCriticalSection (thread->synch_cs);
4656 /*This is called with @thread synch_cs held and it must release it*/
4658 self_suspend_internal (MonoInternalThread *thread)
4660 if (!mono_thread_info_new_interrupt_enabled ()) {
4661 thread->state &= ~ThreadState_SuspendRequested;
4662 thread->state |= ThreadState_Suspended;
4663 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4664 if (thread->suspend_event == NULL) {
4665 LeaveCriticalSection (thread->synch_cs);
4668 if (thread->suspended_event)
4669 SetEvent (thread->suspended_event);
4671 LeaveCriticalSection (thread->synch_cs);
4673 if (shutting_down) {
4674 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4679 WaitForSingleObject (thread->suspend_event, INFINITE);
4681 EnterCriticalSection (thread->synch_cs);
4683 CloseHandle (thread->suspend_event);
4684 thread->suspend_event = NULL;
4685 thread->state &= ~ThreadState_Suspended;
4687 /* The thread that requested the resume will have replaced this event
4688 * and will be waiting for it
4690 SetEvent (thread->resume_event);
4692 LeaveCriticalSection (thread->synch_cs);
4696 transition_to_suspended (thread);
4697 mono_thread_info_self_suspend ();
4700 /*This is called with @thread synch_cs held and it must release it*/
4702 resume_thread_internal (MonoInternalThread *thread)
4704 if (!mono_thread_info_new_interrupt_enabled ()) {
4705 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4706 if (thread->resume_event == NULL) {
4707 LeaveCriticalSection (thread->synch_cs);
4711 /* Awake the thread */
4712 SetEvent (thread->suspend_event);
4714 LeaveCriticalSection (thread->synch_cs);
4716 /* Wait for the thread to awake */
4717 WaitForSingleObject (thread->resume_event, INFINITE);
4718 CloseHandle (thread->resume_event);
4719 thread->resume_event = NULL;
4723 LeaveCriticalSection (thread->synch_cs);
4724 /* Awake the thread */
4725 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4727 EnterCriticalSection (thread->synch_cs);
4728 thread->state &= ~ThreadState_Suspended;
4729 LeaveCriticalSection (thread->synch_cs);