2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threadpool.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internal.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internal.h>
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
51 #define USE_TKILL_ON_ANDROID 1
54 #ifdef PLATFORM_ANDROID
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid, int signal);
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
85 # define G_GSIZE_FORMAT "u"
91 guint32 (*func)(void *);
107 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
108 struct _MonoThreadDomainTls {
109 MonoThreadDomainTls *next;
117 MonoThreadDomainTls *freelist;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 #define mono_threads_lock() mono_mutex_lock (&threads_mutex)
130 #define mono_threads_unlock() mono_mutex_unlock (&threads_mutex)
131 static mono_mutex_t threads_mutex;
133 /* Controls access to context static data */
134 #define mono_contexts_lock() mono_mutex_lock (&contexts_mutex)
135 #define mono_contexts_unlock() mono_mutex_unlock (&contexts_mutex)
136 static mono_mutex_t contexts_mutex;
138 /* Controls access to the 'joinable_threads' hash table */
139 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
140 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
141 static mono_mutex_t joinable_threads_mutex;
143 /* Holds current status of static data heap */
144 static StaticDataInfo thread_static_info;
145 static StaticDataInfo context_static_info;
147 /* The hash of existing threads (key is thread ID, value is
148 * MonoInternalThread*) that need joining before exit
150 static MonoGHashTable *threads=NULL;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable *threads_starting_up = NULL;
159 /* Maps a MonoThread to its start argument */
160 /* Protected by mono_threads_lock () */
161 static MonoGHashTable *thread_start_args = NULL;
163 /* The TLS key that holds the MonoObject assigned to each thread */
164 static MonoNativeTlsKey current_object_key;
167 /* Protected by the threads lock */
168 static GHashTable *joinable_threads;
169 static int joinable_thread_count;
171 #ifdef MONO_HAVE_FAST_TLS
172 /* we need to use both the Tls* functions and __thread because
173 * the gc needs to see all the threads
175 MONO_FAST_TLS_DECLARE(tls_current_object);
176 #define SET_CURRENT_OBJECT(x) do { \
177 MONO_FAST_TLS_SET (tls_current_object, x); \
178 mono_native_tls_set_value (current_object_key, x); \
180 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
182 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
183 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
186 /* function called at thread start */
187 static MonoThreadStartCB mono_thread_start_cb = NULL;
189 /* function called at thread attach */
190 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
192 /* function called at thread cleanup */
193 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
195 /* function called to notify the runtime about a pending exception on the current thread */
196 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
198 /* The default stack size for each thread */
199 static guint32 default_stacksize = 0;
200 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
202 static void thread_adjust_static_data (MonoInternalThread *thread);
203 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
204 static void mono_init_static_data_info (StaticDataInfo *static_data);
205 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
206 static gboolean mono_thread_resume (MonoInternalThread* thread);
207 static void signal_thread_state_change (MonoInternalThread *thread);
208 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
209 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
210 static void self_suspend_internal (MonoInternalThread *thread);
211 static gboolean resume_thread_internal (MonoInternalThread *thread);
213 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
214 static void ref_stack_destroy (gpointer rs);
216 /* Spin lock for InterlockedXXX 64 bit functions */
217 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
218 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
219 static mono_mutex_t interlocked_mutex;
221 /* global count of thread interruptions requested */
222 static gint32 thread_interruption_requested = 0;
224 /* Event signaled when a thread changes its background mode */
225 static HANDLE background_change_event;
227 static gboolean shutting_down = FALSE;
229 static gint32 managed_thread_id_counter = 0;
232 get_next_managed_thread_id (void)
234 return InterlockedIncrement (&managed_thread_id_counter);
238 mono_thread_get_tls_key (void)
240 return current_object_key;
244 mono_thread_get_tls_offset (void)
247 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
251 static inline MonoNativeThreadId
252 thread_get_tid (MonoInternalThread *thread)
254 /* We store the tid as a guint64 to keep the object layout constant between platforms */
255 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
258 /* handle_store() and handle_remove() manage the array of threads that
259 * still need to be waited for when the main thread exits.
261 * If handle_store() returns FALSE the thread must not be started
262 * because Mono is shutting down.
264 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
266 mono_threads_lock ();
268 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
270 if (threads_starting_up)
271 mono_g_hash_table_remove (threads_starting_up, thread);
273 if (shutting_down && !force_attach) {
274 mono_threads_unlock ();
279 MONO_GC_REGISTER_ROOT_FIXED (threads);
280 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
283 /* We don't need to duplicate thread->handle, because it is
284 * only closed when the thread object is finalized by the GC.
286 g_assert (thread->internal_thread);
287 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
288 thread->internal_thread);
290 mono_threads_unlock ();
295 static gboolean handle_remove(MonoInternalThread *thread)
298 gsize tid = thread->tid;
300 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
302 mono_threads_lock ();
305 /* We have to check whether the thread object for the
306 * tid is still the same in the table because the
307 * thread might have been destroyed and the tid reused
308 * in the meantime, in which case the tid would be in
309 * the table, but with another thread object.
311 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
312 mono_g_hash_table_remove (threads, (gpointer)tid);
321 mono_threads_unlock ();
323 /* Don't close the handle here, wait for the object finalizer
324 * to do it. Otherwise, the following race condition applies:
326 * 1) Thread exits (and handle_remove() closes the handle)
328 * 2) Some other handle is reassigned the same slot
330 * 3) Another thread tries to join the first thread, and
331 * blocks waiting for the reassigned handle to be signalled
332 * (which might never happen). This is possible, because the
333 * thread calling Join() still has a reference to the first
339 static void ensure_synch_cs_set (MonoInternalThread *thread)
341 mono_mutex_t *synch_cs;
343 if (thread->synch_cs != NULL) {
347 synch_cs = g_new0 (mono_mutex_t, 1);
348 mono_mutex_init_recursive (synch_cs);
350 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
351 synch_cs, NULL) != NULL) {
352 /* Another thread must have installed this CS */
353 mono_mutex_destroy (synch_cs);
359 lock_thread (MonoInternalThread *thread)
361 if (!thread->synch_cs)
362 ensure_synch_cs_set (thread);
364 g_assert (thread->synch_cs);
365 mono_mutex_lock (thread->synch_cs);
369 unlock_thread (MonoInternalThread *thread)
371 mono_mutex_unlock (thread->synch_cs);
375 * NOTE: this function can be called also for threads different from the current one:
376 * make sure no code called from it will ever assume it is run on the thread that is
377 * getting cleaned up.
379 static void thread_cleanup (MonoInternalThread *thread)
381 g_assert (thread != NULL);
383 if (thread->abort_state_handle) {
384 mono_gchandle_free (thread->abort_state_handle);
385 thread->abort_state_handle = 0;
387 thread->abort_exc = NULL;
388 thread->current_appcontext = NULL;
391 * This is necessary because otherwise we might have
392 * cross-domain references which will not get cleaned up when
393 * the target domain is unloaded.
395 if (thread->cached_culture_info) {
397 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
398 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
402 * thread->synch_cs can be NULL if this was called after
403 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
404 * This can happen only during shutdown.
405 * The shutting_down flag is not always set, so we can't assert on it.
407 if (thread->synch_cs)
408 LOCK_THREAD (thread);
410 thread->state |= ThreadState_Stopped;
411 thread->state &= ~ThreadState_Background;
413 if (thread->synch_cs)
414 UNLOCK_THREAD (thread);
417 An interruption request has leaked to cleanup. Adjust the global counter.
419 This can happen is the abort source thread finds the abortee (this) thread
420 in unmanaged code. If this thread never trips back to managed code or check
421 the local flag it will be left set and positively unbalance the global counter.
423 Leaving the counter unbalanced will cause a performance degradation since all threads
424 will now keep checking their local flags all the time.
426 if (InterlockedExchange (&thread->interruption_requested, 0))
427 InterlockedDecrement (&thread_interruption_requested);
429 /* if the thread is not in the hash it has been removed already */
430 if (!handle_remove (thread)) {
431 if (thread == mono_thread_internal_current ()) {
432 mono_domain_unset ();
433 mono_memory_barrier ();
435 /* This needs to be called even if handle_remove () fails */
436 if (mono_thread_cleanup_fn)
437 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
440 mono_release_type_locks (thread);
442 mono_profiler_thread_end (thread->tid);
444 if (thread == mono_thread_internal_current ()) {
446 * This will signal async signal handlers that the thread has exited.
447 * The profiler callback needs this to be set, so it cannot be done earlier.
449 mono_domain_unset ();
450 mono_memory_barrier ();
453 if (thread == mono_thread_internal_current ())
454 mono_thread_pop_appdomain_ref ();
456 thread->cached_culture_info = NULL;
458 mono_free_static_data (thread->static_data, TRUE);
459 thread->static_data = NULL;
460 ref_stack_destroy (thread->appdomain_refs);
461 thread->appdomain_refs = NULL;
463 if (mono_thread_cleanup_fn)
464 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
466 if (mono_gc_is_moving ()) {
467 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
468 thread->thread_pinning_ref = NULL;
473 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
476 g_assert ((offset & 0x80000000) == 0);
477 offset &= 0x7fffffff;
478 idx = (offset >> 24) - 1;
479 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
483 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
485 static MonoClassField *current_thread_field = NULL;
489 if (!current_thread_field) {
490 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
491 g_assert (current_thread_field);
494 mono_class_vtable (domain, mono_defaults.thread_class);
495 mono_domain_lock (domain);
496 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
497 mono_domain_unlock (domain);
500 return get_thread_static_data (thread, offset);
504 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
506 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
508 g_assert (current->obj.vtable->domain == domain);
510 g_assert (!*current_thread_ptr);
511 *current_thread_ptr = current;
515 create_thread_object (MonoDomain *domain)
517 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
518 return (MonoThread*)mono_gc_alloc_mature (vt);
522 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
524 MonoThread *thread = create_thread_object (domain);
525 MONO_OBJECT_SETREF (thread, internal_thread, internal);
529 static MonoInternalThread*
530 create_internal_thread (void)
532 MonoInternalThread *thread;
535 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
536 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
538 thread->synch_cs = g_new0 (mono_mutex_t, 1);
539 mono_mutex_init_recursive (thread->synch_cs);
541 thread->apartment_state = ThreadApartmentState_Unknown;
542 thread->managed_id = get_next_managed_thread_id ();
543 if (mono_gc_is_moving ()) {
544 thread->thread_pinning_ref = thread;
545 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
552 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
554 MonoDomain *domain = mono_get_root_domain ();
556 if (!candidate || candidate->obj.vtable->domain != domain)
557 candidate = new_thread_with_internal (domain, thread);
558 set_current_thread_for_domain (domain, thread, candidate);
559 g_assert (!thread->root_domain_thread);
560 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
563 static guint32 WINAPI start_wrapper_internal(void *data)
565 MonoThreadInfo *info;
566 StartInfo *start_info = (StartInfo *)data;
567 guint32 (*start_func)(void *);
571 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
574 MonoInternalThread *internal = start_info->obj->internal_thread;
575 MonoObject *start_delegate = start_info->delegate;
576 MonoDomain *domain = start_info->obj->obj.vtable->domain;
578 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
580 /* We can be sure start_info->obj->tid and
581 * start_info->obj->handle have been set, because the thread
582 * was created suspended, and these values were set before the
586 info = mono_thread_info_current ();
588 internal->thread_info = info;
589 internal->small_id = info->small_id;
593 SET_CURRENT_OBJECT (internal);
595 /* Every thread references the appdomain which created it */
596 mono_thread_push_appdomain_ref (domain);
598 if (!mono_domain_set (domain, FALSE)) {
599 /* No point in raising an appdomain_unloaded exception here */
600 /* FIXME: Cleanup here */
601 mono_thread_pop_appdomain_ref ();
605 start_func = start_info->func;
606 start_arg = start_info->start_arg;
608 /* We have to do this here because mono_thread_new_init()
609 requires that root_domain_thread is set up. */
610 thread_adjust_static_data (internal);
611 init_root_domain_thread (internal, start_info->obj);
613 /* This MUST be called before any managed code can be
614 * executed, as it calls the callback function that (for the
615 * jit) sets the lmf marker.
617 mono_thread_new_init (tid, &tid, start_func);
618 internal->stack_ptr = &tid;
620 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
622 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
624 /* On 2.0 profile (and higher), set explicitly since state might have been
626 if (internal->apartment_state == ThreadApartmentState_Unknown)
627 internal->apartment_state = ThreadApartmentState_MTA;
629 mono_thread_init_apartment_state ();
631 if(internal->start_notify!=NULL) {
632 /* Let the thread that called Start() know we're
635 ReleaseSemaphore (internal->start_notify, 1, NULL);
638 mono_threads_lock ();
639 mono_g_hash_table_remove (thread_start_args, start_info->obj);
640 mono_threads_unlock ();
642 mono_thread_set_execution_context (start_info->obj->ec_to_set);
643 start_info->obj->ec_to_set = NULL;
646 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
650 * Call this after calling start_notify, since the profiler callback might want
651 * to lock the thread, and the lock is held by thread_start () which waits for
654 mono_profiler_thread_start (tid);
656 /* if the name was set before starting, we didn't invoke the profiler callback */
657 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
658 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
659 mono_profiler_thread_name (internal->tid, tname);
662 /* start_func is set only for unmanaged start functions */
664 start_func (start_arg);
667 g_assert (start_delegate != NULL);
668 args [0] = start_arg;
669 /* we may want to handle the exception here. See comment below on unhandled exceptions */
670 mono_runtime_delegate_invoke (start_delegate, args, NULL);
673 /* If the thread calls ExitThread at all, this remaining code
674 * will not be executed, but the main thread will eventually
675 * call thread_cleanup() on this thread's behalf.
678 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
680 /* Do any cleanup needed for apartment state. This
681 * cannot be done in thread_cleanup since thread_cleanup could be
682 * called for a thread other than the current thread.
683 * mono_thread_cleanup_apartment_state cleans up apartment
684 * for the current thead */
685 mono_thread_cleanup_apartment_state ();
687 thread_cleanup (internal);
691 /* Remove the reference to the thread object in the TLS data,
692 * so the thread object can be finalized. This won't be
693 * reached if the thread threw an uncaught exception, so those
694 * thread handles will stay referenced :-( (This is due to
695 * missing support for scanning thread-specific data in the
696 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
699 SET_CURRENT_OBJECT (NULL);
704 static guint32 WINAPI start_wrapper(void *data)
708 /* Avoid scanning the frames above this frame during a GC */
709 mono_gc_set_stack_end ((void*)&dummy);
711 return start_wrapper_internal (data);
717 * Common thread creation code.
718 * LOCKING: Acquires the threads lock.
721 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
722 gboolean throw_on_failure)
724 HANDLE thread_handle;
725 MonoNativeThreadId tid;
726 guint32 create_flags;
729 * Join joinable threads to prevent running out of threads since the finalizer
730 * thread might be blocked/backlogged.
732 mono_threads_join_threads ();
734 mono_threads_lock ();
737 mono_threads_unlock ();
741 * The thread start argument may be an object reference, and there is
742 * no ref to keep it alive when the new thread is started but not yet
743 * registered with the collector. So we store it in a GC tracked hash
746 if (thread_start_args == NULL) {
747 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
748 thread_start_args = mono_g_hash_table_new (NULL, NULL);
750 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
751 if (threads_starting_up == NULL) {
752 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
753 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
755 mono_g_hash_table_insert (threads_starting_up, thread, thread);
756 mono_threads_unlock ();
758 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
759 if (!internal->start_notify) {
760 mono_threads_lock ();
761 mono_g_hash_table_remove (threads_starting_up, thread);
762 mono_threads_unlock ();
763 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
769 stack_size = default_stacksize_for_thread (internal);
771 /* Create suspended, so we can do some housekeeping before the thread
774 create_flags = CREATE_SUSPENDED;
776 MONO_PREPARE_BLOCKING
777 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
778 stack_size, create_flags, &tid);
781 if (thread_handle == NULL) {
782 /* The thread couldn't be created, so throw an exception */
783 mono_threads_lock ();
784 mono_g_hash_table_remove (threads_starting_up, thread);
785 mono_threads_unlock ();
787 if (throw_on_failure)
788 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
790 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
793 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
795 internal->handle = thread_handle;
796 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
798 internal->threadpool_thread = threadpool_thread;
799 if (threadpool_thread)
800 mono_thread_set_state (internal, ThreadState_Background);
802 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
804 /* Only store the handle when the thread is about to be
805 * launched, to avoid the main thread deadlocking while trying
806 * to clean up a thread that will never be signalled.
808 if (!handle_store (thread, FALSE))
811 MONO_PREPARE_BLOCKING
812 mono_thread_info_resume (tid);
815 if (internal->start_notify) {
817 * Wait for the thread to set up its TLS data etc, so
818 * theres no potential race condition if someone tries
819 * to look up the data believing the thread has
822 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
824 MONO_PREPARE_BLOCKING
825 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
828 CloseHandle (internal->start_notify);
829 internal->start_notify = NULL;
832 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
837 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
839 if (mono_thread_start_cb) {
840 mono_thread_start_cb (tid, stack_start, func);
844 void mono_threads_set_default_stacksize (guint32 stacksize)
846 default_stacksize = stacksize;
849 guint32 mono_threads_get_default_stacksize (void)
851 return default_stacksize;
855 * mono_thread_create_internal:
859 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
862 MonoInternalThread *internal;
863 StartInfo *start_info;
866 thread = create_thread_object (domain);
867 internal = create_internal_thread ();
868 MONO_OBJECT_SETREF (thread, internal_thread, internal);
870 start_info = g_new0 (StartInfo, 1);
871 start_info->func = func;
872 start_info->obj = thread;
873 start_info->start_arg = arg;
875 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
879 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
880 if (mono_check_corlib_version () == NULL)
881 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
887 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
889 mono_thread_create_internal (domain, func, arg, FALSE, 0);
893 mono_thread_attach (MonoDomain *domain)
895 return mono_thread_attach_full (domain, FALSE);
899 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
901 MonoThreadInfo *info;
902 MonoInternalThread *thread;
903 MonoThread *current_thread;
904 HANDLE thread_handle;
907 if ((thread = mono_thread_internal_current ())) {
908 if (domain != mono_domain_get ())
909 mono_domain_set (domain, TRUE);
910 /* Already attached */
911 return mono_thread_current ();
914 if (!mono_gc_register_thread (&domain)) {
915 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 ());
918 thread = create_internal_thread ();
920 thread_handle = mono_thread_info_open_handle ();
921 g_assert (thread_handle);
923 tid=GetCurrentThreadId ();
925 thread->handle=thread_handle;
927 #ifdef PLATFORM_ANDROID
928 thread->android_tid = (gpointer) gettid ();
930 thread->stack_ptr = &tid;
932 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
934 info = mono_thread_info_current ();
936 thread->thread_info = info;
937 thread->small_id = info->small_id;
939 current_thread = new_thread_with_internal (domain, thread);
941 if (!handle_store (current_thread, force_attach)) {
942 /* Mono is shutting down, so just wait for the end */
947 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
949 SET_CURRENT_OBJECT (thread);
950 mono_domain_set (domain, TRUE);
952 thread_adjust_static_data (thread);
954 init_root_domain_thread (thread, current_thread);
955 if (domain != mono_get_root_domain ())
956 set_current_thread_for_domain (domain, thread, current_thread);
959 if (mono_thread_attach_cb) {
963 mono_thread_info_get_stack_bounds (&staddr, &stsize);
966 mono_thread_attach_cb (tid, &tid);
968 mono_thread_attach_cb (tid, staddr + stsize);
971 // FIXME: Need a separate callback
972 mono_profiler_thread_start (tid);
974 return current_thread;
978 mono_thread_detach_internal (MonoInternalThread *thread)
980 g_return_if_fail (thread != NULL);
982 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
984 thread_cleanup (thread);
986 SET_CURRENT_OBJECT (NULL);
987 mono_domain_unset ();
989 /* Don't need to CloseHandle this thread, even though we took a
990 * reference in mono_thread_attach (), because the GC will do it
991 * when the Thread object is finalised.
996 mono_thread_detach (MonoThread *thread)
999 mono_thread_detach_internal (thread->internal_thread);
1003 * mono_thread_detach_if_exiting:
1005 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1006 * This should be used at the end of embedding code which calls into managed code, and which
1007 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1010 mono_thread_detach_if_exiting (void)
1012 if (mono_thread_info_is_exiting ()) {
1013 MonoInternalThread *thread;
1015 thread = mono_thread_internal_current ();
1017 mono_thread_detach_internal (thread);
1018 mono_thread_info_detach ();
1026 MonoInternalThread *thread = mono_thread_internal_current ();
1028 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1030 thread_cleanup (thread);
1031 SET_CURRENT_OBJECT (NULL);
1032 mono_domain_unset ();
1034 /* we could add a callback here for embedders to use. */
1035 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1036 exit (mono_environment_exitcode_get ());
1037 mono_thread_info_exit ();
1041 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1043 MonoInternalThread *internal = create_internal_thread ();
1045 internal->state = ThreadState_Unstarted;
1047 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1051 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
1054 StartInfo *start_info;
1055 MonoInternalThread *internal;
1058 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1060 if (!this->internal_thread)
1061 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1062 internal = this->internal_thread;
1064 LOCK_THREAD (internal);
1066 if ((internal->state & ThreadState_Unstarted) == 0) {
1067 UNLOCK_THREAD (internal);
1068 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1072 if ((internal->state & ThreadState_Aborted) != 0) {
1073 UNLOCK_THREAD (internal);
1076 /* This is freed in start_wrapper */
1077 start_info = g_new0 (StartInfo, 1);
1078 start_info->func = NULL;
1079 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1080 start_info->delegate = start;
1081 start_info->obj = this;
1082 g_assert (this->obj.vtable->domain == mono_domain_get ());
1084 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1086 UNLOCK_THREAD (internal);
1090 internal->state &= ~ThreadState_Unstarted;
1092 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1094 UNLOCK_THREAD (internal);
1095 return internal->handle;
1099 * This is called from the finalizer of the internal thread object.
1102 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1104 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1107 * Since threads keep a reference to their thread object while running, by the time this function is called,
1108 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1109 * when thread_cleanup () can be called after this.
1112 CloseHandle (thread);
1114 if (this->synch_cs) {
1115 mono_mutex_t *synch_cs = this->synch_cs;
1116 this->synch_cs = NULL;
1117 mono_mutex_destroy (synch_cs);
1122 void *name = this->name;
1129 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1132 MonoInternalThread *thread = mono_thread_internal_current ();
1134 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1136 mono_thread_current_check_pending_interrupt ();
1139 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1141 MONO_PREPARE_BLOCKING
1142 res = SleepEx(ms,TRUE);
1143 MONO_FINISH_BLOCKING
1145 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1147 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1148 MonoException* exc = mono_thread_execute_interruption (thread);
1150 mono_raise_exception (exc);
1162 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1167 ves_icall_System_Threading_Thread_GetDomainID (void)
1169 return mono_domain_get()->domain_id;
1173 ves_icall_System_Threading_Thread_Yield (void)
1175 return mono_thread_info_yield ();
1179 * mono_thread_get_name:
1181 * Return the name of the thread. NAME_LEN is set to the length of the name.
1182 * Return NULL if the thread has no name. The returned memory is owned by the
1186 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1190 LOCK_THREAD (this_obj);
1192 if (!this_obj->name) {
1196 *name_len = this_obj->name_len;
1197 res = g_new (gunichar2, this_obj->name_len);
1198 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1201 UNLOCK_THREAD (this_obj);
1207 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1211 LOCK_THREAD (this_obj);
1213 if (!this_obj->name)
1216 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1218 UNLOCK_THREAD (this_obj);
1224 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1226 LOCK_THREAD (this_obj);
1228 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1229 UNLOCK_THREAD (this_obj);
1231 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1234 if (this_obj->name) {
1235 g_free (this_obj->name);
1236 this_obj->name_len = 0;
1239 this_obj->name = g_new (gunichar2, mono_string_length (name));
1240 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1241 this_obj->name_len = mono_string_length (name);
1244 this_obj->name = NULL;
1247 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1249 UNLOCK_THREAD (this_obj);
1251 if (this_obj->name && this_obj->tid) {
1252 char *tname = mono_string_to_utf8 (name);
1253 mono_profiler_thread_name (this_obj->tid, tname);
1254 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1260 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1262 mono_thread_set_name_internal (this_obj, name, TRUE);
1266 ves_icall_System_Threading_Thread_GetPriority (MonoInternalThread *thread)
1268 return ThreadPriority_Lowest;
1272 ves_icall_System_Threading_Thread_SetPriority (MonoInternalThread *thread, int priority)
1276 /* If the array is already in the requested domain, we just return it,
1277 otherwise we return a copy in that domain. */
1279 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1286 if (mono_object_domain (arr) == domain)
1289 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1290 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1295 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1297 return byte_array_to_domain (arr, mono_get_root_domain ());
1301 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1303 return byte_array_to_domain (arr, mono_domain_get ());
1307 mono_thread_current (void)
1309 MonoDomain *domain = mono_domain_get ();
1310 MonoInternalThread *internal = mono_thread_internal_current ();
1311 MonoThread **current_thread_ptr;
1313 g_assert (internal);
1314 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1316 if (!*current_thread_ptr) {
1317 g_assert (domain != mono_get_root_domain ());
1318 *current_thread_ptr = new_thread_with_internal (domain, internal);
1320 return *current_thread_ptr;
1324 mono_thread_internal_current (void)
1326 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1327 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1332 ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1333 int ms, HANDLE thread)
1335 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1338 mono_thread_current_check_pending_interrupt ();
1342 if ((this->state & ThreadState_Unstarted) != 0) {
1343 UNLOCK_THREAD (this);
1345 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1349 UNLOCK_THREAD (this);
1354 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1356 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1358 MONO_PREPARE_BLOCKING
1359 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1360 MONO_FINISH_BLOCKING
1362 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1364 if(ret==WAIT_OBJECT_0) {
1365 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1370 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1376 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1384 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1386 MONO_PREPARE_BLOCKING
1388 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1390 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1391 MONO_FINISH_BLOCKING
1393 if (ret != WAIT_IO_COMPLETION)
1396 exc = mono_thread_execute_interruption (thread);
1398 mono_raise_exception (exc);
1403 /* Re-calculate ms according to the time passed */
1404 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1405 if (diff_ms >= ms) {
1409 wait = ms - diff_ms;
1415 /* FIXME: exitContext isnt documented */
1416 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1422 MonoObject *waitHandle;
1423 MonoInternalThread *thread = mono_thread_internal_current ();
1425 /* Do this WaitSleepJoin check before creating objects */
1426 mono_thread_current_check_pending_interrupt ();
1428 /* We fail in managed if the array has more than 64 elements */
1429 numhandles = (guint32)mono_array_length(mono_handles);
1430 handles = g_new0(HANDLE, numhandles);
1432 for(i = 0; i < numhandles; i++) {
1433 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1434 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1441 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1443 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1445 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1449 if(ret==WAIT_FAILED) {
1450 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1452 } else if(ret==WAIT_TIMEOUT) {
1453 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1460 /* FIXME: exitContext isnt documented */
1461 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1463 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1464 uintptr_t numhandles;
1467 MonoObject *waitHandle;
1468 MonoInternalThread *thread = mono_thread_internal_current ();
1470 /* Do this WaitSleepJoin check before creating objects */
1471 mono_thread_current_check_pending_interrupt ();
1473 numhandles = mono_array_length(mono_handles);
1474 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1477 for(i = 0; i < numhandles; i++) {
1478 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1479 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1486 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1488 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1490 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1492 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1495 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1497 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1498 return ret - WAIT_OBJECT_0;
1500 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1501 return ret - WAIT_ABANDONED_0;
1508 /* FIXME: exitContext isnt documented */
1509 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1512 MonoInternalThread *thread = mono_thread_internal_current ();
1514 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1520 mono_thread_current_check_pending_interrupt ();
1522 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1524 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1526 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1528 if(ret==WAIT_FAILED) {
1529 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1531 } else if(ret==WAIT_TIMEOUT) {
1532 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1540 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1543 MonoInternalThread *thread = mono_thread_internal_current ();
1548 mono_thread_current_check_pending_interrupt ();
1550 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1552 MONO_PREPARE_BLOCKING
1553 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1554 MONO_FINISH_BLOCKING
1556 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1558 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1561 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1568 mutex = CreateMutex (NULL, owned, NULL);
1570 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1572 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1580 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1581 return(ReleaseMutex (handle));
1584 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1590 *error = ERROR_SUCCESS;
1592 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1594 *error = GetLastError ();
1601 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1608 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1610 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1611 mono_string_chars (name));
1613 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1621 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1625 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1630 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1634 *error = ERROR_SUCCESS;
1636 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1638 *error = GetLastError ();
1644 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1651 event = CreateEvent (NULL, manual, initial, NULL);
1653 event = CreateEvent (NULL, manual, initial,
1654 mono_string_chars (name));
1656 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1664 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1665 return (SetEvent(handle));
1668 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1669 return (ResetEvent(handle));
1673 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1674 CloseHandle (handle);
1677 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1683 *error = ERROR_SUCCESS;
1685 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1687 *error = GetLastError ();
1693 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1695 return InterlockedIncrement (location);
1698 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1700 #if SIZEOF_VOID_P == 4
1701 if (G_UNLIKELY ((size_t)location & 0x7)) {
1703 mono_interlocked_lock ();
1706 mono_interlocked_unlock ();
1710 return InterlockedIncrement64 (location);
1713 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1715 return InterlockedDecrement(location);
1718 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1720 #if SIZEOF_VOID_P == 4
1721 if (G_UNLIKELY ((size_t)location & 0x7)) {
1723 mono_interlocked_lock ();
1726 mono_interlocked_unlock ();
1730 return InterlockedDecrement64 (location);
1733 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1735 return InterlockedExchange(location, value);
1738 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1741 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1742 mono_gc_wbarrier_generic_nostore (location);
1746 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1748 return InterlockedExchangePointer(location, value);
1751 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1753 IntFloatUnion val, ret;
1756 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1762 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1764 #if SIZEOF_VOID_P == 4
1765 if (G_UNLIKELY ((size_t)location & 0x7)) {
1767 mono_interlocked_lock ();
1770 mono_interlocked_unlock ();
1774 return InterlockedExchange64 (location, value);
1778 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1780 LongDoubleUnion val, ret;
1783 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1788 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1790 return InterlockedCompareExchange(location, value, comparand);
1793 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1795 gint32 r = InterlockedCompareExchange(location, value, comparand);
1796 *success = r == comparand;
1800 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1803 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1804 mono_gc_wbarrier_generic_nostore (location);
1808 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1810 return InterlockedCompareExchangePointer(location, value, comparand);
1813 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1815 IntFloatUnion val, ret, cmp;
1818 cmp.fval = comparand;
1819 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1825 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1827 #if SIZEOF_VOID_P == 8
1828 LongDoubleUnion val, comp, ret;
1831 comp.fval = comparand;
1832 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1838 mono_interlocked_lock ();
1840 if (old == comparand)
1842 mono_interlocked_unlock ();
1849 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1851 #if SIZEOF_VOID_P == 4
1852 if (G_UNLIKELY ((size_t)location & 0x7)) {
1854 mono_interlocked_lock ();
1856 if (old == comparand)
1858 mono_interlocked_unlock ();
1862 return InterlockedCompareExchange64 (location, value, comparand);
1866 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1869 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1870 mono_gc_wbarrier_generic_nostore (location);
1875 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1878 res = InterlockedExchangePointer ((gpointer *)location, value);
1879 mono_gc_wbarrier_generic_nostore (location);
1884 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1886 return InterlockedAdd (location, value);
1890 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1892 #if SIZEOF_VOID_P == 4
1893 if (G_UNLIKELY ((size_t)location & 0x7)) {
1895 mono_interlocked_lock ();
1898 mono_interlocked_unlock ();
1902 return InterlockedAdd64 (location, value);
1906 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1908 #if SIZEOF_VOID_P == 4
1909 if (G_UNLIKELY ((size_t)location & 0x7)) {
1911 mono_interlocked_lock ();
1913 mono_interlocked_unlock ();
1917 return InterlockedRead64 (location);
1921 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1923 mono_memory_barrier ();
1927 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1929 mono_thread_clr_state (this, state);
1931 if (state & ThreadState_Background) {
1932 /* If the thread changes the background mode, the main thread has to
1933 * be notified, since it has to rebuild the list of threads to
1936 SetEvent (background_change_event);
1941 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1943 mono_thread_set_state (this, state);
1945 if (state & ThreadState_Background) {
1946 /* If the thread changes the background mode, the main thread has to
1947 * be notified, since it has to rebuild the list of threads to
1950 SetEvent (background_change_event);
1955 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1961 state = this->state;
1963 UNLOCK_THREAD (this);
1968 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
1970 MonoInternalThread *current;
1975 current = mono_thread_internal_current ();
1977 this->thread_interrupt_requested = TRUE;
1978 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
1980 UNLOCK_THREAD (this);
1983 abort_thread_internal (this, TRUE, FALSE);
1987 void mono_thread_current_check_pending_interrupt ()
1989 MonoInternalThread *thread = mono_thread_internal_current ();
1990 gboolean throw = FALSE;
1992 LOCK_THREAD (thread);
1994 if (thread->thread_interrupt_requested) {
1996 thread->thread_interrupt_requested = FALSE;
1999 UNLOCK_THREAD (thread);
2002 mono_raise_exception (mono_get_exception_thread_interrupted ());
2007 mono_thread_get_abort_signal (void)
2009 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
2011 #elif defined(PLATFORM_ANDROID)
2013 #elif !defined (SIGRTMIN)
2018 #endif /* SIGUSR1 */
2020 static int abort_signum = -1;
2022 if (abort_signum != -1)
2023 return abort_signum;
2024 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2025 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2026 struct sigaction sinfo;
2027 sigaction (i, NULL, &sinfo);
2028 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2033 /* fallback to the old way */
2035 #endif /* HOST_WIN32 */
2039 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2041 MonoException* exc = mono_thread_request_interruption (FALSE);
2042 if (exc) mono_raise_exception (exc);
2044 #endif /* HOST_WIN32 */
2047 * signal_thread_state_change
2049 * Tells the thread that his state has changed and it has to enter the new
2050 * state as soon as possible.
2052 static void signal_thread_state_change (MonoInternalThread *thread)
2055 gpointer wait_handle;
2058 if (thread == mono_thread_internal_current ()) {
2059 /* Do it synchronously */
2060 MonoException *exc = mono_thread_request_interruption (FALSE);
2062 mono_raise_exception (exc);
2066 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, (ULONG_PTR)NULL);
2069 * This will cause waits to be broken.
2070 * It will also prevent the thread from entering a wait, so if the thread returns
2071 * from the wait before it receives the abort signal, it will just spin in the wait
2072 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2075 wait_handle = mono_thread_info_prepare_interrupt (thread->handle);
2077 /* fixme: store the state somewhere */
2078 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2080 mono_thread_info_finish_interrupt (wait_handle);
2081 #endif /* HOST_WIN32 */
2085 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2087 LOCK_THREAD (thread);
2089 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2090 (thread->state & ThreadState_StopRequested) != 0 ||
2091 (thread->state & ThreadState_Stopped) != 0)
2093 UNLOCK_THREAD (thread);
2097 if ((thread->state & ThreadState_Unstarted) != 0) {
2098 thread->state |= ThreadState_Aborted;
2099 UNLOCK_THREAD (thread);
2103 thread->state |= ThreadState_AbortRequested;
2104 if (thread->abort_state_handle)
2105 mono_gchandle_free (thread->abort_state_handle);
2107 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2108 g_assert (thread->abort_state_handle);
2110 thread->abort_state_handle = 0;
2112 thread->abort_exc = NULL;
2115 * abort_exc is set in mono_thread_execute_interruption(),
2116 * triggered by the call to signal_thread_state_change(),
2117 * below. There's a point between where we have
2118 * abort_state_handle set, but abort_exc NULL, but that's not
2122 UNLOCK_THREAD (thread);
2124 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2126 /* During shutdown, we can't wait for other threads */
2128 /* Make sure the thread is awake */
2129 mono_thread_resume (thread);
2131 abort_thread_internal (thread, TRUE, TRUE);
2135 ves_icall_System_Threading_Thread_ResetAbort (void)
2137 MonoInternalThread *thread = mono_thread_internal_current ();
2138 gboolean was_aborting;
2140 LOCK_THREAD (thread);
2141 was_aborting = thread->state & ThreadState_AbortRequested;
2142 thread->state &= ~ThreadState_AbortRequested;
2143 UNLOCK_THREAD (thread);
2145 if (!was_aborting) {
2146 const char *msg = "Unable to reset abort because no abort was requested";
2147 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2150 thread->abort_exc = NULL;
2151 if (thread->abort_state_handle) {
2152 mono_gchandle_free (thread->abort_state_handle);
2153 /* This is actually not necessary - the handle
2154 only counts if the exception is set */
2155 thread->abort_state_handle = 0;
2160 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2162 LOCK_THREAD (thread);
2164 thread->state &= ~ThreadState_AbortRequested;
2166 if (thread->abort_exc) {
2167 thread->abort_exc = NULL;
2168 if (thread->abort_state_handle) {
2169 mono_gchandle_free (thread->abort_state_handle);
2170 /* This is actually not necessary - the handle
2171 only counts if the exception is set */
2172 thread->abort_state_handle = 0;
2176 UNLOCK_THREAD (thread);
2180 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2182 MonoInternalThread *thread = this->internal_thread;
2183 MonoObject *state, *deserialized = NULL, *exc;
2186 if (!thread->abort_state_handle)
2189 state = mono_gchandle_get_target (thread->abort_state_handle);
2192 domain = mono_domain_get ();
2193 if (mono_object_domain (state) == domain)
2196 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2198 if (!deserialized) {
2199 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2201 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2202 mono_set_pending_exception (invalid_op_exc);
2206 return deserialized;
2210 mono_thread_suspend (MonoInternalThread *thread)
2212 LOCK_THREAD (thread);
2214 if ((thread->state & ThreadState_Unstarted) != 0 ||
2215 (thread->state & ThreadState_Aborted) != 0 ||
2216 (thread->state & ThreadState_Stopped) != 0)
2218 UNLOCK_THREAD (thread);
2222 if ((thread->state & ThreadState_Suspended) != 0 ||
2223 (thread->state & ThreadState_SuspendRequested) != 0 ||
2224 (thread->state & ThreadState_StopRequested) != 0)
2226 UNLOCK_THREAD (thread);
2230 thread->state |= ThreadState_SuspendRequested;
2232 UNLOCK_THREAD (thread);
2234 suspend_thread_internal (thread, FALSE);
2239 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2241 if (!mono_thread_suspend (thread)) {
2242 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2248 mono_thread_resume (MonoInternalThread *thread)
2250 LOCK_THREAD (thread);
2252 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2253 thread->state &= ~ThreadState_SuspendRequested;
2254 UNLOCK_THREAD (thread);
2258 if ((thread->state & ThreadState_Suspended) == 0 ||
2259 (thread->state & ThreadState_Unstarted) != 0 ||
2260 (thread->state & ThreadState_Aborted) != 0 ||
2261 (thread->state & ThreadState_Stopped) != 0)
2263 UNLOCK_THREAD (thread);
2267 return resume_thread_internal (thread);
2271 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2273 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2274 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2280 mono_threads_is_critical_method (MonoMethod *method)
2282 switch (method->wrapper_type) {
2283 case MONO_WRAPPER_RUNTIME_INVOKE:
2284 case MONO_WRAPPER_XDOMAIN_INVOKE:
2285 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2292 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2297 if (mono_threads_is_critical_method (m)) {
2298 *((gboolean*)data) = TRUE;
2305 is_running_protected_wrapper (void)
2307 gboolean found = FALSE;
2308 mono_stack_walk (find_wrapper, &found);
2312 void mono_thread_internal_stop (MonoInternalThread *thread)
2314 LOCK_THREAD (thread);
2316 if ((thread->state & ThreadState_StopRequested) != 0 ||
2317 (thread->state & ThreadState_Stopped) != 0)
2319 UNLOCK_THREAD (thread);
2323 /* Make sure the thread is awake */
2324 mono_thread_resume (thread);
2326 thread->state |= ThreadState_StopRequested;
2327 thread->state &= ~ThreadState_AbortRequested;
2329 UNLOCK_THREAD (thread);
2331 abort_thread_internal (thread, TRUE, TRUE);
2334 void mono_thread_stop (MonoThread *thread)
2336 mono_thread_internal_stop (thread->internal_thread);
2340 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2343 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2348 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2351 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2356 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2359 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2364 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2367 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2372 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2375 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2376 return (void *) tmp;
2380 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2382 volatile MonoObject *tmp;
2383 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2384 return (MonoObject *) tmp;
2388 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2391 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2396 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2399 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2404 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2406 return InterlockedRead8 (ptr);
2410 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2412 return InterlockedRead16 (ptr);
2416 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2418 return InterlockedRead (ptr);
2422 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2424 #if SIZEOF_VOID_P == 4
2425 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2427 mono_interlocked_lock ();
2428 val = *(gint64*)ptr;
2429 mono_interlocked_unlock ();
2433 return InterlockedRead64 (ptr);
2437 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2439 return InterlockedReadPointer (ptr);
2443 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2447 #if SIZEOF_VOID_P == 4
2448 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2450 mono_interlocked_lock ();
2451 val = *(double*)ptr;
2452 mono_interlocked_unlock ();
2457 u.ival = InterlockedRead64 (ptr);
2463 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2467 u.ival = InterlockedRead (ptr);
2473 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2475 return InterlockedReadPointer (ptr);
2479 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2481 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2485 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2487 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2491 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2493 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2497 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2499 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2503 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2505 mono_atomic_store_release ((volatile void **) ptr, value);
2509 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2511 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2515 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2517 mono_atomic_store_release ((volatile double *) ptr, value);
2521 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2523 mono_atomic_store_release ((volatile float *) ptr, value);
2527 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2529 InterlockedWrite8 (ptr, value);
2533 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2535 InterlockedWrite16 (ptr, value);
2539 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2541 InterlockedWrite (ptr, value);
2545 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2547 #if SIZEOF_VOID_P == 4
2548 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2549 mono_interlocked_lock ();
2550 *(gint64*)ptr = value;
2551 mono_interlocked_unlock ();
2556 InterlockedWrite64 (ptr, value);
2560 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2562 InterlockedWritePointer (ptr, value);
2566 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2570 #if SIZEOF_VOID_P == 4
2571 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2572 mono_interlocked_lock ();
2573 *(double*)ptr = value;
2574 mono_interlocked_unlock ();
2581 InterlockedWrite64 (ptr, u.ival);
2585 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2591 InterlockedWrite (ptr, u.ival);
2595 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2597 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2601 mono_thread_init_tls (void)
2603 MONO_FAST_TLS_INIT (tls_current_object);
2604 mono_native_tls_alloc (¤t_object_key, NULL);
2607 void mono_thread_init (MonoThreadStartCB start_cb,
2608 MonoThreadAttachCB attach_cb)
2610 mono_mutex_init_recursive(&threads_mutex);
2611 mono_mutex_init_recursive(&interlocked_mutex);
2612 mono_mutex_init_recursive(&contexts_mutex);
2613 mono_mutex_init_recursive(&joinable_threads_mutex);
2615 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2616 g_assert(background_change_event != NULL);
2618 mono_init_static_data_info (&thread_static_info);
2619 mono_init_static_data_info (&context_static_info);
2621 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2623 mono_thread_start_cb = start_cb;
2624 mono_thread_attach_cb = attach_cb;
2626 /* Get a pseudo handle to the current process. This is just a
2627 * kludge so that wapi can build a process handle if needed.
2628 * As a pseudo handle is returned, we don't need to clean
2631 GetCurrentProcess ();
2634 void mono_thread_cleanup (void)
2636 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2637 MonoThreadInfo *info;
2639 /* The main thread must abandon any held mutexes (particularly
2640 * important for named mutexes as they are shared across
2641 * processes, see bug 74680.) This will happen when the
2642 * thread exits, but if it's not running in a subthread it
2643 * won't exit in time.
2645 info = mono_thread_info_current ();
2646 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2650 /* This stuff needs more testing, it seems one of these
2651 * critical sections can be locked when mono_thread_cleanup is
2654 mono_mutex_destroy (&threads_mutex);
2655 mono_mutex_destroy (&interlocked_mutex);
2656 mono_mutex_destroy (&contexts_mutex);
2657 mono_mutex_destroy (&delayed_free_table_mutex);
2658 mono_mutex_destroy (&small_id_mutex);
2659 CloseHandle (background_change_event);
2662 mono_native_tls_free (current_object_key);
2666 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2668 mono_thread_cleanup_fn = func;
2672 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2674 thread->internal_thread->manage_callback = func;
2677 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2679 mono_thread_notify_pending_exc_fn = func;
2683 static void print_tids (gpointer key, gpointer value, gpointer user)
2685 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2686 * sizeof(uint) and a cast to uint would overflow
2688 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2689 * print this as a pointer.
2691 g_message ("Waiting for: %p", key);
2696 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2697 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2701 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2705 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2707 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2709 if(ret==WAIT_FAILED) {
2710 /* See the comment in build_wait_tids() */
2711 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2715 for(i=0; i<wait->num; i++)
2716 CloseHandle (wait->handles[i]);
2718 if (ret == WAIT_TIMEOUT)
2721 for(i=0; i<wait->num; i++) {
2722 gsize tid = wait->threads[i]->tid;
2725 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2726 * it can still run io-layer etc. code. So wait for it to really exit.
2727 * FIXME: This won't join threads which are not in the joinable_hash yet.
2729 mono_thread_join ((gpointer)tid);
2731 mono_threads_lock ();
2732 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2733 /* This thread must have been killed, because
2734 * it hasn't cleaned itself up. (It's just
2735 * possible that the thread exited before the
2736 * parent thread had a chance to store the
2737 * handle, and now there is another pointer to
2738 * the already-exited thread stored. In this
2739 * case, we'll just get two
2740 * mono_profiler_thread_end() calls for the
2744 mono_threads_unlock ();
2745 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2746 thread_cleanup (wait->threads[i]);
2748 mono_threads_unlock ();
2753 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2755 guint32 i, ret, count;
2757 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2759 /* Add the thread state change event, so it wakes up if a thread changes
2760 * to background mode.
2763 if (count < MAXIMUM_WAIT_OBJECTS) {
2764 wait->handles [count] = background_change_event;
2768 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2770 if(ret==WAIT_FAILED) {
2771 /* See the comment in build_wait_tids() */
2772 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2776 for(i=0; i<wait->num; i++)
2777 CloseHandle (wait->handles[i]);
2779 if (ret == WAIT_TIMEOUT)
2782 if (ret < wait->num) {
2783 gsize tid = wait->threads[ret]->tid;
2784 mono_threads_lock ();
2785 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2786 /* See comment in wait_for_tids about thread cleanup */
2787 mono_threads_unlock ();
2788 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2789 thread_cleanup (wait->threads [ret]);
2791 mono_threads_unlock ();
2795 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2797 struct wait_data *wait=(struct wait_data *)user;
2799 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2801 MonoInternalThread *thread=(MonoInternalThread *)value;
2803 /* Ignore background threads, we abort them later */
2804 /* Do not lock here since it is not needed and the caller holds threads_lock */
2805 if (thread->state & ThreadState_Background) {
2806 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2807 return; /* just leave, ignore */
2810 if (mono_gc_is_finalizer_internal_thread (thread)) {
2811 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2815 if (thread == mono_thread_internal_current ()) {
2816 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2820 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2821 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2825 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2826 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2830 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2831 if (handle == NULL) {
2832 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2836 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2837 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2838 wait->handles[wait->num]=handle;
2839 wait->threads[wait->num]=thread;
2842 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2844 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2849 /* Just ignore the rest, we can't do anything with
2856 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2858 struct wait_data *wait=(struct wait_data *)user;
2859 gsize self = GetCurrentThreadId ();
2860 MonoInternalThread *thread = value;
2863 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2866 /* The finalizer thread is not a background thread */
2867 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2868 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2870 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2874 /* printf ("A: %d\n", wait->num); */
2875 wait->handles[wait->num]=thread->handle;
2876 wait->threads[wait->num]=thread;
2879 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2880 mono_thread_internal_stop (thread);
2884 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2888 * mono_threads_set_shutting_down:
2890 * Is called by a thread that wants to shut down Mono. If the runtime is already
2891 * shutting down, the calling thread is suspended/stopped, and this function never
2895 mono_threads_set_shutting_down (void)
2897 MonoInternalThread *current_thread = mono_thread_internal_current ();
2899 mono_threads_lock ();
2901 if (shutting_down) {
2902 mono_threads_unlock ();
2904 /* Make sure we're properly suspended/stopped */
2906 LOCK_THREAD (current_thread);
2908 if ((current_thread->state & ThreadState_SuspendRequested) ||
2909 (current_thread->state & ThreadState_AbortRequested) ||
2910 (current_thread->state & ThreadState_StopRequested)) {
2911 UNLOCK_THREAD (current_thread);
2912 mono_thread_execute_interruption (current_thread);
2914 current_thread->state |= ThreadState_Stopped;
2915 UNLOCK_THREAD (current_thread);
2918 /*since we're killing the thread, unset the current domain.*/
2919 mono_domain_unset ();
2921 /* Wake up other threads potentially waiting for us */
2922 mono_thread_info_exit ();
2924 shutting_down = TRUE;
2926 /* Not really a background state change, but this will
2927 * interrupt the main thread if it is waiting for all
2928 * the other threads.
2930 SetEvent (background_change_event);
2932 mono_threads_unlock ();
2936 void mono_thread_manage (void)
2938 struct wait_data wait_data;
2939 struct wait_data *wait = &wait_data;
2941 memset (wait, 0, sizeof (struct wait_data));
2942 /* join each thread that's still running */
2943 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2945 mono_threads_lock ();
2947 THREAD_DEBUG (g_message("%s: No threads", __func__));
2948 mono_threads_unlock ();
2951 mono_threads_unlock ();
2954 mono_threads_lock ();
2955 if (shutting_down) {
2956 /* somebody else is shutting down */
2957 mono_threads_unlock ();
2960 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2961 mono_g_hash_table_foreach (threads, print_tids, NULL));
2963 ResetEvent (background_change_event);
2965 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2966 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2967 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2968 mono_threads_unlock ();
2970 /* Something to wait for */
2971 wait_for_tids_or_state_change (wait, INFINITE);
2973 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2974 } while(wait->num>0);
2976 /* Mono is shutting down, so just wait for the end */
2977 if (!mono_runtime_try_shutdown ()) {
2978 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2979 mono_thread_suspend (mono_thread_internal_current ());
2980 mono_thread_execute_interruption (mono_thread_internal_current ());
2984 * Remove everything but the finalizer thread and self.
2985 * Also abort all the background threads
2988 mono_threads_lock ();
2991 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2992 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2993 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2995 mono_threads_unlock ();
2997 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2999 /* Something to wait for */
3000 wait_for_tids (wait, INFINITE);
3002 } while (wait->num > 0);
3005 * give the subthreads a chance to really quit (this is mainly needed
3006 * to get correct user and system times from getrusage/wait/time(1)).
3007 * This could be removed if we avoid pthread_detach() and use pthread_join().
3009 mono_thread_info_yield ();
3012 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3014 MonoInternalThread *thread=(MonoInternalThread *)value;
3016 if(thread->tid != (gsize)user) {
3017 /*TerminateThread (thread->handle, -1);*/
3021 void mono_thread_abort_all_other_threads (void)
3023 gsize self = GetCurrentThreadId ();
3025 mono_threads_lock ();
3026 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3027 mono_g_hash_table_size (threads));
3028 mono_g_hash_table_foreach (threads, print_tids, NULL));
3030 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3032 mono_threads_unlock ();
3036 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3038 MonoInternalThread *thread = (MonoInternalThread*)value;
3039 struct wait_data *wait = (struct wait_data*)user_data;
3043 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3045 * This needs no locking.
3047 if ((thread->state & ThreadState_Suspended) != 0 ||
3048 (thread->state & ThreadState_Stopped) != 0)
3051 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3052 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3056 wait->handles [wait->num] = handle;
3057 wait->threads [wait->num] = thread;
3063 * mono_thread_suspend_all_other_threads:
3065 * Suspend all managed threads except the finalizer thread and this thread. It is
3066 * not possible to resume them later.
3068 void mono_thread_suspend_all_other_threads (void)
3070 struct wait_data wait_data;
3071 struct wait_data *wait = &wait_data;
3073 gsize self = GetCurrentThreadId ();
3075 guint32 eventidx = 0;
3076 gboolean starting, finished;
3078 memset (wait, 0, sizeof (struct wait_data));
3080 * The other threads could be in an arbitrary state at this point, i.e.
3081 * they could be starting up, shutting down etc. This means that there could be
3082 * threads which are not even in the threads hash table yet.
3086 * First we set a barrier which will be checked by all threads before they
3087 * are added to the threads hash table, and they will exit if the flag is set.
3088 * This ensures that no threads could be added to the hash later.
3089 * We will use shutting_down as the barrier for now.
3091 g_assert (shutting_down);
3094 * We make multiple calls to WaitForMultipleObjects since:
3095 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3096 * - some threads could exit without becoming suspended
3101 * Make a copy of the hashtable since we can't do anything with
3102 * threads while threads_mutex is held.
3105 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3106 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3107 mono_threads_lock ();
3108 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3109 mono_threads_unlock ();
3111 events = g_new0 (gpointer, wait->num);
3113 /* Get the suspended events that we'll be waiting for */
3114 for (i = 0; i < wait->num; ++i) {
3115 MonoInternalThread *thread = wait->threads [i];
3116 gboolean signal_suspend = FALSE;
3118 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3119 //CloseHandle (wait->handles [i]);
3120 wait->threads [i] = NULL; /* ignore this thread in next loop */
3124 LOCK_THREAD (thread);
3126 if (thread->suspended_event == NULL) {
3127 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3128 if (thread->suspended_event == NULL) {
3129 /* Forget this one and go on to the next */
3130 UNLOCK_THREAD (thread);
3135 if ((thread->state & ThreadState_Suspended) != 0 ||
3136 (thread->state & ThreadState_StopRequested) != 0 ||
3137 (thread->state & ThreadState_Stopped) != 0) {
3138 UNLOCK_THREAD (thread);
3139 CloseHandle (wait->handles [i]);
3140 wait->threads [i] = NULL; /* ignore this thread in next loop */
3144 if ((thread->state & ThreadState_SuspendRequested) == 0)
3145 signal_suspend = TRUE;
3147 events [eventidx++] = thread->suspended_event;
3149 /* Convert abort requests into suspend requests */
3150 if ((thread->state & ThreadState_AbortRequested) != 0)
3151 thread->state &= ~ThreadState_AbortRequested;
3153 thread->state |= ThreadState_SuspendRequested;
3155 UNLOCK_THREAD (thread);
3157 /* Signal the thread to suspend */
3158 if (mono_thread_info_new_interrupt_enabled ())
3159 suspend_thread_internal (thread, TRUE);
3160 else if (signal_suspend)
3161 signal_thread_state_change (thread);
3164 /*Only wait on the suspend event if we are using the old path */
3165 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3166 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3167 for (i = 0; i < wait->num; ++i) {
3168 MonoInternalThread *thread = wait->threads [i];
3173 LOCK_THREAD (thread);
3174 if ((thread->state & ThreadState_Suspended) != 0) {
3175 CloseHandle (thread->suspended_event);
3176 thread->suspended_event = NULL;
3178 UNLOCK_THREAD (thread);
3182 if (eventidx <= 0) {
3184 * If there are threads which are starting up, we wait until they
3185 * are suspended when they try to register in the threads hash.
3186 * This is guaranteed to finish, since the threads which can create new
3187 * threads get suspended after a while.
3188 * FIXME: The finalizer thread can still create new threads.
3190 mono_threads_lock ();
3191 if (threads_starting_up)
3192 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3195 mono_threads_unlock ();
3207 collect_threads (gpointer key, gpointer value, gpointer user_data)
3209 MonoInternalThread *thread = (MonoInternalThread*)value;
3210 struct wait_data *wait = (struct wait_data*)user_data;
3213 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3214 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3218 wait->handles [wait->num] = handle;
3219 wait->threads [wait->num] = thread;
3224 static gboolean thread_dump_requested;
3226 static G_GNUC_UNUSED gboolean
3227 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3229 GString *p = (GString*)data;
3230 MonoMethod *method = NULL;
3232 method = mono_jit_info_get_method (frame->ji);
3235 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3236 g_string_append_printf (p, " %s\n", location);
3239 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3244 static SuspendThreadResult
3245 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3247 MonoInternalThread *thread = ud;
3248 GString* text = g_string_new (0);
3250 GError *error = NULL;
3253 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3255 g_string_append_printf (text, "\n\"%s\"", name);
3258 else if (thread->threadpool_thread)
3259 g_string_append (text, "\n\"<threadpool thread>\"");
3261 g_string_append (text, "\n\"<unnamed thread>\"");
3264 /* This no longer works with remote unwinding */
3266 wapi_desc = wapi_current_thread_desc ();
3267 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3272 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, text);
3274 fprintf (stdout, "%s", text->str);
3276 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3277 OutputDebugStringA(text->str);
3280 g_string_free (text, TRUE);
3282 return MonoResumeThread;
3286 dump_thread (gpointer key, gpointer value, gpointer user)
3288 MonoInternalThread *thread = (MonoInternalThread *)value;
3290 if (thread == mono_thread_internal_current ())
3294 FIXME This still can hang if we stop a thread during malloc.
3295 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3296 that takes a callback and runs it with the target suspended.
3297 We probably should loop a bit around trying to get it to either managed code
3300 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
3304 mono_threads_perform_thread_dump (void)
3306 if (!thread_dump_requested)
3309 printf ("Full thread dump:\n");
3311 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3312 something needs then in the process.
3314 mono_loader_lock ();
3315 mono_domain_lock (mono_get_root_domain ());
3317 mono_threads_lock ();
3318 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3319 mono_threads_unlock ();
3321 mono_domain_unlock (mono_get_root_domain ());
3322 mono_loader_unlock ();
3324 thread_dump_requested = FALSE;
3328 * mono_threads_request_thread_dump:
3330 * Ask all threads except the current to print their stacktrace to stdout.
3333 mono_threads_request_thread_dump (void)
3335 struct wait_data wait_data;
3336 struct wait_data *wait = &wait_data;
3339 /*The new thread dump code runs out of the finalizer thread. */
3340 if (mono_thread_info_new_interrupt_enabled ()) {
3341 thread_dump_requested = TRUE;
3342 mono_gc_finalize_notify ();
3347 memset (wait, 0, sizeof (struct wait_data));
3350 * Make a copy of the hashtable since we can't do anything with
3351 * threads while threads_mutex is held.
3353 mono_threads_lock ();
3354 mono_g_hash_table_foreach (threads, collect_threads, wait);
3355 mono_threads_unlock ();
3357 for (i = 0; i < wait->num; ++i) {
3358 MonoInternalThread *thread = wait->threads [i];
3360 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3361 (thread != mono_thread_internal_current ()) &&
3362 !thread->thread_dump_requested) {
3363 thread->thread_dump_requested = TRUE;
3365 signal_thread_state_change (thread);
3368 CloseHandle (wait->handles [i]);
3374 gint allocated; /* +1 so that refs [allocated] == NULL */
3378 typedef struct ref_stack RefStack;
3381 ref_stack_new (gint initial_size)
3385 initial_size = MAX (initial_size, 16) + 1;
3386 rs = g_new0 (RefStack, 1);
3387 rs->refs = g_new0 (gpointer, initial_size);
3388 rs->allocated = initial_size;
3393 ref_stack_destroy (gpointer ptr)
3404 ref_stack_push (RefStack *rs, gpointer ptr)
3406 g_assert (rs != NULL);
3408 if (rs->bottom >= rs->allocated) {
3409 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3410 rs->allocated <<= 1;
3411 rs->refs [rs->allocated] = NULL;
3413 rs->refs [rs->bottom++] = ptr;
3417 ref_stack_pop (RefStack *rs)
3419 if (rs == NULL || rs->bottom == 0)
3423 rs->refs [rs->bottom] = NULL;
3427 ref_stack_find (RefStack *rs, gpointer ptr)
3434 for (refs = rs->refs; refs && *refs; refs++) {
3442 * mono_thread_push_appdomain_ref:
3444 * Register that the current thread may have references to objects in domain
3445 * @domain on its stack. Each call to this function should be paired with a
3446 * call to pop_appdomain_ref.
3449 mono_thread_push_appdomain_ref (MonoDomain *domain)
3451 MonoInternalThread *thread = mono_thread_internal_current ();
3454 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3455 SPIN_LOCK (thread->lock_thread_id);
3456 if (thread->appdomain_refs == NULL)
3457 thread->appdomain_refs = ref_stack_new (16);
3458 ref_stack_push (thread->appdomain_refs, domain);
3459 SPIN_UNLOCK (thread->lock_thread_id);
3464 mono_thread_pop_appdomain_ref (void)
3466 MonoInternalThread *thread = mono_thread_internal_current ();
3469 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3470 SPIN_LOCK (thread->lock_thread_id);
3471 ref_stack_pop (thread->appdomain_refs);
3472 SPIN_UNLOCK (thread->lock_thread_id);
3477 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3480 SPIN_LOCK (thread->lock_thread_id);
3481 res = ref_stack_find (thread->appdomain_refs, domain);
3482 SPIN_UNLOCK (thread->lock_thread_id);
3487 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3489 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3492 typedef struct abort_appdomain_data {
3493 struct wait_data wait;
3495 } abort_appdomain_data;
3498 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3500 MonoInternalThread *thread = (MonoInternalThread*)value;
3501 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3502 MonoDomain *domain = data->domain;
3504 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3505 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3507 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3508 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3511 data->wait.handles [data->wait.num] = handle;
3512 data->wait.threads [data->wait.num] = thread;
3515 /* Just ignore the rest, we can't do anything with
3523 * mono_threads_abort_appdomain_threads:
3525 * Abort threads which has references to the given appdomain.
3528 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3530 #ifdef __native_client__
3534 abort_appdomain_data user_data;
3536 int orig_timeout = timeout;
3539 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3541 start_time = mono_msec_ticks ();
3543 mono_threads_lock ();
3545 user_data.domain = domain;
3546 user_data.wait.num = 0;
3547 /* This shouldn't take any locks */
3548 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3549 mono_threads_unlock ();
3551 if (user_data.wait.num > 0) {
3552 /* Abort the threads outside the threads lock */
3553 for (i = 0; i < user_data.wait.num; ++i)
3554 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3557 * We should wait for the threads either to abort, or to leave the
3558 * domain. We can't do the latter, so we wait with a timeout.
3560 wait_for_tids (&user_data.wait, 100);
3563 /* Update remaining time */
3564 timeout -= mono_msec_ticks () - start_time;
3565 start_time = mono_msec_ticks ();
3567 if (orig_timeout != -1 && timeout < 0)
3570 while (user_data.wait.num > 0);
3572 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3578 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3580 MonoInternalThread *thread = (MonoInternalThread*)value;
3581 MonoDomain *domain = (MonoDomain*)user_data;
3584 /* No locking needed here */
3585 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3587 if (thread->cached_culture_info) {
3588 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3589 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3590 if (obj && obj->vtable->domain == domain)
3591 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3597 * mono_threads_clear_cached_culture:
3599 * Clear the cached_current_culture from all threads if it is in the
3603 mono_threads_clear_cached_culture (MonoDomain *domain)
3605 mono_threads_lock ();
3606 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3607 mono_threads_unlock ();
3611 * mono_thread_get_undeniable_exception:
3613 * Return an exception which needs to be raised when leaving a catch clause.
3614 * This is used for undeniable exception propagation.
3617 mono_thread_get_undeniable_exception (void)
3619 MonoInternalThread *thread = mono_thread_internal_current ();
3621 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3623 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3624 * exception if the thread no longer references a dying appdomain.
3626 thread->abort_exc->trace_ips = NULL;
3627 thread->abort_exc->stack_trace = NULL;
3628 return thread->abort_exc;
3634 #if MONO_SMALL_CONFIG
3635 #define NUM_STATIC_DATA_IDX 4
3636 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3640 #define NUM_STATIC_DATA_IDX 8
3641 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3642 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3646 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3649 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3652 gpointer *static_data = addr;
3653 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3656 if (!static_data [i])
3658 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3659 ptr = static_data [i];
3660 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3661 uintptr_t bmap = static_reference_bitmaps [i][j];
3664 if ((bmap & 1) && *p) {
3665 mark_func (p, gc_data);
3675 * mono_alloc_static_data
3677 * Allocate memory blocks for storing threads or context static data
3680 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3682 guint idx = (offset >> 24) - 1;
3685 gpointer* static_data = *static_data_ptr;
3687 static void* tls_desc = NULL;
3688 if (mono_gc_user_markers_supported () && !tls_desc)
3689 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3690 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3691 *static_data_ptr = static_data;
3692 static_data [0] = static_data;
3695 for (i = 1; i <= idx; ++i) {
3696 if (static_data [i])
3698 if (mono_gc_user_markers_supported () && threadlocal)
3699 static_data [i] = g_malloc0 (static_data_size [i]);
3701 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3706 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3709 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3710 gpointer p = static_data [i];
3714 * At this point, the static data pointer array is still registered with the
3715 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3716 * data. Freeing the individual arrays without first nulling their slots
3717 * would make it possible for mark_tls_slots() to encounter a pointer to
3718 * such an already freed array. See bug #13813.
3720 static_data [i] = NULL;
3721 mono_memory_write_barrier ();
3722 if (mono_gc_user_markers_supported () && threadlocal)
3725 mono_gc_free_fixed (p);
3727 mono_gc_free_fixed (static_data);
3731 * mono_init_static_data_info
3733 * Initializes static data counters
3735 static void mono_init_static_data_info (StaticDataInfo *static_data)
3737 static_data->idx = 0;
3738 static_data->offset = 0;
3739 static_data->freelist = NULL;
3743 * mono_alloc_static_data_slot
3745 * Generates an offset for static data. static_data contains the counters
3746 * used to generate it.
3749 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3753 if (!static_data->idx && !static_data->offset) {
3755 * we use the first chunk of the first allocation also as
3756 * an array for the rest of the data
3758 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3760 static_data->offset += align - 1;
3761 static_data->offset &= ~(align - 1);
3762 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3763 static_data->idx ++;
3764 g_assert (size <= static_data_size [static_data->idx]);
3765 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3766 static_data->offset = 0;
3768 offset = static_data->offset | ((static_data->idx + 1) << 24);
3769 static_data->offset += size;
3774 * ensure thread static fields already allocated are valid for thread
3775 * This function is called when a thread is created or on thread attach.
3778 thread_adjust_static_data (MonoInternalThread *thread)
3782 mono_threads_lock ();
3783 if (thread_static_info.offset || thread_static_info.idx > 0) {
3784 /* get the current allocated size */
3785 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3786 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3788 mono_threads_unlock ();
3792 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3794 MonoInternalThread *thread = value;
3795 guint32 offset = GPOINTER_TO_UINT (user);
3797 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3800 static MonoThreadDomainTls*
3801 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3803 MonoThreadDomainTls* prev = NULL;
3804 MonoThreadDomainTls* tmp = static_data->freelist;
3806 if (tmp->size == size) {
3808 prev->next = tmp->next;
3810 static_data->freelist = tmp->next;
3819 #if SIZEOF_VOID_P == 4
3826 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3829 int idx = (offset >> 24) - 1;
3831 if (!static_reference_bitmaps [idx])
3832 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3833 rb = static_reference_bitmaps [idx];
3835 offset /= sizeof (gpointer);
3836 /* offset is now the bitmap offset */
3837 for (i = 0; i < numbits; ++i) {
3838 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3839 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (ONE_P << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3844 clear_reference_bitmap (guint32 offset, guint32 size)
3846 int idx = (offset >> 24) - 1;
3848 rb = static_reference_bitmaps [idx];
3850 offset /= sizeof (gpointer);
3851 size /= sizeof (gpointer);
3853 /* offset is now the bitmap offset */
3854 for (; offset < size; ++offset)
3855 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3859 * The offset for a special static variable is composed of three parts:
3860 * a bit that indicates the type of static data (0:thread, 1:context),
3861 * an index in the array of chunks of memory for the thread (thread->static_data)
3862 * and an offset in that chunk of mem. This allows allocating less memory in the
3867 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3870 if (static_type == SPECIAL_STATIC_THREAD) {
3871 MonoThreadDomainTls *item;
3872 mono_threads_lock ();
3873 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3874 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3876 offset = item->offset;
3879 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3881 update_tls_reference_bitmap (offset, bitmap, numbits);
3882 /* This can be called during startup */
3883 if (threads != NULL)
3884 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3885 mono_threads_unlock ();
3887 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3888 mono_contexts_lock ();
3889 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3890 mono_contexts_unlock ();
3891 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3897 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3899 /* The high bit means either thread (0) or static (1) data. */
3901 guint32 static_type = (offset & 0x80000000);
3904 offset &= 0x7fffffff;
3905 idx = (offset >> 24) - 1;
3907 if (static_type == 0) {
3908 return get_thread_static_data (thread, offset);
3910 /* Allocate static data block under demand, since we don't have a list
3913 MonoAppContext *context = mono_context_get ();
3914 if (!context->static_data || !context->static_data [idx]) {
3915 mono_contexts_lock ();
3916 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3917 mono_contexts_unlock ();
3919 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3924 mono_get_special_static_data (guint32 offset)
3926 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3935 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3937 MonoInternalThread *thread = value;
3938 TlsOffsetSize *data = user;
3939 int idx = (data->offset >> 24) - 1;
3942 if (!thread->static_data || !thread->static_data [idx])
3944 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3945 mono_gc_bzero_atomic (ptr, data->size);
3949 do_free_special_slot (guint32 offset, guint32 size)
3951 guint32 static_type = (offset & 0x80000000);
3952 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3953 if (static_type == 0) {
3955 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3956 data.offset = offset & 0x7fffffff;
3958 clear_reference_bitmap (data.offset, data.size);
3959 if (threads != NULL)
3960 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3961 item->offset = offset;
3964 if (!mono_runtime_is_shutting_down ()) {
3965 item->next = thread_static_info.freelist;
3966 thread_static_info.freelist = item;
3968 /* We could be called during shutdown after mono_thread_cleanup () is called */
3972 /* FIXME: free context static data as well */
3977 do_free_special (gpointer key, gpointer value, gpointer data)
3979 MonoClassField *field = key;
3980 guint32 offset = GPOINTER_TO_UINT (value);
3983 size = mono_type_size (field->type, &align);
3984 do_free_special_slot (offset, size);
3988 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3990 mono_threads_lock ();
3991 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3992 mono_threads_unlock ();
3996 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3998 mono_threads_lock ();
3999 do_free_special_slot (offset, size);
4000 mono_threads_unlock ();
4004 * allocates room in the thread local area for storing an instance of the struct type
4005 * the allocation is kept track of in domain->tlsrec_list.
4008 mono_thread_alloc_tls (MonoReflectionType *type)
4010 MonoDomain *domain = mono_domain_get ();
4012 MonoTlsDataRecord *tlsrec;
4015 gsize default_bitmap [4] = {0};
4016 uint32_t tls_offset;
4020 klass = mono_class_from_mono_type (type->type);
4021 /* TlsDatum is a struct, so we subtract the object header size offset */
4022 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
4023 size = mono_type_size (type->type, &align);
4024 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
4025 if (bitmap != default_bitmap)
4027 tlsrec = g_new0 (MonoTlsDataRecord, 1);
4028 tlsrec->tls_offset = tls_offset;
4029 tlsrec->size = size;
4030 mono_domain_lock (domain);
4031 tlsrec->next = domain->tlsrec_list;
4032 domain->tlsrec_list = tlsrec;
4033 mono_domain_unlock (domain);
4038 destroy_tls (MonoDomain *domain, uint32_t tls_offset)
4040 MonoTlsDataRecord *prev = NULL;
4041 MonoTlsDataRecord *cur;
4044 mono_domain_lock (domain);
4045 cur = domain->tlsrec_list;
4047 if (cur->tls_offset == tls_offset) {
4049 prev->next = cur->next;
4051 domain->tlsrec_list = cur->next;
4059 mono_domain_unlock (domain);
4061 mono_special_static_data_free_slot (tls_offset, size);
4065 mono_thread_destroy_tls (uint32_t tls_offset)
4067 destroy_tls (mono_domain_get (), tls_offset);
4071 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
4074 mono_thread_destroy_domain_tls (MonoDomain *domain)
4076 while (domain->tlsrec_list)
4077 destroy_tls (domain, domain->tlsrec_list->tls_offset);
4080 static MonoClassField *local_slots = NULL;
4083 /* local tls data to get locals_slot from a thread */
4086 /* index in the locals_slot array */
4091 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4093 LocalSlotID *sid = user_data;
4094 MonoInternalThread *thread = (MonoInternalThread*)value;
4095 MonoArray *slots_array;
4097 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4098 * it is for the right domain, so we need to check if it is allocated an initialized
4099 * for the current thread.
4101 /*g_print ("handling thread %p\n", thread);*/
4102 if (!thread->static_data || !thread->static_data [sid->idx])
4104 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4105 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4107 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4111 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4119 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4121 g_warning ("local_slots field not found in Thread class");
4125 domain = mono_domain_get ();
4126 mono_domain_lock (domain);
4127 if (domain->special_static_fields)
4128 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4129 mono_domain_unlock (domain);
4132 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4133 sid.offset = GPOINTER_TO_UINT (addr);
4134 sid.offset &= 0x7fffffff;
4135 sid.idx = (sid.offset >> 24) - 1;
4136 mono_threads_lock ();
4137 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4138 mono_threads_unlock ();
4140 /* FIXME: clear the slot for MonoAppContexts, too */
4145 static void CALLBACK dummy_apc (ULONG_PTR param)
4151 * mono_thread_execute_interruption
4153 * Performs the operation that the requested thread state requires (abort,
4156 static MonoException*
4157 mono_thread_execute_interruption (MonoInternalThread *thread)
4159 LOCK_THREAD (thread);
4161 /* MonoThread::interruption_requested can only be changed with atomics */
4162 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4163 /* this will consume pending APC calls */
4165 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4167 InterlockedDecrement (&thread_interruption_requested);
4168 /* Clear the interrupted flag of the thread so it can wait again */
4169 mono_thread_info_clear_interruption ();
4172 if ((thread->state & ThreadState_AbortRequested) != 0) {
4173 UNLOCK_THREAD (thread);
4174 if (thread->abort_exc == NULL) {
4176 * This might be racy, but it has to be called outside the lock
4177 * since it calls managed code.
4179 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4181 return thread->abort_exc;
4183 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4184 self_suspend_internal (thread);
4187 else if ((thread->state & ThreadState_StopRequested) != 0) {
4188 /* FIXME: do this through the JIT? */
4190 UNLOCK_THREAD (thread);
4192 mono_thread_exit ();
4194 } else if (thread->pending_exception) {
4197 exc = thread->pending_exception;
4198 thread->pending_exception = NULL;
4200 UNLOCK_THREAD (thread);
4202 } else if (thread->thread_interrupt_requested) {
4204 thread->thread_interrupt_requested = FALSE;
4205 UNLOCK_THREAD (thread);
4207 return(mono_get_exception_thread_interrupted ());
4210 UNLOCK_THREAD (thread);
4216 * mono_thread_request_interruption
4218 * A signal handler can call this method to request the interruption of a
4219 * thread. The result of the interruption will depend on the current state of
4220 * the thread. If the result is an exception that needs to be throw, it is
4221 * provided as return value.
4224 mono_thread_request_interruption (gboolean running_managed)
4226 MonoInternalThread *thread = mono_thread_internal_current ();
4228 /* The thread may already be stopping */
4233 if (thread->interrupt_on_stop &&
4234 thread->state & ThreadState_StopRequested &&
4235 thread->state & ThreadState_Background)
4239 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4241 InterlockedIncrement (&thread_interruption_requested);
4243 if (!running_managed || is_running_protected_wrapper ()) {
4244 /* Can't stop while in unmanaged code. Increase the global interruption
4245 request count. When exiting the unmanaged method the count will be
4246 checked and the thread will be interrupted. */
4248 if (mono_thread_notify_pending_exc_fn && !running_managed)
4249 /* The JIT will notify the thread about the interruption */
4250 /* This shouldn't take any locks */
4251 mono_thread_notify_pending_exc_fn (NULL);
4253 /* this will awake the thread if it is in WaitForSingleObject
4255 /* Our implementation of this function ignores the func argument */
4257 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4259 mono_thread_info_self_interrupt ();
4264 return mono_thread_execute_interruption (thread);
4268 /*This function should be called by a thread after it has exited all of
4269 * its handle blocks at interruption time.*/
4271 mono_thread_resume_interruption (void)
4273 MonoInternalThread *thread = mono_thread_internal_current ();
4274 gboolean still_aborting;
4276 /* The thread may already be stopping */
4280 LOCK_THREAD (thread);
4281 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4282 UNLOCK_THREAD (thread);
4284 /*This can happen if the protected block called Thread::ResetAbort*/
4285 if (!still_aborting)
4288 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4290 InterlockedIncrement (&thread_interruption_requested);
4292 mono_thread_info_self_interrupt ();
4294 return mono_thread_execute_interruption (thread);
4297 gboolean mono_thread_interruption_requested ()
4299 if (thread_interruption_requested) {
4300 MonoInternalThread *thread = mono_thread_internal_current ();
4301 /* The thread may already be stopping */
4303 return (thread->interruption_requested);
4308 static MonoException*
4309 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4311 MonoInternalThread *thread = mono_thread_internal_current ();
4313 /* The thread may already be stopping */
4317 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4318 MonoException* exc = mono_thread_execute_interruption (thread);
4326 * Performs the interruption of the current thread, if one has been requested,
4327 * and the thread is not running a protected wrapper.
4328 * Return the exception which needs to be thrown, if any.
4331 mono_thread_interruption_checkpoint (void)
4333 return mono_thread_interruption_checkpoint_request (FALSE);
4337 * Performs the interruption of the current thread, if one has been requested.
4338 * Return the exception which needs to be thrown, if any.
4341 mono_thread_force_interruption_checkpoint_noraise (void)
4343 return mono_thread_interruption_checkpoint_request (TRUE);
4347 * Performs the interruption of the current thread, if one has been requested.
4348 * Throw the exception which needs to be thrown, if any.
4351 mono_thread_force_interruption_checkpoint (void)
4355 ex = mono_thread_interruption_checkpoint_request (TRUE);
4357 mono_raise_exception (ex);
4361 * mono_thread_get_and_clear_pending_exception:
4363 * Return any pending exceptions for the current thread and clear it as a side effect.
4366 mono_thread_get_and_clear_pending_exception (void)
4368 MonoInternalThread *thread = mono_thread_internal_current ();
4370 /* The thread may already be stopping */
4374 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4375 return mono_thread_execute_interruption (thread);
4378 if (thread->pending_exception) {
4379 MonoException *exc = thread->pending_exception;
4381 thread->pending_exception = NULL;
4389 * mono_set_pending_exception:
4391 * Set the pending exception of the current thread to EXC.
4392 * The exception will be thrown when execution returns to managed code.
4395 mono_set_pending_exception (MonoException *exc)
4397 MonoInternalThread *thread = mono_thread_internal_current ();
4399 /* The thread may already be stopping */
4403 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4405 mono_thread_request_interruption (FALSE);
4409 * mono_thread_interruption_request_flag:
4411 * Returns the address of a flag that will be non-zero if an interruption has
4412 * been requested for a thread. The thread to interrupt may not be the current
4413 * thread, so an additional call to mono_thread_interruption_requested() or
4414 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4417 gint32* mono_thread_interruption_request_flag ()
4419 return &thread_interruption_requested;
4423 mono_thread_init_apartment_state (void)
4426 MonoInternalThread* thread = mono_thread_internal_current ();
4428 /* Positive return value indicates success, either
4429 * S_OK if this is first CoInitialize call, or
4430 * S_FALSE if CoInitialize already called, but with same
4431 * threading model. A negative value indicates failure,
4432 * probably due to trying to change the threading model.
4434 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4435 ? COINIT_APARTMENTTHREADED
4436 : COINIT_MULTITHREADED) < 0) {
4437 thread->apartment_state = ThreadApartmentState_Unknown;
4443 mono_thread_cleanup_apartment_state (void)
4446 MonoInternalThread* thread = mono_thread_internal_current ();
4448 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4455 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4457 LOCK_THREAD (thread);
4458 thread->state |= state;
4459 UNLOCK_THREAD (thread);
4463 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4465 LOCK_THREAD (thread);
4466 thread->state &= ~state;
4467 UNLOCK_THREAD (thread);
4471 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4473 gboolean ret = FALSE;
4475 LOCK_THREAD (thread);
4477 if ((thread->state & test) != 0) {
4481 UNLOCK_THREAD (thread);
4486 //static MonoClassField *execution_context_field;
4489 get_execution_context_addr (void)
4491 MonoDomain *domain = mono_domain_get ();
4492 guint32 offset = domain->execution_context_field_offset;
4495 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4498 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4500 mono_domain_lock (domain);
4501 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4502 mono_domain_unlock (domain);
4505 domain->execution_context_field_offset = offset;
4508 return (MonoObject**) mono_get_special_static_data (offset);
4512 mono_thread_get_execution_context (void)
4514 return *get_execution_context_addr ();
4518 mono_thread_set_execution_context (MonoObject *ec)
4520 *get_execution_context_addr () = ec;
4523 static gboolean has_tls_get = FALSE;
4526 mono_runtime_set_has_tls_get (gboolean val)
4532 mono_runtime_has_tls_get (void)
4538 mono_thread_kill (MonoInternalThread *thread, int signal)
4540 #ifdef __native_client__
4541 /* Workaround pthread_kill abort() in NaCl glibc. */
4544 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
4545 /* Win32 uses QueueUserAPC and callers of this are guarded */
4546 g_assert_not_reached ();
4548 # ifdef PTHREAD_POINTER_ID
4549 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4551 # ifdef USE_TKILL_ON_ANDROID
4552 if (thread->android_tid != 0) {
4554 int old_errno = errno;
4556 ret = tkill ((pid_t) thread->android_tid, signal);
4565 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4567 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4574 self_interrupt_thread (void *_unused)
4576 MonoThreadInfo *info = mono_thread_info_current ();
4577 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4578 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4579 mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
4580 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4584 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4588 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4592 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4594 MonoJitInfo **dest = data;
4600 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4602 MonoJitInfo *ji = NULL;
4605 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4610 MonoInternalThread *thread;
4611 gboolean install_async_abort;
4612 gpointer interrupt_handle;
4615 static SuspendThreadResult
4616 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4618 AbortThreadData *data = ud;
4619 MonoInternalThread *thread = data->thread;
4620 MonoJitInfo *ji = NULL;
4621 gboolean protected_wrapper;
4622 gboolean running_managed;
4624 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4625 return MonoResumeThread;
4627 /*someone is already interrupting it*/
4628 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4629 return MonoResumeThread;
4631 InterlockedIncrement (&thread_interruption_requested);
4633 ji = mono_thread_info_get_last_managed (info);
4634 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4635 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4637 if (!protected_wrapper && running_managed) {
4638 /*We are in managed code*/
4639 /*Set the thread to call */
4640 if (data->install_async_abort)
4641 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4642 return MonoResumeThread;
4644 if (mono_thread_notify_pending_exc_fn)
4645 /* The JIT will notify the thread about the interruption */
4646 mono_thread_notify_pending_exc_fn (info);
4649 * This will cause waits to be broken.
4650 * It will also prevent the thread from entering a wait, so if the thread returns
4651 * from the wait before it receives the abort signal, it will just spin in the wait
4652 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4655 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4656 return MonoResumeThread;
4661 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4663 AbortThreadData data = { 0 };
4664 data.thread = thread;
4665 data.install_async_abort = install_async_abort;
4667 if (!mono_thread_info_new_interrupt_enabled ()) {
4668 signal_thread_state_change (thread);
4673 FIXME this is insanely broken, it doesn't cause interruption to happen
4674 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4676 if (thread == mono_thread_internal_current ()) {
4677 /* Do it synchronously */
4678 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4680 mono_raise_exception (exc);
4681 mono_thread_info_interrupt (thread->handle);
4685 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
4686 if (data.interrupt_handle)
4687 mono_thread_info_finish_interrupt (data.interrupt_handle);
4688 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4692 MonoInternalThread *thread;
4694 gpointer interrupt_handle;
4695 } SuspendThreadData;
4697 static SuspendThreadResult
4698 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4700 SuspendThreadData *data = ud;
4701 MonoInternalThread *thread = data->thread;
4702 MonoJitInfo *ji = NULL;
4703 gboolean protected_wrapper;
4704 gboolean running_managed;
4706 ji = mono_thread_info_get_last_managed (info);
4707 protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4708 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4710 if (running_managed && !protected_wrapper) {
4711 thread->state &= ~ThreadState_SuspendRequested;
4712 thread->state |= ThreadState_Suspended;
4713 return KeepSuspended;
4715 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4716 InterlockedIncrement (&thread_interruption_requested);
4717 if (data->interrupt)
4718 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4720 if (mono_thread_notify_pending_exc_fn && !running_managed)
4721 /* The JIT will notify the thread about the interruption */
4722 mono_thread_notify_pending_exc_fn (info);
4723 return MonoResumeThread;
4728 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4730 if (!mono_thread_info_new_interrupt_enabled ()) {
4731 signal_thread_state_change (thread);
4735 LOCK_THREAD (thread);
4736 if (thread == mono_thread_internal_current ()) {
4737 mono_thread_info_begin_self_suspend ();
4738 //XXX replace this with better named functions
4739 thread->state &= ~ThreadState_SuspendRequested;
4740 thread->state |= ThreadState_Suspended;
4741 UNLOCK_THREAD (thread);
4742 mono_thread_info_end_self_suspend ();
4744 SuspendThreadData data = { 0 };
4745 data.thread = thread;
4746 data.interrupt = interrupt;
4748 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
4749 if (data.interrupt_handle)
4750 mono_thread_info_finish_interrupt (data.interrupt_handle);
4751 UNLOCK_THREAD (thread);
4755 /*This is called with @thread synch_cs held and it must release it*/
4757 self_suspend_internal (MonoInternalThread *thread)
4759 if (!mono_thread_info_new_interrupt_enabled ()) {
4760 thread->state &= ~ThreadState_SuspendRequested;
4761 thread->state |= ThreadState_Suspended;
4762 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4763 if (thread->suspend_event == NULL) {
4764 UNLOCK_THREAD (thread);
4767 if (thread->suspended_event)
4768 SetEvent (thread->suspended_event);
4770 UNLOCK_THREAD (thread);
4772 if (shutting_down) {
4773 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4778 WaitForSingleObject (thread->suspend_event, INFINITE);
4780 LOCK_THREAD (thread);
4782 CloseHandle (thread->suspend_event);
4783 thread->suspend_event = NULL;
4784 thread->state &= ~ThreadState_Suspended;
4786 /* The thread that requested the resume will have replaced this event
4787 * and will be waiting for it
4789 SetEvent (thread->resume_event);
4791 UNLOCK_THREAD (thread);
4795 mono_thread_info_begin_self_suspend ();
4796 thread->state &= ~ThreadState_SuspendRequested;
4797 thread->state |= ThreadState_Suspended;
4798 UNLOCK_THREAD (thread);
4799 mono_thread_info_end_self_suspend ();
4802 /*This is called with @thread synch_cs held and it must release it*/
4804 resume_thread_internal (MonoInternalThread *thread)
4806 if (!mono_thread_info_new_interrupt_enabled ()) {
4807 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4808 if (thread->resume_event == NULL) {
4809 UNLOCK_THREAD (thread);
4813 /* Awake the thread */
4814 SetEvent (thread->suspend_event);
4816 UNLOCK_THREAD (thread);
4818 /* Wait for the thread to awake */
4819 WaitForSingleObject (thread->resume_event, INFINITE);
4820 CloseHandle (thread->resume_event);
4821 thread->resume_event = NULL;
4825 UNLOCK_THREAD (thread);
4826 /* Awake the thread */
4827 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4829 LOCK_THREAD (thread);
4830 thread->state &= ~ThreadState_Suspended;
4831 UNLOCK_THREAD (thread);
4837 * mono_thread_is_foreign:
4838 * @thread: the thread to query
4840 * This function allows one to determine if a thread was created by the mono runtime and has
4841 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4843 * Returns: true if @thread was not created by the runtime.
4846 mono_thread_is_foreign (MonoThread *thread)
4848 MonoThreadInfo *info = thread->internal_thread->thread_info;
4849 return info->runtime_thread == FALSE;
4853 * mono_add_joinable_thread:
4855 * Add TID to the list of joinable threads.
4856 * LOCKING: Acquires the threads lock.
4859 mono_threads_add_joinable_thread (gpointer tid)
4863 * We cannot detach from threads because it causes problems like
4864 * 2fd16f60/r114307. So we collect them and join them when
4865 * we have time (in he finalizer thread).
4867 joinable_threads_lock ();
4868 if (!joinable_threads)
4869 joinable_threads = g_hash_table_new (NULL, NULL);
4870 g_hash_table_insert (joinable_threads, tid, tid);
4871 joinable_thread_count ++;
4872 joinable_threads_unlock ();
4874 mono_gc_finalize_notify ();
4879 * mono_threads_join_threads:
4881 * Join all joinable threads. This is called from the finalizer thread.
4882 * LOCKING: Acquires the threads lock.
4885 mono_threads_join_threads (void)
4888 GHashTableIter iter;
4895 if (!joinable_thread_count)
4899 joinable_threads_lock ();
4901 if (g_hash_table_size (joinable_threads)) {
4902 g_hash_table_iter_init (&iter, joinable_threads);
4903 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4904 thread = (pthread_t)tid;
4905 g_hash_table_remove (joinable_threads, key);
4906 joinable_thread_count --;
4909 joinable_threads_unlock ();
4911 if (thread != pthread_self ())
4912 /* This shouldn't block */
4913 pthread_join (thread, NULL);
4924 * Wait for thread TID to exit.
4925 * LOCKING: Acquires the threads lock.
4928 mono_thread_join (gpointer tid)
4932 gboolean found = FALSE;
4934 joinable_threads_lock ();
4935 if (!joinable_threads)
4936 joinable_threads = g_hash_table_new (NULL, NULL);
4937 if (g_hash_table_lookup (joinable_threads, tid)) {
4938 g_hash_table_remove (joinable_threads, tid);
4939 joinable_thread_count --;
4942 joinable_threads_unlock ();
4945 thread = (pthread_t)tid;
4946 pthread_join (thread, NULL);