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)
19 #if defined(__OpenBSD__)
21 #include <pthread_np.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/domain-internals.h>
26 #include <mono/metadata/profiler-private.h>
27 #include <mono/metadata/threads.h>
28 #include <mono/metadata/threadpool.h>
29 #include <mono/metadata/threads-types.h>
30 #include <mono/metadata/exception.h>
31 #include <mono/metadata/environment.h>
32 #include <mono/metadata/monitor.h>
33 #include <mono/metadata/gc-internal.h>
34 #include <mono/metadata/marshal.h>
35 #include <mono/io-layer/io-layer.h>
37 #include <mono/io-layer/threads.h>
39 #include <mono/metadata/object-internals.h>
40 #include <mono/metadata/mono-debug-debugger.h>
41 #include <mono/utils/mono-compiler.h>
42 #include <mono/utils/mono-mmap.h>
43 #include <mono/utils/mono-membar.h>
44 #include <mono/utils/mono-time.h>
45 #include <mono/utils/mono-threads.h>
46 #include <mono/utils/hazard-pointer.h>
47 #include <mono/utils/mono-tls.h>
49 #include <mono/metadata/gc-internal.h>
51 #ifdef PLATFORM_ANDROID
54 extern int tkill (pid_t tid, int signal);
57 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
58 #define THREAD_DEBUG(a)
59 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
60 #define THREAD_WAIT_DEBUG(a)
61 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
62 #define LIBGC_DEBUG(a)
64 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
65 #define SPIN_LOCK(i) do { \
66 if (SPIN_TRYLOCK (i)) \
70 #define SPIN_UNLOCK(i) i = 0
72 /* Provide this for systems with glib < 2.6 */
73 #ifndef G_GSIZE_FORMAT
74 # if GLIB_SIZEOF_LONG == 8
75 # define G_GSIZE_FORMAT "lu"
77 # define G_GSIZE_FORMAT "u"
83 guint32 (*func)(void *);
99 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
100 struct _MonoThreadDomainTls {
101 MonoThreadDomainTls *next;
109 MonoThreadDomainTls *freelist;
112 /* Number of cached culture objects in the MonoThread->cached_culture_info array
113 * (per-type): we use the first NUM entries for CultureInfo and the last for
114 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
116 #define NUM_CACHED_CULTURES 4
117 #define CULTURES_START_IDX 0
118 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
120 /* Controls access to the 'threads' hash table */
121 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
122 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
123 static CRITICAL_SECTION threads_mutex;
125 /* Controls access to context static data */
126 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
127 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
128 static CRITICAL_SECTION contexts_mutex;
130 /* Holds current status of static data heap */
131 static StaticDataInfo thread_static_info;
132 static StaticDataInfo context_static_info;
134 /* The hash of existing threads (key is thread ID, value is
135 * MonoInternalThread*) that need joining before exit
137 static MonoGHashTable *threads=NULL;
140 * Threads which are starting up and they are not in the 'threads' hash yet.
141 * When handle_store is called for a thread, it will be removed from this hash table.
142 * Protected by mono_threads_lock ().
144 static MonoGHashTable *threads_starting_up = NULL;
146 /* Maps a MonoThread to its start argument */
147 /* Protected by mono_threads_lock () */
148 static MonoGHashTable *thread_start_args = NULL;
150 /* The TLS key that holds the MonoObject assigned to each thread */
151 static MonoNativeTlsKey current_object_key;
153 #ifdef MONO_HAVE_FAST_TLS
154 /* we need to use both the Tls* functions and __thread because
155 * the gc needs to see all the threads
157 MONO_FAST_TLS_DECLARE(tls_current_object);
158 #define SET_CURRENT_OBJECT(x) do { \
159 MONO_FAST_TLS_SET (tls_current_object, x); \
160 mono_native_tls_set_value (current_object_key, x); \
162 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
164 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
165 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
168 /* function called at thread start */
169 static MonoThreadStartCB mono_thread_start_cb = NULL;
171 /* function called at thread attach */
172 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
174 /* function called at thread cleanup */
175 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
177 /* function called to notify the runtime about a pending exception on the current thread */
178 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
180 /* The default stack size for each thread */
181 static guint32 default_stacksize = 0;
182 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
184 static void thread_adjust_static_data (MonoInternalThread *thread);
185 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
186 static void mono_init_static_data_info (StaticDataInfo *static_data);
187 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
188 static gboolean mono_thread_resume (MonoInternalThread* thread);
189 static void mono_thread_start (MonoThread *thread);
190 static void signal_thread_state_change (MonoInternalThread *thread);
191 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
192 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
193 static void self_suspend_internal (MonoInternalThread *thread);
194 static gboolean resume_thread_internal (MonoInternalThread *thread);
196 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
197 static void ref_stack_destroy (gpointer rs);
199 /* Spin lock for InterlockedXXX 64 bit functions */
200 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
201 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
202 static CRITICAL_SECTION interlocked_mutex;
204 /* global count of thread interruptions requested */
205 static gint32 thread_interruption_requested = 0;
207 /* Event signaled when a thread changes its background mode */
208 static HANDLE background_change_event;
210 static gboolean shutting_down = FALSE;
212 static gint32 managed_thread_id_counter = 0;
215 get_next_managed_thread_id (void)
217 return InterlockedIncrement (&managed_thread_id_counter);
221 mono_thread_get_tls_key (void)
223 return current_object_key;
227 mono_thread_get_tls_offset (void)
230 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
234 /* handle_store() and handle_remove() manage the array of threads that
235 * still need to be waited for when the main thread exits.
237 * If handle_store() returns FALSE the thread must not be started
238 * because Mono is shutting down.
240 static gboolean handle_store(MonoThread *thread)
242 mono_threads_lock ();
244 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
246 if (threads_starting_up)
247 mono_g_hash_table_remove (threads_starting_up, thread);
250 mono_threads_unlock ();
255 MONO_GC_REGISTER_ROOT_FIXED (threads);
256 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
259 /* We don't need to duplicate thread->handle, because it is
260 * only closed when the thread object is finalized by the GC.
262 g_assert (thread->internal_thread);
263 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
264 thread->internal_thread);
266 mono_threads_unlock ();
271 static gboolean handle_remove(MonoInternalThread *thread)
274 gsize tid = thread->tid;
276 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
278 mono_threads_lock ();
281 /* We have to check whether the thread object for the
282 * tid is still the same in the table because the
283 * thread might have been destroyed and the tid reused
284 * in the meantime, in which case the tid would be in
285 * the table, but with another thread object.
287 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
288 mono_g_hash_table_remove (threads, (gpointer)tid);
297 mono_threads_unlock ();
299 /* Don't close the handle here, wait for the object finalizer
300 * to do it. Otherwise, the following race condition applies:
302 * 1) Thread exits (and handle_remove() closes the handle)
304 * 2) Some other handle is reassigned the same slot
306 * 3) Another thread tries to join the first thread, and
307 * blocks waiting for the reassigned handle to be signalled
308 * (which might never happen). This is possible, because the
309 * thread calling Join() still has a reference to the first
315 static void ensure_synch_cs_set (MonoInternalThread *thread)
317 CRITICAL_SECTION *synch_cs;
319 if (thread->synch_cs != NULL) {
323 synch_cs = g_new0 (CRITICAL_SECTION, 1);
324 InitializeCriticalSection (synch_cs);
326 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
327 synch_cs, NULL) != NULL) {
328 /* Another thread must have installed this CS */
329 DeleteCriticalSection (synch_cs);
335 * NOTE: this function can be called also for threads different from the current one:
336 * make sure no code called from it will ever assume it is run on the thread that is
337 * getting cleaned up.
339 static void thread_cleanup (MonoInternalThread *thread)
341 g_assert (thread != NULL);
343 if (thread->abort_state_handle) {
344 mono_gchandle_free (thread->abort_state_handle);
345 thread->abort_state_handle = 0;
347 thread->abort_exc = NULL;
348 thread->current_appcontext = NULL;
351 * This is necessary because otherwise we might have
352 * cross-domain references which will not get cleaned up when
353 * the target domain is unloaded.
355 if (thread->cached_culture_info) {
357 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
358 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
361 /* if the thread is not in the hash it has been removed already */
362 if (!handle_remove (thread)) {
363 /* This needs to be called even if handle_remove () fails */
364 if (mono_thread_cleanup_fn)
365 mono_thread_cleanup_fn (thread);
368 mono_release_type_locks (thread);
370 EnterCriticalSection (thread->synch_cs);
372 thread->state |= ThreadState_Stopped;
373 thread->state &= ~ThreadState_Background;
375 LeaveCriticalSection (thread->synch_cs);
377 mono_profiler_thread_end (thread->tid);
379 if (thread == mono_thread_internal_current ())
380 mono_thread_pop_appdomain_ref ();
382 thread->cached_culture_info = NULL;
384 mono_free_static_data (thread->static_data, TRUE);
385 thread->static_data = NULL;
386 ref_stack_destroy (thread->appdomain_refs);
387 thread->appdomain_refs = NULL;
389 if (mono_thread_cleanup_fn)
390 mono_thread_cleanup_fn (thread);
392 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
396 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
399 g_assert ((offset & 0x80000000) == 0);
400 offset &= 0x7fffffff;
401 idx = (offset >> 24) - 1;
402 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
406 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
408 static MonoClassField *current_thread_field = NULL;
412 if (!current_thread_field) {
413 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
414 g_assert (current_thread_field);
417 mono_class_vtable (domain, mono_defaults.thread_class);
418 mono_domain_lock (domain);
419 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
420 mono_domain_unlock (domain);
423 return get_thread_static_data (thread, offset);
427 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
429 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
431 g_assert (current->obj.vtable->domain == domain);
433 g_assert (!*current_thread_ptr);
434 *current_thread_ptr = current;
437 static MonoInternalThread*
438 create_internal_thread_object (void)
440 MonoVTable *vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
441 return (MonoInternalThread*)mono_gc_alloc_mature (vt);
445 create_thread_object (MonoDomain *domain)
447 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
448 return (MonoThread*)mono_gc_alloc_mature (vt);
452 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
454 MonoThread *thread = create_thread_object (domain);
455 MONO_OBJECT_SETREF (thread, internal_thread, internal);
460 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
462 MonoDomain *domain = mono_get_root_domain ();
464 if (!candidate || candidate->obj.vtable->domain != domain)
465 candidate = new_thread_with_internal (domain, thread);
466 set_current_thread_for_domain (domain, thread, candidate);
467 g_assert (!thread->root_domain_thread);
468 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
471 static guint32 WINAPI start_wrapper_internal(void *data)
473 MonoThreadInfo *info;
474 struct StartInfo *start_info=(struct StartInfo *)data;
475 guint32 (*start_func)(void *);
479 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
482 MonoInternalThread *internal = start_info->obj->internal_thread;
483 MonoObject *start_delegate = start_info->delegate;
484 MonoDomain *domain = start_info->obj->obj.vtable->domain;
486 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
488 /* We can be sure start_info->obj->tid and
489 * start_info->obj->handle have been set, because the thread
490 * was created suspended, and these values were set before the
494 info = mono_thread_info_current ();
496 internal->thread_info = info;
501 SET_CURRENT_OBJECT (internal);
503 mono_monitor_init_tls ();
505 /* Every thread references the appdomain which created it */
506 mono_thread_push_appdomain_ref (domain);
508 if (!mono_domain_set (domain, FALSE)) {
509 /* No point in raising an appdomain_unloaded exception here */
510 /* FIXME: Cleanup here */
511 mono_thread_pop_appdomain_ref ();
515 start_func = start_info->func;
516 start_arg = start_info->start_arg;
518 /* We have to do this here because mono_thread_new_init()
519 requires that root_domain_thread is set up. */
520 thread_adjust_static_data (internal);
521 init_root_domain_thread (internal, start_info->obj);
523 /* This MUST be called before any managed code can be
524 * executed, as it calls the callback function that (for the
525 * jit) sets the lmf marker.
527 mono_thread_new_init (tid, &tid, start_func);
528 internal->stack_ptr = &tid;
530 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
532 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
534 /* On 2.0 profile (and higher), set explicitly since state might have been
536 if (internal->apartment_state == ThreadApartmentState_Unknown)
537 internal->apartment_state = ThreadApartmentState_MTA;
539 mono_thread_init_apartment_state ();
541 if(internal->start_notify!=NULL) {
542 /* Let the thread that called Start() know we're
545 ReleaseSemaphore (internal->start_notify, 1, NULL);
548 mono_threads_lock ();
549 mono_g_hash_table_remove (thread_start_args, start_info->obj);
550 mono_threads_unlock ();
552 mono_thread_set_execution_context (start_info->obj->ec_to_set);
553 start_info->obj->ec_to_set = NULL;
556 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
560 * Call this after calling start_notify, since the profiler callback might want
561 * to lock the thread, and the lock is held by thread_start () which waits for
564 mono_profiler_thread_start (tid);
566 /* start_func is set only for unmanaged start functions */
568 start_func (start_arg);
571 g_assert (start_delegate != NULL);
572 args [0] = start_arg;
573 /* we may want to handle the exception here. See comment below on unhandled exceptions */
574 mono_runtime_delegate_invoke (start_delegate, args, NULL);
577 /* If the thread calls ExitThread at all, this remaining code
578 * will not be executed, but the main thread will eventually
579 * call thread_cleanup() on this thread's behalf.
582 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
584 thread_cleanup (internal);
586 /* Do any cleanup needed for apartment state. This
587 * cannot be done in thread_cleanup since thread_cleanup could be
588 * called for a thread other than the current thread.
589 * mono_thread_cleanup_apartment_state cleans up apartment
590 * for the current thead */
591 mono_thread_cleanup_apartment_state ();
593 /* Remove the reference to the thread object in the TLS data,
594 * so the thread object can be finalized. This won't be
595 * reached if the thread threw an uncaught exception, so those
596 * thread handles will stay referenced :-( (This is due to
597 * missing support for scanning thread-specific data in the
598 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
601 SET_CURRENT_OBJECT (NULL);
602 mono_domain_unset ();
607 static guint32 WINAPI start_wrapper(void *data)
612 /* Avoid scanning the frames above this frame during a GC */
613 mono_gc_set_stack_end ((void*)&dummy);
616 return start_wrapper_internal (data);
619 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
621 if (mono_thread_start_cb) {
622 mono_thread_start_cb (tid, stack_start, func);
626 void mono_threads_set_default_stacksize (guint32 stacksize)
628 default_stacksize = stacksize;
631 guint32 mono_threads_get_default_stacksize (void)
633 return default_stacksize;
637 * mono_create_thread:
639 * This is a wrapper around CreateThread which handles differences in the type of
640 * the the 'tid' argument.
642 gpointer mono_create_thread (WapiSecurityAttributes *security,
643 guint32 stacksize, WapiThreadStart start,
644 gpointer param, guint32 create, gsize *tid)
651 res = CreateThread (security, stacksize, start, param, create, &real_tid);
655 res = CreateThread (security, stacksize, start, param, create, tid);
662 * The thread start argument may be an object reference, and there is
663 * no ref to keep it alive when the new thread is started but not yet
664 * registered with the collector. So we store it in a GC tracked hash
667 * LOCKING: Assumes the threads lock is held.
670 register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info)
672 if (thread_start_args == NULL) {
673 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
674 thread_start_args = mono_g_hash_table_new (NULL, NULL);
676 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
679 MonoInternalThread* mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
682 MonoInternalThread *internal;
683 HANDLE thread_handle;
684 struct StartInfo *start_info;
687 thread = create_thread_object (domain);
688 internal = create_internal_thread_object ();
689 MONO_OBJECT_SETREF (thread, internal_thread, internal);
691 start_info=g_new0 (struct StartInfo, 1);
692 start_info->func = func;
693 start_info->obj = thread;
694 start_info->start_arg = arg;
696 mono_threads_lock ();
698 mono_threads_unlock ();
702 if (threads_starting_up == NULL) {
703 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
704 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
707 register_thread_start_argument (thread, start_info);
708 mono_g_hash_table_insert (threads_starting_up, thread, thread);
709 mono_threads_unlock ();
712 stack_size = default_stacksize_for_thread (internal);
714 /* Create suspended, so we can do some housekeeping before the thread
717 thread_handle = mono_create_thread (NULL, stack_size, (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
718 CREATE_SUSPENDED, &tid);
719 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
720 if (thread_handle == NULL) {
721 /* The thread couldn't be created, so throw an exception */
722 mono_threads_lock ();
723 mono_g_hash_table_remove (threads_starting_up, thread);
724 mono_threads_unlock ();
726 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
730 internal->handle=thread_handle;
732 internal->apartment_state=ThreadApartmentState_Unknown;
733 internal->thread_pinning_ref = internal;
734 internal->managed_id = get_next_managed_thread_id ();
735 MONO_GC_REGISTER_ROOT (internal->thread_pinning_ref);
737 internal->synch_cs = g_new0 (CRITICAL_SECTION, 1);
738 InitializeCriticalSection (internal->synch_cs);
740 internal->threadpool_thread = threadpool_thread;
741 if (threadpool_thread)
742 mono_thread_set_state (internal, ThreadState_Background);
744 if (handle_store (thread))
745 ResumeThread (thread_handle);
751 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
753 mono_thread_create_internal (domain, func, arg, FALSE, 0);
757 * mono_thread_get_stack_bounds:
759 * Return the address and size of the current threads stack. Return NULL as the
760 * stack address if the stack address cannot be determined.
763 mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
765 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
766 *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self ());
767 *stsize = pthread_get_stacksize_np (pthread_self ());
769 /* staddr points to the start of the stack, not the end */
771 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
773 /* FIXME: simplify the mess below */
774 #elif !defined(HOST_WIN32)
776 guint8 *current = (guint8*)&attr;
778 pthread_attr_init (&attr);
779 # ifdef HAVE_PTHREAD_GETATTR_NP
780 pthread_getattr_np (pthread_self(), &attr);
782 # ifdef HAVE_PTHREAD_ATTR_GET_NP
783 pthread_attr_get_np (pthread_self(), &attr);
786 pthread_attr_getstacksize (&attr, &stsize);
787 # elif defined(__OpenBSD__)
791 rslt = pthread_stackseg_np(pthread_self(), &ss);
792 g_assert (rslt == 0);
794 *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
795 *stsize = ss.ss_size;
804 # if !defined(__OpenBSD__)
805 pthread_attr_getstack (&attr, (void**)staddr, stsize);
808 g_assert ((current > *staddr) && (current < *staddr + *stsize));
811 pthread_attr_destroy (&attr);
814 *stsize = (size_t)-1;
817 /* When running under emacs, sometimes staddr is not aligned to a page size */
818 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
822 mono_thread_attach (MonoDomain *domain)
824 MonoInternalThread *thread;
825 MonoThread *current_thread;
826 HANDLE thread_handle;
829 if ((thread = mono_thread_internal_current ())) {
830 if (domain != mono_domain_get ())
831 mono_domain_set (domain, TRUE);
832 /* Already attached */
833 return mono_thread_current ();
836 if (!mono_gc_register_thread (&domain)) {
837 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 ());
840 thread = create_internal_thread_object ();
842 thread_handle = GetCurrentThread ();
843 g_assert (thread_handle);
845 tid=GetCurrentThreadId ();
848 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
849 * refer to the thread from other threads for things like aborting.
851 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
852 THREAD_ALL_ACCESS, TRUE, 0);
854 thread->handle=thread_handle;
856 #ifdef PLATFORM_ANDROID
857 thread->android_tid = (gpointer) gettid ();
859 thread->apartment_state=ThreadApartmentState_Unknown;
860 thread->thread_pinning_ref = thread;
861 thread->managed_id = get_next_managed_thread_id ();
862 MONO_GC_REGISTER_ROOT (thread->thread_pinning_ref);
864 thread->stack_ptr = &tid;
866 thread->synch_cs = g_new0 (CRITICAL_SECTION, 1);
867 InitializeCriticalSection (thread->synch_cs);
869 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
871 current_thread = new_thread_with_internal (domain, thread);
873 if (!handle_store (current_thread)) {
874 /* Mono is shutting down, so just wait for the end */
879 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
881 SET_CURRENT_OBJECT (thread);
882 mono_domain_set (domain, TRUE);
884 mono_monitor_init_tls ();
886 thread_adjust_static_data (thread);
888 init_root_domain_thread (thread, current_thread);
889 if (domain != mono_get_root_domain ())
890 set_current_thread_for_domain (domain, thread, current_thread);
893 if (mono_thread_attach_cb) {
897 mono_thread_get_stack_bounds (&staddr, &stsize);
900 mono_thread_attach_cb (tid, &tid);
902 mono_thread_attach_cb (tid, staddr + stsize);
905 // FIXME: Need a separate callback
906 mono_profiler_thread_start (tid);
908 return current_thread;
912 mono_thread_detach (MonoThread *thread)
914 g_return_if_fail (thread != NULL);
916 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
918 thread_cleanup (thread->internal_thread);
920 SET_CURRENT_OBJECT (NULL);
921 mono_domain_unset ();
923 /* Don't need to CloseHandle this thread, even though we took a
924 * reference in mono_thread_attach (), because the GC will do it
925 * when the Thread object is finalised.
932 MonoInternalThread *thread = mono_thread_internal_current ();
934 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
936 thread_cleanup (thread);
937 SET_CURRENT_OBJECT (NULL);
938 mono_domain_unset ();
940 /* we could add a callback here for embedders to use. */
941 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
942 exit (mono_environment_exitcode_get ());
947 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
949 MonoInternalThread *internal = create_internal_thread_object ();
951 internal->state = ThreadState_Unstarted;
952 internal->apartment_state = ThreadApartmentState_Unknown;
953 internal->managed_id = get_next_managed_thread_id ();
955 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
958 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
961 guint32 (*start_func)(void *);
962 struct StartInfo *start_info;
965 MonoInternalThread *internal;
967 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
969 if (!this->internal_thread)
970 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
971 internal = this->internal_thread;
973 ensure_synch_cs_set (internal);
975 EnterCriticalSection (internal->synch_cs);
977 if ((internal->state & ThreadState_Unstarted) == 0) {
978 LeaveCriticalSection (internal->synch_cs);
979 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
983 if ((internal->state & ThreadState_Aborted) != 0) {
984 LeaveCriticalSection (internal->synch_cs);
989 /* This is freed in start_wrapper */
990 start_info = g_new0 (struct StartInfo, 1);
991 start_info->func = start_func;
992 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
993 start_info->delegate = start;
994 start_info->obj = this;
995 g_assert (this->obj.vtable->domain == mono_domain_get ());
997 internal->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
998 if (internal->start_notify==NULL) {
999 LeaveCriticalSection (internal->synch_cs);
1000 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
1001 g_free (start_info);
1005 mono_threads_lock ();
1006 register_thread_start_argument (this, start_info);
1007 if (threads_starting_up == NULL) {
1008 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
1009 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
1011 mono_g_hash_table_insert (threads_starting_up, this, this);
1012 mono_threads_unlock ();
1014 thread=mono_create_thread(NULL, default_stacksize_for_thread (internal), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
1015 CREATE_SUSPENDED, &tid);
1017 LeaveCriticalSection (internal->synch_cs);
1018 mono_threads_lock ();
1019 mono_g_hash_table_remove (threads_starting_up, this);
1020 mono_threads_unlock ();
1021 g_warning("%s: CreateThread error 0x%x", __func__, GetLastError());
1025 internal->handle=thread;
1027 internal->thread_pinning_ref = internal;
1028 MONO_GC_REGISTER_ROOT (internal->thread_pinning_ref);
1031 /* Don't call handle_store() here, delay it to Start.
1032 * We can't join a thread (trying to will just block
1033 * forever) until it actually starts running, so don't
1034 * store the handle till then.
1037 mono_thread_start (this);
1039 internal->state &= ~ThreadState_Unstarted;
1041 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1043 LeaveCriticalSection (internal->synch_cs);
1048 void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1050 MONO_ARCH_SAVE_REGS;
1052 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1055 CloseHandle (thread);
1057 if (this->synch_cs) {
1058 CRITICAL_SECTION *synch_cs = this->synch_cs;
1059 this->synch_cs = NULL;
1060 DeleteCriticalSection (synch_cs);
1065 void *name = this->name;
1071 static void mono_thread_start (MonoThread *thread)
1073 MonoInternalThread *internal = thread->internal_thread;
1075 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1077 /* Only store the handle when the thread is about to be
1078 * launched, to avoid the main thread deadlocking while trying
1079 * to clean up a thread that will never be signalled.
1081 if (!handle_store (thread))
1084 ResumeThread (internal->handle);
1086 if(internal->start_notify!=NULL) {
1087 /* Wait for the thread to set up its TLS data etc, so
1088 * theres no potential race condition if someone tries
1089 * to look up the data believing the thread has
1093 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1095 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
1096 CloseHandle (internal->start_notify);
1097 internal->start_notify = NULL;
1100 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1103 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1106 MonoInternalThread *thread = mono_thread_internal_current ();
1108 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1110 mono_thread_current_check_pending_interrupt ();
1113 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1115 res = SleepEx(ms,TRUE);
1117 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1119 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1120 MonoException* exc = mono_thread_execute_interruption (thread);
1122 mono_raise_exception (exc);
1134 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1139 ves_icall_System_Threading_Thread_GetDomainID (void)
1141 MONO_ARCH_SAVE_REGS;
1143 return mono_domain_get()->domain_id;
1147 ves_icall_System_Threading_Thread_Yield (void)
1150 return SwitchToThread ();
1152 return sched_yield () == 0;
1157 * mono_thread_get_name:
1159 * Return the name of the thread. NAME_LEN is set to the length of the name.
1160 * Return NULL if the thread has no name. The returned memory is owned by the
1164 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1168 ensure_synch_cs_set (this_obj);
1170 EnterCriticalSection (this_obj->synch_cs);
1172 if (!this_obj->name) {
1176 *name_len = this_obj->name_len;
1177 res = g_new (gunichar2, this_obj->name_len);
1178 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1181 LeaveCriticalSection (this_obj->synch_cs);
1187 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1191 ensure_synch_cs_set (this_obj);
1193 EnterCriticalSection (this_obj->synch_cs);
1195 if (!this_obj->name)
1198 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1200 LeaveCriticalSection (this_obj->synch_cs);
1206 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1208 ensure_synch_cs_set (this_obj);
1210 EnterCriticalSection (this_obj->synch_cs);
1212 if (this_obj->name) {
1213 LeaveCriticalSection (this_obj->synch_cs);
1215 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1219 this_obj->name = g_new (gunichar2, mono_string_length (name));
1220 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1221 this_obj->name_len = mono_string_length (name);
1224 this_obj->name = NULL;
1226 LeaveCriticalSection (this_obj->synch_cs);
1227 if (this_obj->name) {
1228 char *tname = mono_string_to_utf8 (name);
1229 mono_profiler_thread_name (this_obj->tid, tname);
1234 /* If the array is already in the requested domain, we just return it,
1235 otherwise we return a copy in that domain. */
1237 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1244 if (mono_object_domain (arr) == domain)
1247 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1248 mono_gc_memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1253 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1255 return byte_array_to_domain (arr, mono_get_root_domain ());
1259 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1261 return byte_array_to_domain (arr, mono_domain_get ());
1265 mono_thread_current (void)
1267 MonoDomain *domain = mono_domain_get ();
1268 MonoInternalThread *internal = mono_thread_internal_current ();
1269 MonoThread **current_thread_ptr;
1271 g_assert (internal);
1272 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1274 if (!*current_thread_ptr) {
1275 g_assert (domain != mono_get_root_domain ());
1276 *current_thread_ptr = new_thread_with_internal (domain, internal);
1278 return *current_thread_ptr;
1282 mono_thread_internal_current (void)
1284 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1285 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1289 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1290 int ms, HANDLE thread)
1292 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1295 mono_thread_current_check_pending_interrupt ();
1297 ensure_synch_cs_set (this);
1299 EnterCriticalSection (this->synch_cs);
1301 if ((this->state & ThreadState_Unstarted) != 0) {
1302 LeaveCriticalSection (this->synch_cs);
1304 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1308 LeaveCriticalSection (this->synch_cs);
1313 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1315 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1317 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1319 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1321 if(ret==WAIT_OBJECT_0) {
1322 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1327 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1332 /* FIXME: exitContext isnt documented */
1333 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1339 MonoObject *waitHandle;
1340 MonoInternalThread *thread = mono_thread_internal_current ();
1342 /* Do this WaitSleepJoin check before creating objects */
1343 mono_thread_current_check_pending_interrupt ();
1345 numhandles = mono_array_length(mono_handles);
1346 handles = g_new0(HANDLE, numhandles);
1348 for(i = 0; i < numhandles; i++) {
1349 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1350 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1357 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1359 ret=WaitForMultipleObjectsEx(numhandles, handles, TRUE, ms, TRUE);
1361 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1365 if(ret==WAIT_FAILED) {
1366 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1368 } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
1369 /* Do we want to try again if we get
1370 * WAIT_IO_COMPLETION? The documentation for
1371 * WaitHandle doesn't give any clues. (We'd have to
1372 * fiddle with the timeout if we retry.)
1374 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1381 /* FIXME: exitContext isnt documented */
1382 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1384 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1388 MonoObject *waitHandle;
1389 MonoInternalThread *thread = mono_thread_internal_current ();
1392 /* Do this WaitSleepJoin check before creating objects */
1393 mono_thread_current_check_pending_interrupt ();
1395 numhandles = mono_array_length(mono_handles);
1396 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1399 for(i = 0; i < numhandles; i++) {
1400 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1401 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1408 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1410 start = (ms == -1) ? 0 : mono_msec_ticks ();
1412 ret = WaitForMultipleObjectsEx (numhandles, handles, FALSE, ms, TRUE);
1413 if (ret != WAIT_IO_COMPLETION)
1418 diff = mono_msec_ticks () - start;
1423 } while (ms == -1 || ms > 0);
1425 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1427 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1430 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1432 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1433 return ret - WAIT_OBJECT_0;
1435 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1436 return ret - WAIT_ABANDONED_0;
1443 /* FIXME: exitContext isnt documented */
1444 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1447 MonoInternalThread *thread = mono_thread_internal_current ();
1449 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1455 mono_thread_current_check_pending_interrupt ();
1457 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1459 ret=WaitForSingleObjectEx (handle, ms, TRUE);
1461 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1463 if(ret==WAIT_FAILED) {
1464 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1466 } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
1467 /* Do we want to try again if we get
1468 * WAIT_IO_COMPLETION? The documentation for
1469 * WaitHandle doesn't give any clues. (We'd have to
1470 * fiddle with the timeout if we retry.)
1472 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1480 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1483 MonoInternalThread *thread = mono_thread_internal_current ();
1485 MONO_ARCH_SAVE_REGS;
1490 mono_thread_current_check_pending_interrupt ();
1492 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1494 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1496 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1498 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1501 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1505 MONO_ARCH_SAVE_REGS;
1510 mutex = CreateMutex (NULL, owned, NULL);
1512 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1514 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1522 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1523 MONO_ARCH_SAVE_REGS;
1525 return(ReleaseMutex (handle));
1528 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1534 MONO_ARCH_SAVE_REGS;
1536 *error = ERROR_SUCCESS;
1538 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1540 *error = GetLastError ();
1547 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1551 MONO_ARCH_SAVE_REGS;
1556 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1558 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1559 mono_string_chars (name));
1561 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1569 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1573 MONO_ARCH_SAVE_REGS;
1575 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1580 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1584 MONO_ARCH_SAVE_REGS;
1586 *error = ERROR_SUCCESS;
1588 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1590 *error = GetLastError ();
1596 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1600 MONO_ARCH_SAVE_REGS;
1605 event = CreateEvent (NULL, manual, initial, NULL);
1607 event = CreateEvent (NULL, manual, initial,
1608 mono_string_chars (name));
1610 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1618 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1619 MONO_ARCH_SAVE_REGS;
1621 return (SetEvent(handle));
1624 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1625 MONO_ARCH_SAVE_REGS;
1627 return (ResetEvent(handle));
1631 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1632 MONO_ARCH_SAVE_REGS;
1634 CloseHandle (handle);
1637 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1643 MONO_ARCH_SAVE_REGS;
1645 *error = ERROR_SUCCESS;
1647 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1649 *error = GetLastError ();
1655 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1657 MONO_ARCH_SAVE_REGS;
1659 return InterlockedIncrement (location);
1662 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1666 MONO_ARCH_SAVE_REGS;
1668 mono_interlocked_lock ();
1672 mono_interlocked_unlock ();
1678 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1680 MONO_ARCH_SAVE_REGS;
1682 return InterlockedDecrement(location);
1685 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1689 MONO_ARCH_SAVE_REGS;
1691 mono_interlocked_lock ();
1695 mono_interlocked_unlock ();
1700 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1702 MONO_ARCH_SAVE_REGS;
1704 return InterlockedExchange(location, value);
1707 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1710 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1711 mono_gc_wbarrier_generic_nostore (location);
1715 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1717 return InterlockedExchangePointer(location, value);
1720 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1722 IntFloatUnion val, ret;
1724 MONO_ARCH_SAVE_REGS;
1727 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1733 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1735 #if SIZEOF_VOID_P == 8
1736 return (gint64) InterlockedExchangePointer((gpointer *) location, (gpointer)value);
1741 * According to MSDN, this function is only atomic with regards to the
1742 * other Interlocked functions on 32 bit platforms.
1744 mono_interlocked_lock ();
1747 mono_interlocked_unlock ();
1754 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1756 #if SIZEOF_VOID_P == 8
1757 LongDoubleUnion val, ret;
1760 ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location, (gpointer)val.ival);
1767 * According to MSDN, this function is only atomic with regards to the
1768 * other Interlocked functions on 32 bit platforms.
1770 mono_interlocked_lock ();
1773 mono_interlocked_unlock ();
1779 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1781 MONO_ARCH_SAVE_REGS;
1783 return InterlockedCompareExchange(location, value, comparand);
1786 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1789 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1790 mono_gc_wbarrier_generic_nostore (location);
1794 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1796 return InterlockedCompareExchangePointer(location, value, comparand);
1799 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1801 IntFloatUnion val, ret, cmp;
1803 MONO_ARCH_SAVE_REGS;
1806 cmp.fval = comparand;
1807 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1813 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1815 #if SIZEOF_VOID_P == 8
1816 LongDoubleUnion val, comp, ret;
1819 comp.fval = comparand;
1820 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1826 mono_interlocked_lock ();
1828 if (old == comparand)
1830 mono_interlocked_unlock ();
1837 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1839 #if SIZEOF_VOID_P == 8
1840 return (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)value, (gpointer)comparand);
1844 mono_interlocked_lock ();
1846 if (old == comparand)
1848 mono_interlocked_unlock ();
1855 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1858 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1859 mono_gc_wbarrier_generic_nostore (location);
1864 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1867 res = InterlockedExchangePointer ((gpointer *)location, value);
1868 mono_gc_wbarrier_generic_nostore (location);
1873 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1875 #if SIZEOF_VOID_P == 8
1876 /* Should be implemented as a JIT intrinsic */
1877 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1882 mono_interlocked_lock ();
1884 *location = orig + value;
1885 mono_interlocked_unlock ();
1887 return orig + value;
1892 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1894 #if SIZEOF_VOID_P == 8
1895 /* Should be implemented as a JIT intrinsic */
1896 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1901 mono_interlocked_lock ();
1903 *location = orig + value;
1904 mono_interlocked_unlock ();
1906 return orig + value;
1911 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1913 #if SIZEOF_VOID_P == 8
1914 /* 64 bit reads are already atomic */
1919 mono_interlocked_lock ();
1921 mono_interlocked_unlock ();
1928 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1930 mono_threads_lock ();
1931 mono_threads_unlock ();
1935 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1937 mono_thread_clr_state (this, state);
1939 if (state & ThreadState_Background) {
1940 /* If the thread changes the background mode, the main thread has to
1941 * be notified, since it has to rebuild the list of threads to
1944 SetEvent (background_change_event);
1949 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1951 mono_thread_set_state (this, state);
1953 if (state & ThreadState_Background) {
1954 /* If the thread changes the background mode, the main thread has to
1955 * be notified, since it has to rebuild the list of threads to
1958 SetEvent (background_change_event);
1963 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1967 ensure_synch_cs_set (this);
1969 EnterCriticalSection (this->synch_cs);
1971 state = this->state;
1973 LeaveCriticalSection (this->synch_cs);
1978 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
1980 MonoInternalThread *current;
1983 ensure_synch_cs_set (this);
1985 current = mono_thread_internal_current ();
1987 EnterCriticalSection (this->synch_cs);
1989 this->thread_interrupt_requested = TRUE;
1990 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
1992 LeaveCriticalSection (this->synch_cs);
1995 abort_thread_internal (this, TRUE, FALSE);
1999 void mono_thread_current_check_pending_interrupt ()
2001 MonoInternalThread *thread = mono_thread_internal_current ();
2002 gboolean throw = FALSE;
2004 mono_debugger_check_interruption ();
2006 ensure_synch_cs_set (thread);
2008 EnterCriticalSection (thread->synch_cs);
2010 if (thread->thread_interrupt_requested) {
2012 thread->thread_interrupt_requested = FALSE;
2015 LeaveCriticalSection (thread->synch_cs);
2018 mono_raise_exception (mono_get_exception_thread_interrupted ());
2023 mono_thread_get_abort_signal (void)
2035 static int abort_signum = -1;
2037 if (abort_signum != -1)
2038 return abort_signum;
2039 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2040 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2041 struct sigaction sinfo;
2042 sigaction (i, NULL, &sinfo);
2043 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2048 /* fallback to the old way */
2051 #endif /* HOST_WIN32 */
2055 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2057 MonoException* exc = mono_thread_request_interruption (FALSE);
2058 if (exc) mono_raise_exception (exc);
2060 #endif /* HOST_WIN32 */
2063 * signal_thread_state_change
2065 * Tells the thread that his state has changed and it has to enter the new
2066 * state as soon as possible.
2068 static void signal_thread_state_change (MonoInternalThread *thread)
2070 if (thread == mono_thread_internal_current ()) {
2071 /* Do it synchronously */
2072 MonoException *exc = mono_thread_request_interruption (FALSE);
2074 mono_raise_exception (exc);
2078 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
2080 /* fixme: store the state somewhere */
2081 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2084 * This will cause waits to be broken.
2085 * It will also prevent the thread from entering a wait, so if the thread returns
2086 * from the wait before it receives the abort signal, it will just spin in the wait
2087 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2090 wapi_interrupt_thread (thread->handle);
2091 #endif /* HOST_WIN32 */
2095 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2097 ensure_synch_cs_set (thread);
2099 EnterCriticalSection (thread->synch_cs);
2101 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2102 (thread->state & ThreadState_StopRequested) != 0 ||
2103 (thread->state & ThreadState_Stopped) != 0)
2105 LeaveCriticalSection (thread->synch_cs);
2109 if ((thread->state & ThreadState_Unstarted) != 0) {
2110 thread->state |= ThreadState_Aborted;
2111 LeaveCriticalSection (thread->synch_cs);
2115 thread->state |= ThreadState_AbortRequested;
2116 if (thread->abort_state_handle)
2117 mono_gchandle_free (thread->abort_state_handle);
2119 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2120 g_assert (thread->abort_state_handle);
2122 thread->abort_state_handle = 0;
2124 thread->abort_exc = NULL;
2127 * abort_exc is set in mono_thread_execute_interruption(),
2128 * triggered by the call to signal_thread_state_change(),
2129 * below. There's a point between where we have
2130 * abort_state_handle set, but abort_exc NULL, but that's not
2134 LeaveCriticalSection (thread->synch_cs);
2136 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2138 /* During shutdown, we can't wait for other threads */
2140 /* Make sure the thread is awake */
2141 mono_thread_resume (thread);
2143 abort_thread_internal (thread, TRUE, TRUE);
2147 ves_icall_System_Threading_Thread_ResetAbort (void)
2149 MonoInternalThread *thread = mono_thread_internal_current ();
2150 gboolean was_aborting;
2152 ensure_synch_cs_set (thread);
2154 EnterCriticalSection (thread->synch_cs);
2155 was_aborting = thread->state & ThreadState_AbortRequested;
2156 thread->state &= ~ThreadState_AbortRequested;
2157 LeaveCriticalSection (thread->synch_cs);
2159 if (!was_aborting) {
2160 const char *msg = "Unable to reset abort because no abort was requested";
2161 mono_raise_exception (mono_get_exception_thread_state (msg));
2163 thread->abort_exc = NULL;
2164 if (thread->abort_state_handle) {
2165 mono_gchandle_free (thread->abort_state_handle);
2166 /* This is actually not necessary - the handle
2167 only counts if the exception is set */
2168 thread->abort_state_handle = 0;
2173 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2175 ensure_synch_cs_set (thread);
2177 EnterCriticalSection (thread->synch_cs);
2179 thread->state &= ~ThreadState_AbortRequested;
2181 if (thread->abort_exc) {
2182 thread->abort_exc = NULL;
2183 if (thread->abort_state_handle) {
2184 mono_gchandle_free (thread->abort_state_handle);
2185 /* This is actually not necessary - the handle
2186 only counts if the exception is set */
2187 thread->abort_state_handle = 0;
2191 LeaveCriticalSection (thread->synch_cs);
2195 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2197 MonoInternalThread *thread = this->internal_thread;
2198 MonoObject *state, *deserialized = NULL, *exc;
2201 if (!thread->abort_state_handle)
2204 state = mono_gchandle_get_target (thread->abort_state_handle);
2207 domain = mono_domain_get ();
2208 if (mono_object_domain (state) == domain)
2211 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2213 if (!deserialized) {
2214 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2216 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2217 mono_raise_exception (invalid_op_exc);
2220 return deserialized;
2224 mono_thread_suspend (MonoInternalThread *thread)
2226 ensure_synch_cs_set (thread);
2228 EnterCriticalSection (thread->synch_cs);
2230 if ((thread->state & ThreadState_Unstarted) != 0 ||
2231 (thread->state & ThreadState_Aborted) != 0 ||
2232 (thread->state & ThreadState_Stopped) != 0)
2234 LeaveCriticalSection (thread->synch_cs);
2238 if ((thread->state & ThreadState_Suspended) != 0 ||
2239 (thread->state & ThreadState_SuspendRequested) != 0 ||
2240 (thread->state & ThreadState_StopRequested) != 0)
2242 LeaveCriticalSection (thread->synch_cs);
2246 thread->state |= ThreadState_SuspendRequested;
2248 LeaveCriticalSection (thread->synch_cs);
2250 suspend_thread_internal (thread, FALSE);
2255 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2257 if (!mono_thread_suspend (thread))
2258 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2262 mono_thread_resume (MonoInternalThread *thread)
2264 ensure_synch_cs_set (thread);
2266 EnterCriticalSection (thread->synch_cs);
2268 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2269 thread->state &= ~ThreadState_SuspendRequested;
2270 LeaveCriticalSection (thread->synch_cs);
2274 if ((thread->state & ThreadState_Suspended) == 0 ||
2275 (thread->state & ThreadState_Unstarted) != 0 ||
2276 (thread->state & ThreadState_Aborted) != 0 ||
2277 (thread->state & ThreadState_Stopped) != 0)
2279 LeaveCriticalSection (thread->synch_cs);
2283 return resume_thread_internal (thread);
2287 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2289 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2290 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2294 mono_threads_is_critical_method (MonoMethod *method)
2296 switch (method->wrapper_type) {
2297 case MONO_WRAPPER_RUNTIME_INVOKE:
2298 case MONO_WRAPPER_XDOMAIN_INVOKE:
2299 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2306 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2311 if (mono_threads_is_critical_method (m)) {
2312 *((gboolean*)data) = TRUE;
2319 is_running_protected_wrapper (void)
2321 gboolean found = FALSE;
2322 mono_stack_walk (find_wrapper, &found);
2326 void mono_thread_internal_stop (MonoInternalThread *thread)
2328 ensure_synch_cs_set (thread);
2330 EnterCriticalSection (thread->synch_cs);
2332 if ((thread->state & ThreadState_StopRequested) != 0 ||
2333 (thread->state & ThreadState_Stopped) != 0)
2335 LeaveCriticalSection (thread->synch_cs);
2339 /* Make sure the thread is awake */
2340 mono_thread_resume (thread);
2342 thread->state |= ThreadState_StopRequested;
2343 thread->state &= ~ThreadState_AbortRequested;
2345 LeaveCriticalSection (thread->synch_cs);
2347 abort_thread_internal (thread, TRUE, TRUE);
2350 void mono_thread_stop (MonoThread *thread)
2352 mono_thread_internal_stop (thread->internal_thread);
2356 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2358 return *((volatile gint8 *) (ptr));
2362 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2364 return *((volatile gint16 *) (ptr));
2368 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2370 return *((volatile gint32 *) (ptr));
2374 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2376 return *((volatile gint64 *) (ptr));
2380 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2382 return (void *) *((volatile void **) ptr);
2386 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2388 *((volatile gint8 *) ptr) = value;
2392 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2394 *((volatile gint16 *) ptr) = value;
2398 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2400 *((volatile gint32 *) ptr) = value;
2404 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2406 *((volatile gint64 *) ptr) = value;
2410 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2412 *((volatile void **) ptr) = value;
2416 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, void *value)
2418 mono_gc_wbarrier_generic_store (ptr, value);
2421 void mono_thread_init (MonoThreadStartCB start_cb,
2422 MonoThreadAttachCB attach_cb)
2424 InitializeCriticalSection(&threads_mutex);
2425 InitializeCriticalSection(&interlocked_mutex);
2426 InitializeCriticalSection(&contexts_mutex);
2428 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2429 g_assert(background_change_event != NULL);
2431 mono_init_static_data_info (&thread_static_info);
2432 mono_init_static_data_info (&context_static_info);
2434 MONO_FAST_TLS_INIT (tls_current_object);
2435 mono_native_tls_alloc (current_object_key, NULL);
2436 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2438 mono_thread_start_cb = start_cb;
2439 mono_thread_attach_cb = attach_cb;
2441 /* Get a pseudo handle to the current process. This is just a
2442 * kludge so that wapi can build a process handle if needed.
2443 * As a pseudo handle is returned, we don't need to clean
2446 GetCurrentProcess ();
2449 void mono_thread_cleanup (void)
2451 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2452 /* The main thread must abandon any held mutexes (particularly
2453 * important for named mutexes as they are shared across
2454 * processes, see bug 74680.) This will happen when the
2455 * thread exits, but if it's not running in a subthread it
2456 * won't exit in time.
2458 /* Using non-w32 API is a nasty kludge, but I couldn't find
2459 * anything in the documentation that would let me do this
2460 * here yet still be safe to call on windows.
2462 _wapi_thread_signal_self (mono_environment_exitcode_get ());
2466 /* This stuff needs more testing, it seems one of these
2467 * critical sections can be locked when mono_thread_cleanup is
2470 DeleteCriticalSection (&threads_mutex);
2471 DeleteCriticalSection (&interlocked_mutex);
2472 DeleteCriticalSection (&contexts_mutex);
2473 DeleteCriticalSection (&delayed_free_table_mutex);
2474 DeleteCriticalSection (&small_id_mutex);
2475 CloseHandle (background_change_event);
2478 mono_native_tls_free (current_object_key);
2482 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2484 mono_thread_cleanup_fn = func;
2488 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2490 thread->internal_thread->manage_callback = func;
2493 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2495 mono_thread_notify_pending_exc_fn = func;
2499 static void print_tids (gpointer key, gpointer value, gpointer user)
2501 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2502 * sizeof(uint) and a cast to uint would overflow
2504 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2505 * print this as a pointer.
2507 g_message ("Waiting for: %p", key);
2512 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2513 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2517 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2521 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2523 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2525 if(ret==WAIT_FAILED) {
2526 /* See the comment in build_wait_tids() */
2527 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2531 for(i=0; i<wait->num; i++)
2532 CloseHandle (wait->handles[i]);
2534 if (ret == WAIT_TIMEOUT)
2537 for(i=0; i<wait->num; i++) {
2538 gsize tid = wait->threads[i]->tid;
2540 mono_threads_lock ();
2541 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2542 /* This thread must have been killed, because
2543 * it hasn't cleaned itself up. (It's just
2544 * possible that the thread exited before the
2545 * parent thread had a chance to store the
2546 * handle, and now there is another pointer to
2547 * the already-exited thread stored. In this
2548 * case, we'll just get two
2549 * mono_profiler_thread_end() calls for the
2553 mono_threads_unlock ();
2554 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2555 thread_cleanup (wait->threads[i]);
2557 mono_threads_unlock ();
2562 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2564 guint32 i, ret, count;
2566 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2568 /* Add the thread state change event, so it wakes up if a thread changes
2569 * to background mode.
2572 if (count < MAXIMUM_WAIT_OBJECTS) {
2573 wait->handles [count] = background_change_event;
2577 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2579 if(ret==WAIT_FAILED) {
2580 /* See the comment in build_wait_tids() */
2581 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2585 for(i=0; i<wait->num; i++)
2586 CloseHandle (wait->handles[i]);
2588 if (ret == WAIT_TIMEOUT)
2591 if (ret < wait->num) {
2592 gsize tid = wait->threads[ret]->tid;
2593 mono_threads_lock ();
2594 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2595 /* See comment in wait_for_tids about thread cleanup */
2596 mono_threads_unlock ();
2597 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2598 thread_cleanup (wait->threads [ret]);
2600 mono_threads_unlock ();
2604 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2606 struct wait_data *wait=(struct wait_data *)user;
2608 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2610 MonoInternalThread *thread=(MonoInternalThread *)value;
2612 /* Ignore background threads, we abort them later */
2613 /* Do not lock here since it is not needed and the caller holds threads_lock */
2614 if (thread->state & ThreadState_Background) {
2615 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2616 return; /* just leave, ignore */
2619 if (mono_gc_is_finalizer_internal_thread (thread)) {
2620 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2624 if (thread == mono_thread_internal_current ()) {
2625 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2629 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2630 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2634 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2635 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2639 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2640 if (handle == NULL) {
2641 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2645 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2646 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2647 wait->handles[wait->num]=handle;
2648 wait->threads[wait->num]=thread;
2651 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2653 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2658 /* Just ignore the rest, we can't do anything with
2665 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2667 struct wait_data *wait=(struct wait_data *)user;
2668 gsize self = GetCurrentThreadId ();
2669 MonoInternalThread *thread = value;
2672 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2675 /* The finalizer thread is not a background thread */
2676 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2677 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2679 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2683 /* printf ("A: %d\n", wait->num); */
2684 wait->handles[wait->num]=thread->handle;
2685 wait->threads[wait->num]=thread;
2688 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2689 mono_thread_internal_stop (thread);
2693 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2697 * mono_threads_set_shutting_down:
2699 * Is called by a thread that wants to shut down Mono. If the runtime is already
2700 * shutting down, the calling thread is suspended/stopped, and this function never
2704 mono_threads_set_shutting_down (void)
2706 MonoInternalThread *current_thread = mono_thread_internal_current ();
2708 mono_threads_lock ();
2710 if (shutting_down) {
2711 mono_threads_unlock ();
2713 /* Make sure we're properly suspended/stopped */
2715 EnterCriticalSection (current_thread->synch_cs);
2717 if ((current_thread->state & ThreadState_SuspendRequested) ||
2718 (current_thread->state & ThreadState_AbortRequested) ||
2719 (current_thread->state & ThreadState_StopRequested)) {
2720 LeaveCriticalSection (current_thread->synch_cs);
2721 mono_thread_execute_interruption (current_thread);
2723 current_thread->state |= ThreadState_Stopped;
2724 LeaveCriticalSection (current_thread->synch_cs);
2727 /*since we're killing the thread, unset the current domain.*/
2728 mono_domain_unset ();
2730 /* Wake up other threads potentially waiting for us */
2733 shutting_down = TRUE;
2735 /* Not really a background state change, but this will
2736 * interrupt the main thread if it is waiting for all
2737 * the other threads.
2739 SetEvent (background_change_event);
2741 mono_threads_unlock ();
2746 * mono_threads_is_shutting_down:
2748 * Returns whether a thread has commenced shutdown of Mono. Note that
2749 * if the function returns FALSE the caller must not assume that
2750 * shutdown is not in progress, because the situation might have
2751 * changed since the function returned. For that reason this function
2752 * is of very limited utility.
2755 mono_threads_is_shutting_down (void)
2757 return shutting_down;
2760 void mono_thread_manage (void)
2762 struct wait_data wait_data;
2763 struct wait_data *wait = &wait_data;
2765 memset (wait, 0, sizeof (struct wait_data));
2766 /* join each thread that's still running */
2767 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2769 mono_threads_lock ();
2771 THREAD_DEBUG (g_message("%s: No threads", __func__));
2772 mono_threads_unlock ();
2775 mono_threads_unlock ();
2778 mono_threads_lock ();
2779 if (shutting_down) {
2780 /* somebody else is shutting down */
2781 mono_threads_unlock ();
2784 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2785 mono_g_hash_table_foreach (threads, print_tids, NULL));
2787 ResetEvent (background_change_event);
2789 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2790 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2791 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2792 mono_threads_unlock ();
2794 /* Something to wait for */
2795 wait_for_tids_or_state_change (wait, INFINITE);
2797 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2798 } while(wait->num>0);
2800 mono_threads_set_shutting_down ();
2802 /* No new threads will be created after this point */
2804 mono_runtime_set_shutting_down ();
2806 THREAD_DEBUG (g_message ("%s: threadpool cleanup", __func__));
2807 mono_thread_pool_cleanup ();
2810 * Remove everything but the finalizer thread and self.
2811 * Also abort all the background threads
2814 mono_threads_lock ();
2817 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2818 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2819 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2821 mono_threads_unlock ();
2823 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2825 /* Something to wait for */
2826 wait_for_tids (wait, INFINITE);
2828 } while (wait->num > 0);
2831 * give the subthreads a chance to really quit (this is mainly needed
2832 * to get correct user and system times from getrusage/wait/time(1)).
2833 * This could be removed if we avoid pthread_detach() and use pthread_join().
2840 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2842 MonoInternalThread *thread=(MonoInternalThread *)value;
2844 if(thread->tid != (gsize)user) {
2845 /*TerminateThread (thread->handle, -1);*/
2849 void mono_thread_abort_all_other_threads (void)
2851 gsize self = GetCurrentThreadId ();
2853 mono_threads_lock ();
2854 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2855 mono_g_hash_table_size (threads));
2856 mono_g_hash_table_foreach (threads, print_tids, NULL));
2858 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2860 mono_threads_unlock ();
2864 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2866 MonoInternalThread *thread = (MonoInternalThread*)value;
2867 struct wait_data *wait = (struct wait_data*)user_data;
2871 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
2873 * This needs no locking.
2875 if ((thread->state & ThreadState_Suspended) != 0 ||
2876 (thread->state & ThreadState_Stopped) != 0)
2879 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2880 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2884 wait->handles [wait->num] = handle;
2885 wait->threads [wait->num] = thread;
2891 * mono_thread_suspend_all_other_threads:
2893 * Suspend all managed threads except the finalizer thread and this thread. It is
2894 * not possible to resume them later.
2896 void mono_thread_suspend_all_other_threads (void)
2898 struct wait_data wait_data;
2899 struct wait_data *wait = &wait_data;
2901 gsize self = GetCurrentThreadId ();
2903 guint32 eventidx = 0;
2904 gboolean starting, finished;
2906 memset (wait, 0, sizeof (struct wait_data));
2908 * The other threads could be in an arbitrary state at this point, i.e.
2909 * they could be starting up, shutting down etc. This means that there could be
2910 * threads which are not even in the threads hash table yet.
2914 * First we set a barrier which will be checked by all threads before they
2915 * are added to the threads hash table, and they will exit if the flag is set.
2916 * This ensures that no threads could be added to the hash later.
2917 * We will use shutting_down as the barrier for now.
2919 g_assert (shutting_down);
2922 * We make multiple calls to WaitForMultipleObjects since:
2923 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
2924 * - some threads could exit without becoming suspended
2929 * Make a copy of the hashtable since we can't do anything with
2930 * threads while threads_mutex is held.
2933 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2934 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2935 mono_threads_lock ();
2936 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
2937 mono_threads_unlock ();
2939 events = g_new0 (gpointer, wait->num);
2941 /* Get the suspended events that we'll be waiting for */
2942 for (i = 0; i < wait->num; ++i) {
2943 MonoInternalThread *thread = wait->threads [i];
2944 gboolean signal_suspend = FALSE;
2946 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2947 //CloseHandle (wait->handles [i]);
2948 wait->threads [i] = NULL; /* ignore this thread in next loop */
2952 ensure_synch_cs_set (thread);
2954 EnterCriticalSection (thread->synch_cs);
2956 if (thread->suspended_event == NULL) {
2957 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2958 if (thread->suspended_event == NULL) {
2959 /* Forget this one and go on to the next */
2960 LeaveCriticalSection (thread->synch_cs);
2965 if ((thread->state & ThreadState_Suspended) != 0 ||
2966 (thread->state & ThreadState_StopRequested) != 0 ||
2967 (thread->state & ThreadState_Stopped) != 0) {
2968 LeaveCriticalSection (thread->synch_cs);
2969 CloseHandle (wait->handles [i]);
2970 wait->threads [i] = NULL; /* ignore this thread in next loop */
2974 if ((thread->state & ThreadState_SuspendRequested) == 0)
2975 signal_suspend = TRUE;
2977 events [eventidx++] = thread->suspended_event;
2979 /* Convert abort requests into suspend requests */
2980 if ((thread->state & ThreadState_AbortRequested) != 0)
2981 thread->state &= ~ThreadState_AbortRequested;
2983 thread->state |= ThreadState_SuspendRequested;
2985 LeaveCriticalSection (thread->synch_cs);
2987 /* Signal the thread to suspend */
2988 if (mono_thread_info_new_interrupt_enabled ())
2989 suspend_thread_internal (thread, TRUE);
2990 else if (signal_suspend)
2991 signal_thread_state_change (thread);
2994 /*Only wait on the suspend event if we are using the old path */
2995 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
2996 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
2997 for (i = 0; i < wait->num; ++i) {
2998 MonoInternalThread *thread = wait->threads [i];
3003 ensure_synch_cs_set (thread);
3005 EnterCriticalSection (thread->synch_cs);
3006 if ((thread->state & ThreadState_Suspended) != 0) {
3007 CloseHandle (thread->suspended_event);
3008 thread->suspended_event = NULL;
3010 LeaveCriticalSection (thread->synch_cs);
3014 if (eventidx <= 0) {
3016 * If there are threads which are starting up, we wait until they
3017 * are suspended when they try to register in the threads hash.
3018 * This is guaranteed to finish, since the threads which can create new
3019 * threads get suspended after a while.
3020 * FIXME: The finalizer thread can still create new threads.
3022 mono_threads_lock ();
3023 if (threads_starting_up)
3024 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3027 mono_threads_unlock ();
3039 collect_threads (gpointer key, gpointer value, gpointer user_data)
3041 MonoInternalThread *thread = (MonoInternalThread*)value;
3042 struct wait_data *wait = (struct wait_data*)user_data;
3045 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3046 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3050 wait->handles [wait->num] = handle;
3051 wait->threads [wait->num] = thread;
3056 static gboolean thread_dump_requested;
3058 static G_GNUC_UNUSED gboolean
3059 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3061 GString *p = (GString*)data;
3062 MonoMethod *method = NULL;
3064 method = frame->ji->method;
3067 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3068 g_string_append_printf (p, " %s\n", location);
3071 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3077 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3079 GString* text = g_string_new (0);
3081 GError *error = NULL;
3084 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3086 g_string_append_printf (text, "\n\"%s\"", name);
3089 else if (thread->threadpool_thread)
3090 g_string_append (text, "\n\"<threadpool thread>\"");
3092 g_string_append (text, "\n\"<unnamed thread>\"");
3095 /* This no longer works with remote unwinding */
3097 wapi_desc = wapi_current_thread_desc ();
3098 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3103 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3104 mono_thread_info_resume (mono_thread_info_get_tid (info));
3106 fprintf (stdout, "%s", text->str);
3108 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3109 OutputDebugStringA(text->str);
3112 g_string_free (text, TRUE);
3117 dump_thread (gpointer key, gpointer value, gpointer user)
3119 MonoInternalThread *thread = (MonoInternalThread *)value;
3120 MonoThreadInfo *info;
3122 if (thread == mono_thread_internal_current ())
3126 FIXME This still can hang if we stop a thread during malloc.
3127 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3128 that takes a callback and runs it with the target suspended.
3129 We probably should loop a bit around trying to get it to either managed code
3132 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3137 print_thread_dump (thread, info);
3141 mono_threads_perform_thread_dump (void)
3143 if (!thread_dump_requested)
3146 printf ("Full thread dump:\n");
3149 * Make a copy of the hashtable since we can't do anything with
3150 * threads while threads_mutex is held.
3152 mono_threads_lock ();
3153 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3154 mono_threads_unlock ();
3156 thread_dump_requested = FALSE;
3160 * mono_threads_request_thread_dump:
3162 * Ask all threads except the current to print their stacktrace to stdout.
3165 mono_threads_request_thread_dump (void)
3167 struct wait_data wait_data;
3168 struct wait_data *wait = &wait_data;
3171 /*The new thread dump code runs out of the finalizer thread. */
3172 if (mono_thread_info_new_interrupt_enabled ()) {
3173 thread_dump_requested = TRUE;
3174 mono_gc_finalize_notify ();
3179 memset (wait, 0, sizeof (struct wait_data));
3182 * Make a copy of the hashtable since we can't do anything with
3183 * threads while threads_mutex is held.
3185 mono_threads_lock ();
3186 mono_g_hash_table_foreach (threads, collect_threads, wait);
3187 mono_threads_unlock ();
3189 for (i = 0; i < wait->num; ++i) {
3190 MonoInternalThread *thread = wait->threads [i];
3192 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3193 (thread != mono_thread_internal_current ()) &&
3194 !thread->thread_dump_requested) {
3195 thread->thread_dump_requested = TRUE;
3197 signal_thread_state_change (thread);
3200 CloseHandle (wait->handles [i]);
3206 gint allocated; /* +1 so that refs [allocated] == NULL */
3210 typedef struct ref_stack RefStack;
3213 ref_stack_new (gint initial_size)
3217 initial_size = MAX (initial_size, 16) + 1;
3218 rs = g_new0 (RefStack, 1);
3219 rs->refs = g_new0 (gpointer, initial_size);
3220 rs->allocated = initial_size;
3225 ref_stack_destroy (gpointer ptr)
3236 ref_stack_push (RefStack *rs, gpointer ptr)
3238 g_assert (rs != NULL);
3240 if (rs->bottom >= rs->allocated) {
3241 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3242 rs->allocated <<= 1;
3243 rs->refs [rs->allocated] = NULL;
3245 rs->refs [rs->bottom++] = ptr;
3249 ref_stack_pop (RefStack *rs)
3251 if (rs == NULL || rs->bottom == 0)
3255 rs->refs [rs->bottom] = NULL;
3259 ref_stack_find (RefStack *rs, gpointer ptr)
3266 for (refs = rs->refs; refs && *refs; refs++) {
3274 * mono_thread_push_appdomain_ref:
3276 * Register that the current thread may have references to objects in domain
3277 * @domain on its stack. Each call to this function should be paired with a
3278 * call to pop_appdomain_ref.
3281 mono_thread_push_appdomain_ref (MonoDomain *domain)
3283 MonoInternalThread *thread = mono_thread_internal_current ();
3286 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3287 SPIN_LOCK (thread->lock_thread_id);
3288 if (thread->appdomain_refs == NULL)
3289 thread->appdomain_refs = ref_stack_new (16);
3290 ref_stack_push (thread->appdomain_refs, domain);
3291 SPIN_UNLOCK (thread->lock_thread_id);
3296 mono_thread_pop_appdomain_ref (void)
3298 MonoInternalThread *thread = mono_thread_internal_current ();
3301 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3302 SPIN_LOCK (thread->lock_thread_id);
3303 ref_stack_pop (thread->appdomain_refs);
3304 SPIN_UNLOCK (thread->lock_thread_id);
3309 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3312 SPIN_LOCK (thread->lock_thread_id);
3313 res = ref_stack_find (thread->appdomain_refs, domain);
3314 SPIN_UNLOCK (thread->lock_thread_id);
3319 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3321 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3324 typedef struct abort_appdomain_data {
3325 struct wait_data wait;
3327 } abort_appdomain_data;
3330 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3332 MonoInternalThread *thread = (MonoInternalThread*)value;
3333 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3334 MonoDomain *domain = data->domain;
3336 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3337 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3339 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3340 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3343 data->wait.handles [data->wait.num] = handle;
3344 data->wait.threads [data->wait.num] = thread;
3347 /* Just ignore the rest, we can't do anything with
3355 * mono_threads_abort_appdomain_threads:
3357 * Abort threads which has references to the given appdomain.
3360 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3362 abort_appdomain_data user_data;
3364 int orig_timeout = timeout;
3367 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3369 start_time = mono_msec_ticks ();
3371 mono_threads_lock ();
3373 user_data.domain = domain;
3374 user_data.wait.num = 0;
3375 /* This shouldn't take any locks */
3376 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3377 mono_threads_unlock ();
3379 if (user_data.wait.num > 0) {
3380 /* Abort the threads outside the threads lock */
3381 for (i = 0; i < user_data.wait.num; ++i)
3382 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3385 * We should wait for the threads either to abort, or to leave the
3386 * domain. We can't do the latter, so we wait with a timeout.
3388 wait_for_tids (&user_data.wait, 100);
3391 /* Update remaining time */
3392 timeout -= mono_msec_ticks () - start_time;
3393 start_time = mono_msec_ticks ();
3395 if (orig_timeout != -1 && timeout < 0)
3398 while (user_data.wait.num > 0);
3400 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3406 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3408 MonoInternalThread *thread = (MonoInternalThread*)value;
3409 MonoDomain *domain = (MonoDomain*)user_data;
3412 /* No locking needed here */
3413 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3415 if (thread->cached_culture_info) {
3416 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3417 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3418 if (obj && obj->vtable->domain == domain)
3419 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3425 * mono_threads_clear_cached_culture:
3427 * Clear the cached_current_culture from all threads if it is in the
3431 mono_threads_clear_cached_culture (MonoDomain *domain)
3433 mono_threads_lock ();
3434 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3435 mono_threads_unlock ();
3439 * mono_thread_get_undeniable_exception:
3441 * Return an exception which needs to be raised when leaving a catch clause.
3442 * This is used for undeniable exception propagation.
3445 mono_thread_get_undeniable_exception (void)
3447 MonoInternalThread *thread = mono_thread_internal_current ();
3449 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3451 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3452 * exception if the thread no longer references a dying appdomain.
3454 thread->abort_exc->trace_ips = NULL;
3455 thread->abort_exc->stack_trace = NULL;
3456 return thread->abort_exc;
3462 #if MONO_SMALL_CONFIG
3463 #define NUM_STATIC_DATA_IDX 4
3464 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3468 #define NUM_STATIC_DATA_IDX 8
3469 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3470 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3474 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3478 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
3481 gpointer *static_data = addr;
3482 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3485 if (!static_data [i])
3487 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3488 ptr = static_data [i];
3489 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3490 uintptr_t bmap = static_reference_bitmaps [i][j];
3493 if ((bmap & 1) && *p) {
3505 * mono_alloc_static_data
3507 * Allocate memory blocks for storing threads or context static data
3510 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3512 guint idx = (offset >> 24) - 1;
3515 gpointer* static_data = *static_data_ptr;
3517 static void* tls_desc = NULL;
3520 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3522 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3523 *static_data_ptr = static_data;
3524 static_data [0] = static_data;
3527 for (i = 1; i <= idx; ++i) {
3528 if (static_data [i])
3531 static_data [i] = threadlocal?g_malloc0 (static_data_size [i]):mono_gc_alloc_fixed (static_data_size [i], NULL);
3533 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3539 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3542 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3543 if (!static_data [i])
3547 g_free (static_data [i]);
3549 mono_gc_free_fixed (static_data [i]);
3551 mono_gc_free_fixed (static_data [i]);
3554 mono_gc_free_fixed (static_data);
3558 * mono_init_static_data_info
3560 * Initializes static data counters
3562 static void mono_init_static_data_info (StaticDataInfo *static_data)
3564 static_data->idx = 0;
3565 static_data->offset = 0;
3566 static_data->freelist = NULL;
3570 * mono_alloc_static_data_slot
3572 * Generates an offset for static data. static_data contains the counters
3573 * used to generate it.
3576 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3580 if (!static_data->idx && !static_data->offset) {
3582 * we use the first chunk of the first allocation also as
3583 * an array for the rest of the data
3585 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3587 static_data->offset += align - 1;
3588 static_data->offset &= ~(align - 1);
3589 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3590 static_data->idx ++;
3591 g_assert (size <= static_data_size [static_data->idx]);
3592 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3593 static_data->offset = 0;
3595 offset = static_data->offset | ((static_data->idx + 1) << 24);
3596 static_data->offset += size;
3601 * ensure thread static fields already allocated are valid for thread
3602 * This function is called when a thread is created or on thread attach.
3605 thread_adjust_static_data (MonoInternalThread *thread)
3609 mono_threads_lock ();
3610 if (thread_static_info.offset || thread_static_info.idx > 0) {
3611 /* get the current allocated size */
3612 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3613 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3615 mono_threads_unlock ();
3619 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3621 MonoInternalThread *thread = value;
3622 guint32 offset = GPOINTER_TO_UINT (user);
3624 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3627 static MonoThreadDomainTls*
3628 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3630 MonoThreadDomainTls* prev = NULL;
3631 MonoThreadDomainTls* tmp = static_data->freelist;
3633 if (tmp->size == size) {
3635 prev->next = tmp->next;
3637 static_data->freelist = tmp->next;
3646 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int max_set)
3649 int idx = (offset >> 24) - 1;
3651 if (!static_reference_bitmaps [idx])
3652 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3653 rb = static_reference_bitmaps [idx];
3655 offset /= sizeof (gpointer);
3656 /* offset is now the bitmap offset */
3657 for (i = 0; i < max_set; ++i) {
3658 if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
3659 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3664 clear_reference_bitmap (guint32 offset, guint32 size)
3666 int idx = (offset >> 24) - 1;
3668 rb = static_reference_bitmaps [idx];
3670 offset /= sizeof (gpointer);
3671 size /= sizeof (gpointer);
3673 /* offset is now the bitmap offset */
3674 for (; offset < size; ++offset)
3675 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3679 * The offset for a special static variable is composed of three parts:
3680 * a bit that indicates the type of static data (0:thread, 1:context),
3681 * an index in the array of chunks of memory for the thread (thread->static_data)
3682 * and an offset in that chunk of mem. This allows allocating less memory in the
3687 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int max_set)
3690 if (static_type == SPECIAL_STATIC_THREAD) {
3691 MonoThreadDomainTls *item;
3692 mono_threads_lock ();
3693 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3694 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3696 offset = item->offset;
3699 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3701 update_tls_reference_bitmap (offset, bitmap, max_set);
3702 /* This can be called during startup */
3703 if (threads != NULL)
3704 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3705 mono_threads_unlock ();
3707 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3708 mono_contexts_lock ();
3709 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3710 mono_contexts_unlock ();
3711 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3717 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3719 /* The high bit means either thread (0) or static (1) data. */
3721 guint32 static_type = (offset & 0x80000000);
3724 offset &= 0x7fffffff;
3725 idx = (offset >> 24) - 1;
3727 if (static_type == 0) {
3728 return get_thread_static_data (thread, offset);
3730 /* Allocate static data block under demand, since we don't have a list
3733 MonoAppContext *context = mono_context_get ();
3734 if (!context->static_data || !context->static_data [idx]) {
3735 mono_contexts_lock ();
3736 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3737 mono_contexts_unlock ();
3739 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3744 mono_get_special_static_data (guint32 offset)
3746 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3755 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3757 MonoInternalThread *thread = value;
3758 TlsOffsetSize *data = user;
3759 int idx = (data->offset >> 24) - 1;
3762 if (!thread->static_data || !thread->static_data [idx])
3764 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3765 mono_gc_bzero (ptr, data->size);
3769 do_free_special_slot (guint32 offset, guint32 size)
3771 guint32 static_type = (offset & 0x80000000);
3772 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3773 if (static_type == 0) {
3775 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3776 data.offset = offset & 0x7fffffff;
3778 clear_reference_bitmap (data.offset, data.size);
3779 if (threads != NULL)
3780 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3781 item->offset = offset;
3784 if (!mono_runtime_is_shutting_down ()) {
3785 item->next = thread_static_info.freelist;
3786 thread_static_info.freelist = item;
3788 /* We could be called during shutdown after mono_thread_cleanup () is called */
3792 /* FIXME: free context static data as well */
3797 do_free_special (gpointer key, gpointer value, gpointer data)
3799 MonoClassField *field = key;
3800 guint32 offset = GPOINTER_TO_UINT (value);
3803 size = mono_type_size (field->type, &align);
3804 do_free_special_slot (offset, size);
3808 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3810 mono_threads_lock ();
3811 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3812 mono_threads_unlock ();
3816 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3818 mono_threads_lock ();
3819 do_free_special_slot (offset, size);
3820 mono_threads_unlock ();
3824 * allocates room in the thread local area for storing an instance of the struct type
3825 * the allocation is kept track of in domain->tlsrec_list.
3828 mono_thread_alloc_tls (MonoReflectionType *type)
3830 MonoDomain *domain = mono_domain_get ();
3832 MonoTlsDataRecord *tlsrec;
3835 gsize default_bitmap [4] = {0};
3836 uint32_t tls_offset;
3840 klass = mono_class_from_mono_type (type->type);
3841 /* TlsDatum is a struct, so we subtract the object header size offset */
3842 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3843 size = mono_type_size (type->type, &align);
3844 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, bitmap, max_set);
3845 if (bitmap != default_bitmap)
3847 tlsrec = g_new0 (MonoTlsDataRecord, 1);
3848 tlsrec->tls_offset = tls_offset;
3849 tlsrec->size = size;
3850 mono_domain_lock (domain);
3851 tlsrec->next = domain->tlsrec_list;
3852 domain->tlsrec_list = tlsrec;
3853 mono_domain_unlock (domain);
3858 mono_thread_destroy_tls (uint32_t tls_offset)
3860 MonoTlsDataRecord *prev = NULL;
3861 MonoTlsDataRecord *cur;
3863 MonoDomain *domain = mono_domain_get ();
3864 mono_domain_lock (domain);
3865 cur = domain->tlsrec_list;
3867 if (cur->tls_offset == tls_offset) {
3869 prev->next = cur->next;
3871 domain->tlsrec_list = cur->next;
3879 mono_domain_unlock (domain);
3881 mono_special_static_data_free_slot (tls_offset, size);
3885 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
3888 mono_thread_destroy_domain_tls (MonoDomain *domain)
3890 while (domain->tlsrec_list)
3891 mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
3894 static MonoClassField *local_slots = NULL;
3897 /* local tls data to get locals_slot from a thread */
3900 /* index in the locals_slot array */
3905 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
3907 LocalSlotID *sid = user_data;
3908 MonoInternalThread *thread = (MonoInternalThread*)value;
3909 MonoArray *slots_array;
3911 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
3912 * it is for the right domain, so we need to check if it is allocated an initialized
3913 * for the current thread.
3915 /*g_print ("handling thread %p\n", thread);*/
3916 if (!thread->static_data || !thread->static_data [sid->idx])
3918 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
3919 if (!slots_array || sid->slot >= mono_array_length (slots_array))
3921 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
3925 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
3933 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
3935 g_warning ("local_slots field not found in Thread class");
3939 domain = mono_domain_get ();
3940 mono_domain_lock (domain);
3941 if (domain->special_static_fields)
3942 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
3943 mono_domain_unlock (domain);
3946 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
3947 sid.offset = GPOINTER_TO_UINT (addr);
3948 sid.offset &= 0x7fffffff;
3949 sid.idx = (sid.offset >> 24) - 1;
3950 mono_threads_lock ();
3951 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
3952 mono_threads_unlock ();
3954 /* FIXME: clear the slot for MonoAppContexts, too */
3959 static void CALLBACK dummy_apc (ULONG_PTR param)
3963 static guint32 dummy_apc (gpointer param)
3970 * mono_thread_execute_interruption
3972 * Performs the operation that the requested thread state requires (abort,
3975 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
3977 ensure_synch_cs_set (thread);
3979 EnterCriticalSection (thread->synch_cs);
3981 /* MonoThread::interruption_requested can only be changed with atomics */
3982 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
3983 /* this will consume pending APC calls */
3984 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
3985 InterlockedDecrement (&thread_interruption_requested);
3987 /* Clear the interrupted flag of the thread so it can wait again */
3988 wapi_clear_interruption ();
3992 if ((thread->state & ThreadState_AbortRequested) != 0) {
3993 LeaveCriticalSection (thread->synch_cs);
3994 if (thread->abort_exc == NULL) {
3996 * This might be racy, but it has to be called outside the lock
3997 * since it calls managed code.
3999 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4001 return thread->abort_exc;
4003 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4004 self_suspend_internal (thread);
4007 else if ((thread->state & ThreadState_StopRequested) != 0) {
4008 /* FIXME: do this through the JIT? */
4010 LeaveCriticalSection (thread->synch_cs);
4012 mono_thread_exit ();
4014 } else if (thread->thread_interrupt_requested) {
4016 thread->thread_interrupt_requested = FALSE;
4017 LeaveCriticalSection (thread->synch_cs);
4019 return(mono_get_exception_thread_interrupted ());
4022 LeaveCriticalSection (thread->synch_cs);
4028 * mono_thread_request_interruption
4030 * A signal handler can call this method to request the interruption of a
4031 * thread. The result of the interruption will depend on the current state of
4032 * the thread. If the result is an exception that needs to be throw, it is
4033 * provided as return value.
4036 mono_thread_request_interruption (gboolean running_managed)
4038 MonoInternalThread *thread = mono_thread_internal_current ();
4040 /* The thread may already be stopping */
4045 if (thread->interrupt_on_stop &&
4046 thread->state & ThreadState_StopRequested &&
4047 thread->state & ThreadState_Background)
4051 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4054 if (!running_managed || is_running_protected_wrapper ()) {
4055 /* Can't stop while in unmanaged code. Increase the global interruption
4056 request count. When exiting the unmanaged method the count will be
4057 checked and the thread will be interrupted. */
4059 InterlockedIncrement (&thread_interruption_requested);
4061 if (mono_thread_notify_pending_exc_fn && !running_managed)
4062 /* The JIT will notify the thread about the interruption */
4063 /* This shouldn't take any locks */
4064 mono_thread_notify_pending_exc_fn ();
4066 /* this will awake the thread if it is in WaitForSingleObject
4068 /* Our implementation of this function ignores the func argument */
4069 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
4073 return mono_thread_execute_interruption (thread);
4077 /*This function should be called by a thread after it has exited all of
4078 * its handle blocks at interruption time.*/
4080 mono_thread_resume_interruption (void)
4082 MonoInternalThread *thread = mono_thread_internal_current ();
4083 gboolean still_aborting;
4085 /* The thread may already be stopping */
4089 ensure_synch_cs_set (thread);
4090 EnterCriticalSection (thread->synch_cs);
4091 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4092 LeaveCriticalSection (thread->synch_cs);
4094 /*This can happen if the protected block called Thread::ResetAbort*/
4095 if (!still_aborting)
4098 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4100 InterlockedIncrement (&thread_interruption_requested);
4103 wapi_self_interrupt ();
4105 return mono_thread_execute_interruption (thread);
4108 gboolean mono_thread_interruption_requested ()
4110 if (thread_interruption_requested) {
4111 MonoInternalThread *thread = mono_thread_internal_current ();
4112 /* The thread may already be stopping */
4114 return (thread->interruption_requested);
4119 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4121 MonoInternalThread *thread = mono_thread_internal_current ();
4123 /* The thread may already be stopping */
4127 mono_debugger_check_interruption ();
4129 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4130 MonoException* exc = mono_thread_execute_interruption (thread);
4131 if (exc) mono_raise_exception (exc);
4136 * Performs the interruption of the current thread, if one has been requested,
4137 * and the thread is not running a protected wrapper.
4139 void mono_thread_interruption_checkpoint ()
4141 mono_thread_interruption_checkpoint_request (FALSE);
4145 * Performs the interruption of the current thread, if one has been requested.
4147 void mono_thread_force_interruption_checkpoint ()
4149 mono_thread_interruption_checkpoint_request (TRUE);
4153 * mono_thread_get_and_clear_pending_exception:
4155 * Return any pending exceptions for the current thread and clear it as a side effect.
4158 mono_thread_get_and_clear_pending_exception (void)
4160 MonoInternalThread *thread = mono_thread_internal_current ();
4162 /* The thread may already be stopping */
4166 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4167 return mono_thread_execute_interruption (thread);
4170 if (thread->pending_exception) {
4171 MonoException *exc = thread->pending_exception;
4173 thread->pending_exception = NULL;
4181 * mono_set_pending_exception:
4183 * Set the pending exception of the current thread to EXC. On platforms which
4184 * support it, the exception will be thrown when execution returns to managed code.
4185 * On other platforms, this function is equivalent to mono_raise_exception ().
4186 * Internal calls which report exceptions using this function instead of
4187 * raise_exception () might be called by JITted code using a more efficient calling
4191 mono_set_pending_exception (MonoException *exc)
4193 MonoInternalThread *thread = mono_thread_internal_current ();
4195 /* The thread may already be stopping */
4199 if (mono_thread_notify_pending_exc_fn) {
4200 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4202 mono_thread_notify_pending_exc_fn ();
4204 /* No way to notify the JIT about the exception, have to throw it now */
4205 mono_raise_exception (exc);
4210 * mono_thread_interruption_request_flag:
4212 * Returns the address of a flag that will be non-zero if an interruption has
4213 * been requested for a thread. The thread to interrupt may not be the current
4214 * thread, so an additional call to mono_thread_interruption_requested() or
4215 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4218 gint32* mono_thread_interruption_request_flag ()
4220 return &thread_interruption_requested;
4224 mono_thread_init_apartment_state (void)
4227 MonoInternalThread* thread = mono_thread_internal_current ();
4229 /* Positive return value indicates success, either
4230 * S_OK if this is first CoInitialize call, or
4231 * S_FALSE if CoInitialize already called, but with same
4232 * threading model. A negative value indicates failure,
4233 * probably due to trying to change the threading model.
4235 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4236 ? COINIT_APARTMENTTHREADED
4237 : COINIT_MULTITHREADED) < 0) {
4238 thread->apartment_state = ThreadApartmentState_Unknown;
4244 mono_thread_cleanup_apartment_state (void)
4247 MonoInternalThread* thread = mono_thread_internal_current ();
4249 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4256 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4258 ensure_synch_cs_set (thread);
4260 EnterCriticalSection (thread->synch_cs);
4261 thread->state |= state;
4262 LeaveCriticalSection (thread->synch_cs);
4266 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4268 ensure_synch_cs_set (thread);
4270 EnterCriticalSection (thread->synch_cs);
4271 thread->state &= ~state;
4272 LeaveCriticalSection (thread->synch_cs);
4276 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4278 gboolean ret = FALSE;
4280 ensure_synch_cs_set (thread);
4282 EnterCriticalSection (thread->synch_cs);
4284 if ((thread->state & test) != 0) {
4288 LeaveCriticalSection (thread->synch_cs);
4293 static MonoClassField *execution_context_field;
4296 get_execution_context_addr (void)
4298 MonoDomain *domain = mono_domain_get ();
4301 if (!execution_context_field) {
4302 execution_context_field = mono_class_get_field_from_name (mono_defaults.thread_class,
4304 g_assert (execution_context_field);
4307 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4309 mono_domain_lock (domain);
4310 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, execution_context_field));
4311 mono_domain_unlock (domain);
4314 return (MonoObject**) mono_get_special_static_data (offset);
4318 mono_thread_get_execution_context (void)
4320 return *get_execution_context_addr ();
4324 mono_thread_set_execution_context (MonoObject *ec)
4326 *get_execution_context_addr () = ec;
4329 static gboolean has_tls_get = FALSE;
4332 mono_runtime_set_has_tls_get (gboolean val)
4338 mono_runtime_has_tls_get (void)
4344 mono_thread_kill (MonoInternalThread *thread, int signal)
4347 /* Win32 uses QueueUserAPC and callers of this are guarded */
4348 g_assert_not_reached ();
4350 # ifdef PTHREAD_POINTER_ID
4351 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4353 # ifdef PLATFORM_ANDROID
4354 if (thread->android_tid != 0) {
4356 int old_errno = errno;
4358 ret = tkill ((pid_t) thread->android_tid, signal);
4367 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4369 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4376 self_interrupt_thread (void *_unused)
4378 MonoThreadInfo *info = mono_thread_info_current ();
4379 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4380 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4381 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4382 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4386 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4390 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4394 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4396 MonoJitInfo **dest = data;
4402 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4404 MonoJitInfo *ji = NULL;
4405 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4410 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4413 MonoThreadInfo *info = NULL;
4414 gboolean protected_wrapper;
4415 gboolean running_managed;
4417 if (!mono_thread_info_new_interrupt_enabled ()) {
4418 signal_thread_state_change (thread);
4423 FIXME this is insanely broken, it doesn't cause interruption to happen
4424 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4426 if (thread == mono_thread_internal_current ()) {
4427 /* Do it synchronously */
4428 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4430 mono_raise_exception (exc);
4432 wapi_interrupt_thread (thread->handle);
4437 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4438 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4442 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4443 mono_thread_info_resume (mono_thread_info_get_tid (info));
4447 /*someone is already interrupting it*/
4448 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4449 mono_thread_info_resume (mono_thread_info_get_tid (info));
4453 ji = mono_thread_info_get_last_managed (info);
4454 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4455 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4457 if (!protected_wrapper && running_managed) {
4458 /*We are in managed code*/
4459 /*Set the thread to call */
4460 if (install_async_abort)
4461 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4462 mono_thread_info_resume (mono_thread_info_get_tid (info));
4465 * This will cause waits to be broken.
4466 * It will also prevent the thread from entering a wait, so if the thread returns
4467 * from the wait before it receives the abort signal, it will just spin in the wait
4468 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4471 InterlockedIncrement (&thread_interruption_requested);
4472 mono_thread_info_resume (mono_thread_info_get_tid (info));
4474 wapi_interrupt_thread (thread->handle);
4477 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4481 transition_to_suspended (MonoInternalThread *thread)
4483 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4484 g_assert (0); /*FIXME we should not reach this */
4485 /*Make sure we balance the suspend count.*/
4486 mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
4488 thread->state &= ~ThreadState_SuspendRequested;
4489 thread->state |= ThreadState_Suspended;
4491 LeaveCriticalSection (thread->synch_cs);
4495 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4497 if (!mono_thread_info_new_interrupt_enabled ()) {
4498 signal_thread_state_change (thread);
4502 EnterCriticalSection (thread->synch_cs);
4503 if (thread == mono_thread_internal_current ()) {
4504 transition_to_suspended (thread);
4505 mono_thread_info_self_suspend ();
4507 MonoThreadInfo *info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt);
4508 MonoJitInfo *ji = mono_thread_info_get_last_managed (info);
4509 gboolean protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4510 gboolean running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4512 if (running_managed && !protected_wrapper) {
4513 transition_to_suspended (thread);
4515 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4516 InterlockedIncrement (&thread_interruption_requested);
4519 wapi_interrupt_thread (thread->handle);
4521 mono_thread_info_resume (mono_thread_info_get_tid (info));
4522 LeaveCriticalSection (thread->synch_cs);
4527 /*This is called with @thread synch_cs held and it must release it*/
4529 self_suspend_internal (MonoInternalThread *thread)
4531 if (!mono_thread_info_new_interrupt_enabled ()) {
4532 thread->state &= ~ThreadState_SuspendRequested;
4533 thread->state |= ThreadState_Suspended;
4534 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4535 if (thread->suspend_event == NULL) {
4536 LeaveCriticalSection (thread->synch_cs);
4539 if (thread->suspended_event)
4540 SetEvent (thread->suspended_event);
4542 LeaveCriticalSection (thread->synch_cs);
4544 if (shutting_down) {
4545 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4550 WaitForSingleObject (thread->suspend_event, INFINITE);
4552 EnterCriticalSection (thread->synch_cs);
4554 CloseHandle (thread->suspend_event);
4555 thread->suspend_event = NULL;
4556 thread->state &= ~ThreadState_Suspended;
4558 /* The thread that requested the resume will have replaced this event
4559 * and will be waiting for it
4561 SetEvent (thread->resume_event);
4563 LeaveCriticalSection (thread->synch_cs);
4567 transition_to_suspended (thread);
4568 mono_thread_info_self_suspend ();
4571 /*This is called with @thread synch_cs held and it must release it*/
4573 resume_thread_internal (MonoInternalThread *thread)
4575 if (!mono_thread_info_new_interrupt_enabled ()) {
4576 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4577 if (thread->resume_event == NULL) {
4578 LeaveCriticalSection (thread->synch_cs);
4582 /* Awake the thread */
4583 SetEvent (thread->suspend_event);
4585 LeaveCriticalSection (thread->synch_cs);
4587 /* Wait for the thread to awake */
4588 WaitForSingleObject (thread->resume_event, INFINITE);
4589 CloseHandle (thread->resume_event);
4590 thread->resume_event = NULL;
4594 LeaveCriticalSection (thread->synch_cs);
4595 /* Awake the thread */
4596 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4598 EnterCriticalSection (thread->synch_cs);
4599 thread->state &= ~ThreadState_Suspended;
4600 LeaveCriticalSection (thread->synch_cs);