2 * threads.c: Thread support internal calls
5 * Dick Porter (dick@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
20 #if defined(__OpenBSD__) || defined(__FreeBSD__)
22 #include <pthread_np.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/domain-internals.h>
27 #include <mono/metadata/profiler-private.h>
28 #include <mono/metadata/threads.h>
29 #include <mono/metadata/threadpool.h>
30 #include <mono/metadata/threads-types.h>
31 #include <mono/metadata/exception.h>
32 #include <mono/metadata/environment.h>
33 #include <mono/metadata/monitor.h>
34 #include <mono/metadata/gc-internal.h>
35 #include <mono/metadata/marshal.h>
36 #include <mono/metadata/runtime.h>
37 #include <mono/io-layer/io-layer.h>
39 #include <mono/io-layer/threads.h>
41 #include <mono/metadata/object-internals.h>
42 #include <mono/metadata/mono-debug-debugger.h>
43 #include <mono/utils/mono-compiler.h>
44 #include <mono/utils/mono-mmap.h>
45 #include <mono/utils/mono-membar.h>
46 #include <mono/utils/mono-time.h>
47 #include <mono/utils/mono-threads.h>
48 #include <mono/utils/hazard-pointer.h>
49 #include <mono/utils/mono-tls.h>
51 #include <mono/metadata/gc-internal.h>
53 #ifdef PLATFORM_ANDROID
56 extern int tkill (pid_t tid, int signal);
59 #if defined(PLATFORM_MACOSX) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
60 void *pthread_get_stackaddr_np(pthread_t);
61 size_t pthread_get_stacksize_np(pthread_t);
64 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_DEBUG(a)
66 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
67 #define THREAD_WAIT_DEBUG(a)
68 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
69 #define LIBGC_DEBUG(a)
71 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
72 #define SPIN_LOCK(i) do { \
73 if (SPIN_TRYLOCK (i)) \
77 #define SPIN_UNLOCK(i) i = 0
79 /* Provide this for systems with glib < 2.6 */
80 #ifndef G_GSIZE_FORMAT
81 # if GLIB_SIZEOF_LONG == 8
82 # define G_GSIZE_FORMAT "lu"
84 # define G_GSIZE_FORMAT "u"
90 guint32 (*func)(void *);
106 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
107 struct _MonoThreadDomainTls {
108 MonoThreadDomainTls *next;
116 MonoThreadDomainTls *freelist;
119 /* Number of cached culture objects in the MonoThread->cached_culture_info array
120 * (per-type): we use the first NUM entries for CultureInfo and the last for
121 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
123 #define NUM_CACHED_CULTURES 4
124 #define CULTURES_START_IDX 0
125 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
127 /* Controls access to the 'threads' hash table */
128 #define mono_threads_lock() EnterCriticalSection (&threads_mutex)
129 #define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
130 static CRITICAL_SECTION threads_mutex;
132 /* Controls access to context static data */
133 #define mono_contexts_lock() EnterCriticalSection (&contexts_mutex)
134 #define mono_contexts_unlock() LeaveCriticalSection (&contexts_mutex)
135 static CRITICAL_SECTION contexts_mutex;
137 /* Holds current status of static data heap */
138 static StaticDataInfo thread_static_info;
139 static StaticDataInfo context_static_info;
141 /* The hash of existing threads (key is thread ID, value is
142 * MonoInternalThread*) that need joining before exit
144 static MonoGHashTable *threads=NULL;
147 * Threads which are starting up and they are not in the 'threads' hash yet.
148 * When handle_store is called for a thread, it will be removed from this hash table.
149 * Protected by mono_threads_lock ().
151 static MonoGHashTable *threads_starting_up = NULL;
153 /* Maps a MonoThread to its start argument */
154 /* Protected by mono_threads_lock () */
155 static MonoGHashTable *thread_start_args = NULL;
157 /* The TLS key that holds the MonoObject assigned to each thread */
158 static MonoNativeTlsKey current_object_key;
160 #ifdef MONO_HAVE_FAST_TLS
161 /* we need to use both the Tls* functions and __thread because
162 * the gc needs to see all the threads
164 MONO_FAST_TLS_DECLARE(tls_current_object);
165 #define SET_CURRENT_OBJECT(x) do { \
166 MONO_FAST_TLS_SET (tls_current_object, x); \
167 mono_native_tls_set_value (current_object_key, x); \
169 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
171 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
172 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
175 /* function called at thread start */
176 static MonoThreadStartCB mono_thread_start_cb = NULL;
178 /* function called at thread attach */
179 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
181 /* function called at thread cleanup */
182 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
184 /* function called to notify the runtime about a pending exception on the current thread */
185 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
187 /* The default stack size for each thread */
188 static guint32 default_stacksize = 0;
189 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
191 static void thread_adjust_static_data (MonoInternalThread *thread);
192 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
193 static void mono_init_static_data_info (StaticDataInfo *static_data);
194 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
195 static gboolean mono_thread_resume (MonoInternalThread* thread);
196 static void mono_thread_start (MonoThread *thread);
197 static void signal_thread_state_change (MonoInternalThread *thread);
198 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
199 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
200 static void self_suspend_internal (MonoInternalThread *thread);
201 static gboolean resume_thread_internal (MonoInternalThread *thread);
203 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
204 static void ref_stack_destroy (gpointer rs);
206 /* Spin lock for InterlockedXXX 64 bit functions */
207 #define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
208 #define mono_interlocked_unlock() LeaveCriticalSection (&interlocked_mutex)
209 static CRITICAL_SECTION interlocked_mutex;
211 /* global count of thread interruptions requested */
212 static gint32 thread_interruption_requested = 0;
214 /* Event signaled when a thread changes its background mode */
215 static HANDLE background_change_event;
217 static gboolean shutting_down = FALSE;
219 static gint32 managed_thread_id_counter = 0;
222 get_next_managed_thread_id (void)
224 return InterlockedIncrement (&managed_thread_id_counter);
228 mono_thread_get_tls_key (void)
230 return current_object_key;
234 mono_thread_get_tls_offset (void)
237 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
241 /* handle_store() and handle_remove() manage the array of threads that
242 * still need to be waited for when the main thread exits.
244 * If handle_store() returns FALSE the thread must not be started
245 * because Mono is shutting down.
247 static gboolean handle_store(MonoThread *thread)
249 mono_threads_lock ();
251 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
253 if (threads_starting_up)
254 mono_g_hash_table_remove (threads_starting_up, thread);
257 mono_threads_unlock ();
262 MONO_GC_REGISTER_ROOT_FIXED (threads);
263 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
266 /* We don't need to duplicate thread->handle, because it is
267 * only closed when the thread object is finalized by the GC.
269 g_assert (thread->internal_thread);
270 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
271 thread->internal_thread);
273 mono_threads_unlock ();
278 static gboolean handle_remove(MonoInternalThread *thread)
281 gsize tid = thread->tid;
283 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
285 mono_threads_lock ();
288 /* We have to check whether the thread object for the
289 * tid is still the same in the table because the
290 * thread might have been destroyed and the tid reused
291 * in the meantime, in which case the tid would be in
292 * the table, but with another thread object.
294 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
295 mono_g_hash_table_remove (threads, (gpointer)tid);
304 mono_threads_unlock ();
306 /* Don't close the handle here, wait for the object finalizer
307 * to do it. Otherwise, the following race condition applies:
309 * 1) Thread exits (and handle_remove() closes the handle)
311 * 2) Some other handle is reassigned the same slot
313 * 3) Another thread tries to join the first thread, and
314 * blocks waiting for the reassigned handle to be signalled
315 * (which might never happen). This is possible, because the
316 * thread calling Join() still has a reference to the first
322 static void ensure_synch_cs_set (MonoInternalThread *thread)
324 CRITICAL_SECTION *synch_cs;
326 if (thread->synch_cs != NULL) {
330 synch_cs = g_new0 (CRITICAL_SECTION, 1);
331 InitializeCriticalSection (synch_cs);
333 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
334 synch_cs, NULL) != NULL) {
335 /* Another thread must have installed this CS */
336 DeleteCriticalSection (synch_cs);
342 * NOTE: this function can be called also for threads different from the current one:
343 * make sure no code called from it will ever assume it is run on the thread that is
344 * getting cleaned up.
346 static void thread_cleanup (MonoInternalThread *thread)
348 g_assert (thread != NULL);
350 if (thread->abort_state_handle) {
351 mono_gchandle_free (thread->abort_state_handle);
352 thread->abort_state_handle = 0;
354 thread->abort_exc = NULL;
355 thread->current_appcontext = NULL;
358 * This is necessary because otherwise we might have
359 * cross-domain references which will not get cleaned up when
360 * the target domain is unloaded.
362 if (thread->cached_culture_info) {
364 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
365 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
368 ensure_synch_cs_set (thread);
370 EnterCriticalSection (thread->synch_cs);
372 thread->state |= ThreadState_Stopped;
373 thread->state &= ~ThreadState_Background;
375 LeaveCriticalSection (thread->synch_cs);
378 An interruption request has leaked to cleanup. Adjust the global counter.
380 This can happen is the abort source thread finds the abortee (this) thread
381 in unmanaged code. If this thread never trips back to managed code or check
382 the local flag it will be left set and positively unbalance the global counter.
384 Leaving the counter unbalanced will cause a performance degradation since all threads
385 will now keep checking their local flags all the time.
387 if (InterlockedExchange (&thread->interruption_requested, 0))
388 InterlockedDecrement (&thread_interruption_requested);
390 /* if the thread is not in the hash it has been removed already */
391 if (!handle_remove (thread)) {
392 /* This needs to be called even if handle_remove () fails */
393 if (mono_thread_cleanup_fn)
394 mono_thread_cleanup_fn (thread);
397 mono_release_type_locks (thread);
399 mono_profiler_thread_end (thread->tid);
401 if (thread == mono_thread_internal_current ())
402 mono_thread_pop_appdomain_ref ();
404 thread->cached_culture_info = NULL;
406 mono_free_static_data (thread->static_data, TRUE);
407 thread->static_data = NULL;
408 ref_stack_destroy (thread->appdomain_refs);
409 thread->appdomain_refs = NULL;
411 if (mono_thread_cleanup_fn)
412 mono_thread_cleanup_fn (thread);
414 if (mono_gc_is_moving ()) {
415 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
416 thread->thread_pinning_ref = NULL;
422 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
425 g_assert ((offset & 0x80000000) == 0);
426 offset &= 0x7fffffff;
427 idx = (offset >> 24) - 1;
428 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
432 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
434 static MonoClassField *current_thread_field = NULL;
438 if (!current_thread_field) {
439 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
440 g_assert (current_thread_field);
443 mono_class_vtable (domain, mono_defaults.thread_class);
444 mono_domain_lock (domain);
445 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
446 mono_domain_unlock (domain);
449 return get_thread_static_data (thread, offset);
453 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
455 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
457 g_assert (current->obj.vtable->domain == domain);
459 g_assert (!*current_thread_ptr);
460 *current_thread_ptr = current;
463 static MonoInternalThread*
464 create_internal_thread_object (void)
466 MonoVTable *vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
467 return (MonoInternalThread*)mono_gc_alloc_mature (vt);
471 create_thread_object (MonoDomain *domain)
473 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
474 return (MonoThread*)mono_gc_alloc_mature (vt);
478 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
480 MonoThread *thread = create_thread_object (domain);
481 MONO_OBJECT_SETREF (thread, internal_thread, internal);
486 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
488 MonoDomain *domain = mono_get_root_domain ();
490 if (!candidate || candidate->obj.vtable->domain != domain)
491 candidate = new_thread_with_internal (domain, thread);
492 set_current_thread_for_domain (domain, thread, candidate);
493 g_assert (!thread->root_domain_thread);
494 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
497 static guint32 WINAPI start_wrapper_internal(void *data)
499 MonoThreadInfo *info;
500 struct StartInfo *start_info=(struct StartInfo *)data;
501 guint32 (*start_func)(void *);
505 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
508 MonoInternalThread *internal = start_info->obj->internal_thread;
509 MonoObject *start_delegate = start_info->delegate;
510 MonoDomain *domain = start_info->obj->obj.vtable->domain;
512 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
514 /* We can be sure start_info->obj->tid and
515 * start_info->obj->handle have been set, because the thread
516 * was created suspended, and these values were set before the
520 info = mono_thread_info_current ();
522 internal->thread_info = info;
527 SET_CURRENT_OBJECT (internal);
529 mono_monitor_init_tls ();
531 /* Every thread references the appdomain which created it */
532 mono_thread_push_appdomain_ref (domain);
534 if (!mono_domain_set (domain, FALSE)) {
535 /* No point in raising an appdomain_unloaded exception here */
536 /* FIXME: Cleanup here */
537 mono_thread_pop_appdomain_ref ();
541 start_func = start_info->func;
542 start_arg = start_info->start_arg;
544 /* We have to do this here because mono_thread_new_init()
545 requires that root_domain_thread is set up. */
546 thread_adjust_static_data (internal);
547 init_root_domain_thread (internal, start_info->obj);
549 /* This MUST be called before any managed code can be
550 * executed, as it calls the callback function that (for the
551 * jit) sets the lmf marker.
553 mono_thread_new_init (tid, &tid, start_func);
554 internal->stack_ptr = &tid;
556 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
558 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
560 /* On 2.0 profile (and higher), set explicitly since state might have been
562 if (internal->apartment_state == ThreadApartmentState_Unknown)
563 internal->apartment_state = ThreadApartmentState_MTA;
565 mono_thread_init_apartment_state ();
567 if(internal->start_notify!=NULL) {
568 /* Let the thread that called Start() know we're
571 ReleaseSemaphore (internal->start_notify, 1, NULL);
574 mono_threads_lock ();
575 mono_g_hash_table_remove (thread_start_args, start_info->obj);
576 mono_threads_unlock ();
578 mono_thread_set_execution_context (start_info->obj->ec_to_set);
579 start_info->obj->ec_to_set = NULL;
582 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
586 * Call this after calling start_notify, since the profiler callback might want
587 * to lock the thread, and the lock is held by thread_start () which waits for
590 mono_profiler_thread_start (tid);
592 /* start_func is set only for unmanaged start functions */
594 start_func (start_arg);
597 g_assert (start_delegate != NULL);
598 args [0] = start_arg;
599 /* we may want to handle the exception here. See comment below on unhandled exceptions */
600 mono_runtime_delegate_invoke (start_delegate, args, NULL);
603 /* If the thread calls ExitThread at all, this remaining code
604 * will not be executed, but the main thread will eventually
605 * call thread_cleanup() on this thread's behalf.
608 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
610 thread_cleanup (internal);
612 /* Do any cleanup needed for apartment state. This
613 * cannot be done in thread_cleanup since thread_cleanup could be
614 * called for a thread other than the current thread.
615 * mono_thread_cleanup_apartment_state cleans up apartment
616 * for the current thead */
617 mono_thread_cleanup_apartment_state ();
619 /* Remove the reference to the thread object in the TLS data,
620 * so the thread object can be finalized. This won't be
621 * reached if the thread threw an uncaught exception, so those
622 * thread handles will stay referenced :-( (This is due to
623 * missing support for scanning thread-specific data in the
624 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
627 SET_CURRENT_OBJECT (NULL);
628 mono_domain_unset ();
633 static guint32 WINAPI start_wrapper(void *data)
637 /* Avoid scanning the frames above this frame during a GC */
638 mono_gc_set_stack_end ((void*)&dummy);
640 return start_wrapper_internal (data);
643 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
645 if (mono_thread_start_cb) {
646 mono_thread_start_cb (tid, stack_start, func);
650 void mono_threads_set_default_stacksize (guint32 stacksize)
652 default_stacksize = stacksize;
655 guint32 mono_threads_get_default_stacksize (void)
657 return default_stacksize;
661 * mono_create_thread:
663 * This is a wrapper around CreateThread which handles differences in the type of
664 * the the 'tid' argument.
666 gpointer mono_create_thread (WapiSecurityAttributes *security,
667 guint32 stacksize, WapiThreadStart start,
668 gpointer param, guint32 create, gsize *tid)
675 res = mono_threads_CreateThread (security, stacksize, start, param, create, &real_tid);
679 res = CreateThread (security, stacksize, start, param, create, tid);
686 * The thread start argument may be an object reference, and there is
687 * no ref to keep it alive when the new thread is started but not yet
688 * registered with the collector. So we store it in a GC tracked hash
691 * LOCKING: Assumes the threads lock is held.
694 register_thread_start_argument (MonoThread *thread, struct StartInfo *start_info)
696 if (thread_start_args == NULL) {
697 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
698 thread_start_args = mono_g_hash_table_new (NULL, NULL);
700 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
704 * mono_thread_create_internal:
706 * If NO_DETACH is TRUE, then the thread is not detached using pthread_detach (). This is needed to fix the race condition where waiting for a thred to exit only waits for its exit event to be
707 * signalled, which can cause shutdown crashes if the thread shutdown code accesses data already freed by the runtime shutdown.
708 * Currently, this is only used for the finalizer thread.
711 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, gboolean no_detach, guint32 stack_size)
714 MonoInternalThread *internal;
715 HANDLE thread_handle;
716 struct StartInfo *start_info;
718 guint32 create_flags;
720 thread = create_thread_object (domain);
721 internal = create_internal_thread_object ();
722 MONO_OBJECT_SETREF (thread, internal_thread, internal);
724 start_info=g_new0 (struct StartInfo, 1);
725 start_info->func = func;
726 start_info->obj = thread;
727 start_info->start_arg = arg;
729 mono_threads_lock ();
731 mono_threads_unlock ();
735 if (threads_starting_up == NULL) {
736 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
737 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
740 register_thread_start_argument (thread, start_info);
741 mono_g_hash_table_insert (threads_starting_up, thread, thread);
742 mono_threads_unlock ();
745 stack_size = default_stacksize_for_thread (internal);
747 /* Create suspended, so we can do some housekeeping before the thread
750 create_flags = CREATE_SUSPENDED;
753 create_flags |= CREATE_NO_DETACH;
755 thread_handle = mono_create_thread (NULL, stack_size, (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
757 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
758 if (thread_handle == NULL) {
759 /* The thread couldn't be created, so throw an exception */
760 mono_threads_lock ();
761 mono_g_hash_table_remove (threads_starting_up, thread);
762 mono_threads_unlock ();
764 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
768 internal->handle=thread_handle;
770 internal->apartment_state=ThreadApartmentState_Unknown;
771 internal->managed_id = get_next_managed_thread_id ();
772 if (mono_gc_is_moving ()) {
773 internal->thread_pinning_ref = internal;
774 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
777 internal->synch_cs = g_new0 (CRITICAL_SECTION, 1);
778 InitializeCriticalSection (internal->synch_cs);
780 internal->threadpool_thread = threadpool_thread;
781 if (threadpool_thread)
782 mono_thread_set_state (internal, ThreadState_Background);
784 if (handle_store (thread))
785 ResumeThread (thread_handle);
787 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
788 if (mono_check_corlib_version () == NULL)
789 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
795 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
797 mono_thread_create_internal (domain, func, arg, FALSE, FALSE, 0);
801 * mono_thread_get_stack_bounds:
803 * Return the address and size of the current threads stack. Return NULL as the
804 * stack address if the stack address cannot be determined.
807 mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
809 #if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
810 *staddr = (guint8*)pthread_get_stackaddr_np (pthread_self ());
811 *stsize = pthread_get_stacksize_np (pthread_self ());
813 /* staddr points to the start of the stack, not the end */
815 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
817 /* FIXME: simplify the mess below */
818 #elif !defined(HOST_WIN32)
820 guint8 *current = (guint8*)&attr;
822 pthread_attr_init (&attr);
823 # ifdef HAVE_PTHREAD_GETATTR_NP
824 pthread_getattr_np (pthread_self(), &attr);
826 # ifdef HAVE_PTHREAD_ATTR_GET_NP
827 pthread_attr_get_np (pthread_self(), &attr);
830 pthread_attr_getstacksize (&attr, &stsize);
831 # elif defined(__OpenBSD__)
835 rslt = pthread_stackseg_np(pthread_self(), &ss);
836 g_assert (rslt == 0);
838 *staddr = (guint8*)((size_t)ss.ss_sp - ss.ss_size);
839 *stsize = ss.ss_size;
848 # if !defined(__OpenBSD__)
849 pthread_attr_getstack (&attr, (void**)staddr, stsize);
852 g_assert ((current > *staddr) && (current < *staddr + *stsize));
855 pthread_attr_destroy (&attr);
858 *stsize = (size_t)-1;
861 /* When running under emacs, sometimes staddr is not aligned to a page size */
862 *staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
866 mono_thread_attach (MonoDomain *domain)
868 MonoInternalThread *thread;
869 MonoThread *current_thread;
870 HANDLE thread_handle;
873 if ((thread = mono_thread_internal_current ())) {
874 if (domain != mono_domain_get ())
875 mono_domain_set (domain, TRUE);
876 /* Already attached */
877 return mono_thread_current ();
880 if (!mono_gc_register_thread (&domain)) {
881 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 ());
884 thread = create_internal_thread_object ();
886 thread_handle = GetCurrentThread ();
887 g_assert (thread_handle);
889 tid=GetCurrentThreadId ();
892 * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
893 * refer to the thread from other threads for things like aborting.
895 DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle,
896 THREAD_ALL_ACCESS, TRUE, 0);
898 thread->handle=thread_handle;
900 #ifdef PLATFORM_ANDROID
901 thread->android_tid = (gpointer) gettid ();
903 thread->apartment_state=ThreadApartmentState_Unknown;
904 thread->managed_id = get_next_managed_thread_id ();
905 if (mono_gc_is_moving ()) {
906 thread->thread_pinning_ref = thread;
907 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
910 thread->stack_ptr = &tid;
912 thread->synch_cs = g_new0 (CRITICAL_SECTION, 1);
913 InitializeCriticalSection (thread->synch_cs);
915 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
917 current_thread = new_thread_with_internal (domain, thread);
919 if (!handle_store (current_thread)) {
920 /* Mono is shutting down, so just wait for the end */
925 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
927 SET_CURRENT_OBJECT (thread);
928 mono_domain_set (domain, TRUE);
930 mono_monitor_init_tls ();
932 thread_adjust_static_data (thread);
934 init_root_domain_thread (thread, current_thread);
935 if (domain != mono_get_root_domain ())
936 set_current_thread_for_domain (domain, thread, current_thread);
939 if (mono_thread_attach_cb) {
943 mono_thread_get_stack_bounds (&staddr, &stsize);
946 mono_thread_attach_cb (tid, &tid);
948 mono_thread_attach_cb (tid, staddr + stsize);
951 // FIXME: Need a separate callback
952 mono_profiler_thread_start (tid);
954 return current_thread;
958 mono_thread_detach (MonoThread *thread)
960 g_return_if_fail (thread != NULL);
962 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->internal_thread->tid));
964 mono_profiler_thread_end (thread->internal_thread->tid);
966 thread_cleanup (thread->internal_thread);
968 SET_CURRENT_OBJECT (NULL);
969 mono_domain_unset ();
971 /* Don't need to CloseHandle this thread, even though we took a
972 * reference in mono_thread_attach (), because the GC will do it
973 * when the Thread object is finalised.
980 MonoInternalThread *thread = mono_thread_internal_current ();
982 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
984 thread_cleanup (thread);
985 SET_CURRENT_OBJECT (NULL);
986 mono_domain_unset ();
988 /* we could add a callback here for embedders to use. */
989 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
990 exit (mono_environment_exitcode_get ());
995 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
997 MonoInternalThread *internal = create_internal_thread_object ();
999 internal->state = ThreadState_Unstarted;
1000 internal->apartment_state = ThreadApartmentState_Unknown;
1001 internal->managed_id = get_next_managed_thread_id ();
1003 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1006 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
1009 guint32 (*start_func)(void *);
1010 struct StartInfo *start_info;
1013 MonoInternalThread *internal;
1015 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1017 if (!this->internal_thread)
1018 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1019 internal = this->internal_thread;
1021 ensure_synch_cs_set (internal);
1023 EnterCriticalSection (internal->synch_cs);
1025 if ((internal->state & ThreadState_Unstarted) == 0) {
1026 LeaveCriticalSection (internal->synch_cs);
1027 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1031 if ((internal->state & ThreadState_Aborted) != 0) {
1032 LeaveCriticalSection (internal->synch_cs);
1037 /* This is freed in start_wrapper */
1038 start_info = g_new0 (struct StartInfo, 1);
1039 start_info->func = start_func;
1040 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1041 start_info->delegate = start;
1042 start_info->obj = this;
1043 g_assert (this->obj.vtable->domain == mono_domain_get ());
1045 internal->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
1046 if (internal->start_notify==NULL) {
1047 LeaveCriticalSection (internal->synch_cs);
1048 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
1049 g_free (start_info);
1053 mono_threads_lock ();
1054 register_thread_start_argument (this, start_info);
1055 if (threads_starting_up == NULL) {
1056 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
1057 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
1059 mono_g_hash_table_insert (threads_starting_up, this, this);
1060 mono_threads_unlock ();
1062 thread=mono_create_thread(NULL, default_stacksize_for_thread (internal), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
1063 CREATE_SUSPENDED, &tid);
1065 LeaveCriticalSection (internal->synch_cs);
1066 mono_threads_lock ();
1067 mono_g_hash_table_remove (threads_starting_up, this);
1068 mono_threads_unlock ();
1069 g_warning("%s: CreateThread error 0x%x", __func__, GetLastError());
1073 internal->handle=thread;
1075 if (mono_gc_is_moving ()) {
1076 internal->thread_pinning_ref = internal;
1077 MONO_GC_REGISTER_ROOT_PINNING (internal->thread_pinning_ref);
1081 /* Don't call handle_store() here, delay it to Start.
1082 * We can't join a thread (trying to will just block
1083 * forever) until it actually starts running, so don't
1084 * store the handle till then.
1087 mono_thread_start (this);
1089 internal->state &= ~ThreadState_Unstarted;
1091 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1093 LeaveCriticalSection (internal->synch_cs);
1098 void ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1100 MONO_ARCH_SAVE_REGS;
1102 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1105 CloseHandle (thread);
1107 if (this->synch_cs) {
1108 CRITICAL_SECTION *synch_cs = this->synch_cs;
1109 this->synch_cs = NULL;
1110 DeleteCriticalSection (synch_cs);
1115 void *name = this->name;
1121 static void mono_thread_start (MonoThread *thread)
1123 MonoInternalThread *internal = thread->internal_thread;
1125 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1127 /* Only store the handle when the thread is about to be
1128 * launched, to avoid the main thread deadlocking while trying
1129 * to clean up a thread that will never be signalled.
1131 if (!handle_store (thread))
1134 ResumeThread (internal->handle);
1136 if(internal->start_notify!=NULL) {
1137 /* Wait for the thread to set up its TLS data etc, so
1138 * theres no potential race condition if someone tries
1139 * to look up the data believing the thread has
1143 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1145 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
1146 CloseHandle (internal->start_notify);
1147 internal->start_notify = NULL;
1150 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
1153 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1156 MonoInternalThread *thread = mono_thread_internal_current ();
1158 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1160 mono_thread_current_check_pending_interrupt ();
1163 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1165 res = SleepEx(ms,TRUE);
1167 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1169 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1170 MonoException* exc = mono_thread_execute_interruption (thread);
1172 mono_raise_exception (exc);
1184 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1189 ves_icall_System_Threading_Thread_GetDomainID (void)
1191 MONO_ARCH_SAVE_REGS;
1193 return mono_domain_get()->domain_id;
1197 ves_icall_System_Threading_Thread_Yield (void)
1200 return SwitchToThread ();
1202 return sched_yield () == 0;
1207 * mono_thread_get_name:
1209 * Return the name of the thread. NAME_LEN is set to the length of the name.
1210 * Return NULL if the thread has no name. The returned memory is owned by the
1214 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1218 ensure_synch_cs_set (this_obj);
1220 EnterCriticalSection (this_obj->synch_cs);
1222 if (!this_obj->name) {
1226 *name_len = this_obj->name_len;
1227 res = g_new (gunichar2, this_obj->name_len);
1228 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1231 LeaveCriticalSection (this_obj->synch_cs);
1237 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1241 ensure_synch_cs_set (this_obj);
1243 EnterCriticalSection (this_obj->synch_cs);
1245 if (!this_obj->name)
1248 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1250 LeaveCriticalSection (this_obj->synch_cs);
1256 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1258 ensure_synch_cs_set (this_obj);
1260 EnterCriticalSection (this_obj->synch_cs);
1262 if (this_obj->flags & MONO_THREAD_FLAG_NAME_SET) {
1263 LeaveCriticalSection (this_obj->synch_cs);
1265 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1269 this_obj->name = g_new (gunichar2, mono_string_length (name));
1270 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1271 this_obj->name_len = mono_string_length (name);
1274 this_obj->name = NULL;
1277 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1279 LeaveCriticalSection (this_obj->synch_cs);
1280 if (this_obj->name) {
1281 char *tname = mono_string_to_utf8 (name);
1282 mono_profiler_thread_name (this_obj->tid, tname);
1288 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1290 mono_thread_set_name_internal (this_obj, name, TRUE);
1293 /* If the array is already in the requested domain, we just return it,
1294 otherwise we return a copy in that domain. */
1296 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1303 if (mono_object_domain (arr) == domain)
1306 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1307 mono_gc_memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1312 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1314 return byte_array_to_domain (arr, mono_get_root_domain ());
1318 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1320 return byte_array_to_domain (arr, mono_domain_get ());
1324 mono_thread_current (void)
1326 MonoDomain *domain = mono_domain_get ();
1327 MonoInternalThread *internal = mono_thread_internal_current ();
1328 MonoThread **current_thread_ptr;
1330 g_assert (internal);
1331 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1333 if (!*current_thread_ptr) {
1334 g_assert (domain != mono_get_root_domain ());
1335 *current_thread_ptr = new_thread_with_internal (domain, internal);
1337 return *current_thread_ptr;
1341 mono_thread_internal_current (void)
1343 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1344 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1348 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1349 int ms, HANDLE thread)
1351 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1354 mono_thread_current_check_pending_interrupt ();
1356 ensure_synch_cs_set (this);
1358 EnterCriticalSection (this->synch_cs);
1360 if ((this->state & ThreadState_Unstarted) != 0) {
1361 LeaveCriticalSection (this->synch_cs);
1363 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1367 LeaveCriticalSection (this->synch_cs);
1372 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1374 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1376 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1378 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1380 if(ret==WAIT_OBJECT_0) {
1381 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1386 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1392 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1400 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1403 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1405 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1407 if (ret != WAIT_IO_COMPLETION)
1410 exc = mono_thread_execute_interruption (thread);
1412 mono_raise_exception (exc);
1417 /* Re-calculate ms according to the time passed */
1418 diff_ms = (mono_100ns_ticks () - start) / 10000;
1419 if (diff_ms >= ms) {
1423 wait = ms - diff_ms;
1429 /* FIXME: exitContext isnt documented */
1430 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1436 MonoObject *waitHandle;
1437 MonoInternalThread *thread = mono_thread_internal_current ();
1439 /* Do this WaitSleepJoin check before creating objects */
1440 mono_thread_current_check_pending_interrupt ();
1442 numhandles = mono_array_length(mono_handles);
1443 handles = g_new0(HANDLE, numhandles);
1445 for(i = 0; i < numhandles; i++) {
1446 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1447 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1454 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1456 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1458 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1462 if(ret==WAIT_FAILED) {
1463 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1465 } else if(ret==WAIT_TIMEOUT) {
1466 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1473 /* FIXME: exitContext isnt documented */
1474 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1476 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1480 MonoObject *waitHandle;
1481 MonoInternalThread *thread = mono_thread_internal_current ();
1483 /* Do this WaitSleepJoin check before creating objects */
1484 mono_thread_current_check_pending_interrupt ();
1486 numhandles = mono_array_length(mono_handles);
1487 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1490 for(i = 0; i < numhandles; i++) {
1491 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1492 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1499 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1501 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1503 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1505 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1508 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1510 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1511 return ret - WAIT_OBJECT_0;
1513 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1514 return ret - WAIT_ABANDONED_0;
1521 /* FIXME: exitContext isnt documented */
1522 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1525 MonoInternalThread *thread = mono_thread_internal_current ();
1527 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1533 mono_thread_current_check_pending_interrupt ();
1535 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1537 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1539 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1541 if(ret==WAIT_FAILED) {
1542 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1544 } else if(ret==WAIT_TIMEOUT) {
1545 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1553 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1556 MonoInternalThread *thread = mono_thread_internal_current ();
1558 MONO_ARCH_SAVE_REGS;
1563 mono_thread_current_check_pending_interrupt ();
1565 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1567 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1569 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1571 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1574 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1578 MONO_ARCH_SAVE_REGS;
1583 mutex = CreateMutex (NULL, owned, NULL);
1585 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1587 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1595 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1596 MONO_ARCH_SAVE_REGS;
1598 return(ReleaseMutex (handle));
1601 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1607 MONO_ARCH_SAVE_REGS;
1609 *error = ERROR_SUCCESS;
1611 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1613 *error = GetLastError ();
1620 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1624 MONO_ARCH_SAVE_REGS;
1629 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1631 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1632 mono_string_chars (name));
1634 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1642 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1646 MONO_ARCH_SAVE_REGS;
1648 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1653 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1657 MONO_ARCH_SAVE_REGS;
1659 *error = ERROR_SUCCESS;
1661 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1663 *error = GetLastError ();
1669 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1673 MONO_ARCH_SAVE_REGS;
1678 event = CreateEvent (NULL, manual, initial, NULL);
1680 event = CreateEvent (NULL, manual, initial,
1681 mono_string_chars (name));
1683 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1691 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1692 MONO_ARCH_SAVE_REGS;
1694 return (SetEvent(handle));
1697 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1698 MONO_ARCH_SAVE_REGS;
1700 return (ResetEvent(handle));
1704 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1705 MONO_ARCH_SAVE_REGS;
1707 CloseHandle (handle);
1710 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1716 MONO_ARCH_SAVE_REGS;
1718 *error = ERROR_SUCCESS;
1720 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1722 *error = GetLastError ();
1728 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1730 MONO_ARCH_SAVE_REGS;
1732 return InterlockedIncrement (location);
1735 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1739 MONO_ARCH_SAVE_REGS;
1741 mono_interlocked_lock ();
1745 mono_interlocked_unlock ();
1751 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1753 MONO_ARCH_SAVE_REGS;
1755 return InterlockedDecrement(location);
1758 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1762 MONO_ARCH_SAVE_REGS;
1764 mono_interlocked_lock ();
1768 mono_interlocked_unlock ();
1773 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1775 MONO_ARCH_SAVE_REGS;
1777 return InterlockedExchange(location, value);
1780 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1783 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1784 mono_gc_wbarrier_generic_nostore (location);
1788 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1790 return InterlockedExchangePointer(location, value);
1793 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1795 IntFloatUnion val, ret;
1797 MONO_ARCH_SAVE_REGS;
1800 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1806 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1808 #if SIZEOF_VOID_P == 8
1809 return (gint64) InterlockedExchangePointer((gpointer *) location, (gpointer)value);
1814 * According to MSDN, this function is only atomic with regards to the
1815 * other Interlocked functions on 32 bit platforms.
1817 mono_interlocked_lock ();
1820 mono_interlocked_unlock ();
1827 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1829 #if SIZEOF_VOID_P == 8
1830 LongDoubleUnion val, ret;
1833 ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location, (gpointer)val.ival);
1840 * According to MSDN, this function is only atomic with regards to the
1841 * other Interlocked functions on 32 bit platforms.
1843 mono_interlocked_lock ();
1846 mono_interlocked_unlock ();
1852 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1854 MONO_ARCH_SAVE_REGS;
1856 return InterlockedCompareExchange(location, value, comparand);
1859 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1862 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1863 mono_gc_wbarrier_generic_nostore (location);
1867 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1869 return InterlockedCompareExchangePointer(location, value, comparand);
1872 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1874 IntFloatUnion val, ret, cmp;
1876 MONO_ARCH_SAVE_REGS;
1879 cmp.fval = comparand;
1880 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1886 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1888 #if SIZEOF_VOID_P == 8
1889 LongDoubleUnion val, comp, ret;
1892 comp.fval = comparand;
1893 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1899 mono_interlocked_lock ();
1901 if (old == comparand)
1903 mono_interlocked_unlock ();
1910 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1912 #if SIZEOF_VOID_P == 8
1913 return (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)value, (gpointer)comparand);
1917 mono_interlocked_lock ();
1919 if (old == comparand)
1921 mono_interlocked_unlock ();
1928 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1931 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1932 mono_gc_wbarrier_generic_nostore (location);
1937 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1940 res = InterlockedExchangePointer ((gpointer *)location, value);
1941 mono_gc_wbarrier_generic_nostore (location);
1946 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1948 #if SIZEOF_VOID_P == 8
1949 /* Should be implemented as a JIT intrinsic */
1950 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1955 mono_interlocked_lock ();
1957 *location = orig + value;
1958 mono_interlocked_unlock ();
1960 return orig + value;
1965 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1967 #if SIZEOF_VOID_P == 8
1968 /* Should be implemented as a JIT intrinsic */
1969 mono_raise_exception (mono_get_exception_not_implemented (NULL));
1974 mono_interlocked_lock ();
1976 *location = orig + value;
1977 mono_interlocked_unlock ();
1979 return orig + value;
1984 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1986 #if SIZEOF_VOID_P == 8
1987 /* 64 bit reads are already atomic */
1992 mono_interlocked_lock ();
1994 mono_interlocked_unlock ();
2001 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2003 mono_threads_lock ();
2004 mono_threads_unlock ();
2008 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
2010 mono_thread_clr_state (this, state);
2012 if (state & ThreadState_Background) {
2013 /* If the thread changes the background mode, the main thread has to
2014 * be notified, since it has to rebuild the list of threads to
2017 SetEvent (background_change_event);
2022 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
2024 mono_thread_set_state (this, state);
2026 if (state & ThreadState_Background) {
2027 /* If the thread changes the background mode, the main thread has to
2028 * be notified, since it has to rebuild the list of threads to
2031 SetEvent (background_change_event);
2036 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
2040 ensure_synch_cs_set (this);
2042 EnterCriticalSection (this->synch_cs);
2044 state = this->state;
2046 LeaveCriticalSection (this->synch_cs);
2051 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
2053 MonoInternalThread *current;
2056 ensure_synch_cs_set (this);
2058 current = mono_thread_internal_current ();
2060 EnterCriticalSection (this->synch_cs);
2062 this->thread_interrupt_requested = TRUE;
2063 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
2065 LeaveCriticalSection (this->synch_cs);
2068 abort_thread_internal (this, TRUE, FALSE);
2072 void mono_thread_current_check_pending_interrupt ()
2074 MonoInternalThread *thread = mono_thread_internal_current ();
2075 gboolean throw = FALSE;
2077 mono_debugger_check_interruption ();
2079 ensure_synch_cs_set (thread);
2081 EnterCriticalSection (thread->synch_cs);
2083 if (thread->thread_interrupt_requested) {
2085 thread->thread_interrupt_requested = FALSE;
2088 LeaveCriticalSection (thread->synch_cs);
2091 mono_raise_exception (mono_get_exception_thread_interrupted ());
2096 mono_thread_get_abort_signal (void)
2100 #elif defined(PLATFORM_ANDROID)
2102 #elif !defined (SIGRTMIN)
2107 #endif /* SIGUSR1 */
2109 static int abort_signum = -1;
2111 if (abort_signum != -1)
2112 return abort_signum;
2113 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2114 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2115 struct sigaction sinfo;
2116 sigaction (i, NULL, &sinfo);
2117 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2122 /* fallback to the old way */
2124 #endif /* HOST_WIN32 */
2128 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2130 MonoException* exc = mono_thread_request_interruption (FALSE);
2131 if (exc) mono_raise_exception (exc);
2133 #endif /* HOST_WIN32 */
2136 * signal_thread_state_change
2138 * Tells the thread that his state has changed and it has to enter the new
2139 * state as soon as possible.
2141 static void signal_thread_state_change (MonoInternalThread *thread)
2143 if (thread == mono_thread_internal_current ()) {
2144 /* Do it synchronously */
2145 MonoException *exc = mono_thread_request_interruption (FALSE);
2147 mono_raise_exception (exc);
2151 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
2153 /* fixme: store the state somewhere */
2154 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2157 * This will cause waits to be broken.
2158 * It will also prevent the thread from entering a wait, so if the thread returns
2159 * from the wait before it receives the abort signal, it will just spin in the wait
2160 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2163 wapi_interrupt_thread (thread->handle);
2164 #endif /* HOST_WIN32 */
2168 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2170 ensure_synch_cs_set (thread);
2172 EnterCriticalSection (thread->synch_cs);
2174 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2175 (thread->state & ThreadState_StopRequested) != 0 ||
2176 (thread->state & ThreadState_Stopped) != 0)
2178 LeaveCriticalSection (thread->synch_cs);
2182 if ((thread->state & ThreadState_Unstarted) != 0) {
2183 thread->state |= ThreadState_Aborted;
2184 LeaveCriticalSection (thread->synch_cs);
2188 thread->state |= ThreadState_AbortRequested;
2189 if (thread->abort_state_handle)
2190 mono_gchandle_free (thread->abort_state_handle);
2192 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2193 g_assert (thread->abort_state_handle);
2195 thread->abort_state_handle = 0;
2197 thread->abort_exc = NULL;
2200 * abort_exc is set in mono_thread_execute_interruption(),
2201 * triggered by the call to signal_thread_state_change(),
2202 * below. There's a point between where we have
2203 * abort_state_handle set, but abort_exc NULL, but that's not
2207 LeaveCriticalSection (thread->synch_cs);
2209 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2211 /* During shutdown, we can't wait for other threads */
2213 /* Make sure the thread is awake */
2214 mono_thread_resume (thread);
2216 abort_thread_internal (thread, TRUE, TRUE);
2220 ves_icall_System_Threading_Thread_ResetAbort (void)
2222 MonoInternalThread *thread = mono_thread_internal_current ();
2223 gboolean was_aborting;
2225 ensure_synch_cs_set (thread);
2227 EnterCriticalSection (thread->synch_cs);
2228 was_aborting = thread->state & ThreadState_AbortRequested;
2229 thread->state &= ~ThreadState_AbortRequested;
2230 LeaveCriticalSection (thread->synch_cs);
2232 if (!was_aborting) {
2233 const char *msg = "Unable to reset abort because no abort was requested";
2234 mono_raise_exception (mono_get_exception_thread_state (msg));
2236 thread->abort_exc = NULL;
2237 if (thread->abort_state_handle) {
2238 mono_gchandle_free (thread->abort_state_handle);
2239 /* This is actually not necessary - the handle
2240 only counts if the exception is set */
2241 thread->abort_state_handle = 0;
2246 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2248 ensure_synch_cs_set (thread);
2250 EnterCriticalSection (thread->synch_cs);
2252 thread->state &= ~ThreadState_AbortRequested;
2254 if (thread->abort_exc) {
2255 thread->abort_exc = NULL;
2256 if (thread->abort_state_handle) {
2257 mono_gchandle_free (thread->abort_state_handle);
2258 /* This is actually not necessary - the handle
2259 only counts if the exception is set */
2260 thread->abort_state_handle = 0;
2264 LeaveCriticalSection (thread->synch_cs);
2268 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2270 MonoInternalThread *thread = this->internal_thread;
2271 MonoObject *state, *deserialized = NULL, *exc;
2274 if (!thread->abort_state_handle)
2277 state = mono_gchandle_get_target (thread->abort_state_handle);
2280 domain = mono_domain_get ();
2281 if (mono_object_domain (state) == domain)
2284 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2286 if (!deserialized) {
2287 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2289 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2290 mono_raise_exception (invalid_op_exc);
2293 return deserialized;
2297 mono_thread_suspend (MonoInternalThread *thread)
2299 ensure_synch_cs_set (thread);
2301 EnterCriticalSection (thread->synch_cs);
2303 if ((thread->state & ThreadState_Unstarted) != 0 ||
2304 (thread->state & ThreadState_Aborted) != 0 ||
2305 (thread->state & ThreadState_Stopped) != 0)
2307 LeaveCriticalSection (thread->synch_cs);
2311 if ((thread->state & ThreadState_Suspended) != 0 ||
2312 (thread->state & ThreadState_SuspendRequested) != 0 ||
2313 (thread->state & ThreadState_StopRequested) != 0)
2315 LeaveCriticalSection (thread->synch_cs);
2319 thread->state |= ThreadState_SuspendRequested;
2321 LeaveCriticalSection (thread->synch_cs);
2323 suspend_thread_internal (thread, FALSE);
2328 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2330 if (!mono_thread_suspend (thread))
2331 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2335 mono_thread_resume (MonoInternalThread *thread)
2337 ensure_synch_cs_set (thread);
2339 EnterCriticalSection (thread->synch_cs);
2341 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2342 thread->state &= ~ThreadState_SuspendRequested;
2343 LeaveCriticalSection (thread->synch_cs);
2347 if ((thread->state & ThreadState_Suspended) == 0 ||
2348 (thread->state & ThreadState_Unstarted) != 0 ||
2349 (thread->state & ThreadState_Aborted) != 0 ||
2350 (thread->state & ThreadState_Stopped) != 0)
2352 LeaveCriticalSection (thread->synch_cs);
2356 return resume_thread_internal (thread);
2360 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2362 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2363 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2367 mono_threads_is_critical_method (MonoMethod *method)
2369 switch (method->wrapper_type) {
2370 case MONO_WRAPPER_RUNTIME_INVOKE:
2371 case MONO_WRAPPER_XDOMAIN_INVOKE:
2372 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2379 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2384 if (mono_threads_is_critical_method (m)) {
2385 *((gboolean*)data) = TRUE;
2392 is_running_protected_wrapper (void)
2394 gboolean found = FALSE;
2395 mono_stack_walk (find_wrapper, &found);
2399 void mono_thread_internal_stop (MonoInternalThread *thread)
2401 ensure_synch_cs_set (thread);
2403 EnterCriticalSection (thread->synch_cs);
2405 if ((thread->state & ThreadState_StopRequested) != 0 ||
2406 (thread->state & ThreadState_Stopped) != 0)
2408 LeaveCriticalSection (thread->synch_cs);
2412 /* Make sure the thread is awake */
2413 mono_thread_resume (thread);
2415 thread->state |= ThreadState_StopRequested;
2416 thread->state &= ~ThreadState_AbortRequested;
2418 LeaveCriticalSection (thread->synch_cs);
2420 abort_thread_internal (thread, TRUE, TRUE);
2423 void mono_thread_stop (MonoThread *thread)
2425 mono_thread_internal_stop (thread->internal_thread);
2429 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2431 return *((volatile gint8 *) (ptr));
2435 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2437 return *((volatile gint16 *) (ptr));
2441 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2443 return *((volatile gint32 *) (ptr));
2447 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2449 return *((volatile gint64 *) (ptr));
2453 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2455 return (void *) *((volatile void **) ptr);
2459 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2461 return *((volatile double *) (ptr));
2465 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2467 return *((volatile float *) (ptr));
2471 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2473 return (MonoObject*)*((volatile MonoObject**)ptr);
2477 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2479 *((volatile gint8 *) ptr) = value;
2483 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2485 *((volatile gint16 *) ptr) = value;
2489 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2491 *((volatile gint32 *) ptr) = value;
2495 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2497 *((volatile gint64 *) ptr) = value;
2501 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2503 *((volatile void **) ptr) = value;
2507 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, void *value)
2509 mono_gc_wbarrier_generic_store (ptr, value);
2513 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2515 *((volatile double *) ptr) = value;
2519 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2521 *((volatile float *) ptr) = value;
2525 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2527 *((volatile MonoObject **) ptr) = value;
2528 mono_gc_wbarrier_generic_nostore (ptr);
2531 void mono_thread_init (MonoThreadStartCB start_cb,
2532 MonoThreadAttachCB attach_cb)
2534 InitializeCriticalSection(&threads_mutex);
2535 InitializeCriticalSection(&interlocked_mutex);
2536 InitializeCriticalSection(&contexts_mutex);
2538 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2539 g_assert(background_change_event != NULL);
2541 mono_init_static_data_info (&thread_static_info);
2542 mono_init_static_data_info (&context_static_info);
2544 MONO_FAST_TLS_INIT (tls_current_object);
2545 mono_native_tls_alloc (¤t_object_key, NULL);
2546 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2548 mono_thread_start_cb = start_cb;
2549 mono_thread_attach_cb = attach_cb;
2551 /* Get a pseudo handle to the current process. This is just a
2552 * kludge so that wapi can build a process handle if needed.
2553 * As a pseudo handle is returned, we don't need to clean
2556 GetCurrentProcess ();
2559 void mono_thread_cleanup (void)
2561 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2562 /* The main thread must abandon any held mutexes (particularly
2563 * important for named mutexes as they are shared across
2564 * processes, see bug 74680.) This will happen when the
2565 * thread exits, but if it's not running in a subthread it
2566 * won't exit in time.
2568 /* Using non-w32 API is a nasty kludge, but I couldn't find
2569 * anything in the documentation that would let me do this
2570 * here yet still be safe to call on windows.
2572 _wapi_thread_signal_self (mono_environment_exitcode_get ());
2576 /* This stuff needs more testing, it seems one of these
2577 * critical sections can be locked when mono_thread_cleanup is
2580 DeleteCriticalSection (&threads_mutex);
2581 DeleteCriticalSection (&interlocked_mutex);
2582 DeleteCriticalSection (&contexts_mutex);
2583 DeleteCriticalSection (&delayed_free_table_mutex);
2584 DeleteCriticalSection (&small_id_mutex);
2585 CloseHandle (background_change_event);
2588 mono_native_tls_free (current_object_key);
2592 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2594 mono_thread_cleanup_fn = func;
2598 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2600 thread->internal_thread->manage_callback = func;
2603 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2605 mono_thread_notify_pending_exc_fn = func;
2609 static void print_tids (gpointer key, gpointer value, gpointer user)
2611 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2612 * sizeof(uint) and a cast to uint would overflow
2614 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2615 * print this as a pointer.
2617 g_message ("Waiting for: %p", key);
2622 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2623 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2627 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2631 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2633 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2635 if(ret==WAIT_FAILED) {
2636 /* See the comment in build_wait_tids() */
2637 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2641 for(i=0; i<wait->num; i++)
2642 CloseHandle (wait->handles[i]);
2644 if (ret == WAIT_TIMEOUT)
2647 for(i=0; i<wait->num; i++) {
2648 gsize tid = wait->threads[i]->tid;
2650 mono_threads_lock ();
2651 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2652 /* This thread must have been killed, because
2653 * it hasn't cleaned itself up. (It's just
2654 * possible that the thread exited before the
2655 * parent thread had a chance to store the
2656 * handle, and now there is another pointer to
2657 * the already-exited thread stored. In this
2658 * case, we'll just get two
2659 * mono_profiler_thread_end() calls for the
2663 mono_threads_unlock ();
2664 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2665 thread_cleanup (wait->threads[i]);
2667 mono_threads_unlock ();
2672 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2674 guint32 i, ret, count;
2676 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2678 /* Add the thread state change event, so it wakes up if a thread changes
2679 * to background mode.
2682 if (count < MAXIMUM_WAIT_OBJECTS) {
2683 wait->handles [count] = background_change_event;
2687 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2689 if(ret==WAIT_FAILED) {
2690 /* See the comment in build_wait_tids() */
2691 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2695 for(i=0; i<wait->num; i++)
2696 CloseHandle (wait->handles[i]);
2698 if (ret == WAIT_TIMEOUT)
2701 if (ret < wait->num) {
2702 gsize tid = wait->threads[ret]->tid;
2703 mono_threads_lock ();
2704 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2705 /* See comment in wait_for_tids about thread cleanup */
2706 mono_threads_unlock ();
2707 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2708 thread_cleanup (wait->threads [ret]);
2710 mono_threads_unlock ();
2714 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2716 struct wait_data *wait=(struct wait_data *)user;
2718 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2720 MonoInternalThread *thread=(MonoInternalThread *)value;
2722 /* Ignore background threads, we abort them later */
2723 /* Do not lock here since it is not needed and the caller holds threads_lock */
2724 if (thread->state & ThreadState_Background) {
2725 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2726 return; /* just leave, ignore */
2729 if (mono_gc_is_finalizer_internal_thread (thread)) {
2730 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2734 if (thread == mono_thread_internal_current ()) {
2735 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2739 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2740 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2744 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2745 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2749 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2750 if (handle == NULL) {
2751 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2755 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2756 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2757 wait->handles[wait->num]=handle;
2758 wait->threads[wait->num]=thread;
2761 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2763 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2768 /* Just ignore the rest, we can't do anything with
2775 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2777 struct wait_data *wait=(struct wait_data *)user;
2778 gsize self = GetCurrentThreadId ();
2779 MonoInternalThread *thread = value;
2782 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2785 /* The finalizer thread is not a background thread */
2786 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2787 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2789 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2793 /* printf ("A: %d\n", wait->num); */
2794 wait->handles[wait->num]=thread->handle;
2795 wait->threads[wait->num]=thread;
2798 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2799 mono_thread_internal_stop (thread);
2803 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2807 * mono_threads_set_shutting_down:
2809 * Is called by a thread that wants to shut down Mono. If the runtime is already
2810 * shutting down, the calling thread is suspended/stopped, and this function never
2814 mono_threads_set_shutting_down (void)
2816 MonoInternalThread *current_thread = mono_thread_internal_current ();
2818 mono_threads_lock ();
2820 if (shutting_down) {
2821 mono_threads_unlock ();
2823 /* Make sure we're properly suspended/stopped */
2825 EnterCriticalSection (current_thread->synch_cs);
2827 if ((current_thread->state & ThreadState_SuspendRequested) ||
2828 (current_thread->state & ThreadState_AbortRequested) ||
2829 (current_thread->state & ThreadState_StopRequested)) {
2830 LeaveCriticalSection (current_thread->synch_cs);
2831 mono_thread_execute_interruption (current_thread);
2833 current_thread->state |= ThreadState_Stopped;
2834 LeaveCriticalSection (current_thread->synch_cs);
2837 /*since we're killing the thread, unset the current domain.*/
2838 mono_domain_unset ();
2840 /* Wake up other threads potentially waiting for us */
2843 shutting_down = TRUE;
2845 /* Not really a background state change, but this will
2846 * interrupt the main thread if it is waiting for all
2847 * the other threads.
2849 SetEvent (background_change_event);
2851 mono_threads_unlock ();
2856 * mono_threads_is_shutting_down:
2858 * Returns whether a thread has commenced shutdown of Mono. Note that
2859 * if the function returns FALSE the caller must not assume that
2860 * shutdown is not in progress, because the situation might have
2861 * changed since the function returned. For that reason this function
2862 * is of very limited utility.
2865 mono_threads_is_shutting_down (void)
2867 return shutting_down;
2870 void mono_thread_manage (void)
2872 struct wait_data wait_data;
2873 struct wait_data *wait = &wait_data;
2875 memset (wait, 0, sizeof (struct wait_data));
2876 /* join each thread that's still running */
2877 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2879 mono_threads_lock ();
2881 THREAD_DEBUG (g_message("%s: No threads", __func__));
2882 mono_threads_unlock ();
2885 mono_threads_unlock ();
2888 mono_threads_lock ();
2889 if (shutting_down) {
2890 /* somebody else is shutting down */
2891 mono_threads_unlock ();
2894 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2895 mono_g_hash_table_foreach (threads, print_tids, NULL));
2897 ResetEvent (background_change_event);
2899 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2900 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2901 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2902 mono_threads_unlock ();
2904 /* Something to wait for */
2905 wait_for_tids_or_state_change (wait, INFINITE);
2907 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2908 } while(wait->num>0);
2910 #ifndef MONO_CROSS_COMPILE
2911 mono_runtime_shutdown ();
2914 mono_threads_set_shutting_down ();
2916 /* No new threads will be created after this point */
2918 mono_runtime_set_shutting_down ();
2920 THREAD_DEBUG (g_message ("%s: threadpool cleanup", __func__));
2921 mono_thread_pool_cleanup ();
2924 * Remove everything but the finalizer thread and self.
2925 * Also abort all the background threads
2928 mono_threads_lock ();
2931 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2932 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2933 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2935 mono_threads_unlock ();
2937 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2939 /* Something to wait for */
2940 wait_for_tids (wait, INFINITE);
2942 } while (wait->num > 0);
2945 * give the subthreads a chance to really quit (this is mainly needed
2946 * to get correct user and system times from getrusage/wait/time(1)).
2947 * This could be removed if we avoid pthread_detach() and use pthread_join().
2954 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2956 MonoInternalThread *thread=(MonoInternalThread *)value;
2958 if(thread->tid != (gsize)user) {
2959 /*TerminateThread (thread->handle, -1);*/
2963 void mono_thread_abort_all_other_threads (void)
2965 gsize self = GetCurrentThreadId ();
2967 mono_threads_lock ();
2968 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2969 mono_g_hash_table_size (threads));
2970 mono_g_hash_table_foreach (threads, print_tids, NULL));
2972 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2974 mono_threads_unlock ();
2978 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2980 MonoInternalThread *thread = (MonoInternalThread*)value;
2981 struct wait_data *wait = (struct wait_data*)user_data;
2985 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
2987 * This needs no locking.
2989 if ((thread->state & ThreadState_Suspended) != 0 ||
2990 (thread->state & ThreadState_Stopped) != 0)
2993 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2994 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2998 wait->handles [wait->num] = handle;
2999 wait->threads [wait->num] = thread;
3005 * mono_thread_suspend_all_other_threads:
3007 * Suspend all managed threads except the finalizer thread and this thread. It is
3008 * not possible to resume them later.
3010 void mono_thread_suspend_all_other_threads (void)
3012 struct wait_data wait_data;
3013 struct wait_data *wait = &wait_data;
3015 gsize self = GetCurrentThreadId ();
3017 guint32 eventidx = 0;
3018 gboolean starting, finished;
3020 memset (wait, 0, sizeof (struct wait_data));
3022 * The other threads could be in an arbitrary state at this point, i.e.
3023 * they could be starting up, shutting down etc. This means that there could be
3024 * threads which are not even in the threads hash table yet.
3028 * First we set a barrier which will be checked by all threads before they
3029 * are added to the threads hash table, and they will exit if the flag is set.
3030 * This ensures that no threads could be added to the hash later.
3031 * We will use shutting_down as the barrier for now.
3033 g_assert (shutting_down);
3036 * We make multiple calls to WaitForMultipleObjects since:
3037 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3038 * - some threads could exit without becoming suspended
3043 * Make a copy of the hashtable since we can't do anything with
3044 * threads while threads_mutex is held.
3047 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3048 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3049 mono_threads_lock ();
3050 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3051 mono_threads_unlock ();
3053 events = g_new0 (gpointer, wait->num);
3055 /* Get the suspended events that we'll be waiting for */
3056 for (i = 0; i < wait->num; ++i) {
3057 MonoInternalThread *thread = wait->threads [i];
3058 gboolean signal_suspend = FALSE;
3060 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3061 //CloseHandle (wait->handles [i]);
3062 wait->threads [i] = NULL; /* ignore this thread in next loop */
3066 ensure_synch_cs_set (thread);
3068 EnterCriticalSection (thread->synch_cs);
3070 if (thread->suspended_event == NULL) {
3071 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3072 if (thread->suspended_event == NULL) {
3073 /* Forget this one and go on to the next */
3074 LeaveCriticalSection (thread->synch_cs);
3079 if ((thread->state & ThreadState_Suspended) != 0 ||
3080 (thread->state & ThreadState_StopRequested) != 0 ||
3081 (thread->state & ThreadState_Stopped) != 0) {
3082 LeaveCriticalSection (thread->synch_cs);
3083 CloseHandle (wait->handles [i]);
3084 wait->threads [i] = NULL; /* ignore this thread in next loop */
3088 if ((thread->state & ThreadState_SuspendRequested) == 0)
3089 signal_suspend = TRUE;
3091 events [eventidx++] = thread->suspended_event;
3093 /* Convert abort requests into suspend requests */
3094 if ((thread->state & ThreadState_AbortRequested) != 0)
3095 thread->state &= ~ThreadState_AbortRequested;
3097 thread->state |= ThreadState_SuspendRequested;
3099 LeaveCriticalSection (thread->synch_cs);
3101 /* Signal the thread to suspend */
3102 if (mono_thread_info_new_interrupt_enabled ())
3103 suspend_thread_internal (thread, TRUE);
3104 else if (signal_suspend)
3105 signal_thread_state_change (thread);
3108 /*Only wait on the suspend event if we are using the old path */
3109 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3110 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3111 for (i = 0; i < wait->num; ++i) {
3112 MonoInternalThread *thread = wait->threads [i];
3117 ensure_synch_cs_set (thread);
3119 EnterCriticalSection (thread->synch_cs);
3120 if ((thread->state & ThreadState_Suspended) != 0) {
3121 CloseHandle (thread->suspended_event);
3122 thread->suspended_event = NULL;
3124 LeaveCriticalSection (thread->synch_cs);
3128 if (eventidx <= 0) {
3130 * If there are threads which are starting up, we wait until they
3131 * are suspended when they try to register in the threads hash.
3132 * This is guaranteed to finish, since the threads which can create new
3133 * threads get suspended after a while.
3134 * FIXME: The finalizer thread can still create new threads.
3136 mono_threads_lock ();
3137 if (threads_starting_up)
3138 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3141 mono_threads_unlock ();
3153 collect_threads (gpointer key, gpointer value, gpointer user_data)
3155 MonoInternalThread *thread = (MonoInternalThread*)value;
3156 struct wait_data *wait = (struct wait_data*)user_data;
3159 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3160 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3164 wait->handles [wait->num] = handle;
3165 wait->threads [wait->num] = thread;
3170 static gboolean thread_dump_requested;
3172 static G_GNUC_UNUSED gboolean
3173 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3175 GString *p = (GString*)data;
3176 MonoMethod *method = NULL;
3178 method = frame->ji->method;
3181 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3182 g_string_append_printf (p, " %s\n", location);
3185 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3191 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3193 GString* text = g_string_new (0);
3195 GError *error = NULL;
3198 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3200 g_string_append_printf (text, "\n\"%s\"", name);
3203 else if (thread->threadpool_thread)
3204 g_string_append (text, "\n\"<threadpool thread>\"");
3206 g_string_append (text, "\n\"<unnamed thread>\"");
3209 /* This no longer works with remote unwinding */
3211 wapi_desc = wapi_current_thread_desc ();
3212 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3217 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3218 mono_thread_info_resume (mono_thread_info_get_tid (info));
3220 fprintf (stdout, "%s", text->str);
3222 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3223 OutputDebugStringA(text->str);
3226 g_string_free (text, TRUE);
3231 dump_thread (gpointer key, gpointer value, gpointer user)
3233 MonoInternalThread *thread = (MonoInternalThread *)value;
3234 MonoThreadInfo *info;
3236 if (thread == mono_thread_internal_current ())
3240 FIXME This still can hang if we stop a thread during malloc.
3241 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3242 that takes a callback and runs it with the target suspended.
3243 We probably should loop a bit around trying to get it to either managed code
3246 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3251 print_thread_dump (thread, info);
3255 mono_threads_perform_thread_dump (void)
3257 if (!thread_dump_requested)
3260 printf ("Full thread dump:\n");
3263 * Make a copy of the hashtable since we can't do anything with
3264 * threads while threads_mutex is held.
3266 mono_threads_lock ();
3267 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3268 mono_threads_unlock ();
3270 thread_dump_requested = FALSE;
3274 * mono_threads_request_thread_dump:
3276 * Ask all threads except the current to print their stacktrace to stdout.
3279 mono_threads_request_thread_dump (void)
3281 struct wait_data wait_data;
3282 struct wait_data *wait = &wait_data;
3285 /*The new thread dump code runs out of the finalizer thread. */
3286 if (mono_thread_info_new_interrupt_enabled ()) {
3287 thread_dump_requested = TRUE;
3288 mono_gc_finalize_notify ();
3293 memset (wait, 0, sizeof (struct wait_data));
3296 * Make a copy of the hashtable since we can't do anything with
3297 * threads while threads_mutex is held.
3299 mono_threads_lock ();
3300 mono_g_hash_table_foreach (threads, collect_threads, wait);
3301 mono_threads_unlock ();
3303 for (i = 0; i < wait->num; ++i) {
3304 MonoInternalThread *thread = wait->threads [i];
3306 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3307 (thread != mono_thread_internal_current ()) &&
3308 !thread->thread_dump_requested) {
3309 thread->thread_dump_requested = TRUE;
3311 signal_thread_state_change (thread);
3314 CloseHandle (wait->handles [i]);
3320 gint allocated; /* +1 so that refs [allocated] == NULL */
3324 typedef struct ref_stack RefStack;
3327 ref_stack_new (gint initial_size)
3331 initial_size = MAX (initial_size, 16) + 1;
3332 rs = g_new0 (RefStack, 1);
3333 rs->refs = g_new0 (gpointer, initial_size);
3334 rs->allocated = initial_size;
3339 ref_stack_destroy (gpointer ptr)
3350 ref_stack_push (RefStack *rs, gpointer ptr)
3352 g_assert (rs != NULL);
3354 if (rs->bottom >= rs->allocated) {
3355 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3356 rs->allocated <<= 1;
3357 rs->refs [rs->allocated] = NULL;
3359 rs->refs [rs->bottom++] = ptr;
3363 ref_stack_pop (RefStack *rs)
3365 if (rs == NULL || rs->bottom == 0)
3369 rs->refs [rs->bottom] = NULL;
3373 ref_stack_find (RefStack *rs, gpointer ptr)
3380 for (refs = rs->refs; refs && *refs; refs++) {
3388 * mono_thread_push_appdomain_ref:
3390 * Register that the current thread may have references to objects in domain
3391 * @domain on its stack. Each call to this function should be paired with a
3392 * call to pop_appdomain_ref.
3395 mono_thread_push_appdomain_ref (MonoDomain *domain)
3397 MonoInternalThread *thread = mono_thread_internal_current ();
3400 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3401 SPIN_LOCK (thread->lock_thread_id);
3402 if (thread->appdomain_refs == NULL)
3403 thread->appdomain_refs = ref_stack_new (16);
3404 ref_stack_push (thread->appdomain_refs, domain);
3405 SPIN_UNLOCK (thread->lock_thread_id);
3410 mono_thread_pop_appdomain_ref (void)
3412 MonoInternalThread *thread = mono_thread_internal_current ();
3415 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3416 SPIN_LOCK (thread->lock_thread_id);
3417 ref_stack_pop (thread->appdomain_refs);
3418 SPIN_UNLOCK (thread->lock_thread_id);
3423 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3426 SPIN_LOCK (thread->lock_thread_id);
3427 res = ref_stack_find (thread->appdomain_refs, domain);
3428 SPIN_UNLOCK (thread->lock_thread_id);
3433 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3435 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3438 typedef struct abort_appdomain_data {
3439 struct wait_data wait;
3441 } abort_appdomain_data;
3444 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3446 MonoInternalThread *thread = (MonoInternalThread*)value;
3447 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3448 MonoDomain *domain = data->domain;
3450 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3451 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3453 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3454 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
3457 data->wait.handles [data->wait.num] = handle;
3458 data->wait.threads [data->wait.num] = thread;
3461 /* Just ignore the rest, we can't do anything with
3469 * mono_threads_abort_appdomain_threads:
3471 * Abort threads which has references to the given appdomain.
3474 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3476 abort_appdomain_data user_data;
3478 int orig_timeout = timeout;
3481 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3483 start_time = mono_msec_ticks ();
3485 mono_threads_lock ();
3487 user_data.domain = domain;
3488 user_data.wait.num = 0;
3489 /* This shouldn't take any locks */
3490 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3491 mono_threads_unlock ();
3493 if (user_data.wait.num > 0) {
3494 /* Abort the threads outside the threads lock */
3495 for (i = 0; i < user_data.wait.num; ++i)
3496 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3499 * We should wait for the threads either to abort, or to leave the
3500 * domain. We can't do the latter, so we wait with a timeout.
3502 wait_for_tids (&user_data.wait, 100);
3505 /* Update remaining time */
3506 timeout -= mono_msec_ticks () - start_time;
3507 start_time = mono_msec_ticks ();
3509 if (orig_timeout != -1 && timeout < 0)
3512 while (user_data.wait.num > 0);
3514 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3520 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3522 MonoInternalThread *thread = (MonoInternalThread*)value;
3523 MonoDomain *domain = (MonoDomain*)user_data;
3526 /* No locking needed here */
3527 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3529 if (thread->cached_culture_info) {
3530 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3531 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3532 if (obj && obj->vtable->domain == domain)
3533 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3539 * mono_threads_clear_cached_culture:
3541 * Clear the cached_current_culture from all threads if it is in the
3545 mono_threads_clear_cached_culture (MonoDomain *domain)
3547 mono_threads_lock ();
3548 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3549 mono_threads_unlock ();
3553 * mono_thread_get_undeniable_exception:
3555 * Return an exception which needs to be raised when leaving a catch clause.
3556 * This is used for undeniable exception propagation.
3559 mono_thread_get_undeniable_exception (void)
3561 MonoInternalThread *thread = mono_thread_internal_current ();
3563 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3565 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3566 * exception if the thread no longer references a dying appdomain.
3568 thread->abort_exc->trace_ips = NULL;
3569 thread->abort_exc->stack_trace = NULL;
3570 return thread->abort_exc;
3576 #if MONO_SMALL_CONFIG
3577 #define NUM_STATIC_DATA_IDX 4
3578 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3582 #define NUM_STATIC_DATA_IDX 8
3583 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3584 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3588 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3591 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
3594 gpointer *static_data = addr;
3595 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3598 if (!static_data [i])
3600 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3601 ptr = static_data [i];
3602 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3603 uintptr_t bmap = static_reference_bitmaps [i][j];
3606 if ((bmap & 1) && *p) {
3617 * mono_alloc_static_data
3619 * Allocate memory blocks for storing threads or context static data
3622 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3624 guint idx = (offset >> 24) - 1;
3627 gpointer* static_data = *static_data_ptr;
3629 static void* tls_desc = NULL;
3630 if (mono_gc_user_markers_supported () && !tls_desc)
3631 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3632 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3633 *static_data_ptr = static_data;
3634 static_data [0] = static_data;
3637 for (i = 1; i <= idx; ++i) {
3638 if (static_data [i])
3640 if (mono_gc_user_markers_supported () && threadlocal)
3641 static_data [i] = g_malloc0 (static_data_size [i]);
3643 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3648 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3651 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3652 if (!static_data [i])
3654 if (mono_gc_user_markers_supported () && threadlocal)
3655 g_free (static_data [i]);
3657 mono_gc_free_fixed (static_data [i]);
3659 mono_gc_free_fixed (static_data);
3663 * mono_init_static_data_info
3665 * Initializes static data counters
3667 static void mono_init_static_data_info (StaticDataInfo *static_data)
3669 static_data->idx = 0;
3670 static_data->offset = 0;
3671 static_data->freelist = NULL;
3675 * mono_alloc_static_data_slot
3677 * Generates an offset for static data. static_data contains the counters
3678 * used to generate it.
3681 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3685 if (!static_data->idx && !static_data->offset) {
3687 * we use the first chunk of the first allocation also as
3688 * an array for the rest of the data
3690 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3692 static_data->offset += align - 1;
3693 static_data->offset &= ~(align - 1);
3694 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3695 static_data->idx ++;
3696 g_assert (size <= static_data_size [static_data->idx]);
3697 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3698 static_data->offset = 0;
3700 offset = static_data->offset | ((static_data->idx + 1) << 24);
3701 static_data->offset += size;
3706 * ensure thread static fields already allocated are valid for thread
3707 * This function is called when a thread is created or on thread attach.
3710 thread_adjust_static_data (MonoInternalThread *thread)
3714 mono_threads_lock ();
3715 if (thread_static_info.offset || thread_static_info.idx > 0) {
3716 /* get the current allocated size */
3717 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3718 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3720 mono_threads_unlock ();
3724 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3726 MonoInternalThread *thread = value;
3727 guint32 offset = GPOINTER_TO_UINT (user);
3729 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3732 static MonoThreadDomainTls*
3733 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3735 MonoThreadDomainTls* prev = NULL;
3736 MonoThreadDomainTls* tmp = static_data->freelist;
3738 if (tmp->size == size) {
3740 prev->next = tmp->next;
3742 static_data->freelist = tmp->next;
3751 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3754 int idx = (offset >> 24) - 1;
3756 if (!static_reference_bitmaps [idx])
3757 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3758 rb = static_reference_bitmaps [idx];
3760 offset /= sizeof (gpointer);
3761 /* offset is now the bitmap offset */
3762 for (i = 0; i < numbits; ++i) {
3763 if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
3764 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3769 clear_reference_bitmap (guint32 offset, guint32 size)
3771 int idx = (offset >> 24) - 1;
3773 rb = static_reference_bitmaps [idx];
3775 offset /= sizeof (gpointer);
3776 size /= sizeof (gpointer);
3778 /* offset is now the bitmap offset */
3779 for (; offset < size; ++offset)
3780 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3784 * The offset for a special static variable is composed of three parts:
3785 * a bit that indicates the type of static data (0:thread, 1:context),
3786 * an index in the array of chunks of memory for the thread (thread->static_data)
3787 * and an offset in that chunk of mem. This allows allocating less memory in the
3792 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3795 if (static_type == SPECIAL_STATIC_THREAD) {
3796 MonoThreadDomainTls *item;
3797 mono_threads_lock ();
3798 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3799 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3801 offset = item->offset;
3804 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3806 update_tls_reference_bitmap (offset, bitmap, numbits);
3807 /* This can be called during startup */
3808 if (threads != NULL)
3809 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3810 mono_threads_unlock ();
3812 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3813 mono_contexts_lock ();
3814 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3815 mono_contexts_unlock ();
3816 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3822 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3824 /* The high bit means either thread (0) or static (1) data. */
3826 guint32 static_type = (offset & 0x80000000);
3829 offset &= 0x7fffffff;
3830 idx = (offset >> 24) - 1;
3832 if (static_type == 0) {
3833 return get_thread_static_data (thread, offset);
3835 /* Allocate static data block under demand, since we don't have a list
3838 MonoAppContext *context = mono_context_get ();
3839 if (!context->static_data || !context->static_data [idx]) {
3840 mono_contexts_lock ();
3841 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3842 mono_contexts_unlock ();
3844 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3849 mono_get_special_static_data (guint32 offset)
3851 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3860 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3862 MonoInternalThread *thread = value;
3863 TlsOffsetSize *data = user;
3864 int idx = (data->offset >> 24) - 1;
3867 if (!thread->static_data || !thread->static_data [idx])
3869 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3870 mono_gc_bzero (ptr, data->size);
3874 do_free_special_slot (guint32 offset, guint32 size)
3876 guint32 static_type = (offset & 0x80000000);
3877 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3878 if (static_type == 0) {
3880 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3881 data.offset = offset & 0x7fffffff;
3883 clear_reference_bitmap (data.offset, data.size);
3884 if (threads != NULL)
3885 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3886 item->offset = offset;
3889 if (!mono_runtime_is_shutting_down ()) {
3890 item->next = thread_static_info.freelist;
3891 thread_static_info.freelist = item;
3893 /* We could be called during shutdown after mono_thread_cleanup () is called */
3897 /* FIXME: free context static data as well */
3902 do_free_special (gpointer key, gpointer value, gpointer data)
3904 MonoClassField *field = key;
3905 guint32 offset = GPOINTER_TO_UINT (value);
3908 size = mono_type_size (field->type, &align);
3909 do_free_special_slot (offset, size);
3913 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3915 mono_threads_lock ();
3916 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3917 mono_threads_unlock ();
3921 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3923 mono_threads_lock ();
3924 do_free_special_slot (offset, size);
3925 mono_threads_unlock ();
3929 * allocates room in the thread local area for storing an instance of the struct type
3930 * the allocation is kept track of in domain->tlsrec_list.
3933 mono_thread_alloc_tls (MonoReflectionType *type)
3935 MonoDomain *domain = mono_domain_get ();
3937 MonoTlsDataRecord *tlsrec;
3940 gsize default_bitmap [4] = {0};
3941 uint32_t tls_offset;
3945 klass = mono_class_from_mono_type (type->type);
3946 /* TlsDatum is a struct, so we subtract the object header size offset */
3947 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3948 size = mono_type_size (type->type, &align);
3949 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3950 if (bitmap != default_bitmap)
3952 tlsrec = g_new0 (MonoTlsDataRecord, 1);
3953 tlsrec->tls_offset = tls_offset;
3954 tlsrec->size = size;
3955 mono_domain_lock (domain);
3956 tlsrec->next = domain->tlsrec_list;
3957 domain->tlsrec_list = tlsrec;
3958 mono_domain_unlock (domain);
3963 mono_thread_destroy_tls (uint32_t tls_offset)
3965 MonoTlsDataRecord *prev = NULL;
3966 MonoTlsDataRecord *cur;
3968 MonoDomain *domain = mono_domain_get ();
3969 mono_domain_lock (domain);
3970 cur = domain->tlsrec_list;
3972 if (cur->tls_offset == tls_offset) {
3974 prev->next = cur->next;
3976 domain->tlsrec_list = cur->next;
3984 mono_domain_unlock (domain);
3986 mono_special_static_data_free_slot (tls_offset, size);
3990 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
3993 mono_thread_destroy_domain_tls (MonoDomain *domain)
3995 while (domain->tlsrec_list)
3996 mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
3999 static MonoClassField *local_slots = NULL;
4002 /* local tls data to get locals_slot from a thread */
4005 /* index in the locals_slot array */
4010 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4012 LocalSlotID *sid = user_data;
4013 MonoInternalThread *thread = (MonoInternalThread*)value;
4014 MonoArray *slots_array;
4016 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4017 * it is for the right domain, so we need to check if it is allocated an initialized
4018 * for the current thread.
4020 /*g_print ("handling thread %p\n", thread);*/
4021 if (!thread->static_data || !thread->static_data [sid->idx])
4023 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4024 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4026 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4030 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4038 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4040 g_warning ("local_slots field not found in Thread class");
4044 domain = mono_domain_get ();
4045 mono_domain_lock (domain);
4046 if (domain->special_static_fields)
4047 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4048 mono_domain_unlock (domain);
4051 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4052 sid.offset = GPOINTER_TO_UINT (addr);
4053 sid.offset &= 0x7fffffff;
4054 sid.idx = (sid.offset >> 24) - 1;
4055 mono_threads_lock ();
4056 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4057 mono_threads_unlock ();
4059 /* FIXME: clear the slot for MonoAppContexts, too */
4064 static void CALLBACK dummy_apc (ULONG_PTR param)
4068 static guint32 dummy_apc (gpointer param)
4075 * mono_thread_execute_interruption
4077 * Performs the operation that the requested thread state requires (abort,
4080 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4082 ensure_synch_cs_set (thread);
4084 EnterCriticalSection (thread->synch_cs);
4086 /* MonoThread::interruption_requested can only be changed with atomics */
4087 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4088 /* this will consume pending APC calls */
4089 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4090 InterlockedDecrement (&thread_interruption_requested);
4092 /* Clear the interrupted flag of the thread so it can wait again */
4093 wapi_clear_interruption ();
4097 if ((thread->state & ThreadState_AbortRequested) != 0) {
4098 LeaveCriticalSection (thread->synch_cs);
4099 if (thread->abort_exc == NULL) {
4101 * This might be racy, but it has to be called outside the lock
4102 * since it calls managed code.
4104 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4106 return thread->abort_exc;
4108 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4109 self_suspend_internal (thread);
4112 else if ((thread->state & ThreadState_StopRequested) != 0) {
4113 /* FIXME: do this through the JIT? */
4115 LeaveCriticalSection (thread->synch_cs);
4117 mono_thread_exit ();
4119 } else if (thread->pending_exception) {
4122 exc = thread->pending_exception;
4123 thread->pending_exception = NULL;
4125 LeaveCriticalSection (thread->synch_cs);
4127 } else if (thread->thread_interrupt_requested) {
4129 thread->thread_interrupt_requested = FALSE;
4130 LeaveCriticalSection (thread->synch_cs);
4132 return(mono_get_exception_thread_interrupted ());
4135 LeaveCriticalSection (thread->synch_cs);
4141 * mono_thread_request_interruption
4143 * A signal handler can call this method to request the interruption of a
4144 * thread. The result of the interruption will depend on the current state of
4145 * the thread. If the result is an exception that needs to be throw, it is
4146 * provided as return value.
4149 mono_thread_request_interruption (gboolean running_managed)
4151 MonoInternalThread *thread = mono_thread_internal_current ();
4153 /* The thread may already be stopping */
4158 if (thread->interrupt_on_stop &&
4159 thread->state & ThreadState_StopRequested &&
4160 thread->state & ThreadState_Background)
4164 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4166 InterlockedIncrement (&thread_interruption_requested);
4168 if (!running_managed || is_running_protected_wrapper ()) {
4169 /* Can't stop while in unmanaged code. Increase the global interruption
4170 request count. When exiting the unmanaged method the count will be
4171 checked and the thread will be interrupted. */
4174 if (mono_thread_notify_pending_exc_fn && !running_managed)
4175 /* The JIT will notify the thread about the interruption */
4176 /* This shouldn't take any locks */
4177 mono_thread_notify_pending_exc_fn ();
4179 /* this will awake the thread if it is in WaitForSingleObject
4181 /* Our implementation of this function ignores the func argument */
4182 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
4186 return mono_thread_execute_interruption (thread);
4190 /*This function should be called by a thread after it has exited all of
4191 * its handle blocks at interruption time.*/
4193 mono_thread_resume_interruption (void)
4195 MonoInternalThread *thread = mono_thread_internal_current ();
4196 gboolean still_aborting;
4198 /* The thread may already be stopping */
4202 ensure_synch_cs_set (thread);
4203 EnterCriticalSection (thread->synch_cs);
4204 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4205 LeaveCriticalSection (thread->synch_cs);
4207 /*This can happen if the protected block called Thread::ResetAbort*/
4208 if (!still_aborting)
4211 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4213 InterlockedIncrement (&thread_interruption_requested);
4216 wapi_self_interrupt ();
4218 return mono_thread_execute_interruption (thread);
4221 gboolean mono_thread_interruption_requested ()
4223 if (thread_interruption_requested) {
4224 MonoInternalThread *thread = mono_thread_internal_current ();
4225 /* The thread may already be stopping */
4227 return (thread->interruption_requested);
4232 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4234 MonoInternalThread *thread = mono_thread_internal_current ();
4236 /* The thread may already be stopping */
4240 mono_debugger_check_interruption ();
4242 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4243 MonoException* exc = mono_thread_execute_interruption (thread);
4244 if (exc) mono_raise_exception (exc);
4249 * Performs the interruption of the current thread, if one has been requested,
4250 * and the thread is not running a protected wrapper.
4252 void mono_thread_interruption_checkpoint ()
4254 mono_thread_interruption_checkpoint_request (FALSE);
4258 * Performs the interruption of the current thread, if one has been requested.
4260 void mono_thread_force_interruption_checkpoint ()
4262 mono_thread_interruption_checkpoint_request (TRUE);
4266 * mono_thread_get_and_clear_pending_exception:
4268 * Return any pending exceptions for the current thread and clear it as a side effect.
4271 mono_thread_get_and_clear_pending_exception (void)
4273 MonoInternalThread *thread = mono_thread_internal_current ();
4275 /* The thread may already be stopping */
4279 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4280 return mono_thread_execute_interruption (thread);
4283 if (thread->pending_exception) {
4284 MonoException *exc = thread->pending_exception;
4286 thread->pending_exception = NULL;
4294 * mono_set_pending_exception:
4296 * Set the pending exception of the current thread to EXC.
4297 * The exception will be thrown when execution returns to managed code.
4300 mono_set_pending_exception (MonoException *exc)
4302 MonoInternalThread *thread = mono_thread_internal_current ();
4304 /* The thread may already be stopping */
4308 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4310 mono_thread_request_interruption (FALSE);
4314 * mono_thread_interruption_request_flag:
4316 * Returns the address of a flag that will be non-zero if an interruption has
4317 * been requested for a thread. The thread to interrupt may not be the current
4318 * thread, so an additional call to mono_thread_interruption_requested() or
4319 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4322 gint32* mono_thread_interruption_request_flag ()
4324 return &thread_interruption_requested;
4328 mono_thread_init_apartment_state (void)
4331 MonoInternalThread* thread = mono_thread_internal_current ();
4333 /* Positive return value indicates success, either
4334 * S_OK if this is first CoInitialize call, or
4335 * S_FALSE if CoInitialize already called, but with same
4336 * threading model. A negative value indicates failure,
4337 * probably due to trying to change the threading model.
4339 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4340 ? COINIT_APARTMENTTHREADED
4341 : COINIT_MULTITHREADED) < 0) {
4342 thread->apartment_state = ThreadApartmentState_Unknown;
4348 mono_thread_cleanup_apartment_state (void)
4351 MonoInternalThread* thread = mono_thread_internal_current ();
4353 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4360 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4362 ensure_synch_cs_set (thread);
4364 EnterCriticalSection (thread->synch_cs);
4365 thread->state |= state;
4366 LeaveCriticalSection (thread->synch_cs);
4370 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4372 ensure_synch_cs_set (thread);
4374 EnterCriticalSection (thread->synch_cs);
4375 thread->state &= ~state;
4376 LeaveCriticalSection (thread->synch_cs);
4380 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4382 gboolean ret = FALSE;
4384 ensure_synch_cs_set (thread);
4386 EnterCriticalSection (thread->synch_cs);
4388 if ((thread->state & test) != 0) {
4392 LeaveCriticalSection (thread->synch_cs);
4397 //static MonoClassField *execution_context_field;
4400 get_execution_context_addr (void)
4402 MonoDomain *domain = mono_domain_get ();
4403 guint32 offset = domain->execution_context_field_offset;
4406 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4409 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4411 mono_domain_lock (domain);
4412 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4413 mono_domain_unlock (domain);
4416 domain->execution_context_field_offset = offset;
4419 return (MonoObject**) mono_get_special_static_data (offset);
4423 mono_thread_get_execution_context (void)
4425 return *get_execution_context_addr ();
4429 mono_thread_set_execution_context (MonoObject *ec)
4431 *get_execution_context_addr () = ec;
4434 static gboolean has_tls_get = FALSE;
4437 mono_runtime_set_has_tls_get (gboolean val)
4443 mono_runtime_has_tls_get (void)
4449 mono_thread_kill (MonoInternalThread *thread, int signal)
4452 /* Win32 uses QueueUserAPC and callers of this are guarded */
4453 g_assert_not_reached ();
4455 # ifdef PTHREAD_POINTER_ID
4456 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4458 # ifdef PLATFORM_ANDROID
4459 if (thread->android_tid != 0) {
4461 int old_errno = errno;
4463 ret = tkill ((pid_t) thread->android_tid, signal);
4472 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4474 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4481 self_interrupt_thread (void *_unused)
4483 MonoThreadInfo *info = mono_thread_info_current ();
4484 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4485 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4486 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4487 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4491 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4495 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4499 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4501 MonoJitInfo **dest = data;
4507 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4509 MonoJitInfo *ji = NULL;
4512 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4517 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4520 MonoThreadInfo *info = NULL;
4521 gboolean protected_wrapper;
4522 gboolean running_managed;
4524 if (!mono_thread_info_new_interrupt_enabled ()) {
4525 signal_thread_state_change (thread);
4530 FIXME this is insanely broken, it doesn't cause interruption to happen
4531 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4533 if (thread == mono_thread_internal_current ()) {
4534 /* Do it synchronously */
4535 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4537 mono_raise_exception (exc);
4539 wapi_interrupt_thread (thread->handle);
4544 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4545 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4549 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4550 mono_thread_info_resume (mono_thread_info_get_tid (info));
4554 /*someone is already interrupting it*/
4555 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4556 mono_thread_info_resume (mono_thread_info_get_tid (info));
4559 InterlockedIncrement (&thread_interruption_requested);
4561 ji = mono_thread_info_get_last_managed (info);
4562 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4563 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4565 if (!protected_wrapper && running_managed) {
4566 /*We are in managed code*/
4567 /*Set the thread to call */
4568 if (install_async_abort)
4569 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4570 mono_thread_info_resume (mono_thread_info_get_tid (info));
4572 gpointer interrupt_handle;
4574 * This will cause waits to be broken.
4575 * It will also prevent the thread from entering a wait, so if the thread returns
4576 * from the wait before it receives the abort signal, it will just spin in the wait
4577 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4581 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4583 mono_thread_info_resume (mono_thread_info_get_tid (info));
4585 wapi_finish_interrupt_thread (interrupt_handle);
4588 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4592 transition_to_suspended (MonoInternalThread *thread)
4594 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4595 g_assert (0); /*FIXME we should not reach this */
4596 /*Make sure we balance the suspend count.*/
4597 mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
4599 thread->state &= ~ThreadState_SuspendRequested;
4600 thread->state |= ThreadState_Suspended;
4602 LeaveCriticalSection (thread->synch_cs);
4606 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4608 if (!mono_thread_info_new_interrupt_enabled ()) {
4609 signal_thread_state_change (thread);
4613 EnterCriticalSection (thread->synch_cs);
4614 if (thread == mono_thread_internal_current ()) {
4615 transition_to_suspended (thread);
4616 mono_thread_info_self_suspend ();
4618 MonoThreadInfo *info;
4620 gboolean protected_wrapper;
4621 gboolean running_managed;
4623 /*A null info usually means the thread is already dead. */
4624 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
4625 LeaveCriticalSection (thread->synch_cs);
4629 ji = mono_thread_info_get_last_managed (info);
4630 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4631 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4633 if (running_managed && !protected_wrapper) {
4634 transition_to_suspended (thread);
4636 gpointer interrupt_handle;
4638 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4639 InterlockedIncrement (&thread_interruption_requested);
4642 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4644 mono_thread_info_resume (mono_thread_info_get_tid (info));
4647 wapi_finish_interrupt_thread (interrupt_handle);
4649 LeaveCriticalSection (thread->synch_cs);
4654 /*This is called with @thread synch_cs held and it must release it*/
4656 self_suspend_internal (MonoInternalThread *thread)
4658 if (!mono_thread_info_new_interrupt_enabled ()) {
4659 thread->state &= ~ThreadState_SuspendRequested;
4660 thread->state |= ThreadState_Suspended;
4661 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4662 if (thread->suspend_event == NULL) {
4663 LeaveCriticalSection (thread->synch_cs);
4666 if (thread->suspended_event)
4667 SetEvent (thread->suspended_event);
4669 LeaveCriticalSection (thread->synch_cs);
4671 if (shutting_down) {
4672 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4677 WaitForSingleObject (thread->suspend_event, INFINITE);
4679 EnterCriticalSection (thread->synch_cs);
4681 CloseHandle (thread->suspend_event);
4682 thread->suspend_event = NULL;
4683 thread->state &= ~ThreadState_Suspended;
4685 /* The thread that requested the resume will have replaced this event
4686 * and will be waiting for it
4688 SetEvent (thread->resume_event);
4690 LeaveCriticalSection (thread->synch_cs);
4694 transition_to_suspended (thread);
4695 mono_thread_info_self_suspend ();
4698 /*This is called with @thread synch_cs held and it must release it*/
4700 resume_thread_internal (MonoInternalThread *thread)
4702 if (!mono_thread_info_new_interrupt_enabled ()) {
4703 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4704 if (thread->resume_event == NULL) {
4705 LeaveCriticalSection (thread->synch_cs);
4709 /* Awake the thread */
4710 SetEvent (thread->suspend_event);
4712 LeaveCriticalSection (thread->synch_cs);
4714 /* Wait for the thread to awake */
4715 WaitForSingleObject (thread->resume_event, INFINITE);
4716 CloseHandle (thread->resume_event);
4717 thread->resume_event = NULL;
4721 LeaveCriticalSection (thread->synch_cs);
4722 /* Awake the thread */
4723 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4725 EnterCriticalSection (thread->synch_cs);
4726 thread->state &= ~ThreadState_Suspended;
4727 LeaveCriticalSection (thread->synch_cs);