2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
20 #if defined(__OpenBSD__) || defined(__FreeBSD__)
22 #include <pthread_np.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/domain-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/threads.h>
29 #include <mono/metadata/threadpool.h>
30 #include <mono/metadata/threads-types.h>
31 #include <mono/metadata/exception.h>
32 #include <mono/metadata/environment.h>
33 #include <mono/metadata/monitor.h>
34 #include <mono/metadata/gc-internal.h>
35 #include <mono/metadata/marshal.h>
36 #include <mono/metadata/runtime.h>
37 #include <mono/io-layer/io-layer.h>
39 #include <mono/io-layer/threads.h>
41 #include <mono/metadata/object-internals.h>
42 #include <mono/metadata/mono-debug-debugger.h>
43 #include <mono/utils/mono-compiler.h>
44 #include <mono/utils/mono-mmap.h>
45 #include <mono/utils/mono-membar.h>
46 #include <mono/utils/mono-time.h>
47 #include <mono/utils/mono-threads.h>
48 #include <mono/utils/hazard-pointer.h>
49 #include <mono/utils/mono-tls.h>
50 #include <mono/utils/atomic.h>
51 #include <mono/utils/mono-memory-model.h>
53 #include <mono/metadata/gc-internal.h>
55 #ifdef PLATFORM_ANDROID
58 extern int tkill (pid_t tid, int signal);
61 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
62 void *pthread_get_stackaddr_np(pthread_t);
63 size_t pthread_get_stacksize_np(pthread_t);
66 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
67 #define THREAD_DEBUG(a)
68 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
69 #define THREAD_WAIT_DEBUG(a)
70 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
71 #define LIBGC_DEBUG(a)
73 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
74 #define SPIN_LOCK(i) do { \
75 if (SPIN_TRYLOCK (i)) \
79 #define SPIN_UNLOCK(i) i = 0
81 /* Provide this for systems with glib < 2.6 */
82 #ifndef G_GSIZE_FORMAT
83 # if GLIB_SIZEOF_LONG == 8
84 # define G_GSIZE_FORMAT "lu"
86 # define G_GSIZE_FORMAT "u"
92 guint32 (*func)(void *);
108 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
109 struct _MonoThreadDomainTls {
110 MonoThreadDomainTls *next;
118 MonoThreadDomainTls *freelist;
121 /* Number of cached culture objects in the MonoThread->cached_culture_info array
122 * (per-type): we use the first NUM entries for CultureInfo and the last for
123 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
125 #define NUM_CACHED_CULTURES 4
126 #define CULTURES_START_IDX 0
127 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
129 /* Controls access to the 'threads' hash table */
130 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
131 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
132 static CRITICAL_SECTION threads_mutex;
134 /* Controls access to context static data */
135 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
136 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
137 static CRITICAL_SECTION contexts_mutex;
139 /* Holds current status of static data heap */
140 static StaticDataInfo thread_static_info;
141 static StaticDataInfo context_static_info;
143 /* The hash of existing threads (key is thread ID, value is
144 * MonoInternalThread*) that need joining before exit
146 static MonoGHashTable *threads=NULL;
149 * Threads which are starting up and they are not in the 'threads' hash yet.
150 * When handle_store is called for a thread, it will be removed from this hash table.
151 * Protected by mono_threads_lock ().
153 static MonoGHashTable *threads_starting_up = NULL;
155 /* Maps a MonoThread to its start argument */
156 /* Protected by mono_threads_lock () */
157 static MonoGHashTable *thread_start_args = NULL;
159 /* The TLS key that holds the MonoObject assigned to each thread */
160 static MonoNativeTlsKey current_object_key;
162 #ifdef MONO_HAVE_FAST_TLS
163 /* we need to use both the Tls* functions and __thread because
164 * the gc needs to see all the threads
166 MONO_FAST_TLS_DECLARE(tls_current_object);
167 #define SET_CURRENT_OBJECT(x) do { \
168 MONO_FAST_TLS_SET (tls_current_object, x); \
169 mono_native_tls_set_value (current_object_key, x); \
171 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
173 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
174 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
177 /* function called at thread start */
178 static MonoThreadStartCB mono_thread_start_cb = NULL;
180 /* function called at thread attach */
181 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
183 /* function called at thread cleanup */
184 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
186 /* function called to notify the runtime about a pending exception on the current thread */
187 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
189 /* The default stack size for each thread */
190 static guint32 default_stacksize = 0;
191 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
193 static void thread_adjust_static_data (MonoInternalThread *thread);
194 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
195 static void mono_init_static_data_info (StaticDataInfo *static_data);
196 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
197 static gboolean mono_thread_resume (MonoInternalThread* thread);
198 static void mono_thread_start (MonoThread *thread);
199 static void signal_thread_state_change (MonoInternalThread *thread);
200 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
201 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
202 static void self_suspend_internal (MonoInternalThread *thread);
203 static gboolean resume_thread_internal (MonoInternalThread *thread);
205 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
206 static void ref_stack_destroy (gpointer rs);
208 /* Spin lock for InterlockedXXX 64 bit functions */
209 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
210 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
211 static CRITICAL_SECTION interlocked_mutex;
213 /* global count of thread interruptions requested */
214 static gint32 thread_interruption_requested = 0;
216 /* Event signaled when a thread changes its background mode */
217 static HANDLE background_change_event;
219 static gboolean shutting_down = FALSE;
221 static gint32 managed_thread_id_counter = 0;
224 get_next_managed_thread_id (void)
226 return InterlockedIncrement (&managed_thread_id_counter);
230 mono_thread_get_tls_key (void)
232 return current_object_key;
236 mono_thread_get_tls_offset (void)
239 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
243 /* handle_store() and handle_remove() manage the array of threads that
244 * still need to be waited for when the main thread exits.
246 * If handle_store() returns FALSE the thread must not be started
247 * because Mono is shutting down.
249 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
251 mono_threads_lock ();
253 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
255 if (threads_starting_up)
256 mono_g_hash_table_remove (threads_starting_up, thread);
258 if (shutting_down && !force_attach) {
259 mono_threads_unlock ();
264 MONO_GC_REGISTER_ROOT_FIXED (threads);
265 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
268 /* We don't need to duplicate thread->handle, because it is
269 * only closed when the thread object is finalized by the GC.
271 g_assert (thread->internal_thread);
272 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
273 thread->internal_thread);
275 mono_threads_unlock ();
280 static gboolean handle_remove(MonoInternalThread *thread)
283 gsize tid = thread->tid;
285 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
287 mono_threads_lock ();
290 /* We have to check whether the thread object for the
291 * tid is still the same in the table because the
292 * thread might have been destroyed and the tid reused
293 * in the meantime, in which case the tid would be in
294 * the table, but with another thread object.
296 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
297 mono_g_hash_table_remove (threads, (gpointer)tid);
306 mono_threads_unlock ();
308 /* Don't close the handle here, wait for the object finalizer
309 * to do it. Otherwise, the following race condition applies:
311 * 1) Thread exits (and handle_remove() closes the handle)
313 * 2) Some other handle is reassigned the same slot
315 * 3) Another thread tries to join the first thread, and
316 * blocks waiting for the reassigned handle to be signalled
317 * (which might never happen). This is possible, because the
318 * thread calling Join() still has a reference to the first
324 static void ensure_synch_cs_set (MonoInternalThread *thread)
326 CRITICAL_SECTION *synch_cs;
328 if (thread->synch_cs != NULL) {
332 synch_cs = g_new0 (CRITICAL_SECTION, 1);
333 InitializeCriticalSection (synch_cs);
335 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
336 synch_cs, NULL) != NULL) {
337 /* Another thread must have installed this CS */
338 DeleteCriticalSection (synch_cs);
344 * NOTE: this function can be called also for threads different from the current one:
345 * make sure no code called from it will ever assume it is run on the thread that is
346 * getting cleaned up.
348 static void thread_cleanup (MonoInternalThread *thread)
350 g_assert (thread != NULL);
352 if (thread->abort_state_handle) {
353 mono_gchandle_free (thread->abort_state_handle);
354 thread->abort_state_handle = 0;
356 thread->abort_exc = NULL;
357 thread->current_appcontext = NULL;
360 * This is necessary because otherwise we might have
361 * cross-domain references which will not get cleaned up when
362 * the target domain is unloaded.
364 if (thread->cached_culture_info) {
366 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
367 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
370 ensure_synch_cs_set (thread);
372 EnterCriticalSection (thread->synch_cs);
374 thread->state |= ThreadState_Stopped;
375 thread->state &= ~ThreadState_Background;
377 LeaveCriticalSection (thread->synch_cs);
380 An interruption request has leaked to cleanup. Adjust the global counter.
382 This can happen is the abort source thread finds the abortee (this) thread
383 in unmanaged code. If this thread never trips back to managed code or check
384 the local flag it will be left set and positively unbalance the global counter.
386 Leaving the counter unbalanced will cause a performance degradation since all threads
387 will now keep checking their local flags all the time.
389 if (InterlockedExchange (&thread->interruption_requested, 0))
390 InterlockedDecrement (&thread_interruption_requested);
392 /* if the thread is not in the hash it has been removed already */
393 if (!handle_remove (thread)) {
394 if (thread == mono_thread_internal_current ()) {
395 mono_domain_unset ();
396 mono_memory_barrier ();
398 /* This needs to be called even if handle_remove () fails */
399 if (mono_thread_cleanup_fn)
400 mono_thread_cleanup_fn (thread);
403 mono_release_type_locks (thread);
405 mono_profiler_thread_end (thread->tid);
407 if (thread == mono_thread_internal_current ()) {
409 * This will signal async signal handlers that the thread has exited.
410 * The profiler callback needs this to be set, so it cannot be done earlier.
412 mono_domain_unset ();
413 mono_memory_barrier ();
416 if (thread == mono_thread_internal_current ())
417 mono_thread_pop_appdomain_ref ();
419 thread->cached_culture_info = NULL;
421 mono_free_static_data (thread->static_data, TRUE);
422 thread->static_data = NULL;
423 ref_stack_destroy (thread->appdomain_refs);
424 thread->appdomain_refs = NULL;
426 if (mono_thread_cleanup_fn)
427 mono_thread_cleanup_fn (thread);
429 if (mono_gc_is_moving ()) {
430 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
431 thread->thread_pinning_ref = NULL;
437 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
440 g_assert ((offset & 0x80000000) == 0);
441 offset &= 0x7fffffff;
442 idx = (offset >> 24) - 1;
443 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
447 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
449 static MonoClassField *current_thread_field = NULL;
453 if (!current_thread_field) {
454 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
455 g_assert (current_thread_field);
458 mono_class_vtable (domain, mono_defaults.thread_class);
459 mono_domain_lock (domain);
460 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
461 mono_domain_unlock (domain);
464 return get_thread_static_data (thread, offset);
468 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
470 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
472 g_assert (current->obj.vtable->domain == domain);
474 g_assert (!*current_thread_ptr);
475 *current_thread_ptr = current;
478 static MonoInternalThread*
479 create_internal_thread_object (void)
481 MonoVTable *vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
482 return (MonoInternalThread*)mono_gc_alloc_mature (vt);
486 create_thread_object (MonoDomain *domain)
488 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
489 return (MonoThread*)mono_gc_alloc_mature (vt);
493 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
495 MonoThread *thread = create_thread_object (domain);
496 MONO_OBJECT_SETREF (thread, internal_thread, internal);
501 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
503 MonoDomain *domain = mono_get_root_domain ();
505 if (!candidate || candidate->obj.vtable->domain != domain)
506 candidate = new_thread_with_internal (domain, thread);
507 set_current_thread_for_domain (domain, thread, candidate);
508 g_assert (!thread->root_domain_thread);
509 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
512 static guint32 WINAPI start_wrapper_internal(void *data)
514 MonoThreadInfo *info;
515 struct StartInfo *start_info=(struct StartInfo *)data;
516 guint32 (*start_func)(void *);
520 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
523 MonoInternalThread *internal = start_info->obj->internal_thread;
524 MonoObject *start_delegate = start_info->delegate;
525 MonoDomain *domain = start_info->obj->obj.vtable->domain;
527 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
529 /* We can be sure start_info->obj->tid and
530 * start_info->obj->handle have been set, because the thread
531 * was created suspended, and these values were set before the
535 info = mono_thread_info_current ();
537 internal->thread_info = info;
542 SET_CURRENT_OBJECT (internal);
544 mono_monitor_init_tls ();
546 /* Every thread references the appdomain which created it */
547 mono_thread_push_appdomain_ref (domain);
549 if (!mono_domain_set (domain, FALSE)) {
550 /* No point in raising an appdomain_unloaded exception here */
551 /* FIXME: Cleanup here */
552 mono_thread_pop_appdomain_ref ();
556 start_func = start_info->func;
557 start_arg = start_info->start_arg;
559 /* We have to do this here because mono_thread_new_init()
560 requires that root_domain_thread is set up. */
561 thread_adjust_static_data (internal);
562 init_root_domain_thread (internal, start_info->obj);
564 /* This MUST be called before any managed code can be
565 * executed, as it calls the callback function that (for the
566 * jit) sets the lmf marker.
568 mono_thread_new_init (tid, &tid, start_func);
569 internal->stack_ptr = &tid;
571 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
573 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
575 /* On 2.0 profile (and higher), set explicitly since state might have been
577 if (internal->apartment_state == ThreadApartmentState_Unknown)
578 internal->apartment_state = ThreadApartmentState_MTA;
580 mono_thread_init_apartment_state ();
582 if(internal->start_notify!=NULL) {
583 /* Let the thread that called Start() know we're
586 ReleaseSemaphore (internal->start_notify, 1, NULL);
589 mono_threads_lock ();
590 mono_g_hash_table_remove (thread_start_args, start_info->obj);
591 mono_threads_unlock ();
593 mono_thread_set_execution_context (start_info->obj->ec_to_set);
594 start_info->obj->ec_to_set = NULL;
597 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
601 * Call this after calling start_notify, since the profiler callback might want
602 * to lock the thread, and the lock is held by thread_start () which waits for
605 mono_profiler_thread_start (tid);
607 /* start_func is set only for unmanaged start functions */
609 start_func (start_arg);
612 g_assert (start_delegate != NULL);
613 args [0] = start_arg;
614 /* we may want to handle the exception here. See comment below on unhandled exceptions */
615 mono_runtime_delegate_invoke (start_delegate, args, NULL);
618 /* If the thread calls ExitThread at all, this remaining code
619 * will not be executed, but the main thread will eventually
620 * call thread_cleanup() on this thread's behalf.
623 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
625 /* Do any cleanup needed for apartment state. This
626 * cannot be done in thread_cleanup since thread_cleanup could be
627 * called for a thread other than the current thread.
628 * mono_thread_cleanup_apartment_state cleans up apartment
629 * for the current thead */
630 mono_thread_cleanup_apartment_state ();
632 thread_cleanup (internal);
634 /* Remove the reference to the thread object in the TLS data,
635 * so the thread object can be finalized. This won't be
636 * reached if the thread threw an uncaught exception, so those
637 * thread handles will stay referenced :-( (This is due to
638 * missing support for scanning thread-specific data in the
639 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
642 SET_CURRENT_OBJECT (NULL);
647 static guint32 WINAPI start_wrapper(void *data)
651 /* Avoid scanning the frames above this frame during a GC */
652 mono_gc_set_stack_end ((void*)&dummy);
654 return start_wrapper_internal (data);
657 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
659 if (mono_thread_start_cb) {
660 mono_thread_start_cb (tid, stack_start, func);
664 void mono_threads_set_default_stacksize (guint32 stacksize)
666 default_stacksize = stacksize;
669 guint32 mono_threads_get_default_stacksize (void)
671 return default_stacksize;
675 * mono_create_thread:
677 * This is a wrapper around CreateThread which handles differences in the type of
678 * the the 'tid' argument.
680 gpointer mono_create_thread (WapiSecurityAttributes *security,
681 guint32 stacksize, WapiThreadStart start,
682 gpointer param, guint32 create, gsize *tid)
689 res = mono_threads_CreateThread (security, stacksize, start, param, create, &real_tid);
693 res = CreateThread (security, stacksize, start, param, create, tid);
700 * The thread start argument may be an object reference, and there is
701 * no ref to keep it alive when the new thread is started but not yet
702 * registered with the collector. So we store it in a GC tracked hash
705 * LOCKING: Assumes the threads lock is held.
708 register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info)
710 if (thread_start_args == NULL) {
711 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
712 thread_start_args = mono_g_hash_table_new (NULL, NULL);
714 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
718 * mono_thread_create_internal:
720 * If NO_DETACH is TRUE, then the thread is not detached using pthread_detach (). This is needed to fix the race condition where waiting for a thred to exit only waits for its exit event to be
721 * signalled, which can cause shutdown crashes if the thread shutdown code accesses data already freed by the runtime shutdown.
722 * Currently, this is only used for the finalizer thread.
725 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size)
728 MonoInternalThread *internal;
729 HANDLE thread_handle;
730 struct StartInfo *start_info;
732 guint32 create_flags;
734 thread = create_thread_object (domain);
735 internal = create_internal_thread_object ();
736 MONO_OBJECT_SETREF (thread, internal_thread, internal);
738 start_info=g_new0 (struct StartInfo, 1);
739 start_info->func = func;
740 start_info->obj = thread;
741 start_info->start_arg = arg;
743 mono_threads_lock ();
745 mono_threads_unlock ();
749 if (threads_starting_up == NULL) {
750 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
751 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
754 register_thread_start_argument (thread, start_info);
755 mono_g_hash_table_insert (threads_starting_up, thread, thread);
756 mono_threads_unlock ();
759 stack_size = default_stacksize_for_thread (internal);
761 /* Create suspended, so we can do some housekeeping before the thread
764 create_flags = CREATE_SUSPENDED;
767 create_flags |= CREATE_NO_DETACH;
769 thread_handle = mono_create_thread (NULL, stack_size, (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
771 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
772 if (thread_handle == NULL) {
773 /* The thread couldn't be created, so throw an exception */
774 mono_threads_lock ();
775 mono_g_hash_table_remove (threads_starting_up, thread);
776 mono_threads_unlock ();
778 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
782 internal->handle=thread_handle;
784 internal->apartment_state=ThreadApartmentState_Unknown;
785 internal->managed_id = get_next_managed_thread_id ();
786 if (mono_gc_is_moving ()) {
787 internal->thread_pinning_ref = internal;
788 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
791 internal->synch_cs = g_new0 (CRITICAL_SECTION, 1);
792 InitializeCriticalSection (internal->synch_cs);
794 internal->threadpool_thread = threadpool_thread;
795 if (threadpool_thread)
796 mono_thread_set_state (internal, ThreadState_Background);
798 if (handle_store (thread, FALSE))
799 ResumeThread (thread_handle);
801 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
802 if (mono_check_corlib_version () == NULL)
803 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
809 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
811 mono_thread_create_internal (domain, func, arg, FALSE, FALSE, 0);
814 #if defined(HOST_WIN32) && HAVE_DECL___READFSDWORD==0
815 static __inline__ __attribute__((always_inline))
817 __readfsdword (unsigned long offset)
820 // __asm__("movl %%fs:%a[offset], %k[value]" : [value] "=q" (value) : [offset] "irm" (offset));
821 __asm__ volatile ("movl %%fs:%1,%0"
822 : "=r" (value) ,"=m" ((*(volatile long *) offset)));
828 * mono_thread_get_stack_bounds:
830 * Return the address and size of the current threads stack. Return NULL as the
831 * stack address if the stack address cannot be determined.
834 mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
836 #if defined(HOST_WIN32)
838 /* http://en.wikipedia.org/wiki/Win32_Thread_Information_Block */
839 void* tib = (void*)__readfsdword(0x18);
840 guint8 *stackTop = (guint8*)*(int*)((char*)tib + 4);
841 guint8 *stackBottom = (guint8*)*(int*)((char*)tib + 8);
843 *staddr = stackBottom;
844 *stsize = stackTop - stackBottom;
847 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
849 *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self());
850 *stsize = pthread_get_stacksize_np (pthread_self());
855 * Mavericks reports stack sizes as 512kb:
856 * http://permalink.gmane.org/gmane.comp.java.openjdk.hotspot.devel/11590
857 * https://bugs.openjdk.java.net/browse/JDK-8020753
859 if (*stsize == 512 * 1024)
860 *stsize = 2048 * mono_pagesize ();
863 /* staddr points to the start of the stack, not the end */
866 /* When running under emacs, sometimes staddr is not aligned to a page size */
867 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize() - 1));
870 #elif (defined(HAVE_PTHREAD_GETATTR_NP) || defined(HAVE_PTHREAD_ATTR_GET_NP)) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
874 guint8 *current = (guint8*)&attr;
877 *stsize = (size_t)-1;
879 pthread_attr_init (&attr);
881 #if defined(HAVE_PTHREAD_GETATTR_NP)
883 pthread_getattr_np (pthread_self(), &attr);
885 #elif defined(HAVE_PTHREAD_ATTR_GET_NP)
887 pthread_attr_get_np (pthread_self(), &attr);
890 #error Cannot determine which API is needed to retrieve pthread attributes.
893 pthread_attr_getstack (&attr, (void**)staddr, stsize);
894 pthread_attr_destroy (&attr);
897 g_assert ((current > *staddr) && (current < *staddr + *stsize));
899 /* When running under emacs, sometimes staddr is not aligned to a page size */
900 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
903 #elif defined(__OpenBSD__)
905 /* TODO : Determine if this code is actually still needed. It may already be covered by the case above. */
908 guint8 *current = (guint8*)&attr;
911 *stsize = (size_t)-1;
913 pthread_attr_init (&attr);
918 rslt = pthread_stackseg_np(pthread_self(), &ss);
919 g_assert (rslt == 0);
921 *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
922 *stsize = ss.ss_size;
924 pthread_attr_destroy (&attr);
927 g_assert ((current > *staddr) && (current < *staddr + *stsize));
929 /* When running under emacs, sometimes staddr is not aligned to a page size */
930 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
933 #elif defined(sun) || defined(__native_client__)
934 /* Solaris/Illumos, NaCl */
936 pthread_attr_init (&attr);
937 pthread_attr_getstacksize (&attr, &stsize);
938 pthread_attr_destroy (&attr);
943 /* FIXME: It'd be better to use the 'error' preprocessor macro here so we know
944 at compile-time if the target platform isn't supported. */
945 #warning "Unable to determine how to retrieve a thread's stack-bounds for this platform in 'mono_thread_get_stack_bounds()'."
953 mono_thread_attach (MonoDomain *domain)
955 return mono_thread_attach_full (domain, FALSE);
959 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
961 MonoThreadInfo *info;
962 MonoInternalThread *thread;
963 MonoThread *current_thread;
964 HANDLE thread_handle;
967 if ((thread = mono_thread_internal_current ())) {
968 if (domain != mono_domain_get ())
969 mono_domain_set (domain, TRUE);
970 /* Already attached */
971 return mono_thread_current ();
974 if (!mono_gc_register_thread (&domain)) {
975 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 ());
978 thread = create_internal_thread_object ();
980 thread_handle = GetCurrentThread ();
981 g_assert (thread_handle);
983 tid=GetCurrentThreadId ();
986 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
987 * refer to the thread from other threads for things like aborting.
989 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
990 THREAD_ALL_ACCESS, TRUE, 0);
992 thread->handle=thread_handle;
994 #ifdef PLATFORM_ANDROID
995 thread->android_tid = (gpointer) gettid ();
997 thread->apartment_state=ThreadApartmentState_Unknown;
998 thread->managed_id = get_next_managed_thread_id ();
999 if (mono_gc_is_moving ()) {
1000 thread->thread_pinning_ref = thread;
1001 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
1004 thread->stack_ptr = &tid;
1006 thread->synch_cs = g_new0 (CRITICAL_SECTION, 1);
1007 InitializeCriticalSection (thread->synch_cs);
1009 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
1011 info = mono_thread_info_current ();
1013 thread->thread_info = info;
1015 current_thread = new_thread_with_internal (domain, thread);
1017 if (!handle_store (current_thread, force_attach)) {
1018 /* Mono is shutting down, so just wait for the end */
1023 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
1025 SET_CURRENT_OBJECT (thread);
1026 mono_domain_set (domain, TRUE);
1028 mono_monitor_init_tls ();
1030 thread_adjust_static_data (thread);
1032 init_root_domain_thread (thread, current_thread);
1033 if (domain != mono_get_root_domain ())
1034 set_current_thread_for_domain (domain, thread, current_thread);
1037 if (mono_thread_attach_cb) {
1041 mono_thread_get_stack_bounds (&staddr, &stsize);
1044 mono_thread_attach_cb (tid, &tid);
1046 mono_thread_attach_cb (tid, staddr + stsize);
1049 // FIXME: Need a separate callback
1050 mono_profiler_thread_start (tid);
1052 return current_thread;
1056 mono_thread_detach (MonoThread *thread)
1058 g_return_if_fail (thread != NULL);
1060 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
1062 thread_cleanup (thread->internal_thread);
1064 SET_CURRENT_OBJECT (NULL);
1065 mono_domain_unset ();
1067 /* Don't need to CloseHandle this thread, even though we took a
1068 * reference in mono_thread_attach (), because the GC will do it
1069 * when the Thread object is finalised.
1076 MonoInternalThread *thread = mono_thread_internal_current ();
1078 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1080 thread_cleanup (thread);
1081 SET_CURRENT_OBJECT (NULL);
1082 mono_domain_unset ();
1084 /* we could add a callback here for embedders to use. */
1085 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1086 exit (mono_environment_exitcode_get ());
1091 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1093 MonoInternalThread *internal = create_internal_thread_object ();
1095 internal->state = ThreadState_Unstarted;
1096 internal->apartment_state = ThreadApartmentState_Unknown;
1097 internal->managed_id = get_next_managed_thread_id ();
1099 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1102 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
1105 guint32 (*start_func)(void *);
1106 struct StartInfo *start_info;
1109 MonoInternalThread *internal;
1111 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1113 if (!this->internal_thread)
1114 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1115 internal = this->internal_thread;
1117 ensure_synch_cs_set (internal);
1119 EnterCriticalSection (internal->synch_cs);
1121 if ((internal->state & ThreadState_Unstarted) == 0) {
1122 LeaveCriticalSection (internal->synch_cs);
1123 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1127 if ((internal->state & ThreadState_Aborted) != 0) {
1128 LeaveCriticalSection (internal->synch_cs);
1133 /* This is freed in start_wrapper */
1134 start_info = g_new0 (struct StartInfo, 1);
1135 start_info->func = start_func;
1136 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1137 start_info->delegate = start;
1138 start_info->obj = this;
1139 g_assert (this->obj.vtable->domain == mono_domain_get ());
1141 internal->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
1142 if (internal->start_notify==NULL) {
1143 LeaveCriticalSection (internal->synch_cs);
1144 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
1145 g_free (start_info);
1149 mono_threads_lock ();
1150 register_thread_start_argument (this, start_info);
1151 if (threads_starting_up == NULL) {
1152 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
1153 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
1155 mono_g_hash_table_insert (threads_starting_up, this, this);
1156 mono_threads_unlock ();
1158 thread=mono_create_thread(NULL, default_stacksize_for_thread (internal), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
1159 CREATE_SUSPENDED, &tid);
1161 LeaveCriticalSection (internal->synch_cs);
1162 mono_threads_lock ();
1163 mono_g_hash_table_remove (threads_starting_up, this);
1164 mono_threads_unlock ();
1165 g_warning("%s: CreateThread error 0x%x", __func__, GetLastError());
1169 internal->handle=thread;
1171 if (mono_gc_is_moving ()) {
1172 internal->thread_pinning_ref = internal;
1173 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
1177 /* Don't call handle_store() here, delay it to Start.
1178 * We can't join a thread (trying to will just block
1179 * forever) until it actually starts running, so don't
1180 * store the handle till then.
1183 mono_thread_start (this);
1185 internal->state &= ~ThreadState_Unstarted;
1187 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1189 LeaveCriticalSection (internal->synch_cs);
1194 void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1196 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1199 CloseHandle (thread);
1201 if (this->synch_cs) {
1202 CRITICAL_SECTION *synch_cs = this->synch_cs;
1203 this->synch_cs = NULL;
1204 DeleteCriticalSection (synch_cs);
1209 void *name = this->name;
1215 static void mono_thread_start (MonoThread *thread)
1217 MonoInternalThread *internal = thread->internal_thread;
1219 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1221 /* Only store the handle when the thread is about to be
1222 * launched, to avoid the main thread deadlocking while trying
1223 * to clean up a thread that will never be signalled.
1225 if (!handle_store (thread, FALSE))
1228 ResumeThread (internal->handle);
1230 if(internal->start_notify!=NULL) {
1231 /* Wait for the thread to set up its TLS data etc, so
1232 * theres no potential race condition if someone tries
1233 * to look up the data believing the thread has
1237 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1239 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
1240 CloseHandle (internal->start_notify);
1241 internal->start_notify = NULL;
1244 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1247 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1250 MonoInternalThread *thread = mono_thread_internal_current ();
1252 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1254 mono_thread_current_check_pending_interrupt ();
1257 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1259 res = SleepEx(ms,TRUE);
1261 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1263 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1264 MonoException* exc = mono_thread_execute_interruption (thread);
1266 mono_raise_exception (exc);
1278 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1283 ves_icall_System_Threading_Thread_GetDomainID (void)
1285 return mono_domain_get()->domain_id;
1289 ves_icall_System_Threading_Thread_Yield (void)
1292 return SwitchToThread ();
1294 return sched_yield () == 0;
1299 * mono_thread_get_name:
1301 * Return the name of the thread. NAME_LEN is set to the length of the name.
1302 * Return NULL if the thread has no name. The returned memory is owned by the
1306 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1310 ensure_synch_cs_set (this_obj);
1312 EnterCriticalSection (this_obj->synch_cs);
1314 if (!this_obj->name) {
1318 *name_len = this_obj->name_len;
1319 res = g_new (gunichar2, this_obj->name_len);
1320 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1323 LeaveCriticalSection (this_obj->synch_cs);
1329 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1333 ensure_synch_cs_set (this_obj);
1335 EnterCriticalSection (this_obj->synch_cs);
1337 if (!this_obj->name)
1340 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1342 LeaveCriticalSection (this_obj->synch_cs);
1348 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1350 ensure_synch_cs_set (this_obj);
1352 EnterCriticalSection (this_obj->synch_cs);
1354 if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1355 LeaveCriticalSection (this_obj->synch_cs);
1357 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1361 this_obj->name = g_new (gunichar2, mono_string_length (name));
1362 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1363 this_obj->name_len = mono_string_length (name);
1366 this_obj->name = NULL;
1369 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1371 LeaveCriticalSection (this_obj->synch_cs);
1372 if (this_obj->name) {
1373 char *tname = mono_string_to_utf8 (name);
1374 mono_profiler_thread_name (this_obj->tid, tname);
1380 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1382 mono_thread_set_name_internal (this_obj, name, TRUE);
1385 /* If the array is already in the requested domain, we just return it,
1386 otherwise we return a copy in that domain. */
1388 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1395 if (mono_object_domain (arr) == domain)
1398 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1399 mono_gc_memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1404 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1406 return byte_array_to_domain (arr, mono_get_root_domain ());
1410 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1412 return byte_array_to_domain (arr, mono_domain_get ());
1416 mono_thread_current (void)
1418 MonoDomain *domain = mono_domain_get ();
1419 MonoInternalThread *internal = mono_thread_internal_current ();
1420 MonoThread **current_thread_ptr;
1422 g_assert (internal);
1423 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1425 if (!*current_thread_ptr) {
1426 g_assert (domain != mono_get_root_domain ());
1427 *current_thread_ptr = new_thread_with_internal (domain, internal);
1429 return *current_thread_ptr;
1433 mono_thread_internal_current (void)
1435 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1436 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1440 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1441 int ms, HANDLE thread)
1443 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1446 mono_thread_current_check_pending_interrupt ();
1448 ensure_synch_cs_set (this);
1450 EnterCriticalSection (this->synch_cs);
1452 if ((this->state & ThreadState_Unstarted) != 0) {
1453 LeaveCriticalSection (this->synch_cs);
1455 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1459 LeaveCriticalSection (this->synch_cs);
1464 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1466 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1468 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1470 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1472 if(ret==WAIT_OBJECT_0) {
1473 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1478 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1484 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1492 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1495 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1497 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1499 if (ret != WAIT_IO_COMPLETION)
1502 exc = mono_thread_execute_interruption (thread);
1504 mono_raise_exception (exc);
1509 /* Re-calculate ms according to the time passed */
1510 diff_ms = (mono_100ns_ticks () - start) / 10000;
1511 if (diff_ms >= ms) {
1515 wait = ms - diff_ms;
1521 /* FIXME: exitContext isnt documented */
1522 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1528 MonoObject *waitHandle;
1529 MonoInternalThread *thread = mono_thread_internal_current ();
1531 /* Do this WaitSleepJoin check before creating objects */
1532 mono_thread_current_check_pending_interrupt ();
1534 numhandles = mono_array_length(mono_handles);
1535 handles = g_new0(HANDLE, numhandles);
1537 for(i = 0; i < numhandles; i++) {
1538 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1539 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1546 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1548 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1550 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1554 if(ret==WAIT_FAILED) {
1555 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1557 } else if(ret==WAIT_TIMEOUT) {
1558 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1565 /* FIXME: exitContext isnt documented */
1566 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1568 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1572 MonoObject *waitHandle;
1573 MonoInternalThread *thread = mono_thread_internal_current ();
1575 /* Do this WaitSleepJoin check before creating objects */
1576 mono_thread_current_check_pending_interrupt ();
1578 numhandles = mono_array_length(mono_handles);
1579 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1582 for(i = 0; i < numhandles; i++) {
1583 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1584 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1591 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1593 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1595 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1597 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1600 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1602 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1603 return ret - WAIT_OBJECT_0;
1605 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1606 return ret - WAIT_ABANDONED_0;
1613 /* FIXME: exitContext isnt documented */
1614 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1617 MonoInternalThread *thread = mono_thread_internal_current ();
1619 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1625 mono_thread_current_check_pending_interrupt ();
1627 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1629 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1631 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1633 if(ret==WAIT_FAILED) {
1634 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1636 } else if(ret==WAIT_TIMEOUT) {
1637 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1645 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1648 MonoInternalThread *thread = mono_thread_internal_current ();
1653 mono_thread_current_check_pending_interrupt ();
1655 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1657 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1659 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1661 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1664 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1671 mutex = CreateMutex (NULL, owned, NULL);
1673 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1675 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1683 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1684 return(ReleaseMutex (handle));
1687 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1693 *error = ERROR_SUCCESS;
1695 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1697 *error = GetLastError ();
1704 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1711 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1713 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1714 mono_string_chars (name));
1716 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1724 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1728 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1733 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1737 *error = ERROR_SUCCESS;
1739 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1741 *error = GetLastError ();
1747 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1754 event = CreateEvent (NULL, manual, initial, NULL);
1756 event = CreateEvent (NULL, manual, initial,
1757 mono_string_chars (name));
1759 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1767 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1768 return (SetEvent(handle));
1771 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1772 return (ResetEvent(handle));
1776 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1777 CloseHandle (handle);
1780 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1786 *error = ERROR_SUCCESS;
1788 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1790 *error = GetLastError ();
1796 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1798 return InterlockedIncrement (location);
1801 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1803 #if SIZEOF_VOID_P == 4
1804 if (G_UNLIKELY ((size_t)location & 0x7)) {
1806 mono_interlocked_lock ();
1809 mono_interlocked_unlock ();
1813 return InterlockedIncrement64 (location);
1816 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1818 return InterlockedDecrement(location);
1821 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1823 #if SIZEOF_VOID_P == 4
1824 if (G_UNLIKELY ((size_t)location & 0x7)) {
1826 mono_interlocked_lock ();
1829 mono_interlocked_unlock ();
1833 return InterlockedDecrement64 (location);
1836 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1838 return InterlockedExchange(location, value);
1841 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1844 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1845 mono_gc_wbarrier_generic_nostore (location);
1849 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1851 return InterlockedExchangePointer(location, value);
1854 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1856 IntFloatUnion val, ret;
1859 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1865 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1867 #if SIZEOF_VOID_P == 4
1868 if (G_UNLIKELY ((size_t)location & 0x7)) {
1870 mono_interlocked_lock ();
1873 mono_interlocked_unlock ();
1877 return InterlockedExchange64 (location, value);
1881 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1883 LongDoubleUnion val, ret;
1886 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1891 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1893 return InterlockedCompareExchange(location, value, comparand);
1896 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1899 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1900 mono_gc_wbarrier_generic_nostore (location);
1904 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1906 return InterlockedCompareExchangePointer(location, value, comparand);
1909 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1911 IntFloatUnion val, ret, cmp;
1914 cmp.fval = comparand;
1915 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1921 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1923 #if SIZEOF_VOID_P == 8
1924 LongDoubleUnion val, comp, ret;
1927 comp.fval = comparand;
1928 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1934 mono_interlocked_lock ();
1936 if (old == comparand)
1938 mono_interlocked_unlock ();
1945 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1947 #if SIZEOF_VOID_P == 4
1948 if (G_UNLIKELY ((size_t)location & 0x7)) {
1950 mono_interlocked_lock ();
1952 if (old == comparand)
1954 mono_interlocked_unlock ();
1958 return InterlockedCompareExchange64 (location, value, comparand);
1962 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1965 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1966 mono_gc_wbarrier_generic_nostore (location);
1971 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1974 res = InterlockedExchangePointer ((gpointer *)location, value);
1975 mono_gc_wbarrier_generic_nostore (location);
1980 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1982 return InterlockedAdd (location, value);
1986 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1988 #if SIZEOF_VOID_P == 4
1989 if (G_UNLIKELY ((size_t)location & 0x7)) {
1991 mono_interlocked_lock ();
1994 mono_interlocked_unlock ();
1998 return InterlockedAdd64 (location, value);
2002 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2004 #if SIZEOF_VOID_P == 4
2005 if (G_UNLIKELY ((size_t)location & 0x7)) {
2007 mono_interlocked_lock ();
2009 mono_interlocked_unlock ();
2013 return InterlockedRead64 (location);
2017 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2019 mono_memory_barrier ();
2023 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
2025 mono_thread_clr_state (this, state);
2027 if (state & ThreadState_Background) {
2028 /* If the thread changes the background mode, the main thread has to
2029 * be notified, since it has to rebuild the list of threads to
2032 SetEvent (background_change_event);
2037 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
2039 mono_thread_set_state (this, state);
2041 if (state & ThreadState_Background) {
2042 /* If the thread changes the background mode, the main thread has to
2043 * be notified, since it has to rebuild the list of threads to
2046 SetEvent (background_change_event);
2051 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2055 ensure_synch_cs_set (this);
2057 EnterCriticalSection (this->synch_cs);
2059 state = this->state;
2061 LeaveCriticalSection (this->synch_cs);
2066 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
2068 MonoInternalThread *current;
2071 ensure_synch_cs_set (this);
2073 current = mono_thread_internal_current ();
2075 EnterCriticalSection (this->synch_cs);
2077 this->thread_interrupt_requested = TRUE;
2078 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
2080 LeaveCriticalSection (this->synch_cs);
2083 abort_thread_internal (this, TRUE, FALSE);
2087 void mono_thread_current_check_pending_interrupt ()
2089 MonoInternalThread *thread = mono_thread_internal_current ();
2090 gboolean throw = FALSE;
2092 ensure_synch_cs_set (thread);
2094 EnterCriticalSection (thread->synch_cs);
2096 if (thread->thread_interrupt_requested) {
2098 thread->thread_interrupt_requested = FALSE;
2101 LeaveCriticalSection (thread->synch_cs);
2104 mono_raise_exception (mono_get_exception_thread_interrupted ());
2109 mono_thread_get_abort_signal (void)
2113 #elif defined(PLATFORM_ANDROID)
2115 #elif !defined (SIGRTMIN)
2120 #endif /* SIGUSR1 */
2122 static int abort_signum = -1;
2124 if (abort_signum != -1)
2125 return abort_signum;
2126 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2127 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2128 struct sigaction sinfo;
2129 sigaction (i, NULL, &sinfo);
2130 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2135 /* fallback to the old way */
2137 #endif /* HOST_WIN32 */
2141 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2143 MonoException* exc = mono_thread_request_interruption (FALSE);
2144 if (exc) mono_raise_exception (exc);
2146 #endif /* HOST_WIN32 */
2149 * signal_thread_state_change
2151 * Tells the thread that his state has changed and it has to enter the new
2152 * state as soon as possible.
2154 static void signal_thread_state_change (MonoInternalThread *thread)
2156 if (thread == mono_thread_internal_current ()) {
2157 /* Do it synchronously */
2158 MonoException *exc = mono_thread_request_interruption (FALSE);
2160 mono_raise_exception (exc);
2164 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
2166 /* fixme: store the state somewhere */
2167 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2170 * This will cause waits to be broken.
2171 * It will also prevent the thread from entering a wait, so if the thread returns
2172 * from the wait before it receives the abort signal, it will just spin in the wait
2173 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2176 wapi_interrupt_thread (thread->handle);
2177 #endif /* HOST_WIN32 */
2181 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2183 ensure_synch_cs_set (thread);
2185 EnterCriticalSection (thread->synch_cs);
2187 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2188 (thread->state & ThreadState_StopRequested) != 0 ||
2189 (thread->state & ThreadState_Stopped) != 0)
2191 LeaveCriticalSection (thread->synch_cs);
2195 if ((thread->state & ThreadState_Unstarted) != 0) {
2196 thread->state |= ThreadState_Aborted;
2197 LeaveCriticalSection (thread->synch_cs);
2201 thread->state |= ThreadState_AbortRequested;
2202 if (thread->abort_state_handle)
2203 mono_gchandle_free (thread->abort_state_handle);
2205 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2206 g_assert (thread->abort_state_handle);
2208 thread->abort_state_handle = 0;
2210 thread->abort_exc = NULL;
2213 * abort_exc is set in mono_thread_execute_interruption(),
2214 * triggered by the call to signal_thread_state_change(),
2215 * below. There's a point between where we have
2216 * abort_state_handle set, but abort_exc NULL, but that's not
2220 LeaveCriticalSection (thread->synch_cs);
2222 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2224 /* During shutdown, we can't wait for other threads */
2226 /* Make sure the thread is awake */
2227 mono_thread_resume (thread);
2229 abort_thread_internal (thread, TRUE, TRUE);
2233 ves_icall_System_Threading_Thread_ResetAbort (void)
2235 MonoInternalThread *thread = mono_thread_internal_current ();
2236 gboolean was_aborting;
2238 ensure_synch_cs_set (thread);
2240 EnterCriticalSection (thread->synch_cs);
2241 was_aborting = thread->state & ThreadState_AbortRequested;
2242 thread->state &= ~ThreadState_AbortRequested;
2243 LeaveCriticalSection (thread->synch_cs);
2245 if (!was_aborting) {
2246 const char *msg = "Unable to reset abort because no abort was requested";
2247 mono_raise_exception (mono_get_exception_thread_state (msg));
2249 thread->abort_exc = NULL;
2250 if (thread->abort_state_handle) {
2251 mono_gchandle_free (thread->abort_state_handle);
2252 /* This is actually not necessary - the handle
2253 only counts if the exception is set */
2254 thread->abort_state_handle = 0;
2259 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2261 ensure_synch_cs_set (thread);
2263 EnterCriticalSection (thread->synch_cs);
2265 thread->state &= ~ThreadState_AbortRequested;
2267 if (thread->abort_exc) {
2268 thread->abort_exc = NULL;
2269 if (thread->abort_state_handle) {
2270 mono_gchandle_free (thread->abort_state_handle);
2271 /* This is actually not necessary - the handle
2272 only counts if the exception is set */
2273 thread->abort_state_handle = 0;
2277 LeaveCriticalSection (thread->synch_cs);
2281 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2283 MonoInternalThread *thread = this->internal_thread;
2284 MonoObject *state, *deserialized = NULL, *exc;
2287 if (!thread->abort_state_handle)
2290 state = mono_gchandle_get_target (thread->abort_state_handle);
2293 domain = mono_domain_get ();
2294 if (mono_object_domain (state) == domain)
2297 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2299 if (!deserialized) {
2300 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2302 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2303 mono_raise_exception (invalid_op_exc);
2306 return deserialized;
2310 mono_thread_suspend (MonoInternalThread *thread)
2312 ensure_synch_cs_set (thread);
2314 EnterCriticalSection (thread->synch_cs);
2316 if ((thread->state & ThreadState_Unstarted) != 0 ||
2317 (thread->state & ThreadState_Aborted) != 0 ||
2318 (thread->state & ThreadState_Stopped) != 0)
2320 LeaveCriticalSection (thread->synch_cs);
2324 if ((thread->state & ThreadState_Suspended) != 0 ||
2325 (thread->state & ThreadState_SuspendRequested) != 0 ||
2326 (thread->state & ThreadState_StopRequested) != 0)
2328 LeaveCriticalSection (thread->synch_cs);
2332 thread->state |= ThreadState_SuspendRequested;
2334 LeaveCriticalSection (thread->synch_cs);
2336 suspend_thread_internal (thread, FALSE);
2341 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2343 if (!mono_thread_suspend (thread))
2344 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2348 mono_thread_resume (MonoInternalThread *thread)
2350 ensure_synch_cs_set (thread);
2352 EnterCriticalSection (thread->synch_cs);
2354 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2355 thread->state &= ~ThreadState_SuspendRequested;
2356 LeaveCriticalSection (thread->synch_cs);
2360 if ((thread->state & ThreadState_Suspended) == 0 ||
2361 (thread->state & ThreadState_Unstarted) != 0 ||
2362 (thread->state & ThreadState_Aborted) != 0 ||
2363 (thread->state & ThreadState_Stopped) != 0)
2365 LeaveCriticalSection (thread->synch_cs);
2369 return resume_thread_internal (thread);
2373 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2375 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2376 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2380 mono_threads_is_critical_method (MonoMethod *method)
2382 switch (method->wrapper_type) {
2383 case MONO_WRAPPER_RUNTIME_INVOKE:
2384 case MONO_WRAPPER_XDOMAIN_INVOKE:
2385 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2392 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2397 if (mono_threads_is_critical_method (m)) {
2398 *((gboolean*)data) = TRUE;
2405 is_running_protected_wrapper (void)
2407 gboolean found = FALSE;
2408 mono_stack_walk (find_wrapper, &found);
2412 void mono_thread_internal_stop (MonoInternalThread *thread)
2414 ensure_synch_cs_set (thread);
2416 EnterCriticalSection (thread->synch_cs);
2418 if ((thread->state & ThreadState_StopRequested) != 0 ||
2419 (thread->state & ThreadState_Stopped) != 0)
2421 LeaveCriticalSection (thread->synch_cs);
2425 /* Make sure the thread is awake */
2426 mono_thread_resume (thread);
2428 thread->state |= ThreadState_StopRequested;
2429 thread->state &= ~ThreadState_AbortRequested;
2431 LeaveCriticalSection (thread->synch_cs);
2433 abort_thread_internal (thread, TRUE, TRUE);
2436 void mono_thread_stop (MonoThread *thread)
2438 mono_thread_internal_stop (thread->internal_thread);
2442 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2445 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2450 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2453 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2458 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2461 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2466 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2469 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2474 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2477 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2478 return (void *) tmp;
2482 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2484 volatile MonoObject *tmp;
2485 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2486 return (MonoObject *) tmp;
2490 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2493 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2498 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2501 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2506 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2508 return InterlockedRead8 (ptr);
2512 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2514 return InterlockedRead16 (ptr);
2518 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2520 return InterlockedRead (ptr);
2524 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2526 #if SIZEOF_VOID_P == 4
2527 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2529 mono_interlocked_lock ();
2530 val = *(gint64*)ptr;
2531 mono_interlocked_unlock ();
2535 return InterlockedRead64 (ptr);
2539 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2541 return InterlockedReadPointer (ptr);
2545 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2549 #if SIZEOF_VOID_P == 4
2550 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2552 mono_interlocked_lock ();
2553 val = *(double*)ptr;
2554 mono_interlocked_unlock ();
2559 u.ival = InterlockedRead64 (ptr);
2565 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2569 u.ival = InterlockedRead (ptr);
2575 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2577 return InterlockedReadPointer (ptr);
2581 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2583 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2587 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2589 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2593 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2595 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2599 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2601 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2605 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2607 mono_atomic_store_release ((volatile void **) ptr, value);
2611 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2613 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2617 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2619 mono_atomic_store_release ((volatile double *) ptr, value);
2623 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2625 mono_atomic_store_release ((volatile float *) ptr, value);
2629 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2631 InterlockedWrite8 (ptr, value);
2635 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2637 InterlockedWrite16 (ptr, value);
2641 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2643 InterlockedWrite (ptr, value);
2647 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2649 #if SIZEOF_VOID_P == 4
2650 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2651 mono_interlocked_lock ();
2652 *(gint64*)ptr = value;
2653 mono_interlocked_unlock ();
2658 InterlockedWrite64 (ptr, value);
2662 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2664 InterlockedWritePointer (ptr, value);
2668 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2672 #if SIZEOF_VOID_P == 4
2673 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2674 mono_interlocked_lock ();
2675 *(double*)ptr = value;
2676 mono_interlocked_unlock ();
2683 InterlockedWrite64 (ptr, u.ival);
2687 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2693 InterlockedWrite (ptr, u.ival);
2697 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2699 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2703 mono_thread_init_tls (void)
2705 MONO_FAST_TLS_INIT (tls_current_object);
2706 mono_native_tls_alloc (¤t_object_key, NULL);
2709 void mono_thread_init (MonoThreadStartCB start_cb,
2710 MonoThreadAttachCB attach_cb)
2712 InitializeCriticalSection(&threads_mutex);
2713 InitializeCriticalSection(&interlocked_mutex);
2714 InitializeCriticalSection(&contexts_mutex);
2716 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2717 g_assert(background_change_event != NULL);
2719 mono_init_static_data_info (&thread_static_info);
2720 mono_init_static_data_info (&context_static_info);
2722 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2724 mono_thread_start_cb = start_cb;
2725 mono_thread_attach_cb = attach_cb;
2727 /* Get a pseudo handle to the current process. This is just a
2728 * kludge so that wapi can build a process handle if needed.
2729 * As a pseudo handle is returned, we don't need to clean
2732 GetCurrentProcess ();
2735 void mono_thread_cleanup (void)
2737 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2738 /* The main thread must abandon any held mutexes (particularly
2739 * important for named mutexes as they are shared across
2740 * processes, see bug 74680.) This will happen when the
2741 * thread exits, but if it's not running in a subthread it
2742 * won't exit in time.
2744 /* Using non-w32 API is a nasty kludge, but I couldn't find
2745 * anything in the documentation that would let me do this
2746 * here yet still be safe to call on windows.
2748 _wapi_thread_signal_self (mono_environment_exitcode_get ());
2752 /* This stuff needs more testing, it seems one of these
2753 * critical sections can be locked when mono_thread_cleanup is
2756 DeleteCriticalSection (&threads_mutex);
2757 DeleteCriticalSection (&interlocked_mutex);
2758 DeleteCriticalSection (&contexts_mutex);
2759 DeleteCriticalSection (&delayed_free_table_mutex);
2760 DeleteCriticalSection (&small_id_mutex);
2761 CloseHandle (background_change_event);
2764 mono_native_tls_free (current_object_key);
2768 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2770 mono_thread_cleanup_fn = func;
2774 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2776 thread->internal_thread->manage_callback = func;
2779 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2781 mono_thread_notify_pending_exc_fn = func;
2785 static void print_tids (gpointer key, gpointer value, gpointer user)
2787 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2788 * sizeof(uint) and a cast to uint would overflow
2790 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2791 * print this as a pointer.
2793 g_message ("Waiting for: %p", key);
2798 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2799 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2803 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2807 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2809 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2811 if(ret==WAIT_FAILED) {
2812 /* See the comment in build_wait_tids() */
2813 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2817 for(i=0; i<wait->num; i++)
2818 CloseHandle (wait->handles[i]);
2820 if (ret == WAIT_TIMEOUT)
2823 for(i=0; i<wait->num; i++) {
2824 gsize tid = wait->threads[i]->tid;
2826 mono_threads_lock ();
2827 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2828 /* This thread must have been killed, because
2829 * it hasn't cleaned itself up. (It's just
2830 * possible that the thread exited before the
2831 * parent thread had a chance to store the
2832 * handle, and now there is another pointer to
2833 * the already-exited thread stored. In this
2834 * case, we'll just get two
2835 * mono_profiler_thread_end() calls for the
2839 mono_threads_unlock ();
2840 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2841 thread_cleanup (wait->threads[i]);
2843 mono_threads_unlock ();
2848 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2850 guint32 i, ret, count;
2852 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2854 /* Add the thread state change event, so it wakes up if a thread changes
2855 * to background mode.
2858 if (count < MAXIMUM_WAIT_OBJECTS) {
2859 wait->handles [count] = background_change_event;
2863 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2865 if(ret==WAIT_FAILED) {
2866 /* See the comment in build_wait_tids() */
2867 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2871 for(i=0; i<wait->num; i++)
2872 CloseHandle (wait->handles[i]);
2874 if (ret == WAIT_TIMEOUT)
2877 if (ret < wait->num) {
2878 gsize tid = wait->threads[ret]->tid;
2879 mono_threads_lock ();
2880 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2881 /* See comment in wait_for_tids about thread cleanup */
2882 mono_threads_unlock ();
2883 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2884 thread_cleanup (wait->threads [ret]);
2886 mono_threads_unlock ();
2890 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2892 struct wait_data *wait=(struct wait_data *)user;
2894 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2896 MonoInternalThread *thread=(MonoInternalThread *)value;
2898 /* Ignore background threads, we abort them later */
2899 /* Do not lock here since it is not needed and the caller holds threads_lock */
2900 if (thread->state & ThreadState_Background) {
2901 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2902 return; /* just leave, ignore */
2905 if (mono_gc_is_finalizer_internal_thread (thread)) {
2906 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2910 if (thread == mono_thread_internal_current ()) {
2911 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2915 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2916 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2920 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2921 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2925 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2926 if (handle == NULL) {
2927 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2931 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2932 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2933 wait->handles[wait->num]=handle;
2934 wait->threads[wait->num]=thread;
2937 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2939 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2944 /* Just ignore the rest, we can't do anything with
2951 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2953 struct wait_data *wait=(struct wait_data *)user;
2954 gsize self = GetCurrentThreadId ();
2955 MonoInternalThread *thread = value;
2958 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2961 /* The finalizer thread is not a background thread */
2962 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2963 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2965 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2969 /* printf ("A: %d\n", wait->num); */
2970 wait->handles[wait->num]=thread->handle;
2971 wait->threads[wait->num]=thread;
2974 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2975 mono_thread_internal_stop (thread);
2979 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2983 * mono_threads_set_shutting_down:
2985 * Is called by a thread that wants to shut down Mono. If the runtime is already
2986 * shutting down, the calling thread is suspended/stopped, and this function never
2990 mono_threads_set_shutting_down (void)
2992 MonoInternalThread *current_thread = mono_thread_internal_current ();
2994 mono_threads_lock ();
2996 if (shutting_down) {
2997 mono_threads_unlock ();
2999 /* Make sure we're properly suspended/stopped */
3001 EnterCriticalSection (current_thread->synch_cs);
3003 if ((current_thread->state & ThreadState_SuspendRequested) ||
3004 (current_thread->state & ThreadState_AbortRequested) ||
3005 (current_thread->state & ThreadState_StopRequested)) {
3006 LeaveCriticalSection (current_thread->synch_cs);
3007 mono_thread_execute_interruption (current_thread);
3009 current_thread->state |= ThreadState_Stopped;
3010 LeaveCriticalSection (current_thread->synch_cs);
3013 /*since we're killing the thread, unset the current domain.*/
3014 mono_domain_unset ();
3016 /* Wake up other threads potentially waiting for us */
3019 shutting_down = TRUE;
3021 /* Not really a background state change, but this will
3022 * interrupt the main thread if it is waiting for all
3023 * the other threads.
3025 SetEvent (background_change_event);
3027 mono_threads_unlock ();
3031 void mono_thread_manage (void)
3033 struct wait_data wait_data;
3034 struct wait_data *wait = &wait_data;
3036 memset (wait, 0, sizeof (struct wait_data));
3037 /* join each thread that's still running */
3038 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3040 mono_threads_lock ();
3042 THREAD_DEBUG (g_message("%s: No threads", __func__));
3043 mono_threads_unlock ();
3046 mono_threads_unlock ();
3049 mono_threads_lock ();
3050 if (shutting_down) {
3051 /* somebody else is shutting down */
3052 mono_threads_unlock ();
3055 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3056 mono_g_hash_table_foreach (threads, print_tids, NULL));
3058 ResetEvent (background_change_event);
3060 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3061 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3062 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3063 mono_threads_unlock ();
3065 /* Something to wait for */
3066 wait_for_tids_or_state_change (wait, INFINITE);
3068 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3069 } while(wait->num>0);
3071 /* Mono is shutting down, so just wait for the end */
3072 if (!mono_runtime_try_shutdown ()) {
3073 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3074 mono_thread_suspend (mono_thread_internal_current ());
3075 mono_thread_execute_interruption (mono_thread_internal_current ());
3079 * Remove everything but the finalizer thread and self.
3080 * Also abort all the background threads
3083 mono_threads_lock ();
3086 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3087 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3088 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3090 mono_threads_unlock ();
3092 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3094 /* Something to wait for */
3095 wait_for_tids (wait, INFINITE);
3097 } while (wait->num > 0);
3100 * give the subthreads a chance to really quit (this is mainly needed
3101 * to get correct user and system times from getrusage/wait/time(1)).
3102 * This could be removed if we avoid pthread_detach() and use pthread_join().
3109 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3111 MonoInternalThread *thread=(MonoInternalThread *)value;
3113 if(thread->tid != (gsize)user) {
3114 /*TerminateThread (thread->handle, -1);*/
3118 void mono_thread_abort_all_other_threads (void)
3120 gsize self = GetCurrentThreadId ();
3122 mono_threads_lock ();
3123 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3124 mono_g_hash_table_size (threads));
3125 mono_g_hash_table_foreach (threads, print_tids, NULL));
3127 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3129 mono_threads_unlock ();
3133 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3135 MonoInternalThread *thread = (MonoInternalThread*)value;
3136 struct wait_data *wait = (struct wait_data*)user_data;
3140 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3142 * This needs no locking.
3144 if ((thread->state & ThreadState_Suspended) != 0 ||
3145 (thread->state & ThreadState_Stopped) != 0)
3148 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3149 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3153 wait->handles [wait->num] = handle;
3154 wait->threads [wait->num] = thread;
3160 * mono_thread_suspend_all_other_threads:
3162 * Suspend all managed threads except the finalizer thread and this thread. It is
3163 * not possible to resume them later.
3165 void mono_thread_suspend_all_other_threads (void)
3167 struct wait_data wait_data;
3168 struct wait_data *wait = &wait_data;
3170 gsize self = GetCurrentThreadId ();
3172 guint32 eventidx = 0;
3173 gboolean starting, finished;
3175 memset (wait, 0, sizeof (struct wait_data));
3177 * The other threads could be in an arbitrary state at this point, i.e.
3178 * they could be starting up, shutting down etc. This means that there could be
3179 * threads which are not even in the threads hash table yet.
3183 * First we set a barrier which will be checked by all threads before they
3184 * are added to the threads hash table, and they will exit if the flag is set.
3185 * This ensures that no threads could be added to the hash later.
3186 * We will use shutting_down as the barrier for now.
3188 g_assert (shutting_down);
3191 * We make multiple calls to WaitForMultipleObjects since:
3192 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3193 * - some threads could exit without becoming suspended
3198 * Make a copy of the hashtable since we can't do anything with
3199 * threads while threads_mutex is held.
3202 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3203 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3204 mono_threads_lock ();
3205 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3206 mono_threads_unlock ();
3208 events = g_new0 (gpointer, wait->num);
3210 /* Get the suspended events that we'll be waiting for */
3211 for (i = 0; i < wait->num; ++i) {
3212 MonoInternalThread *thread = wait->threads [i];
3213 gboolean signal_suspend = FALSE;
3215 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3216 //CloseHandle (wait->handles [i]);
3217 wait->threads [i] = NULL; /* ignore this thread in next loop */
3221 ensure_synch_cs_set (thread);
3223 EnterCriticalSection (thread->synch_cs);
3225 if (thread->suspended_event == NULL) {
3226 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3227 if (thread->suspended_event == NULL) {
3228 /* Forget this one and go on to the next */
3229 LeaveCriticalSection (thread->synch_cs);
3234 if ((thread->state & ThreadState_Suspended) != 0 ||
3235 (thread->state & ThreadState_StopRequested) != 0 ||
3236 (thread->state & ThreadState_Stopped) != 0) {
3237 LeaveCriticalSection (thread->synch_cs);
3238 CloseHandle (wait->handles [i]);
3239 wait->threads [i] = NULL; /* ignore this thread in next loop */
3243 if ((thread->state & ThreadState_SuspendRequested) == 0)
3244 signal_suspend = TRUE;
3246 events [eventidx++] = thread->suspended_event;
3248 /* Convert abort requests into suspend requests */
3249 if ((thread->state & ThreadState_AbortRequested) != 0)
3250 thread->state &= ~ThreadState_AbortRequested;
3252 thread->state |= ThreadState_SuspendRequested;
3254 LeaveCriticalSection (thread->synch_cs);
3256 /* Signal the thread to suspend */
3257 if (mono_thread_info_new_interrupt_enabled ())
3258 suspend_thread_internal (thread, TRUE);
3259 else if (signal_suspend)
3260 signal_thread_state_change (thread);
3263 /*Only wait on the suspend event if we are using the old path */
3264 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3265 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3266 for (i = 0; i < wait->num; ++i) {
3267 MonoInternalThread *thread = wait->threads [i];
3272 ensure_synch_cs_set (thread);
3274 EnterCriticalSection (thread->synch_cs);
3275 if ((thread->state & ThreadState_Suspended) != 0) {
3276 CloseHandle (thread->suspended_event);
3277 thread->suspended_event = NULL;
3279 LeaveCriticalSection (thread->synch_cs);
3283 if (eventidx <= 0) {
3285 * If there are threads which are starting up, we wait until they
3286 * are suspended when they try to register in the threads hash.
3287 * This is guaranteed to finish, since the threads which can create new
3288 * threads get suspended after a while.
3289 * FIXME: The finalizer thread can still create new threads.
3291 mono_threads_lock ();
3292 if (threads_starting_up)
3293 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3296 mono_threads_unlock ();
3308 collect_threads (gpointer key, gpointer value, gpointer user_data)
3310 MonoInternalThread *thread = (MonoInternalThread*)value;
3311 struct wait_data *wait = (struct wait_data*)user_data;
3314 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3315 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3319 wait->handles [wait->num] = handle;
3320 wait->threads [wait->num] = thread;
3325 static gboolean thread_dump_requested;
3327 static G_GNUC_UNUSED gboolean
3328 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3330 GString *p = (GString*)data;
3331 MonoMethod *method = NULL;
3333 method = mono_jit_info_get_method (frame->ji);
3336 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3337 g_string_append_printf (p, " %s\n", location);
3340 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3346 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3348 GString* text = g_string_new (0);
3350 GError *error = NULL;
3353 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3355 g_string_append_printf (text, "\n\"%s\"", name);
3358 else if (thread->threadpool_thread)
3359 g_string_append (text, "\n\"<threadpool thread>\"");
3361 g_string_append (text, "\n\"<unnamed thread>\"");
3364 /* This no longer works with remote unwinding */
3366 wapi_desc = wapi_current_thread_desc ();
3367 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3372 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3373 mono_thread_info_resume (mono_thread_info_get_tid (info));
3375 fprintf (stdout, "%s", text->str);
3377 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3378 OutputDebugStringA(text->str);
3381 g_string_free (text, TRUE);
3386 dump_thread (gpointer key, gpointer value, gpointer user)
3388 MonoInternalThread *thread = (MonoInternalThread *)value;
3389 MonoThreadInfo *info;
3391 if (thread == mono_thread_internal_current ())
3395 FIXME This still can hang if we stop a thread during malloc.
3396 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3397 that takes a callback and runs it with the target suspended.
3398 We probably should loop a bit around trying to get it to either managed code
3401 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3406 print_thread_dump (thread, info);
3410 mono_threads_perform_thread_dump (void)
3412 if (!thread_dump_requested)
3415 printf ("Full thread dump:\n");
3418 * Make a copy of the hashtable since we can't do anything with
3419 * threads while threads_mutex is held.
3421 mono_threads_lock ();
3422 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3423 mono_threads_unlock ();
3425 thread_dump_requested = FALSE;
3429 * mono_threads_request_thread_dump:
3431 * Ask all threads except the current to print their stacktrace to stdout.
3434 mono_threads_request_thread_dump (void)
3436 struct wait_data wait_data;
3437 struct wait_data *wait = &wait_data;
3440 /*The new thread dump code runs out of the finalizer thread. */
3441 if (mono_thread_info_new_interrupt_enabled ()) {
3442 thread_dump_requested = TRUE;
3443 mono_gc_finalize_notify ();
3448 memset (wait, 0, sizeof (struct wait_data));
3451 * Make a copy of the hashtable since we can't do anything with
3452 * threads while threads_mutex is held.
3454 mono_threads_lock ();
3455 mono_g_hash_table_foreach (threads, collect_threads, wait);
3456 mono_threads_unlock ();
3458 for (i = 0; i < wait->num; ++i) {
3459 MonoInternalThread *thread = wait->threads [i];
3461 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3462 (thread != mono_thread_internal_current ()) &&
3463 !thread->thread_dump_requested) {
3464 thread->thread_dump_requested = TRUE;
3466 signal_thread_state_change (thread);
3469 CloseHandle (wait->handles [i]);
3475 gint allocated; /* +1 so that refs [allocated] == NULL */
3479 typedef struct ref_stack RefStack;
3482 ref_stack_new (gint initial_size)
3486 initial_size = MAX (initial_size, 16) + 1;
3487 rs = g_new0 (RefStack, 1);
3488 rs->refs = g_new0 (gpointer, initial_size);
3489 rs->allocated = initial_size;
3494 ref_stack_destroy (gpointer ptr)
3505 ref_stack_push (RefStack *rs, gpointer ptr)
3507 g_assert (rs != NULL);
3509 if (rs->bottom >= rs->allocated) {
3510 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3511 rs->allocated <<= 1;
3512 rs->refs [rs->allocated] = NULL;
3514 rs->refs [rs->bottom++] = ptr;
3518 ref_stack_pop (RefStack *rs)
3520 if (rs == NULL || rs->bottom == 0)
3524 rs->refs [rs->bottom] = NULL;
3528 ref_stack_find (RefStack *rs, gpointer ptr)
3535 for (refs = rs->refs; refs && *refs; refs++) {
3543 * mono_thread_push_appdomain_ref:
3545 * Register that the current thread may have references to objects in domain
3546 * @domain on its stack. Each call to this function should be paired with a
3547 * call to pop_appdomain_ref.
3550 mono_thread_push_appdomain_ref (MonoDomain *domain)
3552 MonoInternalThread *thread = mono_thread_internal_current ();
3555 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3556 SPIN_LOCK (thread->lock_thread_id);
3557 if (thread->appdomain_refs == NULL)
3558 thread->appdomain_refs = ref_stack_new (16);
3559 ref_stack_push (thread->appdomain_refs, domain);
3560 SPIN_UNLOCK (thread->lock_thread_id);
3565 mono_thread_pop_appdomain_ref (void)
3567 MonoInternalThread *thread = mono_thread_internal_current ();
3570 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3571 SPIN_LOCK (thread->lock_thread_id);
3572 ref_stack_pop (thread->appdomain_refs);
3573 SPIN_UNLOCK (thread->lock_thread_id);
3578 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3581 SPIN_LOCK (thread->lock_thread_id);
3582 res = ref_stack_find (thread->appdomain_refs, domain);
3583 SPIN_UNLOCK (thread->lock_thread_id);
3588 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3590 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3593 typedef struct abort_appdomain_data {
3594 struct wait_data wait;
3596 } abort_appdomain_data;
3599 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3601 MonoInternalThread *thread = (MonoInternalThread*)value;
3602 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3603 MonoDomain *domain = data->domain;
3605 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3606 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3608 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3609 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3612 data->wait.handles [data->wait.num] = handle;
3613 data->wait.threads [data->wait.num] = thread;
3616 /* Just ignore the rest, we can't do anything with
3624 * mono_threads_abort_appdomain_threads:
3626 * Abort threads which has references to the given appdomain.
3629 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3631 #ifdef __native_client__
3635 abort_appdomain_data user_data;
3637 int orig_timeout = timeout;
3640 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3642 start_time = mono_msec_ticks ();
3644 mono_threads_lock ();
3646 user_data.domain = domain;
3647 user_data.wait.num = 0;
3648 /* This shouldn't take any locks */
3649 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3650 mono_threads_unlock ();
3652 if (user_data.wait.num > 0) {
3653 /* Abort the threads outside the threads lock */
3654 for (i = 0; i < user_data.wait.num; ++i)
3655 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3658 * We should wait for the threads either to abort, or to leave the
3659 * domain. We can't do the latter, so we wait with a timeout.
3661 wait_for_tids (&user_data.wait, 100);
3664 /* Update remaining time */
3665 timeout -= mono_msec_ticks () - start_time;
3666 start_time = mono_msec_ticks ();
3668 if (orig_timeout != -1 && timeout < 0)
3671 while (user_data.wait.num > 0);
3673 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3679 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3681 MonoInternalThread *thread = (MonoInternalThread*)value;
3682 MonoDomain *domain = (MonoDomain*)user_data;
3685 /* No locking needed here */
3686 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3688 if (thread->cached_culture_info) {
3689 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3690 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3691 if (obj && obj->vtable->domain == domain)
3692 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3698 * mono_threads_clear_cached_culture:
3700 * Clear the cached_current_culture from all threads if it is in the
3704 mono_threads_clear_cached_culture (MonoDomain *domain)
3706 mono_threads_lock ();
3707 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3708 mono_threads_unlock ();
3712 * mono_thread_get_undeniable_exception:
3714 * Return an exception which needs to be raised when leaving a catch clause.
3715 * This is used for undeniable exception propagation.
3718 mono_thread_get_undeniable_exception (void)
3720 MonoInternalThread *thread = mono_thread_internal_current ();
3722 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3724 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3725 * exception if the thread no longer references a dying appdomain.
3727 thread->abort_exc->trace_ips = NULL;
3728 thread->abort_exc->stack_trace = NULL;
3729 return thread->abort_exc;
3735 #if MONO_SMALL_CONFIG
3736 #define NUM_STATIC_DATA_IDX 4
3737 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3741 #define NUM_STATIC_DATA_IDX 8
3742 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3743 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3747 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3750 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
3753 gpointer *static_data = addr;
3754 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3757 if (!static_data [i])
3759 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3760 ptr = static_data [i];
3761 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3762 uintptr_t bmap = static_reference_bitmaps [i][j];
3765 if ((bmap & 1) && *p) {
3776 * mono_alloc_static_data
3778 * Allocate memory blocks for storing threads or context static data
3781 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3783 guint idx = (offset >> 24) - 1;
3786 gpointer* static_data = *static_data_ptr;
3788 static void* tls_desc = NULL;
3789 if (mono_gc_user_markers_supported () && !tls_desc)
3790 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3791 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3792 *static_data_ptr = static_data;
3793 static_data [0] = static_data;
3796 for (i = 1; i <= idx; ++i) {
3797 if (static_data [i])
3799 if (mono_gc_user_markers_supported () && threadlocal)
3800 static_data [i] = g_malloc0 (static_data_size [i]);
3802 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3807 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3810 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3811 gpointer p = static_data [i];
3815 * At this point, the static data pointer array is still registered with the
3816 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3817 * data. Freeing the individual arrays without first nulling their slots
3818 * would make it possible for mark_tls_slots() to encounter a pointer to
3819 * such an already freed array. See bug #13813.
3821 static_data [i] = NULL;
3822 mono_memory_write_barrier ();
3823 if (mono_gc_user_markers_supported () && threadlocal)
3826 mono_gc_free_fixed (p);
3828 mono_gc_free_fixed (static_data);
3832 * mono_init_static_data_info
3834 * Initializes static data counters
3836 static void mono_init_static_data_info (StaticDataInfo *static_data)
3838 static_data->idx = 0;
3839 static_data->offset = 0;
3840 static_data->freelist = NULL;
3844 * mono_alloc_static_data_slot
3846 * Generates an offset for static data. static_data contains the counters
3847 * used to generate it.
3850 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3854 if (!static_data->idx && !static_data->offset) {
3856 * we use the first chunk of the first allocation also as
3857 * an array for the rest of the data
3859 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3861 static_data->offset += align - 1;
3862 static_data->offset &= ~(align - 1);
3863 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3864 static_data->idx ++;
3865 g_assert (size <= static_data_size [static_data->idx]);
3866 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3867 static_data->offset = 0;
3869 offset = static_data->offset | ((static_data->idx + 1) << 24);
3870 static_data->offset += size;
3875 * ensure thread static fields already allocated are valid for thread
3876 * This function is called when a thread is created or on thread attach.
3879 thread_adjust_static_data (MonoInternalThread *thread)
3883 mono_threads_lock ();
3884 if (thread_static_info.offset || thread_static_info.idx > 0) {
3885 /* get the current allocated size */
3886 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3887 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3889 mono_threads_unlock ();
3893 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3895 MonoInternalThread *thread = value;
3896 guint32 offset = GPOINTER_TO_UINT (user);
3898 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3901 static MonoThreadDomainTls*
3902 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3904 MonoThreadDomainTls* prev = NULL;
3905 MonoThreadDomainTls* tmp = static_data->freelist;
3907 if (tmp->size == size) {
3909 prev->next = tmp->next;
3911 static_data->freelist = tmp->next;
3920 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3923 int idx = (offset >> 24) - 1;
3925 if (!static_reference_bitmaps [idx])
3926 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3927 rb = static_reference_bitmaps [idx];
3929 offset /= sizeof (gpointer);
3930 /* offset is now the bitmap offset */
3931 for (i = 0; i < numbits; ++i) {
3932 if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
3933 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3938 clear_reference_bitmap (guint32 offset, guint32 size)
3940 int idx = (offset >> 24) - 1;
3942 rb = static_reference_bitmaps [idx];
3944 offset /= sizeof (gpointer);
3945 size /= sizeof (gpointer);
3947 /* offset is now the bitmap offset */
3948 for (; offset < size; ++offset)
3949 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3953 * The offset for a special static variable is composed of three parts:
3954 * a bit that indicates the type of static data (0:thread, 1:context),
3955 * an index in the array of chunks of memory for the thread (thread->static_data)
3956 * and an offset in that chunk of mem. This allows allocating less memory in the
3961 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3964 if (static_type == SPECIAL_STATIC_THREAD) {
3965 MonoThreadDomainTls *item;
3966 mono_threads_lock ();
3967 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3968 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3970 offset = item->offset;
3973 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3975 update_tls_reference_bitmap (offset, bitmap, numbits);
3976 /* This can be called during startup */
3977 if (threads != NULL)
3978 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3979 mono_threads_unlock ();
3981 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3982 mono_contexts_lock ();
3983 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3984 mono_contexts_unlock ();
3985 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3991 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3993 /* The high bit means either thread (0) or static (1) data. */
3995 guint32 static_type = (offset & 0x80000000);
3998 offset &= 0x7fffffff;
3999 idx = (offset >> 24) - 1;
4001 if (static_type == 0) {
4002 return get_thread_static_data (thread, offset);
4004 /* Allocate static data block under demand, since we don't have a list
4007 MonoAppContext *context = mono_context_get ();
4008 if (!context->static_data || !context->static_data [idx]) {
4009 mono_contexts_lock ();
4010 mono_alloc_static_data (&(context->static_data), offset, FALSE);
4011 mono_contexts_unlock ();
4013 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
4018 mono_get_special_static_data (guint32 offset)
4020 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4029 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4031 MonoInternalThread *thread = value;
4032 TlsOffsetSize *data = user;
4033 int idx = (data->offset >> 24) - 1;
4036 if (!thread->static_data || !thread->static_data [idx])
4038 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
4039 mono_gc_bzero (ptr, data->size);
4043 do_free_special_slot (guint32 offset, guint32 size)
4045 guint32 static_type = (offset & 0x80000000);
4046 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
4047 if (static_type == 0) {
4049 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
4050 data.offset = offset & 0x7fffffff;
4052 clear_reference_bitmap (data.offset, data.size);
4053 if (threads != NULL)
4054 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4055 item->offset = offset;
4058 if (!mono_runtime_is_shutting_down ()) {
4059 item->next = thread_static_info.freelist;
4060 thread_static_info.freelist = item;
4062 /* We could be called during shutdown after mono_thread_cleanup () is called */
4066 /* FIXME: free context static data as well */
4071 do_free_special (gpointer key, gpointer value, gpointer data)
4073 MonoClassField *field = key;
4074 guint32 offset = GPOINTER_TO_UINT (value);
4077 size = mono_type_size (field->type, &align);
4078 do_free_special_slot (offset, size);
4082 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4084 mono_threads_lock ();
4085 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4086 mono_threads_unlock ();
4090 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4092 mono_threads_lock ();
4093 do_free_special_slot (offset, size);
4094 mono_threads_unlock ();
4098 * allocates room in the thread local area for storing an instance of the struct type
4099 * the allocation is kept track of in domain->tlsrec_list.
4102 mono_thread_alloc_tls (MonoReflectionType *type)
4104 MonoDomain *domain = mono_domain_get ();
4106 MonoTlsDataRecord *tlsrec;
4109 gsize default_bitmap [4] = {0};
4110 uint32_t tls_offset;
4114 klass = mono_class_from_mono_type (type->type);
4115 /* TlsDatum is a struct, so we subtract the object header size offset */
4116 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
4117 size = mono_type_size (type->type, &align);
4118 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
4119 if (bitmap != default_bitmap)
4121 tlsrec = g_new0 (MonoTlsDataRecord, 1);
4122 tlsrec->tls_offset = tls_offset;
4123 tlsrec->size = size;
4124 mono_domain_lock (domain);
4125 tlsrec->next = domain->tlsrec_list;
4126 domain->tlsrec_list = tlsrec;
4127 mono_domain_unlock (domain);
4132 mono_thread_destroy_tls (uint32_t tls_offset)
4134 MonoTlsDataRecord *prev = NULL;
4135 MonoTlsDataRecord *cur;
4137 MonoDomain *domain = mono_domain_get ();
4138 mono_domain_lock (domain);
4139 cur = domain->tlsrec_list;
4141 if (cur->tls_offset == tls_offset) {
4143 prev->next = cur->next;
4145 domain->tlsrec_list = cur->next;
4153 mono_domain_unlock (domain);
4155 mono_special_static_data_free_slot (tls_offset, size);
4159 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
4162 mono_thread_destroy_domain_tls (MonoDomain *domain)
4164 while (domain->tlsrec_list)
4165 mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
4168 static MonoClassField *local_slots = NULL;
4171 /* local tls data to get locals_slot from a thread */
4174 /* index in the locals_slot array */
4179 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4181 LocalSlotID *sid = user_data;
4182 MonoInternalThread *thread = (MonoInternalThread*)value;
4183 MonoArray *slots_array;
4185 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4186 * it is for the right domain, so we need to check if it is allocated an initialized
4187 * for the current thread.
4189 /*g_print ("handling thread %p\n", thread);*/
4190 if (!thread->static_data || !thread->static_data [sid->idx])
4192 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4193 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4195 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4199 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4207 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4209 g_warning ("local_slots field not found in Thread class");
4213 domain = mono_domain_get ();
4214 mono_domain_lock (domain);
4215 if (domain->special_static_fields)
4216 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4217 mono_domain_unlock (domain);
4220 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4221 sid.offset = GPOINTER_TO_UINT (addr);
4222 sid.offset &= 0x7fffffff;
4223 sid.idx = (sid.offset >> 24) - 1;
4224 mono_threads_lock ();
4225 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4226 mono_threads_unlock ();
4228 /* FIXME: clear the slot for MonoAppContexts, too */
4233 static void CALLBACK dummy_apc (ULONG_PTR param)
4237 static guint32 dummy_apc (gpointer param)
4244 * mono_thread_execute_interruption
4246 * Performs the operation that the requested thread state requires (abort,
4249 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4251 ensure_synch_cs_set (thread);
4253 EnterCriticalSection (thread->synch_cs);
4255 /* MonoThread::interruption_requested can only be changed with atomics */
4256 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4257 /* this will consume pending APC calls */
4258 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4259 InterlockedDecrement (&thread_interruption_requested);
4261 /* Clear the interrupted flag of the thread so it can wait again */
4262 wapi_clear_interruption ();
4266 if ((thread->state & ThreadState_AbortRequested) != 0) {
4267 LeaveCriticalSection (thread->synch_cs);
4268 if (thread->abort_exc == NULL) {
4270 * This might be racy, but it has to be called outside the lock
4271 * since it calls managed code.
4273 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4275 return thread->abort_exc;
4277 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4278 self_suspend_internal (thread);
4281 else if ((thread->state & ThreadState_StopRequested) != 0) {
4282 /* FIXME: do this through the JIT? */
4284 LeaveCriticalSection (thread->synch_cs);
4286 mono_thread_exit ();
4288 } else if (thread->pending_exception) {
4291 exc = thread->pending_exception;
4292 thread->pending_exception = NULL;
4294 LeaveCriticalSection (thread->synch_cs);
4296 } else if (thread->thread_interrupt_requested) {
4298 thread->thread_interrupt_requested = FALSE;
4299 LeaveCriticalSection (thread->synch_cs);
4301 return(mono_get_exception_thread_interrupted ());
4304 LeaveCriticalSection (thread->synch_cs);
4310 * mono_thread_request_interruption
4312 * A signal handler can call this method to request the interruption of a
4313 * thread. The result of the interruption will depend on the current state of
4314 * the thread. If the result is an exception that needs to be throw, it is
4315 * provided as return value.
4318 mono_thread_request_interruption (gboolean running_managed)
4320 MonoInternalThread *thread = mono_thread_internal_current ();
4322 /* The thread may already be stopping */
4327 if (thread->interrupt_on_stop &&
4328 thread->state & ThreadState_StopRequested &&
4329 thread->state & ThreadState_Background)
4333 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4335 InterlockedIncrement (&thread_interruption_requested);
4337 if (!running_managed || is_running_protected_wrapper ()) {
4338 /* Can't stop while in unmanaged code. Increase the global interruption
4339 request count. When exiting the unmanaged method the count will be
4340 checked and the thread will be interrupted. */
4343 if (mono_thread_notify_pending_exc_fn && !running_managed)
4344 /* The JIT will notify the thread about the interruption */
4345 /* This shouldn't take any locks */
4346 mono_thread_notify_pending_exc_fn ();
4348 /* this will awake the thread if it is in WaitForSingleObject
4350 /* Our implementation of this function ignores the func argument */
4351 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
4355 return mono_thread_execute_interruption (thread);
4359 /*This function should be called by a thread after it has exited all of
4360 * its handle blocks at interruption time.*/
4362 mono_thread_resume_interruption (void)
4364 MonoInternalThread *thread = mono_thread_internal_current ();
4365 gboolean still_aborting;
4367 /* The thread may already be stopping */
4371 ensure_synch_cs_set (thread);
4372 EnterCriticalSection (thread->synch_cs);
4373 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4374 LeaveCriticalSection (thread->synch_cs);
4376 /*This can happen if the protected block called Thread::ResetAbort*/
4377 if (!still_aborting)
4380 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4382 InterlockedIncrement (&thread_interruption_requested);
4385 wapi_self_interrupt ();
4387 return mono_thread_execute_interruption (thread);
4390 gboolean mono_thread_interruption_requested ()
4392 if (thread_interruption_requested) {
4393 MonoInternalThread *thread = mono_thread_internal_current ();
4394 /* The thread may already be stopping */
4396 return (thread->interruption_requested);
4401 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4403 MonoInternalThread *thread = mono_thread_internal_current ();
4405 /* The thread may already be stopping */
4409 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4410 MonoException* exc = mono_thread_execute_interruption (thread);
4411 if (exc) mono_raise_exception (exc);
4416 * Performs the interruption of the current thread, if one has been requested,
4417 * and the thread is not running a protected wrapper.
4419 void mono_thread_interruption_checkpoint ()
4421 mono_thread_interruption_checkpoint_request (FALSE);
4425 * Performs the interruption of the current thread, if one has been requested.
4427 void mono_thread_force_interruption_checkpoint ()
4429 mono_thread_interruption_checkpoint_request (TRUE);
4433 * mono_thread_get_and_clear_pending_exception:
4435 * Return any pending exceptions for the current thread and clear it as a side effect.
4438 mono_thread_get_and_clear_pending_exception (void)
4440 MonoInternalThread *thread = mono_thread_internal_current ();
4442 /* The thread may already be stopping */
4446 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4447 return mono_thread_execute_interruption (thread);
4450 if (thread->pending_exception) {
4451 MonoException *exc = thread->pending_exception;
4453 thread->pending_exception = NULL;
4461 * mono_set_pending_exception:
4463 * Set the pending exception of the current thread to EXC.
4464 * The exception will be thrown when execution returns to managed code.
4467 mono_set_pending_exception (MonoException *exc)
4469 MonoInternalThread *thread = mono_thread_internal_current ();
4471 /* The thread may already be stopping */
4475 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4477 mono_thread_request_interruption (FALSE);
4481 * mono_thread_interruption_request_flag:
4483 * Returns the address of a flag that will be non-zero if an interruption has
4484 * been requested for a thread. The thread to interrupt may not be the current
4485 * thread, so an additional call to mono_thread_interruption_requested() or
4486 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4489 gint32* mono_thread_interruption_request_flag ()
4491 return &thread_interruption_requested;
4495 mono_thread_init_apartment_state (void)
4498 MonoInternalThread* thread = mono_thread_internal_current ();
4500 /* Positive return value indicates success, either
4501 * S_OK if this is first CoInitialize call, or
4502 * S_FALSE if CoInitialize already called, but with same
4503 * threading model. A negative value indicates failure,
4504 * probably due to trying to change the threading model.
4506 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4507 ? COINIT_APARTMENTTHREADED
4508 : COINIT_MULTITHREADED) < 0) {
4509 thread->apartment_state = ThreadApartmentState_Unknown;
4515 mono_thread_cleanup_apartment_state (void)
4518 MonoInternalThread* thread = mono_thread_internal_current ();
4520 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4527 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4529 ensure_synch_cs_set (thread);
4531 EnterCriticalSection (thread->synch_cs);
4532 thread->state |= state;
4533 LeaveCriticalSection (thread->synch_cs);
4537 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4539 ensure_synch_cs_set (thread);
4541 EnterCriticalSection (thread->synch_cs);
4542 thread->state &= ~state;
4543 LeaveCriticalSection (thread->synch_cs);
4547 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4549 gboolean ret = FALSE;
4551 ensure_synch_cs_set (thread);
4553 EnterCriticalSection (thread->synch_cs);
4555 if ((thread->state & test) != 0) {
4559 LeaveCriticalSection (thread->synch_cs);
4564 //static MonoClassField *execution_context_field;
4567 get_execution_context_addr (void)
4569 MonoDomain *domain = mono_domain_get ();
4570 guint32 offset = domain->execution_context_field_offset;
4573 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4576 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4578 mono_domain_lock (domain);
4579 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4580 mono_domain_unlock (domain);
4583 domain->execution_context_field_offset = offset;
4586 return (MonoObject**) mono_get_special_static_data (offset);
4590 mono_thread_get_execution_context (void)
4592 return *get_execution_context_addr ();
4596 mono_thread_set_execution_context (MonoObject *ec)
4598 *get_execution_context_addr () = ec;
4601 static gboolean has_tls_get = FALSE;
4604 mono_runtime_set_has_tls_get (gboolean val)
4610 mono_runtime_has_tls_get (void)
4616 mono_thread_kill (MonoInternalThread *thread, int signal)
4618 #ifdef __native_client__
4619 /* Workaround pthread_kill abort() in NaCl glibc. */
4623 /* Win32 uses QueueUserAPC and callers of this are guarded */
4624 g_assert_not_reached ();
4626 # ifdef PTHREAD_POINTER_ID
4627 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4629 # ifdef PLATFORM_ANDROID
4630 if (thread->android_tid != 0) {
4632 int old_errno = errno;
4634 ret = tkill ((pid_t) thread->android_tid, signal);
4643 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4645 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4652 self_interrupt_thread (void *_unused)
4654 MonoThreadInfo *info = mono_thread_info_current ();
4655 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4656 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4657 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4658 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4662 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4666 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4670 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4672 MonoJitInfo **dest = data;
4678 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4680 MonoJitInfo *ji = NULL;
4683 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4688 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4691 MonoThreadInfo *info = NULL;
4692 gboolean protected_wrapper;
4693 gboolean running_managed;
4695 if (!mono_thread_info_new_interrupt_enabled ()) {
4696 signal_thread_state_change (thread);
4701 FIXME this is insanely broken, it doesn't cause interruption to happen
4702 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4704 if (thread == mono_thread_internal_current ()) {
4705 /* Do it synchronously */
4706 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4708 mono_raise_exception (exc);
4710 wapi_interrupt_thread (thread->handle);
4715 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4716 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4720 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4721 mono_thread_info_resume (mono_thread_info_get_tid (info));
4725 /*someone is already interrupting it*/
4726 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4727 mono_thread_info_resume (mono_thread_info_get_tid (info));
4730 InterlockedIncrement (&thread_interruption_requested);
4732 ji = mono_thread_info_get_last_managed (info);
4733 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4734 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4736 if (!protected_wrapper && running_managed) {
4737 /*We are in managed code*/
4738 /*Set the thread to call */
4739 if (install_async_abort)
4740 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4741 mono_thread_info_resume (mono_thread_info_get_tid (info));
4743 gpointer interrupt_handle;
4745 * This will cause waits to be broken.
4746 * It will also prevent the thread from entering a wait, so if the thread returns
4747 * from the wait before it receives the abort signal, it will just spin in the wait
4748 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4752 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4754 mono_thread_info_resume (mono_thread_info_get_tid (info));
4756 wapi_finish_interrupt_thread (interrupt_handle);
4759 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4763 transition_to_suspended (MonoInternalThread *thread)
4765 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4766 g_assert (0); /*FIXME we should not reach this */
4767 /*Make sure we balance the suspend count.*/
4768 mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
4770 thread->state &= ~ThreadState_SuspendRequested;
4771 thread->state |= ThreadState_Suspended;
4772 mono_thread_info_finish_suspend ();
4774 LeaveCriticalSection (thread->synch_cs);
4778 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4780 if (!mono_thread_info_new_interrupt_enabled ()) {
4781 signal_thread_state_change (thread);
4785 EnterCriticalSection (thread->synch_cs);
4786 if (thread == mono_thread_internal_current ()) {
4787 transition_to_suspended (thread);
4788 mono_thread_info_self_suspend ();
4790 MonoThreadInfo *info;
4792 gboolean protected_wrapper;
4793 gboolean running_managed;
4795 /*A null info usually means the thread is already dead. */
4796 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
4797 LeaveCriticalSection (thread->synch_cs);
4801 ji = mono_thread_info_get_last_managed (info);
4802 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4803 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4805 if (running_managed && !protected_wrapper) {
4806 transition_to_suspended (thread);
4808 gpointer interrupt_handle;
4810 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4811 InterlockedIncrement (&thread_interruption_requested);
4814 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4816 mono_thread_info_resume (mono_thread_info_get_tid (info));
4819 wapi_finish_interrupt_thread (interrupt_handle);
4821 LeaveCriticalSection (thread->synch_cs);
4826 /*This is called with @thread synch_cs held and it must release it*/
4828 self_suspend_internal (MonoInternalThread *thread)
4830 if (!mono_thread_info_new_interrupt_enabled ()) {
4831 thread->state &= ~ThreadState_SuspendRequested;
4832 thread->state |= ThreadState_Suspended;
4833 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4834 if (thread->suspend_event == NULL) {
4835 LeaveCriticalSection (thread->synch_cs);
4838 if (thread->suspended_event)
4839 SetEvent (thread->suspended_event);
4841 LeaveCriticalSection (thread->synch_cs);
4843 if (shutting_down) {
4844 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4849 WaitForSingleObject (thread->suspend_event, INFINITE);
4851 EnterCriticalSection (thread->synch_cs);
4853 CloseHandle (thread->suspend_event);
4854 thread->suspend_event = NULL;
4855 thread->state &= ~ThreadState_Suspended;
4857 /* The thread that requested the resume will have replaced this event
4858 * and will be waiting for it
4860 SetEvent (thread->resume_event);
4862 LeaveCriticalSection (thread->synch_cs);
4866 transition_to_suspended (thread);
4867 mono_thread_info_self_suspend ();
4870 /*This is called with @thread synch_cs held and it must release it*/
4872 resume_thread_internal (MonoInternalThread *thread)
4874 if (!mono_thread_info_new_interrupt_enabled ()) {
4875 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4876 if (thread->resume_event == NULL) {
4877 LeaveCriticalSection (thread->synch_cs);
4881 /* Awake the thread */
4882 SetEvent (thread->suspend_event);
4884 LeaveCriticalSection (thread->synch_cs);
4886 /* Wait for the thread to awake */
4887 WaitForSingleObject (thread->resume_event, INFINITE);
4888 CloseHandle (thread->resume_event);
4889 thread->resume_event = NULL;
4893 LeaveCriticalSection (thread->synch_cs);
4894 /* Awake the thread */
4895 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4897 EnterCriticalSection (thread->synch_cs);
4898 thread->state &= ~ThreadState_Suspended;
4899 LeaveCriticalSection (thread->synch_cs);
4905 * mono_thread_is_foreign:
4906 * @thread: the thread to query
4908 * This function allows one to determine if a thread was created by the mono runtime and has
4909 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4911 * Returns: true if @thread was not created by the runtime.
4914 mono_thread_is_foreign (MonoThread *thread)
4916 MonoThreadInfo *info = thread->internal_thread->thread_info;
4917 return info->runtime_thread == FALSE;