2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
20 #if defined(__OpenBSD__) || defined(__FreeBSD__)
22 #include <pthread_np.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/domain-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/threads.h>
29 #include <mono/metadata/threadpool.h>
30 #include <mono/metadata/threads-types.h>
31 #include <mono/metadata/exception.h>
32 #include <mono/metadata/environment.h>
33 #include <mono/metadata/monitor.h>
34 #include <mono/metadata/gc-internal.h>
35 #include <mono/metadata/marshal.h>
36 #include <mono/io-layer/io-layer.h>
38 #include <mono/io-layer/threads.h>
40 #include <mono/metadata/object-internals.h>
41 #include <mono/metadata/mono-debug-debugger.h>
42 #include <mono/utils/mono-compiler.h>
43 #include <mono/utils/mono-mmap.h>
44 #include <mono/utils/mono-membar.h>
45 #include <mono/utils/mono-time.h>
46 #include <mono/utils/mono-threads.h>
47 #include <mono/utils/hazard-pointer.h>
48 #include <mono/utils/mono-tls.h>
50 #include <mono/metadata/gc-internal.h>
52 #ifdef PLATFORM_ANDROID
55 extern int tkill (pid_t tid, int signal);
58 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
59 void *pthread_get_stackaddr_np(pthread_t);
60 size_t pthread_get_stacksize_np(pthread_t);
63 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
64 #define THREAD_DEBUG(a)
65 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
66 #define THREAD_WAIT_DEBUG(a)
67 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
68 #define LIBGC_DEBUG(a)
70 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
71 #define SPIN_LOCK(i) do { \
72 if (SPIN_TRYLOCK (i)) \
76 #define SPIN_UNLOCK(i) i = 0
78 /* Provide this for systems with glib < 2.6 */
79 #ifndef G_GSIZE_FORMAT
80 # if GLIB_SIZEOF_LONG == 8
81 # define G_GSIZE_FORMAT "lu"
83 # define G_GSIZE_FORMAT "u"
89 guint32 (*func)(void *);
105 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
106 struct _MonoThreadDomainTls {
107 MonoThreadDomainTls *next;
115 MonoThreadDomainTls *freelist;
118 /* Number of cached culture objects in the MonoThread->cached_culture_info array
119 * (per-type): we use the first NUM entries for CultureInfo and the last for
120 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
122 #define NUM_CACHED_CULTURES 4
123 #define CULTURES_START_IDX 0
124 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
126 /* Controls access to the 'threads' hash table */
127 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
128 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
129 static CRITICAL_SECTION threads_mutex;
131 /* Controls access to context static data */
132 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
133 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
134 static CRITICAL_SECTION contexts_mutex;
136 /* Holds current status of static data heap */
137 static StaticDataInfo thread_static_info;
138 static StaticDataInfo context_static_info;
140 /* The hash of existing threads (key is thread ID, value is
141 * MonoInternalThread*) that need joining before exit
143 static MonoGHashTable *threads=NULL;
146 * Threads which are starting up and they are not in the 'threads' hash yet.
147 * When handle_store is called for a thread, it will be removed from this hash table.
148 * Protected by mono_threads_lock ().
150 static MonoGHashTable *threads_starting_up = NULL;
152 /* Maps a MonoThread to its start argument */
153 /* Protected by mono_threads_lock () */
154 static MonoGHashTable *thread_start_args = NULL;
156 /* The TLS key that holds the MonoObject assigned to each thread */
157 static MonoNativeTlsKey current_object_key;
159 #ifdef MONO_HAVE_FAST_TLS
160 /* we need to use both the Tls* functions and __thread because
161 * the gc needs to see all the threads
163 MONO_FAST_TLS_DECLARE(tls_current_object);
164 #define SET_CURRENT_OBJECT(x) do { \
165 MONO_FAST_TLS_SET (tls_current_object, x); \
166 mono_native_tls_set_value (current_object_key, x); \
168 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
170 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
171 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
174 /* function called at thread start */
175 static MonoThreadStartCB mono_thread_start_cb = NULL;
177 /* function called at thread attach */
178 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
180 /* function called at thread cleanup */
181 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
183 /* function called to notify the runtime about a pending exception on the current thread */
184 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
186 /* The default stack size for each thread */
187 static guint32 default_stacksize = 0;
188 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
190 static void thread_adjust_static_data (MonoInternalThread *thread);
191 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
192 static void mono_init_static_data_info (StaticDataInfo *static_data);
193 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
194 static gboolean mono_thread_resume (MonoInternalThread* thread);
195 static void mono_thread_start (MonoThread *thread);
196 static void signal_thread_state_change (MonoInternalThread *thread);
197 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
198 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
199 static void self_suspend_internal (MonoInternalThread *thread);
200 static gboolean resume_thread_internal (MonoInternalThread *thread);
202 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
203 static void ref_stack_destroy (gpointer rs);
205 /* Spin lock for InterlockedXXX 64 bit functions */
206 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
207 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
208 static CRITICAL_SECTION interlocked_mutex;
210 /* global count of thread interruptions requested */
211 static gint32 thread_interruption_requested = 0;
213 /* Event signaled when a thread changes its background mode */
214 static HANDLE background_change_event;
216 static gboolean shutting_down = FALSE;
218 static gint32 managed_thread_id_counter = 0;
221 get_next_managed_thread_id (void)
223 return InterlockedIncrement (&managed_thread_id_counter);
227 mono_thread_get_tls_key (void)
229 return current_object_key;
233 mono_thread_get_tls_offset (void)
236 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
240 /* handle_store() and handle_remove() manage the array of threads that
241 * still need to be waited for when the main thread exits.
243 * If handle_store() returns FALSE the thread must not be started
244 * because Mono is shutting down.
246 static gboolean handle_store(MonoThread *thread)
248 mono_threads_lock ();
250 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
252 if (threads_starting_up)
253 mono_g_hash_table_remove (threads_starting_up, thread);
256 mono_threads_unlock ();
261 MONO_GC_REGISTER_ROOT_FIXED (threads);
262 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
265 /* We don't need to duplicate thread->handle, because it is
266 * only closed when the thread object is finalized by the GC.
268 g_assert (thread->internal_thread);
269 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
270 thread->internal_thread);
272 mono_threads_unlock ();
277 static gboolean handle_remove(MonoInternalThread *thread)
280 gsize tid = thread->tid;
282 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
284 mono_threads_lock ();
287 /* We have to check whether the thread object for the
288 * tid is still the same in the table because the
289 * thread might have been destroyed and the tid reused
290 * in the meantime, in which case the tid would be in
291 * the table, but with another thread object.
293 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
294 mono_g_hash_table_remove (threads, (gpointer)tid);
303 mono_threads_unlock ();
305 /* Don't close the handle here, wait for the object finalizer
306 * to do it. Otherwise, the following race condition applies:
308 * 1) Thread exits (and handle_remove() closes the handle)
310 * 2) Some other handle is reassigned the same slot
312 * 3) Another thread tries to join the first thread, and
313 * blocks waiting for the reassigned handle to be signalled
314 * (which might never happen). This is possible, because the
315 * thread calling Join() still has a reference to the first
321 static void ensure_synch_cs_set (MonoInternalThread *thread)
323 CRITICAL_SECTION *synch_cs;
325 if (thread->synch_cs != NULL) {
329 synch_cs = g_new0 (CRITICAL_SECTION, 1);
330 InitializeCriticalSection (synch_cs);
332 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
333 synch_cs, NULL) != NULL) {
334 /* Another thread must have installed this CS */
335 DeleteCriticalSection (synch_cs);
341 * NOTE: this function can be called also for threads different from the current one:
342 * make sure no code called from it will ever assume it is run on the thread that is
343 * getting cleaned up.
345 static void thread_cleanup (MonoInternalThread *thread)
347 g_assert (thread != NULL);
349 if (thread->abort_state_handle) {
350 mono_gchandle_free (thread->abort_state_handle);
351 thread->abort_state_handle = 0;
353 thread->abort_exc = NULL;
354 thread->current_appcontext = NULL;
357 * This is necessary because otherwise we might have
358 * cross-domain references which will not get cleaned up when
359 * the target domain is unloaded.
361 if (thread->cached_culture_info) {
363 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
364 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
367 ensure_synch_cs_set (thread);
369 EnterCriticalSection (thread->synch_cs);
371 thread->state |= ThreadState_Stopped;
372 thread->state &= ~ThreadState_Background;
374 LeaveCriticalSection (thread->synch_cs);
377 An interruption request has leaked to cleanup. Adjust the global counter.
379 This can happen is the abort source thread finds the abortee (this) thread
380 in unmanaged code. If this thread never trips back to managed code or check
381 the local flag it will be left set and positively unbalance the global counter.
383 Leaving the counter unbalanced will cause a performance degradation since all threads
384 will now keep checking their local flags all the time.
386 if (InterlockedExchange (&thread->interruption_requested, 0))
387 InterlockedDecrement (&thread_interruption_requested);
389 /* if the thread is not in the hash it has been removed already */
390 if (!handle_remove (thread)) {
391 /* This needs to be called even if handle_remove () fails */
392 if (mono_thread_cleanup_fn)
393 mono_thread_cleanup_fn (thread);
396 mono_release_type_locks (thread);
398 mono_profiler_thread_end (thread->tid);
400 if (thread == mono_thread_internal_current ())
401 mono_thread_pop_appdomain_ref ();
403 thread->cached_culture_info = NULL;
405 mono_free_static_data (thread->static_data, TRUE);
406 thread->static_data = NULL;
407 ref_stack_destroy (thread->appdomain_refs);
408 thread->appdomain_refs = NULL;
410 if (mono_thread_cleanup_fn)
411 mono_thread_cleanup_fn (thread);
413 if (mono_gc_is_moving ()) {
414 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
415 thread->thread_pinning_ref = NULL;
421 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
424 g_assert ((offset & 0x80000000) == 0);
425 offset &= 0x7fffffff;
426 idx = (offset >> 24) - 1;
427 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
431 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
433 static MonoClassField *current_thread_field = NULL;
437 if (!current_thread_field) {
438 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
439 g_assert (current_thread_field);
442 mono_class_vtable (domain, mono_defaults.thread_class);
443 mono_domain_lock (domain);
444 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
445 mono_domain_unlock (domain);
448 return get_thread_static_data (thread, offset);
452 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
454 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
456 g_assert (current->obj.vtable->domain == domain);
458 g_assert (!*current_thread_ptr);
459 *current_thread_ptr = current;
462 static MonoInternalThread*
463 create_internal_thread_object (void)
465 MonoVTable *vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
466 return (MonoInternalThread*)mono_gc_alloc_mature (vt);
470 create_thread_object (MonoDomain *domain)
472 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
473 return (MonoThread*)mono_gc_alloc_mature (vt);
477 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
479 MonoThread *thread = create_thread_object (domain);
480 MONO_OBJECT_SETREF (thread, internal_thread, internal);
485 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
487 MonoDomain *domain = mono_get_root_domain ();
489 if (!candidate || candidate->obj.vtable->domain != domain)
490 candidate = new_thread_with_internal (domain, thread);
491 set_current_thread_for_domain (domain, thread, candidate);
492 g_assert (!thread->root_domain_thread);
493 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
496 static guint32 WINAPI start_wrapper_internal(void *data)
498 MonoThreadInfo *info;
499 struct StartInfo *start_info=(struct StartInfo *)data;
500 guint32 (*start_func)(void *);
504 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
507 MonoInternalThread *internal = start_info->obj->internal_thread;
508 MonoObject *start_delegate = start_info->delegate;
509 MonoDomain *domain = start_info->obj->obj.vtable->domain;
511 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
513 /* We can be sure start_info->obj->tid and
514 * start_info->obj->handle have been set, because the thread
515 * was created suspended, and these values were set before the
519 info = mono_thread_info_current ();
521 internal->thread_info = info;
526 SET_CURRENT_OBJECT (internal);
528 mono_monitor_init_tls ();
530 /* Every thread references the appdomain which created it */
531 mono_thread_push_appdomain_ref (domain);
533 if (!mono_domain_set (domain, FALSE)) {
534 /* No point in raising an appdomain_unloaded exception here */
535 /* FIXME: Cleanup here */
536 mono_thread_pop_appdomain_ref ();
540 start_func = start_info->func;
541 start_arg = start_info->start_arg;
543 /* We have to do this here because mono_thread_new_init()
544 requires that root_domain_thread is set up. */
545 thread_adjust_static_data (internal);
546 init_root_domain_thread (internal, start_info->obj);
548 /* This MUST be called before any managed code can be
549 * executed, as it calls the callback function that (for the
550 * jit) sets the lmf marker.
552 mono_thread_new_init (tid, &tid, start_func);
553 internal->stack_ptr = &tid;
555 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
557 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
559 /* On 2.0 profile (and higher), set explicitly since state might have been
561 if (internal->apartment_state == ThreadApartmentState_Unknown)
562 internal->apartment_state = ThreadApartmentState_MTA;
564 mono_thread_init_apartment_state ();
566 if(internal->start_notify!=NULL) {
567 /* Let the thread that called Start() know we're
570 ReleaseSemaphore (internal->start_notify, 1, NULL);
573 mono_threads_lock ();
574 mono_g_hash_table_remove (thread_start_args, start_info->obj);
575 mono_threads_unlock ();
577 mono_thread_set_execution_context (start_info->obj->ec_to_set);
578 start_info->obj->ec_to_set = NULL;
581 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
585 * Call this after calling start_notify, since the profiler callback might want
586 * to lock the thread, and the lock is held by thread_start () which waits for
589 mono_profiler_thread_start (tid);
591 /* start_func is set only for unmanaged start functions */
593 start_func (start_arg);
596 g_assert (start_delegate != NULL);
597 args [0] = start_arg;
598 /* we may want to handle the exception here. See comment below on unhandled exceptions */
599 mono_runtime_delegate_invoke (start_delegate, args, NULL);
602 /* If the thread calls ExitThread at all, this remaining code
603 * will not be executed, but the main thread will eventually
604 * call thread_cleanup() on this thread's behalf.
607 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
609 thread_cleanup (internal);
611 /* Do any cleanup needed for apartment state. This
612 * cannot be done in thread_cleanup since thread_cleanup could be
613 * called for a thread other than the current thread.
614 * mono_thread_cleanup_apartment_state cleans up apartment
615 * for the current thead */
616 mono_thread_cleanup_apartment_state ();
618 /* Remove the reference to the thread object in the TLS data,
619 * so the thread object can be finalized. This won't be
620 * reached if the thread threw an uncaught exception, so those
621 * thread handles will stay referenced :-( (This is due to
622 * missing support for scanning thread-specific data in the
623 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
626 SET_CURRENT_OBJECT (NULL);
627 mono_domain_unset ();
632 static guint32 WINAPI start_wrapper(void *data)
636 /* Avoid scanning the frames above this frame during a GC */
637 mono_gc_set_stack_end ((void*)&dummy);
639 return start_wrapper_internal (data);
642 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
644 if (mono_thread_start_cb) {
645 mono_thread_start_cb (tid, stack_start, func);
649 void mono_threads_set_default_stacksize (guint32 stacksize)
651 default_stacksize = stacksize;
654 guint32 mono_threads_get_default_stacksize (void)
656 return default_stacksize;
660 * mono_create_thread:
662 * This is a wrapper around CreateThread which handles differences in the type of
663 * the the 'tid' argument.
665 gpointer mono_create_thread (WapiSecurityAttributes *security,
666 guint32 stacksize, WapiThreadStart start,
667 gpointer param, guint32 create, gsize *tid)
674 res = mono_threads_CreateThread (security, stacksize, start, param, create, &real_tid);
678 res = CreateThread (security, stacksize, start, param, create, tid);
685 * The thread start argument may be an object reference, and there is
686 * no ref to keep it alive when the new thread is started but not yet
687 * registered with the collector. So we store it in a GC tracked hash
690 * LOCKING: Assumes the threads lock is held.
693 register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info)
695 if (thread_start_args == NULL) {
696 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
697 thread_start_args = mono_g_hash_table_new (NULL, NULL);
699 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
703 * mono_thread_create_internal:
705 * If NO_DETACH is TRUE, then the thread is not detached using pthread_detach (). This is needed to fix the race condition where waiting for a thred to exit only waits for its exit event to be
706 * signalled, which can cause shutdown crashes if the thread shutdown code accesses data already freed by the runtime shutdown.
707 * Currently, this is only used for the finalizer thread.
710 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size)
713 MonoInternalThread *internal;
714 HANDLE thread_handle;
715 struct StartInfo *start_info;
717 guint32 create_flags;
719 thread = create_thread_object (domain);
720 internal = create_internal_thread_object ();
721 MONO_OBJECT_SETREF (thread, internal_thread, internal);
723 start_info=g_new0 (struct StartInfo, 1);
724 start_info->func = func;
725 start_info->obj = thread;
726 start_info->start_arg = arg;
728 mono_threads_lock ();
730 mono_threads_unlock ();
734 if (threads_starting_up == NULL) {
735 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
736 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
739 register_thread_start_argument (thread, start_info);
740 mono_g_hash_table_insert (threads_starting_up, thread, thread);
741 mono_threads_unlock ();
744 stack_size = default_stacksize_for_thread (internal);
746 /* Create suspended, so we can do some housekeeping before the thread
749 create_flags = CREATE_SUSPENDED;
752 create_flags |= CREATE_NO_DETACH;
754 thread_handle = mono_create_thread (NULL, stack_size, (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
756 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
757 if (thread_handle == NULL) {
758 /* The thread couldn't be created, so throw an exception */
759 mono_threads_lock ();
760 mono_g_hash_table_remove (threads_starting_up, thread);
761 mono_threads_unlock ();
763 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
767 internal->handle=thread_handle;
769 internal->apartment_state=ThreadApartmentState_Unknown;
770 internal->managed_id = get_next_managed_thread_id ();
771 if (mono_gc_is_moving ()) {
772 internal->thread_pinning_ref = internal;
773 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
776 internal->synch_cs = g_new0 (CRITICAL_SECTION, 1);
777 InitializeCriticalSection (internal->synch_cs);
779 internal->threadpool_thread = threadpool_thread;
780 if (threadpool_thread)
781 mono_thread_set_state (internal, ThreadState_Background);
783 if (handle_store (thread))
784 ResumeThread (thread_handle);
786 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
787 if (mono_check_corlib_version () == NULL)
788 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
794 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
796 mono_thread_create_internal (domain, func, arg, FALSE, FALSE, 0);
800 * mono_thread_get_stack_bounds:
802 * Return the address and size of the current threads stack. Return NULL as the
803 * stack address if the stack address cannot be determined.
806 mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
808 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
809 *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self ());
810 *stsize = pthread_get_stacksize_np (pthread_self ());
812 /* staddr points to the start of the stack, not the end */
814 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
816 /* FIXME: simplify the mess below */
817 #elif !defined(HOST_WIN32)
819 guint8 *current = (guint8*)&attr;
821 pthread_attr_init (&attr);
822 # ifdef HAVE_PTHREAD_GETATTR_NP
823 pthread_getattr_np (pthread_self(), &attr);
825 # ifdef HAVE_PTHREAD_ATTR_GET_NP
826 pthread_attr_get_np (pthread_self(), &attr);
829 pthread_attr_getstacksize (&attr, &stsize);
830 # elif defined(__OpenBSD__)
834 rslt = pthread_stackseg_np(pthread_self(), &ss);
835 g_assert (rslt == 0);
837 *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
838 *stsize = ss.ss_size;
847 # if !defined(__OpenBSD__)
848 pthread_attr_getstack (&attr, (void**)staddr, stsize);
851 g_assert ((current > *staddr) && (current < *staddr + *stsize));
854 pthread_attr_destroy (&attr);
857 *stsize = (size_t)-1;
860 /* When running under emacs, sometimes staddr is not aligned to a page size */
861 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
865 mono_thread_attach (MonoDomain *domain)
867 MonoInternalThread *thread;
868 MonoThread *current_thread;
869 HANDLE thread_handle;
872 if ((thread = mono_thread_internal_current ())) {
873 if (domain != mono_domain_get ())
874 mono_domain_set (domain, TRUE);
875 /* Already attached */
876 return mono_thread_current ();
879 if (!mono_gc_register_thread (&domain)) {
880 g_error ("Thread %"G_GSIZE_FORMAT" calling into managed code is not registered with the GC. On UNIX, this can be fixed by #include-ing <gc.h> before <pthread.h> in the file containing the thread creation code.", GetCurrentThreadId ());
883 thread = create_internal_thread_object ();
885 thread_handle = GetCurrentThread ();
886 g_assert (thread_handle);
888 tid=GetCurrentThreadId ();
891 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
892 * refer to the thread from other threads for things like aborting.
894 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
895 THREAD_ALL_ACCESS, TRUE, 0);
897 thread->handle=thread_handle;
899 #ifdef PLATFORM_ANDROID
900 thread->android_tid = (gpointer) gettid ();
902 thread->apartment_state=ThreadApartmentState_Unknown;
903 thread->managed_id = get_next_managed_thread_id ();
904 if (mono_gc_is_moving ()) {
905 thread->thread_pinning_ref = thread;
906 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
909 thread->stack_ptr = &tid;
911 thread->synch_cs = g_new0 (CRITICAL_SECTION, 1);
912 InitializeCriticalSection (thread->synch_cs);
914 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
916 current_thread = new_thread_with_internal (domain, thread);
918 if (!handle_store (current_thread)) {
919 /* Mono is shutting down, so just wait for the end */
924 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
926 SET_CURRENT_OBJECT (thread);
927 mono_domain_set (domain, TRUE);
929 mono_monitor_init_tls ();
931 thread_adjust_static_data (thread);
933 init_root_domain_thread (thread, current_thread);
934 if (domain != mono_get_root_domain ())
935 set_current_thread_for_domain (domain, thread, current_thread);
938 if (mono_thread_attach_cb) {
942 mono_thread_get_stack_bounds (&staddr, &stsize);
945 mono_thread_attach_cb (tid, &tid);
947 mono_thread_attach_cb (tid, staddr + stsize);
950 // FIXME: Need a separate callback
951 mono_profiler_thread_start (tid);
953 return current_thread;
957 mono_thread_detach (MonoThread *thread)
959 g_return_if_fail (thread != NULL);
961 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
963 mono_profiler_thread_end (thread->internal_thread->tid);
965 thread_cleanup (thread->internal_thread);
967 SET_CURRENT_OBJECT (NULL);
968 mono_domain_unset ();
970 /* Don't need to CloseHandle this thread, even though we took a
971 * reference in mono_thread_attach (), because the GC will do it
972 * when the Thread object is finalised.
979 MonoInternalThread *thread = mono_thread_internal_current ();
981 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
983 thread_cleanup (thread);
984 SET_CURRENT_OBJECT (NULL);
985 mono_domain_unset ();
987 /* we could add a callback here for embedders to use. */
988 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
989 exit (mono_environment_exitcode_get ());
994 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
996 MonoInternalThread *internal = create_internal_thread_object ();
998 internal->state = ThreadState_Unstarted;
999 internal->apartment_state = ThreadApartmentState_Unknown;
1000 internal->managed_id = get_next_managed_thread_id ();
1002 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1005 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
1008 guint32 (*start_func)(void *);
1009 struct StartInfo *start_info;
1012 MonoInternalThread *internal;
1014 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1016 if (!this->internal_thread)
1017 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1018 internal = this->internal_thread;
1020 ensure_synch_cs_set (internal);
1022 EnterCriticalSection (internal->synch_cs);
1024 if ((internal->state & ThreadState_Unstarted) == 0) {
1025 LeaveCriticalSection (internal->synch_cs);
1026 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1030 if ((internal->state & ThreadState_Aborted) != 0) {
1031 LeaveCriticalSection (internal->synch_cs);
1036 /* This is freed in start_wrapper */
1037 start_info = g_new0 (struct StartInfo, 1);
1038 start_info->func = start_func;
1039 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1040 start_info->delegate = start;
1041 start_info->obj = this;
1042 g_assert (this->obj.vtable->domain == mono_domain_get ());
1044 internal->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
1045 if (internal->start_notify==NULL) {
1046 LeaveCriticalSection (internal->synch_cs);
1047 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
1048 g_free (start_info);
1052 mono_threads_lock ();
1053 register_thread_start_argument (this, start_info);
1054 if (threads_starting_up == NULL) {
1055 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
1056 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
1058 mono_g_hash_table_insert (threads_starting_up, this, this);
1059 mono_threads_unlock ();
1061 thread=mono_create_thread(NULL, default_stacksize_for_thread (internal), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
1062 CREATE_SUSPENDED, &tid);
1064 LeaveCriticalSection (internal->synch_cs);
1065 mono_threads_lock ();
1066 mono_g_hash_table_remove (threads_starting_up, this);
1067 mono_threads_unlock ();
1068 g_warning("%s: CreateThread error 0x%x", __func__, GetLastError());
1072 internal->handle=thread;
1074 if (mono_gc_is_moving ()) {
1075 internal->thread_pinning_ref = internal;
1076 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
1080 /* Don't call handle_store() here, delay it to Start.
1081 * We can't join a thread (trying to will just block
1082 * forever) until it actually starts running, so don't
1083 * store the handle till then.
1086 mono_thread_start (this);
1088 internal->state &= ~ThreadState_Unstarted;
1090 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1092 LeaveCriticalSection (internal->synch_cs);
1097 void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1099 MONO_ARCH_SAVE_REGS;
1101 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1104 CloseHandle (thread);
1106 if (this->synch_cs) {
1107 CRITICAL_SECTION *synch_cs = this->synch_cs;
1108 this->synch_cs = NULL;
1109 DeleteCriticalSection (synch_cs);
1114 void *name = this->name;
1120 static void mono_thread_start (MonoThread *thread)
1122 MonoInternalThread *internal = thread->internal_thread;
1124 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1126 /* Only store the handle when the thread is about to be
1127 * launched, to avoid the main thread deadlocking while trying
1128 * to clean up a thread that will never be signalled.
1130 if (!handle_store (thread))
1133 ResumeThread (internal->handle);
1135 if(internal->start_notify!=NULL) {
1136 /* Wait for the thread to set up its TLS data etc, so
1137 * theres no potential race condition if someone tries
1138 * to look up the data believing the thread has
1142 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1144 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
1145 CloseHandle (internal->start_notify);
1146 internal->start_notify = NULL;
1149 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1152 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1155 MonoInternalThread *thread = mono_thread_internal_current ();
1157 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1159 mono_thread_current_check_pending_interrupt ();
1162 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1164 res = SleepEx(ms,TRUE);
1166 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1168 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1169 MonoException* exc = mono_thread_execute_interruption (thread);
1171 mono_raise_exception (exc);
1183 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1188 ves_icall_System_Threading_Thread_GetDomainID (void)
1190 MONO_ARCH_SAVE_REGS;
1192 return mono_domain_get()->domain_id;
1196 ves_icall_System_Threading_Thread_Yield (void)
1199 return SwitchToThread ();
1201 return sched_yield () == 0;
1206 * mono_thread_get_name:
1208 * Return the name of the thread. NAME_LEN is set to the length of the name.
1209 * Return NULL if the thread has no name. The returned memory is owned by the
1213 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1217 ensure_synch_cs_set (this_obj);
1219 EnterCriticalSection (this_obj->synch_cs);
1221 if (!this_obj->name) {
1225 *name_len = this_obj->name_len;
1226 res = g_new (gunichar2, this_obj->name_len);
1227 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1230 LeaveCriticalSection (this_obj->synch_cs);
1236 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1240 ensure_synch_cs_set (this_obj);
1242 EnterCriticalSection (this_obj->synch_cs);
1244 if (!this_obj->name)
1247 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1249 LeaveCriticalSection (this_obj->synch_cs);
1255 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1257 ensure_synch_cs_set (this_obj);
1259 EnterCriticalSection (this_obj->synch_cs);
1261 if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1262 LeaveCriticalSection (this_obj->synch_cs);
1264 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1268 this_obj->name = g_new (gunichar2, mono_string_length (name));
1269 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1270 this_obj->name_len = mono_string_length (name);
1273 this_obj->name = NULL;
1276 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1278 LeaveCriticalSection (this_obj->synch_cs);
1279 if (this_obj->name) {
1280 char *tname = mono_string_to_utf8 (name);
1281 mono_profiler_thread_name (this_obj->tid, tname);
1287 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1289 mono_thread_set_name_internal (this_obj, name, TRUE);
1292 /* If the array is already in the requested domain, we just return it,
1293 otherwise we return a copy in that domain. */
1295 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1302 if (mono_object_domain (arr) == domain)
1305 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1306 mono_gc_memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1311 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1313 return byte_array_to_domain (arr, mono_get_root_domain ());
1317 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1319 return byte_array_to_domain (arr, mono_domain_get ());
1323 mono_thread_current (void)
1325 MonoDomain *domain = mono_domain_get ();
1326 MonoInternalThread *internal = mono_thread_internal_current ();
1327 MonoThread **current_thread_ptr;
1329 g_assert (internal);
1330 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1332 if (!*current_thread_ptr) {
1333 g_assert (domain != mono_get_root_domain ());
1334 *current_thread_ptr = new_thread_with_internal (domain, internal);
1336 return *current_thread_ptr;
1340 mono_thread_internal_current (void)
1342 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1343 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1347 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1348 int ms, HANDLE thread)
1350 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1353 mono_thread_current_check_pending_interrupt ();
1355 ensure_synch_cs_set (this);
1357 EnterCriticalSection (this->synch_cs);
1359 if ((this->state & ThreadState_Unstarted) != 0) {
1360 LeaveCriticalSection (this->synch_cs);
1362 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1366 LeaveCriticalSection (this->synch_cs);
1371 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1373 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1375 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1377 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1379 if(ret==WAIT_OBJECT_0) {
1380 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1385 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1391 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1399 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1402 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1404 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1406 if (ret != WAIT_IO_COMPLETION)
1409 exc = mono_thread_execute_interruption (thread);
1411 mono_raise_exception (exc);
1416 /* Re-calculate ms according to the time passed */
1417 diff_ms = (mono_100ns_ticks () - start) / 10000;
1418 if (diff_ms >= ms) {
1422 wait = ms - diff_ms;
1428 /* FIXME: exitContext isnt documented */
1429 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1435 MonoObject *waitHandle;
1436 MonoInternalThread *thread = mono_thread_internal_current ();
1438 /* Do this WaitSleepJoin check before creating objects */
1439 mono_thread_current_check_pending_interrupt ();
1441 numhandles = mono_array_length(mono_handles);
1442 handles = g_new0(HANDLE, numhandles);
1444 for(i = 0; i < numhandles; i++) {
1445 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1446 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1453 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1455 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1457 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1461 if(ret==WAIT_FAILED) {
1462 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1464 } else if(ret==WAIT_TIMEOUT) {
1465 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1472 /* FIXME: exitContext isnt documented */
1473 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1475 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1479 MonoObject *waitHandle;
1480 MonoInternalThread *thread = mono_thread_internal_current ();
1482 /* Do this WaitSleepJoin check before creating objects */
1483 mono_thread_current_check_pending_interrupt ();
1485 numhandles = mono_array_length(mono_handles);
1486 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1489 for(i = 0; i < numhandles; i++) {
1490 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1491 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1498 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1500 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1502 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1504 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1507 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1509 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1510 return ret - WAIT_OBJECT_0;
1512 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1513 return ret - WAIT_ABANDONED_0;
1520 /* FIXME: exitContext isnt documented */
1521 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1524 MonoInternalThread *thread = mono_thread_internal_current ();
1526 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1532 mono_thread_current_check_pending_interrupt ();
1534 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1536 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1538 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1540 if(ret==WAIT_FAILED) {
1541 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1543 } else if(ret==WAIT_TIMEOUT) {
1544 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1552 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1555 MonoInternalThread *thread = mono_thread_internal_current ();
1557 MONO_ARCH_SAVE_REGS;
1562 mono_thread_current_check_pending_interrupt ();
1564 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1566 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1568 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1570 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1573 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1577 MONO_ARCH_SAVE_REGS;
1582 mutex = CreateMutex (NULL, owned, NULL);
1584 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1586 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1594 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1595 MONO_ARCH_SAVE_REGS;
1597 return(ReleaseMutex (handle));
1600 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1606 MONO_ARCH_SAVE_REGS;
1608 *error = ERROR_SUCCESS;
1610 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1612 *error = GetLastError ();
1619 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1623 MONO_ARCH_SAVE_REGS;
1628 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1630 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1631 mono_string_chars (name));
1633 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1641 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1645 MONO_ARCH_SAVE_REGS;
1647 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1652 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1656 MONO_ARCH_SAVE_REGS;
1658 *error = ERROR_SUCCESS;
1660 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1662 *error = GetLastError ();
1668 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1672 MONO_ARCH_SAVE_REGS;
1677 event = CreateEvent (NULL, manual, initial, NULL);
1679 event = CreateEvent (NULL, manual, initial,
1680 mono_string_chars (name));
1682 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1690 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1691 MONO_ARCH_SAVE_REGS;
1693 return (SetEvent(handle));
1696 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1697 MONO_ARCH_SAVE_REGS;
1699 return (ResetEvent(handle));
1703 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1704 MONO_ARCH_SAVE_REGS;
1706 CloseHandle (handle);
1709 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1715 MONO_ARCH_SAVE_REGS;
1717 *error = ERROR_SUCCESS;
1719 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1721 *error = GetLastError ();
1727 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1729 MONO_ARCH_SAVE_REGS;
1731 return InterlockedIncrement (location);
1734 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1738 MONO_ARCH_SAVE_REGS;
1740 mono_interlocked_lock ();
1744 mono_interlocked_unlock ();
1750 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1752 MONO_ARCH_SAVE_REGS;
1754 return InterlockedDecrement(location);
1757 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1761 MONO_ARCH_SAVE_REGS;
1763 mono_interlocked_lock ();
1767 mono_interlocked_unlock ();
1772 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1774 MONO_ARCH_SAVE_REGS;
1776 return InterlockedExchange(location, value);
1779 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1782 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1783 mono_gc_wbarrier_generic_nostore (location);
1787 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1789 return InterlockedExchangePointer(location, value);
1792 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1794 IntFloatUnion val, ret;
1796 MONO_ARCH_SAVE_REGS;
1799 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1805 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1807 #if SIZEOF_VOID_P == 8
1808 return (gint64) InterlockedExchangePointer((gpointer *) location, (gpointer)value);
1813 * According to MSDN, this function is only atomic with regards to the
1814 * other Interlocked functions on 32 bit platforms.
1816 mono_interlocked_lock ();
1819 mono_interlocked_unlock ();
1826 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1828 #if SIZEOF_VOID_P == 8
1829 LongDoubleUnion val, ret;
1832 ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location, (gpointer)val.ival);
1839 * According to MSDN, this function is only atomic with regards to the
1840 * other Interlocked functions on 32 bit platforms.
1842 mono_interlocked_lock ();
1845 mono_interlocked_unlock ();
1851 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1853 MONO_ARCH_SAVE_REGS;
1855 return InterlockedCompareExchange(location, value, comparand);
1858 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1861 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1862 mono_gc_wbarrier_generic_nostore (location);
1866 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1868 return InterlockedCompareExchangePointer(location, value, comparand);
1871 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1873 IntFloatUnion val, ret, cmp;
1875 MONO_ARCH_SAVE_REGS;
1878 cmp.fval = comparand;
1879 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1885 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1887 #if SIZEOF_VOID_P == 8
1888 LongDoubleUnion val, comp, ret;
1891 comp.fval = comparand;
1892 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1898 mono_interlocked_lock ();
1900 if (old == comparand)
1902 mono_interlocked_unlock ();
1909 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1911 #if SIZEOF_VOID_P == 8
1912 return (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)value, (gpointer)comparand);
1916 mono_interlocked_lock ();
1918 if (old == comparand)
1920 mono_interlocked_unlock ();
1927 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1930 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1931 mono_gc_wbarrier_generic_nostore (location);
1936 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1939 res = InterlockedExchangePointer ((gpointer *)location, value);
1940 mono_gc_wbarrier_generic_nostore (location);
1945 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1947 #if SIZEOF_VOID_P == 8
1948 /* Should be implemented as a JIT intrinsic */
1949 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1954 mono_interlocked_lock ();
1956 *location = orig + value;
1957 mono_interlocked_unlock ();
1959 return orig + value;
1964 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1966 #if SIZEOF_VOID_P == 8
1967 /* Should be implemented as a JIT intrinsic */
1968 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1973 mono_interlocked_lock ();
1975 *location = orig + value;
1976 mono_interlocked_unlock ();
1978 return orig + value;
1983 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1985 #if SIZEOF_VOID_P == 8
1986 /* 64 bit reads are already atomic */
1991 mono_interlocked_lock ();
1993 mono_interlocked_unlock ();
2000 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2002 mono_threads_lock ();
2003 mono_threads_unlock ();
2007 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
2009 mono_thread_clr_state (this, state);
2011 if (state & ThreadState_Background) {
2012 /* If the thread changes the background mode, the main thread has to
2013 * be notified, since it has to rebuild the list of threads to
2016 SetEvent (background_change_event);
2021 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
2023 mono_thread_set_state (this, state);
2025 if (state & ThreadState_Background) {
2026 /* If the thread changes the background mode, the main thread has to
2027 * be notified, since it has to rebuild the list of threads to
2030 SetEvent (background_change_event);
2035 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2039 ensure_synch_cs_set (this);
2041 EnterCriticalSection (this->synch_cs);
2043 state = this->state;
2045 LeaveCriticalSection (this->synch_cs);
2050 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
2052 MonoInternalThread *current;
2055 ensure_synch_cs_set (this);
2057 current = mono_thread_internal_current ();
2059 EnterCriticalSection (this->synch_cs);
2061 this->thread_interrupt_requested = TRUE;
2062 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
2064 LeaveCriticalSection (this->synch_cs);
2067 abort_thread_internal (this, TRUE, FALSE);
2071 void mono_thread_current_check_pending_interrupt ()
2073 MonoInternalThread *thread = mono_thread_internal_current ();
2074 gboolean throw = FALSE;
2076 mono_debugger_check_interruption ();
2078 ensure_synch_cs_set (thread);
2080 EnterCriticalSection (thread->synch_cs);
2082 if (thread->thread_interrupt_requested) {
2084 thread->thread_interrupt_requested = FALSE;
2087 LeaveCriticalSection (thread->synch_cs);
2090 mono_raise_exception (mono_get_exception_thread_interrupted ());
2095 mono_thread_get_abort_signal (void)
2099 #elif defined(PLATFORM_ANDROID)
2101 #elif !defined (SIGRTMIN)
2106 #endif /* SIGUSR1 */
2108 static int abort_signum = -1;
2110 if (abort_signum != -1)
2111 return abort_signum;
2112 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2113 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2114 struct sigaction sinfo;
2115 sigaction (i, NULL, &sinfo);
2116 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2121 /* fallback to the old way */
2123 #endif /* HOST_WIN32 */
2127 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2129 MonoException* exc = mono_thread_request_interruption (FALSE);
2130 if (exc) mono_raise_exception (exc);
2132 #endif /* HOST_WIN32 */
2135 * signal_thread_state_change
2137 * Tells the thread that his state has changed and it has to enter the new
2138 * state as soon as possible.
2140 static void signal_thread_state_change (MonoInternalThread *thread)
2142 if (thread == mono_thread_internal_current ()) {
2143 /* Do it synchronously */
2144 MonoException *exc = mono_thread_request_interruption (FALSE);
2146 mono_raise_exception (exc);
2150 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
2152 /* fixme: store the state somewhere */
2153 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2156 * This will cause waits to be broken.
2157 * It will also prevent the thread from entering a wait, so if the thread returns
2158 * from the wait before it receives the abort signal, it will just spin in the wait
2159 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2162 wapi_interrupt_thread (thread->handle);
2163 #endif /* HOST_WIN32 */
2167 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2169 ensure_synch_cs_set (thread);
2171 EnterCriticalSection (thread->synch_cs);
2173 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2174 (thread->state & ThreadState_StopRequested) != 0 ||
2175 (thread->state & ThreadState_Stopped) != 0)
2177 LeaveCriticalSection (thread->synch_cs);
2181 if ((thread->state & ThreadState_Unstarted) != 0) {
2182 thread->state |= ThreadState_Aborted;
2183 LeaveCriticalSection (thread->synch_cs);
2187 thread->state |= ThreadState_AbortRequested;
2188 if (thread->abort_state_handle)
2189 mono_gchandle_free (thread->abort_state_handle);
2191 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2192 g_assert (thread->abort_state_handle);
2194 thread->abort_state_handle = 0;
2196 thread->abort_exc = NULL;
2199 * abort_exc is set in mono_thread_execute_interruption(),
2200 * triggered by the call to signal_thread_state_change(),
2201 * below. There's a point between where we have
2202 * abort_state_handle set, but abort_exc NULL, but that's not
2206 LeaveCriticalSection (thread->synch_cs);
2208 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2210 /* During shutdown, we can't wait for other threads */
2212 /* Make sure the thread is awake */
2213 mono_thread_resume (thread);
2215 abort_thread_internal (thread, TRUE, TRUE);
2219 ves_icall_System_Threading_Thread_ResetAbort (void)
2221 MonoInternalThread *thread = mono_thread_internal_current ();
2222 gboolean was_aborting;
2224 ensure_synch_cs_set (thread);
2226 EnterCriticalSection (thread->synch_cs);
2227 was_aborting = thread->state & ThreadState_AbortRequested;
2228 thread->state &= ~ThreadState_AbortRequested;
2229 LeaveCriticalSection (thread->synch_cs);
2231 if (!was_aborting) {
2232 const char *msg = "Unable to reset abort because no abort was requested";
2233 mono_raise_exception (mono_get_exception_thread_state (msg));
2235 thread->abort_exc = NULL;
2236 if (thread->abort_state_handle) {
2237 mono_gchandle_free (thread->abort_state_handle);
2238 /* This is actually not necessary - the handle
2239 only counts if the exception is set */
2240 thread->abort_state_handle = 0;
2245 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2247 ensure_synch_cs_set (thread);
2249 EnterCriticalSection (thread->synch_cs);
2251 thread->state &= ~ThreadState_AbortRequested;
2253 if (thread->abort_exc) {
2254 thread->abort_exc = NULL;
2255 if (thread->abort_state_handle) {
2256 mono_gchandle_free (thread->abort_state_handle);
2257 /* This is actually not necessary - the handle
2258 only counts if the exception is set */
2259 thread->abort_state_handle = 0;
2263 LeaveCriticalSection (thread->synch_cs);
2267 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2269 MonoInternalThread *thread = this->internal_thread;
2270 MonoObject *state, *deserialized = NULL, *exc;
2273 if (!thread->abort_state_handle)
2276 state = mono_gchandle_get_target (thread->abort_state_handle);
2279 domain = mono_domain_get ();
2280 if (mono_object_domain (state) == domain)
2283 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2285 if (!deserialized) {
2286 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2288 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2289 mono_raise_exception (invalid_op_exc);
2292 return deserialized;
2296 mono_thread_suspend (MonoInternalThread *thread)
2298 ensure_synch_cs_set (thread);
2300 EnterCriticalSection (thread->synch_cs);
2302 if ((thread->state & ThreadState_Unstarted) != 0 ||
2303 (thread->state & ThreadState_Aborted) != 0 ||
2304 (thread->state & ThreadState_Stopped) != 0)
2306 LeaveCriticalSection (thread->synch_cs);
2310 if ((thread->state & ThreadState_Suspended) != 0 ||
2311 (thread->state & ThreadState_SuspendRequested) != 0 ||
2312 (thread->state & ThreadState_StopRequested) != 0)
2314 LeaveCriticalSection (thread->synch_cs);
2318 thread->state |= ThreadState_SuspendRequested;
2320 LeaveCriticalSection (thread->synch_cs);
2322 suspend_thread_internal (thread, FALSE);
2327 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2329 if (!mono_thread_suspend (thread))
2330 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2334 mono_thread_resume (MonoInternalThread *thread)
2336 ensure_synch_cs_set (thread);
2338 EnterCriticalSection (thread->synch_cs);
2340 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2341 thread->state &= ~ThreadState_SuspendRequested;
2342 LeaveCriticalSection (thread->synch_cs);
2346 if ((thread->state & ThreadState_Suspended) == 0 ||
2347 (thread->state & ThreadState_Unstarted) != 0 ||
2348 (thread->state & ThreadState_Aborted) != 0 ||
2349 (thread->state & ThreadState_Stopped) != 0)
2351 LeaveCriticalSection (thread->synch_cs);
2355 return resume_thread_internal (thread);
2359 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2361 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2362 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2366 mono_threads_is_critical_method (MonoMethod *method)
2368 switch (method->wrapper_type) {
2369 case MONO_WRAPPER_RUNTIME_INVOKE:
2370 case MONO_WRAPPER_XDOMAIN_INVOKE:
2371 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2378 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2383 if (mono_threads_is_critical_method (m)) {
2384 *((gboolean*)data) = TRUE;
2391 is_running_protected_wrapper (void)
2393 gboolean found = FALSE;
2394 mono_stack_walk (find_wrapper, &found);
2398 void mono_thread_internal_stop (MonoInternalThread *thread)
2400 ensure_synch_cs_set (thread);
2402 EnterCriticalSection (thread->synch_cs);
2404 if ((thread->state & ThreadState_StopRequested) != 0 ||
2405 (thread->state & ThreadState_Stopped) != 0)
2407 LeaveCriticalSection (thread->synch_cs);
2411 /* Make sure the thread is awake */
2412 mono_thread_resume (thread);
2414 thread->state |= ThreadState_StopRequested;
2415 thread->state &= ~ThreadState_AbortRequested;
2417 LeaveCriticalSection (thread->synch_cs);
2419 abort_thread_internal (thread, TRUE, TRUE);
2422 void mono_thread_stop (MonoThread *thread)
2424 mono_thread_internal_stop (thread->internal_thread);
2428 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2430 return *((volatile gint8 *) (ptr));
2434 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2436 return *((volatile gint16 *) (ptr));
2440 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2442 return *((volatile gint32 *) (ptr));
2446 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2448 return *((volatile gint64 *) (ptr));
2452 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2454 return (void *) *((volatile void **) ptr);
2458 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2460 return *((volatile double *) (ptr));
2464 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2466 return *((volatile float *) (ptr));
2470 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2472 *((volatile gint8 *) ptr) = value;
2476 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2478 *((volatile gint16 *) ptr) = value;
2482 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2484 *((volatile gint32 *) ptr) = value;
2488 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2490 *((volatile gint64 *) ptr) = value;
2494 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2496 *((volatile void **) ptr) = value;
2500 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, void *value)
2502 mono_gc_wbarrier_generic_store (ptr, value);
2506 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2508 *((volatile double *) ptr) = value;
2512 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2514 *((volatile float *) ptr) = value;
2517 void mono_thread_init (MonoThreadStartCB start_cb,
2518 MonoThreadAttachCB attach_cb)
2520 InitializeCriticalSection(&threads_mutex);
2521 InitializeCriticalSection(&interlocked_mutex);
2522 InitializeCriticalSection(&contexts_mutex);
2524 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2525 g_assert(background_change_event != NULL);
2527 mono_init_static_data_info (&thread_static_info);
2528 mono_init_static_data_info (&context_static_info);
2530 MONO_FAST_TLS_INIT (tls_current_object);
2531 mono_native_tls_alloc (¤t_object_key, NULL);
2532 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2534 mono_thread_start_cb = start_cb;
2535 mono_thread_attach_cb = attach_cb;
2537 /* Get a pseudo handle to the current process. This is just a
2538 * kludge so that wapi can build a process handle if needed.
2539 * As a pseudo handle is returned, we don't need to clean
2542 GetCurrentProcess ();
2545 void mono_thread_cleanup (void)
2547 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2548 /* The main thread must abandon any held mutexes (particularly
2549 * important for named mutexes as they are shared across
2550 * processes, see bug 74680.) This will happen when the
2551 * thread exits, but if it's not running in a subthread it
2552 * won't exit in time.
2554 /* Using non-w32 API is a nasty kludge, but I couldn't find
2555 * anything in the documentation that would let me do this
2556 * here yet still be safe to call on windows.
2558 _wapi_thread_signal_self (mono_environment_exitcode_get ());
2562 /* This stuff needs more testing, it seems one of these
2563 * critical sections can be locked when mono_thread_cleanup is
2566 DeleteCriticalSection (&threads_mutex);
2567 DeleteCriticalSection (&interlocked_mutex);
2568 DeleteCriticalSection (&contexts_mutex);
2569 DeleteCriticalSection (&delayed_free_table_mutex);
2570 DeleteCriticalSection (&small_id_mutex);
2571 CloseHandle (background_change_event);
2574 mono_native_tls_free (current_object_key);
2578 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2580 mono_thread_cleanup_fn = func;
2584 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2586 thread->internal_thread->manage_callback = func;
2589 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2591 mono_thread_notify_pending_exc_fn = func;
2595 static void print_tids (gpointer key, gpointer value, gpointer user)
2597 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2598 * sizeof(uint) and a cast to uint would overflow
2600 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2601 * print this as a pointer.
2603 g_message ("Waiting for: %p", key);
2608 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2609 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2613 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2617 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2619 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2621 if(ret==WAIT_FAILED) {
2622 /* See the comment in build_wait_tids() */
2623 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2627 for(i=0; i<wait->num; i++)
2628 CloseHandle (wait->handles[i]);
2630 if (ret == WAIT_TIMEOUT)
2633 for(i=0; i<wait->num; i++) {
2634 gsize tid = wait->threads[i]->tid;
2636 mono_threads_lock ();
2637 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2638 /* This thread must have been killed, because
2639 * it hasn't cleaned itself up. (It's just
2640 * possible that the thread exited before the
2641 * parent thread had a chance to store the
2642 * handle, and now there is another pointer to
2643 * the already-exited thread stored. In this
2644 * case, we'll just get two
2645 * mono_profiler_thread_end() calls for the
2649 mono_threads_unlock ();
2650 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2651 thread_cleanup (wait->threads[i]);
2653 mono_threads_unlock ();
2658 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2660 guint32 i, ret, count;
2662 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2664 /* Add the thread state change event, so it wakes up if a thread changes
2665 * to background mode.
2668 if (count < MAXIMUM_WAIT_OBJECTS) {
2669 wait->handles [count] = background_change_event;
2673 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2675 if(ret==WAIT_FAILED) {
2676 /* See the comment in build_wait_tids() */
2677 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2681 for(i=0; i<wait->num; i++)
2682 CloseHandle (wait->handles[i]);
2684 if (ret == WAIT_TIMEOUT)
2687 if (ret < wait->num) {
2688 gsize tid = wait->threads[ret]->tid;
2689 mono_threads_lock ();
2690 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2691 /* See comment in wait_for_tids about thread cleanup */
2692 mono_threads_unlock ();
2693 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2694 thread_cleanup (wait->threads [ret]);
2696 mono_threads_unlock ();
2700 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2702 struct wait_data *wait=(struct wait_data *)user;
2704 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2706 MonoInternalThread *thread=(MonoInternalThread *)value;
2708 /* Ignore background threads, we abort them later */
2709 /* Do not lock here since it is not needed and the caller holds threads_lock */
2710 if (thread->state & ThreadState_Background) {
2711 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2712 return; /* just leave, ignore */
2715 if (mono_gc_is_finalizer_internal_thread (thread)) {
2716 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2720 if (thread == mono_thread_internal_current ()) {
2721 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2725 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2726 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2730 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2731 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2735 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2736 if (handle == NULL) {
2737 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2741 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2742 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2743 wait->handles[wait->num]=handle;
2744 wait->threads[wait->num]=thread;
2747 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2749 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2754 /* Just ignore the rest, we can't do anything with
2761 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2763 struct wait_data *wait=(struct wait_data *)user;
2764 gsize self = GetCurrentThreadId ();
2765 MonoInternalThread *thread = value;
2768 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2771 /* The finalizer thread is not a background thread */
2772 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2773 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2775 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2779 /* printf ("A: %d\n", wait->num); */
2780 wait->handles[wait->num]=thread->handle;
2781 wait->threads[wait->num]=thread;
2784 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2785 mono_thread_internal_stop (thread);
2789 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2793 * mono_threads_set_shutting_down:
2795 * Is called by a thread that wants to shut down Mono. If the runtime is already
2796 * shutting down, the calling thread is suspended/stopped, and this function never
2800 mono_threads_set_shutting_down (void)
2802 MonoInternalThread *current_thread = mono_thread_internal_current ();
2804 mono_threads_lock ();
2806 if (shutting_down) {
2807 mono_threads_unlock ();
2809 /* Make sure we're properly suspended/stopped */
2811 EnterCriticalSection (current_thread->synch_cs);
2813 if ((current_thread->state & ThreadState_SuspendRequested) ||
2814 (current_thread->state & ThreadState_AbortRequested) ||
2815 (current_thread->state & ThreadState_StopRequested)) {
2816 LeaveCriticalSection (current_thread->synch_cs);
2817 mono_thread_execute_interruption (current_thread);
2819 current_thread->state |= ThreadState_Stopped;
2820 LeaveCriticalSection (current_thread->synch_cs);
2823 /*since we're killing the thread, unset the current domain.*/
2824 mono_domain_unset ();
2826 /* Wake up other threads potentially waiting for us */
2829 shutting_down = TRUE;
2831 /* Not really a background state change, but this will
2832 * interrupt the main thread if it is waiting for all
2833 * the other threads.
2835 SetEvent (background_change_event);
2837 mono_threads_unlock ();
2842 * mono_threads_is_shutting_down:
2844 * Returns whether a thread has commenced shutdown of Mono. Note that
2845 * if the function returns FALSE the caller must not assume that
2846 * shutdown is not in progress, because the situation might have
2847 * changed since the function returned. For that reason this function
2848 * is of very limited utility.
2851 mono_threads_is_shutting_down (void)
2853 return shutting_down;
2856 void mono_thread_manage (void)
2858 struct wait_data wait_data;
2859 struct wait_data *wait = &wait_data;
2861 memset (wait, 0, sizeof (struct wait_data));
2862 /* join each thread that's still running */
2863 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2865 mono_threads_lock ();
2867 THREAD_DEBUG (g_message("%s: No threads", __func__));
2868 mono_threads_unlock ();
2871 mono_threads_unlock ();
2874 mono_threads_lock ();
2875 if (shutting_down) {
2876 /* somebody else is shutting down */
2877 mono_threads_unlock ();
2880 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2881 mono_g_hash_table_foreach (threads, print_tids, NULL));
2883 ResetEvent (background_change_event);
2885 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2886 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2887 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2888 mono_threads_unlock ();
2890 /* Something to wait for */
2891 wait_for_tids_or_state_change (wait, INFINITE);
2893 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2894 } while(wait->num>0);
2896 mono_threads_set_shutting_down ();
2898 /* No new threads will be created after this point */
2900 mono_runtime_set_shutting_down ();
2902 THREAD_DEBUG (g_message ("%s: threadpool cleanup", __func__));
2903 mono_thread_pool_cleanup ();
2906 * Remove everything but the finalizer thread and self.
2907 * Also abort all the background threads
2910 mono_threads_lock ();
2913 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2914 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2915 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2917 mono_threads_unlock ();
2919 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2921 /* Something to wait for */
2922 wait_for_tids (wait, INFINITE);
2924 } while (wait->num > 0);
2927 * give the subthreads a chance to really quit (this is mainly needed
2928 * to get correct user and system times from getrusage/wait/time(1)).
2929 * This could be removed if we avoid pthread_detach() and use pthread_join().
2936 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2938 MonoInternalThread *thread=(MonoInternalThread *)value;
2940 if(thread->tid != (gsize)user) {
2941 /*TerminateThread (thread->handle, -1);*/
2945 void mono_thread_abort_all_other_threads (void)
2947 gsize self = GetCurrentThreadId ();
2949 mono_threads_lock ();
2950 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2951 mono_g_hash_table_size (threads));
2952 mono_g_hash_table_foreach (threads, print_tids, NULL));
2954 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2956 mono_threads_unlock ();
2960 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2962 MonoInternalThread *thread = (MonoInternalThread*)value;
2963 struct wait_data *wait = (struct wait_data*)user_data;
2967 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
2969 * This needs no locking.
2971 if ((thread->state & ThreadState_Suspended) != 0 ||
2972 (thread->state & ThreadState_Stopped) != 0)
2975 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2976 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2980 wait->handles [wait->num] = handle;
2981 wait->threads [wait->num] = thread;
2987 * mono_thread_suspend_all_other_threads:
2989 * Suspend all managed threads except the finalizer thread and this thread. It is
2990 * not possible to resume them later.
2992 void mono_thread_suspend_all_other_threads (void)
2994 struct wait_data wait_data;
2995 struct wait_data *wait = &wait_data;
2997 gsize self = GetCurrentThreadId ();
2999 guint32 eventidx = 0;
3000 gboolean starting, finished;
3002 memset (wait, 0, sizeof (struct wait_data));
3004 * The other threads could be in an arbitrary state at this point, i.e.
3005 * they could be starting up, shutting down etc. This means that there could be
3006 * threads which are not even in the threads hash table yet.
3010 * First we set a barrier which will be checked by all threads before they
3011 * are added to the threads hash table, and they will exit if the flag is set.
3012 * This ensures that no threads could be added to the hash later.
3013 * We will use shutting_down as the barrier for now.
3015 g_assert (shutting_down);
3018 * We make multiple calls to WaitForMultipleObjects since:
3019 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3020 * - some threads could exit without becoming suspended
3025 * Make a copy of the hashtable since we can't do anything with
3026 * threads while threads_mutex is held.
3029 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3030 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3031 mono_threads_lock ();
3032 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3033 mono_threads_unlock ();
3035 events = g_new0 (gpointer, wait->num);
3037 /* Get the suspended events that we'll be waiting for */
3038 for (i = 0; i < wait->num; ++i) {
3039 MonoInternalThread *thread = wait->threads [i];
3040 gboolean signal_suspend = FALSE;
3042 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3043 //CloseHandle (wait->handles [i]);
3044 wait->threads [i] = NULL; /* ignore this thread in next loop */
3048 ensure_synch_cs_set (thread);
3050 EnterCriticalSection (thread->synch_cs);
3052 if (thread->suspended_event == NULL) {
3053 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3054 if (thread->suspended_event == NULL) {
3055 /* Forget this one and go on to the next */
3056 LeaveCriticalSection (thread->synch_cs);
3061 if ((thread->state & ThreadState_Suspended) != 0 ||
3062 (thread->state & ThreadState_StopRequested) != 0 ||
3063 (thread->state & ThreadState_Stopped) != 0) {
3064 LeaveCriticalSection (thread->synch_cs);
3065 CloseHandle (wait->handles [i]);
3066 wait->threads [i] = NULL; /* ignore this thread in next loop */
3070 if ((thread->state & ThreadState_SuspendRequested) == 0)
3071 signal_suspend = TRUE;
3073 events [eventidx++] = thread->suspended_event;
3075 /* Convert abort requests into suspend requests */
3076 if ((thread->state & ThreadState_AbortRequested) != 0)
3077 thread->state &= ~ThreadState_AbortRequested;
3079 thread->state |= ThreadState_SuspendRequested;
3081 LeaveCriticalSection (thread->synch_cs);
3083 /* Signal the thread to suspend */
3084 if (mono_thread_info_new_interrupt_enabled ())
3085 suspend_thread_internal (thread, TRUE);
3086 else if (signal_suspend)
3087 signal_thread_state_change (thread);
3090 /*Only wait on the suspend event if we are using the old path */
3091 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3092 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3093 for (i = 0; i < wait->num; ++i) {
3094 MonoInternalThread *thread = wait->threads [i];
3099 ensure_synch_cs_set (thread);
3101 EnterCriticalSection (thread->synch_cs);
3102 if ((thread->state & ThreadState_Suspended) != 0) {
3103 CloseHandle (thread->suspended_event);
3104 thread->suspended_event = NULL;
3106 LeaveCriticalSection (thread->synch_cs);
3110 if (eventidx <= 0) {
3112 * If there are threads which are starting up, we wait until they
3113 * are suspended when they try to register in the threads hash.
3114 * This is guaranteed to finish, since the threads which can create new
3115 * threads get suspended after a while.
3116 * FIXME: The finalizer thread can still create new threads.
3118 mono_threads_lock ();
3119 if (threads_starting_up)
3120 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3123 mono_threads_unlock ();
3135 collect_threads (gpointer key, gpointer value, gpointer user_data)
3137 MonoInternalThread *thread = (MonoInternalThread*)value;
3138 struct wait_data *wait = (struct wait_data*)user_data;
3141 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3142 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3146 wait->handles [wait->num] = handle;
3147 wait->threads [wait->num] = thread;
3152 static gboolean thread_dump_requested;
3154 static G_GNUC_UNUSED gboolean
3155 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3157 GString *p = (GString*)data;
3158 MonoMethod *method = NULL;
3160 method = frame->ji->method;
3163 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3164 g_string_append_printf (p, " %s\n", location);
3167 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3173 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3175 GString* text = g_string_new (0);
3177 GError *error = NULL;
3180 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3182 g_string_append_printf (text, "\n\"%s\"", name);
3185 else if (thread->threadpool_thread)
3186 g_string_append (text, "\n\"<threadpool thread>\"");
3188 g_string_append (text, "\n\"<unnamed thread>\"");
3191 /* This no longer works with remote unwinding */
3193 wapi_desc = wapi_current_thread_desc ();
3194 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3199 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3200 mono_thread_info_resume (mono_thread_info_get_tid (info));
3202 fprintf (stdout, "%s", text->str);
3204 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3205 OutputDebugStringA(text->str);
3208 g_string_free (text, TRUE);
3213 dump_thread (gpointer key, gpointer value, gpointer user)
3215 MonoInternalThread *thread = (MonoInternalThread *)value;
3216 MonoThreadInfo *info;
3218 if (thread == mono_thread_internal_current ())
3222 FIXME This still can hang if we stop a thread during malloc.
3223 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3224 that takes a callback and runs it with the target suspended.
3225 We probably should loop a bit around trying to get it to either managed code
3228 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3233 print_thread_dump (thread, info);
3237 mono_threads_perform_thread_dump (void)
3239 if (!thread_dump_requested)
3242 printf ("Full thread dump:\n");
3245 * Make a copy of the hashtable since we can't do anything with
3246 * threads while threads_mutex is held.
3248 mono_threads_lock ();
3249 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3250 mono_threads_unlock ();
3252 thread_dump_requested = FALSE;
3256 * mono_threads_request_thread_dump:
3258 * Ask all threads except the current to print their stacktrace to stdout.
3261 mono_threads_request_thread_dump (void)
3263 struct wait_data wait_data;
3264 struct wait_data *wait = &wait_data;
3267 /*The new thread dump code runs out of the finalizer thread. */
3268 if (mono_thread_info_new_interrupt_enabled ()) {
3269 thread_dump_requested = TRUE;
3270 mono_gc_finalize_notify ();
3275 memset (wait, 0, sizeof (struct wait_data));
3278 * Make a copy of the hashtable since we can't do anything with
3279 * threads while threads_mutex is held.
3281 mono_threads_lock ();
3282 mono_g_hash_table_foreach (threads, collect_threads, wait);
3283 mono_threads_unlock ();
3285 for (i = 0; i < wait->num; ++i) {
3286 MonoInternalThread *thread = wait->threads [i];
3288 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3289 (thread != mono_thread_internal_current ()) &&
3290 !thread->thread_dump_requested) {
3291 thread->thread_dump_requested = TRUE;
3293 signal_thread_state_change (thread);
3296 CloseHandle (wait->handles [i]);
3302 gint allocated; /* +1 so that refs [allocated] == NULL */
3306 typedef struct ref_stack RefStack;
3309 ref_stack_new (gint initial_size)
3313 initial_size = MAX (initial_size, 16) + 1;
3314 rs = g_new0 (RefStack, 1);
3315 rs->refs = g_new0 (gpointer, initial_size);
3316 rs->allocated = initial_size;
3321 ref_stack_destroy (gpointer ptr)
3332 ref_stack_push (RefStack *rs, gpointer ptr)
3334 g_assert (rs != NULL);
3336 if (rs->bottom >= rs->allocated) {
3337 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3338 rs->allocated <<= 1;
3339 rs->refs [rs->allocated] = NULL;
3341 rs->refs [rs->bottom++] = ptr;
3345 ref_stack_pop (RefStack *rs)
3347 if (rs == NULL || rs->bottom == 0)
3351 rs->refs [rs->bottom] = NULL;
3355 ref_stack_find (RefStack *rs, gpointer ptr)
3362 for (refs = rs->refs; refs && *refs; refs++) {
3370 * mono_thread_push_appdomain_ref:
3372 * Register that the current thread may have references to objects in domain
3373 * @domain on its stack. Each call to this function should be paired with a
3374 * call to pop_appdomain_ref.
3377 mono_thread_push_appdomain_ref (MonoDomain *domain)
3379 MonoInternalThread *thread = mono_thread_internal_current ();
3382 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3383 SPIN_LOCK (thread->lock_thread_id);
3384 if (thread->appdomain_refs == NULL)
3385 thread->appdomain_refs = ref_stack_new (16);
3386 ref_stack_push (thread->appdomain_refs, domain);
3387 SPIN_UNLOCK (thread->lock_thread_id);
3392 mono_thread_pop_appdomain_ref (void)
3394 MonoInternalThread *thread = mono_thread_internal_current ();
3397 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3398 SPIN_LOCK (thread->lock_thread_id);
3399 ref_stack_pop (thread->appdomain_refs);
3400 SPIN_UNLOCK (thread->lock_thread_id);
3405 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3408 SPIN_LOCK (thread->lock_thread_id);
3409 res = ref_stack_find (thread->appdomain_refs, domain);
3410 SPIN_UNLOCK (thread->lock_thread_id);
3415 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3417 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3420 typedef struct abort_appdomain_data {
3421 struct wait_data wait;
3423 } abort_appdomain_data;
3426 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3428 MonoInternalThread *thread = (MonoInternalThread*)value;
3429 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3430 MonoDomain *domain = data->domain;
3432 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3433 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3435 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3436 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3439 data->wait.handles [data->wait.num] = handle;
3440 data->wait.threads [data->wait.num] = thread;
3443 /* Just ignore the rest, we can't do anything with
3451 * mono_threads_abort_appdomain_threads:
3453 * Abort threads which has references to the given appdomain.
3456 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3458 abort_appdomain_data user_data;
3460 int orig_timeout = timeout;
3463 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3465 start_time = mono_msec_ticks ();
3467 mono_threads_lock ();
3469 user_data.domain = domain;
3470 user_data.wait.num = 0;
3471 /* This shouldn't take any locks */
3472 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3473 mono_threads_unlock ();
3475 if (user_data.wait.num > 0) {
3476 /* Abort the threads outside the threads lock */
3477 for (i = 0; i < user_data.wait.num; ++i)
3478 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3481 * We should wait for the threads either to abort, or to leave the
3482 * domain. We can't do the latter, so we wait with a timeout.
3484 wait_for_tids (&user_data.wait, 100);
3487 /* Update remaining time */
3488 timeout -= mono_msec_ticks () - start_time;
3489 start_time = mono_msec_ticks ();
3491 if (orig_timeout != -1 && timeout < 0)
3494 while (user_data.wait.num > 0);
3496 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3502 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3504 MonoInternalThread *thread = (MonoInternalThread*)value;
3505 MonoDomain *domain = (MonoDomain*)user_data;
3508 /* No locking needed here */
3509 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3511 if (thread->cached_culture_info) {
3512 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3513 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3514 if (obj && obj->vtable->domain == domain)
3515 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3521 * mono_threads_clear_cached_culture:
3523 * Clear the cached_current_culture from all threads if it is in the
3527 mono_threads_clear_cached_culture (MonoDomain *domain)
3529 mono_threads_lock ();
3530 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3531 mono_threads_unlock ();
3535 * mono_thread_get_undeniable_exception:
3537 * Return an exception which needs to be raised when leaving a catch clause.
3538 * This is used for undeniable exception propagation.
3541 mono_thread_get_undeniable_exception (void)
3543 MonoInternalThread *thread = mono_thread_internal_current ();
3545 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3547 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3548 * exception if the thread no longer references a dying appdomain.
3550 thread->abort_exc->trace_ips = NULL;
3551 thread->abort_exc->stack_trace = NULL;
3552 return thread->abort_exc;
3558 #if MONO_SMALL_CONFIG
3559 #define NUM_STATIC_DATA_IDX 4
3560 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3564 #define NUM_STATIC_DATA_IDX 8
3565 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3566 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3570 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3573 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
3576 gpointer *static_data = addr;
3577 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3580 if (!static_data [i])
3582 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3583 ptr = static_data [i];
3584 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3585 uintptr_t bmap = static_reference_bitmaps [i][j];
3588 if ((bmap & 1) && *p) {
3599 * mono_alloc_static_data
3601 * Allocate memory blocks for storing threads or context static data
3604 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3606 guint idx = (offset >> 24) - 1;
3609 gpointer* static_data = *static_data_ptr;
3611 static void* tls_desc = NULL;
3612 if (mono_gc_user_markers_supported () && !tls_desc)
3613 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3614 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3615 *static_data_ptr = static_data;
3616 static_data [0] = static_data;
3619 for (i = 1; i <= idx; ++i) {
3620 if (static_data [i])
3622 if (mono_gc_user_markers_supported () && threadlocal)
3623 static_data [i] = g_malloc0 (static_data_size [i]);
3625 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3630 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3633 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3634 if (!static_data [i])
3636 if (mono_gc_user_markers_supported () && threadlocal)
3637 g_free (static_data [i]);
3639 mono_gc_free_fixed (static_data [i]);
3641 mono_gc_free_fixed (static_data);
3645 * mono_init_static_data_info
3647 * Initializes static data counters
3649 static void mono_init_static_data_info (StaticDataInfo *static_data)
3651 static_data->idx = 0;
3652 static_data->offset = 0;
3653 static_data->freelist = NULL;
3657 * mono_alloc_static_data_slot
3659 * Generates an offset for static data. static_data contains the counters
3660 * used to generate it.
3663 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3667 if (!static_data->idx && !static_data->offset) {
3669 * we use the first chunk of the first allocation also as
3670 * an array for the rest of the data
3672 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3674 static_data->offset += align - 1;
3675 static_data->offset &= ~(align - 1);
3676 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3677 static_data->idx ++;
3678 g_assert (size <= static_data_size [static_data->idx]);
3679 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3680 static_data->offset = 0;
3682 offset = static_data->offset | ((static_data->idx + 1) << 24);
3683 static_data->offset += size;
3688 * ensure thread static fields already allocated are valid for thread
3689 * This function is called when a thread is created or on thread attach.
3692 thread_adjust_static_data (MonoInternalThread *thread)
3696 mono_threads_lock ();
3697 if (thread_static_info.offset || thread_static_info.idx > 0) {
3698 /* get the current allocated size */
3699 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3700 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3702 mono_threads_unlock ();
3706 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3708 MonoInternalThread *thread = value;
3709 guint32 offset = GPOINTER_TO_UINT (user);
3711 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3714 static MonoThreadDomainTls*
3715 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3717 MonoThreadDomainTls* prev = NULL;
3718 MonoThreadDomainTls* tmp = static_data->freelist;
3720 if (tmp->size == size) {
3722 prev->next = tmp->next;
3724 static_data->freelist = tmp->next;
3733 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3736 int idx = (offset >> 24) - 1;
3738 if (!static_reference_bitmaps [idx])
3739 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3740 rb = static_reference_bitmaps [idx];
3742 offset /= sizeof (gpointer);
3743 /* offset is now the bitmap offset */
3744 for (i = 0; i < numbits; ++i) {
3745 if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
3746 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3751 clear_reference_bitmap (guint32 offset, guint32 size)
3753 int idx = (offset >> 24) - 1;
3755 rb = static_reference_bitmaps [idx];
3757 offset /= sizeof (gpointer);
3758 size /= sizeof (gpointer);
3760 /* offset is now the bitmap offset */
3761 for (; offset < size; ++offset)
3762 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3766 * The offset for a special static variable is composed of three parts:
3767 * a bit that indicates the type of static data (0:thread, 1:context),
3768 * an index in the array of chunks of memory for the thread (thread->static_data)
3769 * and an offset in that chunk of mem. This allows allocating less memory in the
3774 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3777 if (static_type == SPECIAL_STATIC_THREAD) {
3778 MonoThreadDomainTls *item;
3779 mono_threads_lock ();
3780 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3781 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3783 offset = item->offset;
3786 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3788 update_tls_reference_bitmap (offset, bitmap, numbits);
3789 /* This can be called during startup */
3790 if (threads != NULL)
3791 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3792 mono_threads_unlock ();
3794 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3795 mono_contexts_lock ();
3796 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3797 mono_contexts_unlock ();
3798 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3804 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3806 /* The high bit means either thread (0) or static (1) data. */
3808 guint32 static_type = (offset & 0x80000000);
3811 offset &= 0x7fffffff;
3812 idx = (offset >> 24) - 1;
3814 if (static_type == 0) {
3815 return get_thread_static_data (thread, offset);
3817 /* Allocate static data block under demand, since we don't have a list
3820 MonoAppContext *context = mono_context_get ();
3821 if (!context->static_data || !context->static_data [idx]) {
3822 mono_contexts_lock ();
3823 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3824 mono_contexts_unlock ();
3826 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3831 mono_get_special_static_data (guint32 offset)
3833 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3842 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3844 MonoInternalThread *thread = value;
3845 TlsOffsetSize *data = user;
3846 int idx = (data->offset >> 24) - 1;
3849 if (!thread->static_data || !thread->static_data [idx])
3851 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3852 mono_gc_bzero (ptr, data->size);
3856 do_free_special_slot (guint32 offset, guint32 size)
3858 guint32 static_type = (offset & 0x80000000);
3859 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3860 if (static_type == 0) {
3862 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3863 data.offset = offset & 0x7fffffff;
3865 clear_reference_bitmap (data.offset, data.size);
3866 if (threads != NULL)
3867 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3868 item->offset = offset;
3871 if (!mono_runtime_is_shutting_down ()) {
3872 item->next = thread_static_info.freelist;
3873 thread_static_info.freelist = item;
3875 /* We could be called during shutdown after mono_thread_cleanup () is called */
3879 /* FIXME: free context static data as well */
3884 do_free_special (gpointer key, gpointer value, gpointer data)
3886 MonoClassField *field = key;
3887 guint32 offset = GPOINTER_TO_UINT (value);
3890 size = mono_type_size (field->type, &align);
3891 do_free_special_slot (offset, size);
3895 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3897 mono_threads_lock ();
3898 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3899 mono_threads_unlock ();
3903 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3905 mono_threads_lock ();
3906 do_free_special_slot (offset, size);
3907 mono_threads_unlock ();
3911 * allocates room in the thread local area for storing an instance of the struct type
3912 * the allocation is kept track of in domain->tlsrec_list.
3915 mono_thread_alloc_tls (MonoReflectionType *type)
3917 MonoDomain *domain = mono_domain_get ();
3919 MonoTlsDataRecord *tlsrec;
3922 gsize default_bitmap [4] = {0};
3923 uint32_t tls_offset;
3927 klass = mono_class_from_mono_type (type->type);
3928 /* TlsDatum is a struct, so we subtract the object header size offset */
3929 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3930 size = mono_type_size (type->type, &align);
3931 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3932 if (bitmap != default_bitmap)
3934 tlsrec = g_new0 (MonoTlsDataRecord, 1);
3935 tlsrec->tls_offset = tls_offset;
3936 tlsrec->size = size;
3937 mono_domain_lock (domain);
3938 tlsrec->next = domain->tlsrec_list;
3939 domain->tlsrec_list = tlsrec;
3940 mono_domain_unlock (domain);
3945 mono_thread_destroy_tls (uint32_t tls_offset)
3947 MonoTlsDataRecord *prev = NULL;
3948 MonoTlsDataRecord *cur;
3950 MonoDomain *domain = mono_domain_get ();
3951 mono_domain_lock (domain);
3952 cur = domain->tlsrec_list;
3954 if (cur->tls_offset == tls_offset) {
3956 prev->next = cur->next;
3958 domain->tlsrec_list = cur->next;
3966 mono_domain_unlock (domain);
3968 mono_special_static_data_free_slot (tls_offset, size);
3972 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
3975 mono_thread_destroy_domain_tls (MonoDomain *domain)
3977 while (domain->tlsrec_list)
3978 mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
3981 static MonoClassField *local_slots = NULL;
3984 /* local tls data to get locals_slot from a thread */
3987 /* index in the locals_slot array */
3992 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
3994 LocalSlotID *sid = user_data;
3995 MonoInternalThread *thread = (MonoInternalThread*)value;
3996 MonoArray *slots_array;
3998 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
3999 * it is for the right domain, so we need to check if it is allocated an initialized
4000 * for the current thread.
4002 /*g_print ("handling thread %p\n", thread);*/
4003 if (!thread->static_data || !thread->static_data [sid->idx])
4005 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4006 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4008 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4012 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4020 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4022 g_warning ("local_slots field not found in Thread class");
4026 domain = mono_domain_get ();
4027 mono_domain_lock (domain);
4028 if (domain->special_static_fields)
4029 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4030 mono_domain_unlock (domain);
4033 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4034 sid.offset = GPOINTER_TO_UINT (addr);
4035 sid.offset &= 0x7fffffff;
4036 sid.idx = (sid.offset >> 24) - 1;
4037 mono_threads_lock ();
4038 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4039 mono_threads_unlock ();
4041 /* FIXME: clear the slot for MonoAppContexts, too */
4046 static void CALLBACK dummy_apc (ULONG_PTR param)
4050 static guint32 dummy_apc (gpointer param)
4057 * mono_thread_execute_interruption
4059 * Performs the operation that the requested thread state requires (abort,
4062 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4064 ensure_synch_cs_set (thread);
4066 EnterCriticalSection (thread->synch_cs);
4068 /* MonoThread::interruption_requested can only be changed with atomics */
4069 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4070 /* this will consume pending APC calls */
4071 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4072 InterlockedDecrement (&thread_interruption_requested);
4074 /* Clear the interrupted flag of the thread so it can wait again */
4075 wapi_clear_interruption ();
4079 if ((thread->state & ThreadState_AbortRequested) != 0) {
4080 LeaveCriticalSection (thread->synch_cs);
4081 if (thread->abort_exc == NULL) {
4083 * This might be racy, but it has to be called outside the lock
4084 * since it calls managed code.
4086 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4088 return thread->abort_exc;
4090 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4091 self_suspend_internal (thread);
4094 else if ((thread->state & ThreadState_StopRequested) != 0) {
4095 /* FIXME: do this through the JIT? */
4097 LeaveCriticalSection (thread->synch_cs);
4099 mono_thread_exit ();
4101 } else if (thread->pending_exception) {
4104 exc = thread->pending_exception;
4105 thread->pending_exception = NULL;
4107 LeaveCriticalSection (thread->synch_cs);
4109 } else if (thread->thread_interrupt_requested) {
4111 thread->thread_interrupt_requested = FALSE;
4112 LeaveCriticalSection (thread->synch_cs);
4114 return(mono_get_exception_thread_interrupted ());
4117 LeaveCriticalSection (thread->synch_cs);
4123 * mono_thread_request_interruption
4125 * A signal handler can call this method to request the interruption of a
4126 * thread. The result of the interruption will depend on the current state of
4127 * the thread. If the result is an exception that needs to be throw, it is
4128 * provided as return value.
4131 mono_thread_request_interruption (gboolean running_managed)
4133 MonoInternalThread *thread = mono_thread_internal_current ();
4135 /* The thread may already be stopping */
4140 if (thread->interrupt_on_stop &&
4141 thread->state & ThreadState_StopRequested &&
4142 thread->state & ThreadState_Background)
4146 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4148 InterlockedIncrement (&thread_interruption_requested);
4150 if (!running_managed || is_running_protected_wrapper ()) {
4151 /* Can't stop while in unmanaged code. Increase the global interruption
4152 request count. When exiting the unmanaged method the count will be
4153 checked and the thread will be interrupted. */
4156 if (mono_thread_notify_pending_exc_fn && !running_managed)
4157 /* The JIT will notify the thread about the interruption */
4158 /* This shouldn't take any locks */
4159 mono_thread_notify_pending_exc_fn ();
4161 /* this will awake the thread if it is in WaitForSingleObject
4163 /* Our implementation of this function ignores the func argument */
4164 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
4168 return mono_thread_execute_interruption (thread);
4172 /*This function should be called by a thread after it has exited all of
4173 * its handle blocks at interruption time.*/
4175 mono_thread_resume_interruption (void)
4177 MonoInternalThread *thread = mono_thread_internal_current ();
4178 gboolean still_aborting;
4180 /* The thread may already be stopping */
4184 ensure_synch_cs_set (thread);
4185 EnterCriticalSection (thread->synch_cs);
4186 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4187 LeaveCriticalSection (thread->synch_cs);
4189 /*This can happen if the protected block called Thread::ResetAbort*/
4190 if (!still_aborting)
4193 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4195 InterlockedIncrement (&thread_interruption_requested);
4198 wapi_self_interrupt ();
4200 return mono_thread_execute_interruption (thread);
4203 gboolean mono_thread_interruption_requested ()
4205 if (thread_interruption_requested) {
4206 MonoInternalThread *thread = mono_thread_internal_current ();
4207 /* The thread may already be stopping */
4209 return (thread->interruption_requested);
4214 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4216 MonoInternalThread *thread = mono_thread_internal_current ();
4218 /* The thread may already be stopping */
4222 mono_debugger_check_interruption ();
4224 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4225 MonoException* exc = mono_thread_execute_interruption (thread);
4226 if (exc) mono_raise_exception (exc);
4231 * Performs the interruption of the current thread, if one has been requested,
4232 * and the thread is not running a protected wrapper.
4234 void mono_thread_interruption_checkpoint ()
4236 mono_thread_interruption_checkpoint_request (FALSE);
4240 * Performs the interruption of the current thread, if one has been requested.
4242 void mono_thread_force_interruption_checkpoint ()
4244 mono_thread_interruption_checkpoint_request (TRUE);
4248 * mono_thread_get_and_clear_pending_exception:
4250 * Return any pending exceptions for the current thread and clear it as a side effect.
4253 mono_thread_get_and_clear_pending_exception (void)
4255 MonoInternalThread *thread = mono_thread_internal_current ();
4257 /* The thread may already be stopping */
4261 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4262 return mono_thread_execute_interruption (thread);
4265 if (thread->pending_exception) {
4266 MonoException *exc = thread->pending_exception;
4268 thread->pending_exception = NULL;
4276 * mono_set_pending_exception:
4278 * Set the pending exception of the current thread to EXC.
4279 * The exception will be thrown when execution returns to managed code.
4282 mono_set_pending_exception (MonoException *exc)
4284 MonoInternalThread *thread = mono_thread_internal_current ();
4286 /* The thread may already be stopping */
4290 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4292 mono_thread_request_interruption (FALSE);
4296 * mono_thread_interruption_request_flag:
4298 * Returns the address of a flag that will be non-zero if an interruption has
4299 * been requested for a thread. The thread to interrupt may not be the current
4300 * thread, so an additional call to mono_thread_interruption_requested() or
4301 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4304 gint32* mono_thread_interruption_request_flag ()
4306 return &thread_interruption_requested;
4310 mono_thread_init_apartment_state (void)
4313 MonoInternalThread* thread = mono_thread_internal_current ();
4315 /* Positive return value indicates success, either
4316 * S_OK if this is first CoInitialize call, or
4317 * S_FALSE if CoInitialize already called, but with same
4318 * threading model. A negative value indicates failure,
4319 * probably due to trying to change the threading model.
4321 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4322 ? COINIT_APARTMENTTHREADED
4323 : COINIT_MULTITHREADED) < 0) {
4324 thread->apartment_state = ThreadApartmentState_Unknown;
4330 mono_thread_cleanup_apartment_state (void)
4333 MonoInternalThread* thread = mono_thread_internal_current ();
4335 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4342 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4344 ensure_synch_cs_set (thread);
4346 EnterCriticalSection (thread->synch_cs);
4347 thread->state |= state;
4348 LeaveCriticalSection (thread->synch_cs);
4352 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4354 ensure_synch_cs_set (thread);
4356 EnterCriticalSection (thread->synch_cs);
4357 thread->state &= ~state;
4358 LeaveCriticalSection (thread->synch_cs);
4362 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4364 gboolean ret = FALSE;
4366 ensure_synch_cs_set (thread);
4368 EnterCriticalSection (thread->synch_cs);
4370 if ((thread->state & test) != 0) {
4374 LeaveCriticalSection (thread->synch_cs);
4379 //static MonoClassField *execution_context_field;
4382 get_execution_context_addr (void)
4384 MonoDomain *domain = mono_domain_get ();
4385 guint32 offset = domain->execution_context_field_offset;
4388 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4391 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4393 mono_domain_lock (domain);
4394 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4395 mono_domain_unlock (domain);
4398 domain->execution_context_field_offset = offset;
4401 return (MonoObject**) mono_get_special_static_data (offset);
4405 mono_thread_get_execution_context (void)
4407 return *get_execution_context_addr ();
4411 mono_thread_set_execution_context (MonoObject *ec)
4413 *get_execution_context_addr () = ec;
4416 static gboolean has_tls_get = FALSE;
4419 mono_runtime_set_has_tls_get (gboolean val)
4425 mono_runtime_has_tls_get (void)
4431 mono_thread_kill (MonoInternalThread *thread, int signal)
4434 /* Win32 uses QueueUserAPC and callers of this are guarded */
4435 g_assert_not_reached ();
4437 # ifdef PTHREAD_POINTER_ID
4438 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4440 # ifdef PLATFORM_ANDROID
4441 if (thread->android_tid != 0) {
4443 int old_errno = errno;
4445 ret = tkill ((pid_t) thread->android_tid, signal);
4454 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4456 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4463 self_interrupt_thread (void *_unused)
4465 MonoThreadInfo *info = mono_thread_info_current ();
4466 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4467 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4468 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4469 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4473 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4477 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4481 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4483 MonoJitInfo **dest = data;
4489 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4491 MonoJitInfo *ji = NULL;
4494 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4499 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4502 MonoThreadInfo *info = NULL;
4503 gboolean protected_wrapper;
4504 gboolean running_managed;
4506 if (!mono_thread_info_new_interrupt_enabled ()) {
4507 signal_thread_state_change (thread);
4512 FIXME this is insanely broken, it doesn't cause interruption to happen
4513 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4515 if (thread == mono_thread_internal_current ()) {
4516 /* Do it synchronously */
4517 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4519 mono_raise_exception (exc);
4521 wapi_interrupt_thread (thread->handle);
4526 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4527 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4531 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4532 mono_thread_info_resume (mono_thread_info_get_tid (info));
4536 /*someone is already interrupting it*/
4537 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4538 mono_thread_info_resume (mono_thread_info_get_tid (info));
4541 InterlockedIncrement (&thread_interruption_requested);
4543 ji = mono_thread_info_get_last_managed (info);
4544 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4545 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4547 if (!protected_wrapper && running_managed) {
4548 /*We are in managed code*/
4549 /*Set the thread to call */
4550 if (install_async_abort)
4551 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4552 mono_thread_info_resume (mono_thread_info_get_tid (info));
4554 gpointer interrupt_handle;
4556 * This will cause waits to be broken.
4557 * It will also prevent the thread from entering a wait, so if the thread returns
4558 * from the wait before it receives the abort signal, it will just spin in the wait
4559 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4563 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4565 mono_thread_info_resume (mono_thread_info_get_tid (info));
4567 wapi_finish_interrupt_thread (interrupt_handle);
4570 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4574 transition_to_suspended (MonoInternalThread *thread)
4576 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4577 g_assert (0); /*FIXME we should not reach this */
4578 /*Make sure we balance the suspend count.*/
4579 mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
4581 thread->state &= ~ThreadState_SuspendRequested;
4582 thread->state |= ThreadState_Suspended;
4584 LeaveCriticalSection (thread->synch_cs);
4588 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4590 if (!mono_thread_info_new_interrupt_enabled ()) {
4591 signal_thread_state_change (thread);
4595 EnterCriticalSection (thread->synch_cs);
4596 if (thread == mono_thread_internal_current ()) {
4597 transition_to_suspended (thread);
4598 mono_thread_info_self_suspend ();
4600 MonoThreadInfo *info;
4602 gboolean protected_wrapper;
4603 gboolean running_managed;
4605 /*A null info usually means the thread is already dead. */
4606 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt)))
4609 ji = mono_thread_info_get_last_managed (info);
4610 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4611 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4613 if (running_managed && !protected_wrapper) {
4614 transition_to_suspended (thread);
4616 gpointer interrupt_handle;
4618 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4619 InterlockedIncrement (&thread_interruption_requested);
4622 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4624 mono_thread_info_resume (mono_thread_info_get_tid (info));
4627 wapi_finish_interrupt_thread (interrupt_handle);
4629 LeaveCriticalSection (thread->synch_cs);
4634 /*This is called with @thread synch_cs held and it must release it*/
4636 self_suspend_internal (MonoInternalThread *thread)
4638 if (!mono_thread_info_new_interrupt_enabled ()) {
4639 thread->state &= ~ThreadState_SuspendRequested;
4640 thread->state |= ThreadState_Suspended;
4641 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4642 if (thread->suspend_event == NULL) {
4643 LeaveCriticalSection (thread->synch_cs);
4646 if (thread->suspended_event)
4647 SetEvent (thread->suspended_event);
4649 LeaveCriticalSection (thread->synch_cs);
4651 if (shutting_down) {
4652 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4657 WaitForSingleObject (thread->suspend_event, INFINITE);
4659 EnterCriticalSection (thread->synch_cs);
4661 CloseHandle (thread->suspend_event);
4662 thread->suspend_event = NULL;
4663 thread->state &= ~ThreadState_Suspended;
4665 /* The thread that requested the resume will have replaced this event
4666 * and will be waiting for it
4668 SetEvent (thread->resume_event);
4670 LeaveCriticalSection (thread->synch_cs);
4674 transition_to_suspended (thread);
4675 mono_thread_info_self_suspend ();
4678 /*This is called with @thread synch_cs held and it must release it*/
4680 resume_thread_internal (MonoInternalThread *thread)
4682 if (!mono_thread_info_new_interrupt_enabled ()) {
4683 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4684 if (thread->resume_event == NULL) {
4685 LeaveCriticalSection (thread->synch_cs);
4689 /* Awake the thread */
4690 SetEvent (thread->suspend_event);
4692 LeaveCriticalSection (thread->synch_cs);
4694 /* Wait for the thread to awake */
4695 WaitForSingleObject (thread->resume_event, INFINITE);
4696 CloseHandle (thread->resume_event);
4697 thread->resume_event = NULL;
4701 LeaveCriticalSection (thread->synch_cs);
4702 /* Awake the thread */
4703 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4705 EnterCriticalSection (thread->synch_cs);
4706 thread->state &= ~ThreadState_Suspended;
4707 LeaveCriticalSection (thread->synch_cs);