[threading] Wrap the threads lock with cooperative coode.
[mono-project.git] / mono / metadata / threads.c
blob14fc722e4ff10db656635970b2f86eb1f76b5226
1 /*
2 * threads.c: Thread support internal calls
4 * Author:
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)
14 #include <config.h>
16 #include <glib.h>
17 #include <string.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/domain-internals.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/threadpool.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internal.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/io-layer/io-layer.h>
32 #include <mono/metadata/object-internals.h>
33 #include <mono/metadata/mono-debug-debugger.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/hazard-pointer.h>
40 #include <mono/utils/mono-tls.h>
41 #include <mono/utils/atomic.h>
42 #include <mono/utils/mono-memory-model.h>
44 #include <mono/metadata/gc-internal.h>
46 #ifdef HAVE_SIGNAL_H
47 #include <signal.h>
48 #endif
50 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
51 #define USE_TKILL_ON_ANDROID 1
52 #endif
54 #ifdef PLATFORM_ANDROID
55 #include <errno.h>
57 #ifdef USE_TKILL_ON_ANDROID
58 extern int tkill (pid_t tid, int signal);
59 #endif
60 #endif
62 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
63 #define THREAD_DEBUG(a)
64 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
65 #define THREAD_WAIT_DEBUG(a)
66 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
67 #define LIBGC_DEBUG(a)
69 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
70 #define SPIN_LOCK(i) do { \
71 if (SPIN_TRYLOCK (i)) \
72 break; \
73 } while (1)
75 #define SPIN_UNLOCK(i) i = 0
77 #define LOCK_THREAD(thread) lock_thread((thread))
78 #define UNLOCK_THREAD(thread) unlock_thread((thread))
80 /* Provide this for systems with glib < 2.6 */
81 #ifndef G_GSIZE_FORMAT
82 # if GLIB_SIZEOF_LONG == 8
83 # define G_GSIZE_FORMAT "lu"
84 # else
85 # define G_GSIZE_FORMAT "u"
86 # endif
87 #endif
89 typedef struct
91 guint32 (*func)(void *);
92 MonoThread *obj;
93 MonoObject *delegate;
94 void *start_arg;
95 } StartInfo;
97 typedef union {
98 gint32 ival;
99 gfloat fval;
100 } IntFloatUnion;
102 typedef union {
103 gint64 ival;
104 gdouble fval;
105 } LongDoubleUnion;
107 typedef struct _MonoThreadDomainTls MonoThreadDomainTls;
108 struct _MonoThreadDomainTls {
109 MonoThreadDomainTls *next;
110 guint32 offset;
111 guint32 size;
114 typedef struct {
115 int idx;
116 int offset;
117 MonoThreadDomainTls *freelist;
118 } StaticDataInfo;
120 /* Number of cached culture objects in the MonoThread->cached_culture_info array
121 * (per-type): we use the first NUM entries for CultureInfo and the last for
122 * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
124 #define NUM_CACHED_CULTURES 4
125 #define CULTURES_START_IDX 0
126 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
128 /* Controls access to the 'threads' hash table */
129 static void mono_threads_lock (void);
130 static void mono_threads_unlock (void);
131 static mono_mutex_t threads_mutex;
133 /* Controls access to context static data */
134 #define mono_contexts_lock() mono_mutex_lock (&contexts_mutex)
135 #define mono_contexts_unlock() mono_mutex_unlock (&contexts_mutex)
136 static mono_mutex_t contexts_mutex;
138 /* Controls access to the 'joinable_threads' hash table */
139 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
140 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
141 static mono_mutex_t joinable_threads_mutex;
143 /* Holds current status of static data heap */
144 static StaticDataInfo thread_static_info;
145 static StaticDataInfo context_static_info;
147 /* The hash of existing threads (key is thread ID, value is
148 * MonoInternalThread*) that need joining before exit
150 static MonoGHashTable *threads=NULL;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable *threads_starting_up = NULL;
159 /* Maps a MonoThread to its start argument */
160 /* Protected by mono_threads_lock () */
161 static MonoGHashTable *thread_start_args = NULL;
163 /* The TLS key that holds the MonoObject assigned to each thread */
164 static MonoNativeTlsKey current_object_key;
166 /* Contains tids */
167 /* Protected by the threads lock */
168 static GHashTable *joinable_threads;
169 static int joinable_thread_count;
171 #ifdef MONO_HAVE_FAST_TLS
172 /* we need to use both the Tls* functions and __thread because
173 * the gc needs to see all the threads
175 MONO_FAST_TLS_DECLARE(tls_current_object);
176 #define SET_CURRENT_OBJECT(x) do { \
177 MONO_FAST_TLS_SET (tls_current_object, x); \
178 mono_native_tls_set_value (current_object_key, x); \
179 } while (FALSE)
180 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
181 #else
182 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
183 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
184 #endif
186 /* function called at thread start */
187 static MonoThreadStartCB mono_thread_start_cb = NULL;
189 /* function called at thread attach */
190 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
192 /* function called at thread cleanup */
193 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
195 /* function called to notify the runtime about a pending exception on the current thread */
196 static MonoThreadNotifyPendingExcFunc mono_thread_notify_pending_exc_fn = NULL;
198 /* The default stack size for each thread */
199 static guint32 default_stacksize = 0;
200 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
202 static void thread_adjust_static_data (MonoInternalThread *thread);
203 static void mono_free_static_data (gpointer* static_data, gboolean threadlocal);
204 static void mono_init_static_data_info (StaticDataInfo *static_data);
205 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
206 static gboolean mono_thread_resume (MonoInternalThread* thread);
207 static void signal_thread_state_change (MonoInternalThread *thread);
208 static void abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort);
209 static void suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt);
210 static void self_suspend_internal (MonoInternalThread *thread);
211 static gboolean resume_thread_internal (MonoInternalThread *thread);
213 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread);
214 static void ref_stack_destroy (gpointer rs);
216 /* Spin lock for InterlockedXXX 64 bit functions */
217 #define mono_interlocked_lock() mono_mutex_lock (&interlocked_mutex)
218 #define mono_interlocked_unlock() mono_mutex_unlock (&interlocked_mutex)
219 static mono_mutex_t interlocked_mutex;
221 /* global count of thread interruptions requested */
222 static gint32 thread_interruption_requested = 0;
224 /* Event signaled when a thread changes its background mode */
225 static HANDLE background_change_event;
227 static gboolean shutting_down = FALSE;
229 static gint32 managed_thread_id_counter = 0;
232 static void
233 mono_threads_lock (void)
235 MONO_TRY_BLOCKING
236 mono_locks_acquire (&threads_mutex, ThreadsLock);
237 MONO_FINISH_TRY_BLOCKING
240 static void
241 mono_threads_unlock (void)
243 mono_locks_release (&threads_mutex, ThreadsLock);
247 static guint32
248 get_next_managed_thread_id (void)
250 return InterlockedIncrement (&managed_thread_id_counter);
253 MonoNativeTlsKey
254 mono_thread_get_tls_key (void)
256 return current_object_key;
259 gint32
260 mono_thread_get_tls_offset (void)
262 int offset;
263 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
264 return offset;
267 static inline MonoNativeThreadId
268 thread_get_tid (MonoInternalThread *thread)
270 /* We store the tid as a guint64 to keep the object layout constant between platforms */
271 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
274 /* handle_store() and handle_remove() manage the array of threads that
275 * still need to be waited for when the main thread exits.
277 * If handle_store() returns FALSE the thread must not be started
278 * because Mono is shutting down.
280 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
282 mono_threads_lock ();
284 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
286 if (threads_starting_up)
287 mono_g_hash_table_remove (threads_starting_up, thread);
289 if (shutting_down && !force_attach) {
290 mono_threads_unlock ();
291 return FALSE;
294 if(threads==NULL) {
295 MONO_GC_REGISTER_ROOT_FIXED (threads);
296 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
299 /* We don't need to duplicate thread->handle, because it is
300 * only closed when the thread object is finalized by the GC.
302 g_assert (thread->internal_thread);
303 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
304 thread->internal_thread);
306 mono_threads_unlock ();
308 return TRUE;
311 static gboolean handle_remove(MonoInternalThread *thread)
313 gboolean ret;
314 gsize tid = thread->tid;
316 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
318 mono_threads_lock ();
320 if (threads) {
321 /* We have to check whether the thread object for the
322 * tid is still the same in the table because the
323 * thread might have been destroyed and the tid reused
324 * in the meantime, in which case the tid would be in
325 * the table, but with another thread object.
327 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
328 mono_g_hash_table_remove (threads, (gpointer)tid);
329 ret = TRUE;
330 } else {
331 ret = FALSE;
334 else
335 ret = FALSE;
337 mono_threads_unlock ();
339 /* Don't close the handle here, wait for the object finalizer
340 * to do it. Otherwise, the following race condition applies:
342 * 1) Thread exits (and handle_remove() closes the handle)
344 * 2) Some other handle is reassigned the same slot
346 * 3) Another thread tries to join the first thread, and
347 * blocks waiting for the reassigned handle to be signalled
348 * (which might never happen). This is possible, because the
349 * thread calling Join() still has a reference to the first
350 * thread's object.
352 return ret;
355 static void ensure_synch_cs_set (MonoInternalThread *thread)
357 mono_mutex_t *synch_cs;
359 if (thread->synch_cs != NULL) {
360 return;
363 synch_cs = g_new0 (mono_mutex_t, 1);
364 mono_mutex_init_recursive (synch_cs);
366 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
367 synch_cs, NULL) != NULL) {
368 /* Another thread must have installed this CS */
369 mono_mutex_destroy (synch_cs);
370 g_free (synch_cs);
374 static inline void
375 lock_thread (MonoInternalThread *thread)
377 if (!thread->synch_cs)
378 ensure_synch_cs_set (thread);
380 g_assert (thread->synch_cs);
381 mono_mutex_lock (thread->synch_cs);
384 static inline void
385 unlock_thread (MonoInternalThread *thread)
387 mono_mutex_unlock (thread->synch_cs);
391 * NOTE: this function can be called also for threads different from the current one:
392 * make sure no code called from it will ever assume it is run on the thread that is
393 * getting cleaned up.
395 static void thread_cleanup (MonoInternalThread *thread)
397 g_assert (thread != NULL);
399 if (thread->abort_state_handle) {
400 mono_gchandle_free (thread->abort_state_handle);
401 thread->abort_state_handle = 0;
403 thread->abort_exc = NULL;
404 thread->current_appcontext = NULL;
407 * This is necessary because otherwise we might have
408 * cross-domain references which will not get cleaned up when
409 * the target domain is unloaded.
411 if (thread->cached_culture_info) {
412 int i;
413 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
414 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
418 * thread->synch_cs can be NULL if this was called after
419 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
420 * This can happen only during shutdown.
421 * The shutting_down flag is not always set, so we can't assert on it.
423 if (thread->synch_cs)
424 LOCK_THREAD (thread);
426 thread->state |= ThreadState_Stopped;
427 thread->state &= ~ThreadState_Background;
429 if (thread->synch_cs)
430 UNLOCK_THREAD (thread);
433 An interruption request has leaked to cleanup. Adjust the global counter.
435 This can happen is the abort source thread finds the abortee (this) thread
436 in unmanaged code. If this thread never trips back to managed code or check
437 the local flag it will be left set and positively unbalance the global counter.
439 Leaving the counter unbalanced will cause a performance degradation since all threads
440 will now keep checking their local flags all the time.
442 if (InterlockedExchange (&thread->interruption_requested, 0))
443 InterlockedDecrement (&thread_interruption_requested);
445 /* if the thread is not in the hash it has been removed already */
446 if (!handle_remove (thread)) {
447 if (thread == mono_thread_internal_current ()) {
448 mono_domain_unset ();
449 mono_memory_barrier ();
451 /* This needs to be called even if handle_remove () fails */
452 if (mono_thread_cleanup_fn)
453 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
454 return;
456 mono_release_type_locks (thread);
458 mono_profiler_thread_end (thread->tid);
460 if (thread == mono_thread_internal_current ()) {
462 * This will signal async signal handlers that the thread has exited.
463 * The profiler callback needs this to be set, so it cannot be done earlier.
465 mono_domain_unset ();
466 mono_memory_barrier ();
469 if (thread == mono_thread_internal_current ())
470 mono_thread_pop_appdomain_ref ();
472 thread->cached_culture_info = NULL;
474 mono_free_static_data (thread->static_data, TRUE);
475 thread->static_data = NULL;
476 ref_stack_destroy (thread->appdomain_refs);
477 thread->appdomain_refs = NULL;
479 if (mono_thread_cleanup_fn)
480 mono_thread_cleanup_fn ((MonoNativeThreadId)thread->tid);
482 if (mono_gc_is_moving ()) {
483 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
484 thread->thread_pinning_ref = NULL;
488 static gpointer
489 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
491 int idx;
492 g_assert ((offset & 0x80000000) == 0);
493 offset &= 0x7fffffff;
494 idx = (offset >> 24) - 1;
495 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
498 static MonoThread**
499 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
501 static MonoClassField *current_thread_field = NULL;
503 guint32 offset;
505 if (!current_thread_field) {
506 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
507 g_assert (current_thread_field);
510 mono_class_vtable (domain, mono_defaults.thread_class);
511 mono_domain_lock (domain);
512 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
513 mono_domain_unlock (domain);
514 g_assert (offset);
516 return get_thread_static_data (thread, offset);
519 static void
520 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
522 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
524 g_assert (current->obj.vtable->domain == domain);
526 g_assert (!*current_thread_ptr);
527 *current_thread_ptr = current;
530 static MonoThread*
531 create_thread_object (MonoDomain *domain)
533 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
534 return (MonoThread*)mono_gc_alloc_mature (vt);
537 static MonoThread*
538 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
540 MonoThread *thread = create_thread_object (domain);
541 MONO_OBJECT_SETREF (thread, internal_thread, internal);
542 return thread;
545 static MonoInternalThread*
546 create_internal_thread (void)
548 MonoInternalThread *thread;
549 MonoVTable *vt;
551 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
552 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
554 thread->synch_cs = g_new0 (mono_mutex_t, 1);
555 mono_mutex_init_recursive (thread->synch_cs);
557 thread->apartment_state = ThreadApartmentState_Unknown;
558 thread->managed_id = get_next_managed_thread_id ();
559 if (mono_gc_is_moving ()) {
560 thread->thread_pinning_ref = thread;
561 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
564 return thread;
567 static void
568 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
570 MonoDomain *domain = mono_get_root_domain ();
572 if (!candidate || candidate->obj.vtable->domain != domain)
573 candidate = new_thread_with_internal (domain, thread);
574 set_current_thread_for_domain (domain, thread, candidate);
575 g_assert (!thread->root_domain_thread);
576 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
579 static guint32 WINAPI start_wrapper_internal(void *data)
581 MonoThreadInfo *info;
582 StartInfo *start_info = (StartInfo *)data;
583 guint32 (*start_func)(void *);
584 void *start_arg;
585 gsize tid;
587 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
588 * GC stack walk.
590 MonoInternalThread *internal = start_info->obj->internal_thread;
591 MonoObject *start_delegate = start_info->delegate;
592 MonoDomain *domain = start_info->obj->obj.vtable->domain;
594 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
596 /* We can be sure start_info->obj->tid and
597 * start_info->obj->handle have been set, because the thread
598 * was created suspended, and these values were set before the
599 * thread resumed
602 info = mono_thread_info_current ();
603 g_assert (info);
604 internal->thread_info = info;
605 internal->small_id = info->small_id;
607 tid=internal->tid;
609 SET_CURRENT_OBJECT (internal);
611 /* Every thread references the appdomain which created it */
612 mono_thread_push_appdomain_ref (domain);
614 if (!mono_domain_set (domain, FALSE)) {
615 /* No point in raising an appdomain_unloaded exception here */
616 /* FIXME: Cleanup here */
617 mono_thread_pop_appdomain_ref ();
618 return 0;
621 start_func = start_info->func;
622 start_arg = start_info->start_arg;
624 /* We have to do this here because mono_thread_new_init()
625 requires that root_domain_thread is set up. */
626 thread_adjust_static_data (internal);
627 init_root_domain_thread (internal, start_info->obj);
629 /* This MUST be called before any managed code can be
630 * executed, as it calls the callback function that (for the
631 * jit) sets the lmf marker.
633 mono_thread_new_init (tid, &tid, start_func);
634 internal->stack_ptr = &tid;
636 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
638 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
640 /* On 2.0 profile (and higher), set explicitly since state might have been
641 Unknown */
642 if (internal->apartment_state == ThreadApartmentState_Unknown)
643 internal->apartment_state = ThreadApartmentState_MTA;
645 mono_thread_init_apartment_state ();
647 if(internal->start_notify!=NULL) {
648 /* Let the thread that called Start() know we're
649 * ready
651 ReleaseSemaphore (internal->start_notify, 1, NULL);
654 mono_threads_lock ();
655 mono_g_hash_table_remove (thread_start_args, start_info->obj);
656 mono_threads_unlock ();
658 mono_thread_set_execution_context (start_info->obj->ec_to_set);
659 start_info->obj->ec_to_set = NULL;
661 g_free (start_info);
662 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
663 internal->tid));
666 * Call this after calling start_notify, since the profiler callback might want
667 * to lock the thread, and the lock is held by thread_start () which waits for
668 * start_notify.
670 mono_profiler_thread_start (tid);
672 /* if the name was set before starting, we didn't invoke the profiler callback */
673 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
674 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
675 mono_profiler_thread_name (internal->tid, tname);
676 g_free (tname);
678 /* start_func is set only for unmanaged start functions */
679 if (start_func) {
680 start_func (start_arg);
681 } else {
682 void *args [1];
683 g_assert (start_delegate != NULL);
684 args [0] = start_arg;
685 /* we may want to handle the exception here. See comment below on unhandled exceptions */
686 mono_runtime_delegate_invoke (start_delegate, args, NULL);
689 /* If the thread calls ExitThread at all, this remaining code
690 * will not be executed, but the main thread will eventually
691 * call thread_cleanup() on this thread's behalf.
694 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
696 /* Do any cleanup needed for apartment state. This
697 * cannot be done in thread_cleanup since thread_cleanup could be
698 * called for a thread other than the current thread.
699 * mono_thread_cleanup_apartment_state cleans up apartment
700 * for the current thead */
701 mono_thread_cleanup_apartment_state ();
703 thread_cleanup (internal);
705 internal->tid = 0;
707 /* Remove the reference to the thread object in the TLS data,
708 * so the thread object can be finalized. This won't be
709 * reached if the thread threw an uncaught exception, so those
710 * thread handles will stay referenced :-( (This is due to
711 * missing support for scanning thread-specific data in the
712 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
713 * to TLS data.)
715 SET_CURRENT_OBJECT (NULL);
717 return(0);
720 static guint32 WINAPI start_wrapper(void *data)
722 volatile int dummy;
724 /* Avoid scanning the frames above this frame during a GC */
725 mono_gc_set_stack_end ((void*)&dummy);
727 return start_wrapper_internal (data);
731 * create_thread:
733 * Common thread creation code.
734 * LOCKING: Acquires the threads lock.
736 static gboolean
737 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
738 gboolean throw_on_failure)
740 HANDLE thread_handle;
741 MonoNativeThreadId tid;
742 guint32 create_flags;
745 * Join joinable threads to prevent running out of threads since the finalizer
746 * thread might be blocked/backlogged.
748 mono_threads_join_threads ();
750 mono_threads_lock ();
751 if (shutting_down) {
752 g_free (start_info);
753 mono_threads_unlock ();
754 return FALSE;
757 * The thread start argument may be an object reference, and there is
758 * no ref to keep it alive when the new thread is started but not yet
759 * registered with the collector. So we store it in a GC tracked hash
760 * table.
762 if (thread_start_args == NULL) {
763 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
764 thread_start_args = mono_g_hash_table_new (NULL, NULL);
766 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
767 if (threads_starting_up == NULL) {
768 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
769 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
771 mono_g_hash_table_insert (threads_starting_up, thread, thread);
772 mono_threads_unlock ();
774 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
775 if (!internal->start_notify) {
776 mono_threads_lock ();
777 mono_g_hash_table_remove (threads_starting_up, thread);
778 mono_threads_unlock ();
779 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
780 g_free (start_info);
781 return FALSE;
784 if (stack_size == 0)
785 stack_size = default_stacksize_for_thread (internal);
787 /* Create suspended, so we can do some housekeeping before the thread
788 * starts
790 create_flags = CREATE_SUSPENDED;
792 MONO_PREPARE_BLOCKING
793 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
794 stack_size, create_flags, &tid);
795 MONO_FINISH_BLOCKING
797 if (thread_handle == NULL) {
798 /* The thread couldn't be created, so throw an exception */
799 mono_threads_lock ();
800 mono_g_hash_table_remove (threads_starting_up, thread);
801 mono_threads_unlock ();
802 g_free (start_info);
803 if (throw_on_failure)
804 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
805 else
806 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
807 return FALSE;
809 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
811 internal->handle = thread_handle;
812 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
814 internal->threadpool_thread = threadpool_thread;
815 if (threadpool_thread)
816 mono_thread_set_state (internal, ThreadState_Background);
818 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
820 /* Only store the handle when the thread is about to be
821 * launched, to avoid the main thread deadlocking while trying
822 * to clean up a thread that will never be signalled.
824 if (!handle_store (thread, FALSE))
825 return FALSE;
827 MONO_PREPARE_BLOCKING
828 mono_thread_info_resume (tid);
829 MONO_FINISH_BLOCKING
831 if (internal->start_notify) {
833 * Wait for the thread to set up its TLS data etc, so
834 * theres no potential race condition if someone tries
835 * to look up the data believing the thread has
836 * started
838 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
840 MONO_PREPARE_BLOCKING
841 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
842 MONO_FINISH_BLOCKING
844 CloseHandle (internal->start_notify);
845 internal->start_notify = NULL;
848 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
850 return TRUE;
853 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
855 if (mono_thread_start_cb) {
856 mono_thread_start_cb (tid, stack_start, func);
860 void mono_threads_set_default_stacksize (guint32 stacksize)
862 default_stacksize = stacksize;
865 guint32 mono_threads_get_default_stacksize (void)
867 return default_stacksize;
871 * mono_thread_create_internal:
874 MonoInternalThread*
875 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
877 MonoThread *thread;
878 MonoInternalThread *internal;
879 StartInfo *start_info;
880 gboolean res;
882 thread = create_thread_object (domain);
883 internal = create_internal_thread ();
884 MONO_OBJECT_SETREF (thread, internal_thread, internal);
886 start_info = g_new0 (StartInfo, 1);
887 start_info->func = func;
888 start_info->obj = thread;
889 start_info->start_arg = arg;
891 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
892 if (!res)
893 return NULL;
895 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
896 if (mono_check_corlib_version () == NULL)
897 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
899 return internal;
902 void
903 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
905 mono_thread_create_internal (domain, func, arg, FALSE, 0);
908 MonoThread *
909 mono_thread_attach (MonoDomain *domain)
911 return mono_thread_attach_full (domain, FALSE);
914 MonoThread *
915 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
917 MonoThreadInfo *info;
918 MonoInternalThread *thread;
919 MonoThread *current_thread;
920 HANDLE thread_handle;
921 gsize tid;
923 if ((thread = mono_thread_internal_current ())) {
924 if (domain != mono_domain_get ())
925 mono_domain_set (domain, TRUE);
926 /* Already attached */
927 return mono_thread_current ();
930 if (!mono_gc_register_thread (&domain)) {
931 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 ());
934 thread = create_internal_thread ();
936 thread_handle = mono_thread_info_open_handle ();
937 g_assert (thread_handle);
939 tid=GetCurrentThreadId ();
941 thread->handle=thread_handle;
942 thread->tid=tid;
943 #ifdef PLATFORM_ANDROID
944 thread->android_tid = (gpointer) gettid ();
945 #endif
946 thread->stack_ptr = &tid;
948 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
950 info = mono_thread_info_current ();
951 g_assert (info);
952 thread->thread_info = info;
953 thread->small_id = info->small_id;
955 current_thread = new_thread_with_internal (domain, thread);
957 if (!handle_store (current_thread, force_attach)) {
958 /* Mono is shutting down, so just wait for the end */
959 for (;;)
960 Sleep (10000);
963 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
965 SET_CURRENT_OBJECT (thread);
966 mono_domain_set (domain, TRUE);
968 thread_adjust_static_data (thread);
970 init_root_domain_thread (thread, current_thread);
971 if (domain != mono_get_root_domain ())
972 set_current_thread_for_domain (domain, thread, current_thread);
975 if (mono_thread_attach_cb) {
976 guint8 *staddr;
977 size_t stsize;
979 mono_thread_info_get_stack_bounds (&staddr, &stsize);
981 if (staddr == NULL)
982 mono_thread_attach_cb (tid, &tid);
983 else
984 mono_thread_attach_cb (tid, staddr + stsize);
987 // FIXME: Need a separate callback
988 mono_profiler_thread_start (tid);
990 return current_thread;
993 void
994 mono_thread_detach_internal (MonoInternalThread *thread)
996 g_return_if_fail (thread != NULL);
998 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1000 thread_cleanup (thread);
1002 SET_CURRENT_OBJECT (NULL);
1003 mono_domain_unset ();
1005 /* Don't need to CloseHandle this thread, even though we took a
1006 * reference in mono_thread_attach (), because the GC will do it
1007 * when the Thread object is finalised.
1011 void
1012 mono_thread_detach (MonoThread *thread)
1014 if (thread)
1015 mono_thread_detach_internal (thread->internal_thread);
1019 * mono_thread_detach_if_exiting:
1021 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1022 * This should be used at the end of embedding code which calls into managed code, and which
1023 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1025 void
1026 mono_thread_detach_if_exiting (void)
1028 if (mono_thread_info_is_exiting ()) {
1029 MonoInternalThread *thread;
1031 thread = mono_thread_internal_current ();
1032 if (thread) {
1033 mono_thread_detach_internal (thread);
1034 mono_thread_info_detach ();
1039 void
1040 mono_thread_exit ()
1042 MonoInternalThread *thread = mono_thread_internal_current ();
1044 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1046 thread_cleanup (thread);
1047 SET_CURRENT_OBJECT (NULL);
1048 mono_domain_unset ();
1050 /* we could add a callback here for embedders to use. */
1051 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1052 exit (mono_environment_exitcode_get ());
1053 mono_thread_info_exit ();
1056 void
1057 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1059 MonoInternalThread *internal = create_internal_thread ();
1061 internal->state = ThreadState_Unstarted;
1063 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1066 HANDLE
1067 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
1068 MonoObject *start)
1070 StartInfo *start_info;
1071 MonoInternalThread *internal;
1072 gboolean res;
1074 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1076 if (!this->internal_thread)
1077 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1078 internal = this->internal_thread;
1080 LOCK_THREAD (internal);
1082 if ((internal->state & ThreadState_Unstarted) == 0) {
1083 UNLOCK_THREAD (internal);
1084 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1085 return NULL;
1088 if ((internal->state & ThreadState_Aborted) != 0) {
1089 UNLOCK_THREAD (internal);
1090 return this;
1092 /* This is freed in start_wrapper */
1093 start_info = g_new0 (StartInfo, 1);
1094 start_info->func = NULL;
1095 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1096 start_info->delegate = start;
1097 start_info->obj = this;
1098 g_assert (this->obj.vtable->domain == mono_domain_get ());
1100 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1101 if (!res) {
1102 UNLOCK_THREAD (internal);
1103 return NULL;
1106 internal->state &= ~ThreadState_Unstarted;
1108 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1110 UNLOCK_THREAD (internal);
1111 return internal->handle;
1115 * This is called from the finalizer of the internal thread object.
1117 void
1118 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1120 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1123 * Since threads keep a reference to their thread object while running, by the time this function is called,
1124 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1125 * when thread_cleanup () can be called after this.
1127 if (thread)
1128 CloseHandle (thread);
1130 if (this->synch_cs) {
1131 mono_mutex_t *synch_cs = this->synch_cs;
1132 this->synch_cs = NULL;
1133 mono_mutex_destroy (synch_cs);
1134 g_free (synch_cs);
1137 if (this->name) {
1138 void *name = this->name;
1139 this->name = NULL;
1140 g_free (name);
1144 void
1145 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1147 guint32 res;
1148 MonoInternalThread *thread = mono_thread_internal_current ();
1150 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1152 mono_thread_current_check_pending_interrupt ();
1154 while (TRUE) {
1155 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1157 MONO_PREPARE_BLOCKING
1158 res = SleepEx(ms,TRUE);
1159 MONO_FINISH_BLOCKING
1161 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1163 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1164 MonoException* exc = mono_thread_execute_interruption (thread);
1165 if (exc) {
1166 mono_raise_exception (exc);
1167 } else {
1168 // FIXME: !INFINITE
1169 if (ms != INFINITE)
1170 break;
1172 } else {
1173 break;
1178 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1182 gint32
1183 ves_icall_System_Threading_Thread_GetDomainID (void)
1185 return mono_domain_get()->domain_id;
1188 gboolean
1189 ves_icall_System_Threading_Thread_Yield (void)
1191 return mono_thread_info_yield ();
1195 * mono_thread_get_name:
1197 * Return the name of the thread. NAME_LEN is set to the length of the name.
1198 * Return NULL if the thread has no name. The returned memory is owned by the
1199 * caller.
1201 gunichar2*
1202 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1204 gunichar2 *res;
1206 LOCK_THREAD (this_obj);
1208 if (!this_obj->name) {
1209 *name_len = 0;
1210 res = NULL;
1211 } else {
1212 *name_len = this_obj->name_len;
1213 res = g_new (gunichar2, this_obj->name_len);
1214 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1217 UNLOCK_THREAD (this_obj);
1219 return res;
1222 MonoString*
1223 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1225 MonoString* str;
1227 LOCK_THREAD (this_obj);
1229 if (!this_obj->name)
1230 str = NULL;
1231 else
1232 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1234 UNLOCK_THREAD (this_obj);
1236 return str;
1239 void
1240 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1242 LOCK_THREAD (this_obj);
1244 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1245 UNLOCK_THREAD (this_obj);
1247 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1248 return;
1250 if (this_obj->name) {
1251 g_free (this_obj->name);
1252 this_obj->name_len = 0;
1254 if (name) {
1255 this_obj->name = g_new (gunichar2, mono_string_length (name));
1256 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1257 this_obj->name_len = mono_string_length (name);
1259 else
1260 this_obj->name = NULL;
1262 if (managed)
1263 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1265 UNLOCK_THREAD (this_obj);
1267 if (this_obj->name && this_obj->tid) {
1268 char *tname = mono_string_to_utf8 (name);
1269 mono_profiler_thread_name (this_obj->tid, tname);
1270 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1271 mono_free (tname);
1275 void
1276 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1278 mono_thread_set_name_internal (this_obj, name, TRUE);
1282 ves_icall_System_Threading_Thread_GetPriority (MonoInternalThread *thread)
1284 return ThreadPriority_Lowest;
1287 void
1288 ves_icall_System_Threading_Thread_SetPriority (MonoInternalThread *thread, int priority)
1292 /* If the array is already in the requested domain, we just return it,
1293 otherwise we return a copy in that domain. */
1294 static MonoArray*
1295 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1297 MonoArray *copy;
1299 if (!arr)
1300 return NULL;
1302 if (mono_object_domain (arr) == domain)
1303 return arr;
1305 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1306 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1307 return copy;
1310 MonoArray*
1311 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1313 return byte_array_to_domain (arr, mono_get_root_domain ());
1316 MonoArray*
1317 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1319 return byte_array_to_domain (arr, mono_domain_get ());
1322 MonoThread *
1323 mono_thread_current (void)
1325 MonoDomain *domain = mono_domain_get ();
1326 MonoInternalThread *internal = mono_thread_internal_current ();
1327 MonoThread **current_thread_ptr;
1329 g_assert (internal);
1330 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1332 if (!*current_thread_ptr) {
1333 g_assert (domain != mono_get_root_domain ());
1334 *current_thread_ptr = new_thread_with_internal (domain, internal);
1336 return *current_thread_ptr;
1339 MonoInternalThread*
1340 mono_thread_internal_current (void)
1342 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1343 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1344 return res;
1347 gboolean
1348 ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1349 int ms, HANDLE thread)
1351 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1352 gboolean ret;
1354 mono_thread_current_check_pending_interrupt ();
1356 LOCK_THREAD (this);
1358 if ((this->state & ThreadState_Unstarted) != 0) {
1359 UNLOCK_THREAD (this);
1361 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1362 return FALSE;
1365 UNLOCK_THREAD (this);
1367 if(ms== -1) {
1368 ms=INFINITE;
1370 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1372 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1374 MONO_PREPARE_BLOCKING
1375 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1376 MONO_FINISH_BLOCKING
1378 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1380 if(ret==WAIT_OBJECT_0) {
1381 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1383 return(TRUE);
1386 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1388 return(FALSE);
1391 static gint32
1392 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1394 MonoException *exc;
1395 guint32 ret;
1396 gint64 start;
1397 gint32 diff_ms;
1398 gint32 wait = ms;
1400 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1401 do {
1402 MONO_PREPARE_BLOCKING
1403 if (multiple)
1404 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1405 else
1406 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1407 MONO_FINISH_BLOCKING
1409 if (ret != WAIT_IO_COMPLETION)
1410 break;
1412 exc = mono_thread_execute_interruption (thread);
1413 if (exc)
1414 mono_raise_exception (exc);
1416 if (ms == -1)
1417 continue;
1419 /* Re-calculate ms according to the time passed */
1420 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1421 if (diff_ms >= ms) {
1422 ret = WAIT_TIMEOUT;
1423 break;
1425 wait = ms - diff_ms;
1426 } while (TRUE);
1428 return ret;
1431 /* FIXME: exitContext isnt documented */
1432 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1434 HANDLE *handles;
1435 guint32 numhandles;
1436 guint32 ret;
1437 guint32 i;
1438 MonoObject *waitHandle;
1439 MonoInternalThread *thread = mono_thread_internal_current ();
1441 /* Do this WaitSleepJoin check before creating objects */
1442 mono_thread_current_check_pending_interrupt ();
1444 /* We fail in managed if the array has more than 64 elements */
1445 numhandles = (guint32)mono_array_length(mono_handles);
1446 handles = g_new0(HANDLE, numhandles);
1448 for(i = 0; i < numhandles; i++) {
1449 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1450 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1453 if(ms== -1) {
1454 ms=INFINITE;
1457 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1459 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1461 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1463 g_free(handles);
1465 if(ret==WAIT_FAILED) {
1466 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1467 return(FALSE);
1468 } else if(ret==WAIT_TIMEOUT) {
1469 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1470 return(FALSE);
1473 return(TRUE);
1476 /* FIXME: exitContext isnt documented */
1477 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1479 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1480 uintptr_t numhandles;
1481 guint32 ret;
1482 guint32 i;
1483 MonoObject *waitHandle;
1484 MonoInternalThread *thread = mono_thread_internal_current ();
1486 /* Do this WaitSleepJoin check before creating objects */
1487 mono_thread_current_check_pending_interrupt ();
1489 numhandles = mono_array_length(mono_handles);
1490 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1491 return WAIT_FAILED;
1493 for(i = 0; i < numhandles; i++) {
1494 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1495 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1498 if(ms== -1) {
1499 ms=INFINITE;
1502 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1504 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1506 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1508 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1511 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1513 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1514 return ret - WAIT_OBJECT_0;
1516 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1517 return ret - WAIT_ABANDONED_0;
1519 else {
1520 return ret;
1524 /* FIXME: exitContext isnt documented */
1525 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1527 guint32 ret;
1528 MonoInternalThread *thread = mono_thread_internal_current ();
1530 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1532 if(ms== -1) {
1533 ms=INFINITE;
1536 mono_thread_current_check_pending_interrupt ();
1538 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1540 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1542 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1544 if(ret==WAIT_FAILED) {
1545 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1546 return(FALSE);
1547 } else if(ret==WAIT_TIMEOUT) {
1548 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1549 return(FALSE);
1552 return(TRUE);
1555 gboolean
1556 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1558 guint32 ret;
1559 MonoInternalThread *thread = mono_thread_internal_current ();
1561 if (ms == -1)
1562 ms = INFINITE;
1564 mono_thread_current_check_pending_interrupt ();
1566 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1568 MONO_PREPARE_BLOCKING
1569 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1570 MONO_FINISH_BLOCKING
1572 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1574 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1577 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1579 HANDLE mutex;
1581 *created = TRUE;
1583 if (name == NULL) {
1584 mutex = CreateMutex (NULL, owned, NULL);
1585 } else {
1586 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1588 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1589 *created = FALSE;
1593 return(mutex);
1596 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1597 return(ReleaseMutex (handle));
1600 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1601 gint32 rights,
1602 gint32 *error)
1604 HANDLE ret;
1606 *error = ERROR_SUCCESS;
1608 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1609 if (ret == NULL) {
1610 *error = GetLastError ();
1613 return(ret);
1617 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1619 HANDLE sem;
1621 *created = TRUE;
1623 if (name == NULL) {
1624 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1625 } else {
1626 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1627 mono_string_chars (name));
1629 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1630 *created = FALSE;
1634 return(sem);
1637 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1639 gint32 prevcount;
1641 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1643 return (prevcount);
1646 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1648 HANDLE ret;
1650 *error = ERROR_SUCCESS;
1652 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1653 if (ret == NULL) {
1654 *error = GetLastError ();
1657 return(ret);
1660 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1662 HANDLE event;
1664 *created = TRUE;
1666 if (name == NULL) {
1667 event = CreateEvent (NULL, manual, initial, NULL);
1668 } else {
1669 event = CreateEvent (NULL, manual, initial,
1670 mono_string_chars (name));
1672 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1673 *created = FALSE;
1677 return(event);
1680 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1681 return (SetEvent(handle));
1684 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1685 return (ResetEvent(handle));
1688 void
1689 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1690 CloseHandle (handle);
1693 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1694 gint32 rights,
1695 gint32 *error)
1697 HANDLE ret;
1699 *error = ERROR_SUCCESS;
1701 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1702 if (ret == NULL) {
1703 *error = GetLastError ();
1706 return(ret);
1709 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1711 return InterlockedIncrement (location);
1714 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1716 #if SIZEOF_VOID_P == 4
1717 if (G_UNLIKELY ((size_t)location & 0x7)) {
1718 gint64 ret;
1719 mono_interlocked_lock ();
1720 (*location)++;
1721 ret = *location;
1722 mono_interlocked_unlock ();
1723 return ret;
1725 #endif
1726 return InterlockedIncrement64 (location);
1729 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1731 return InterlockedDecrement(location);
1734 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1736 #if SIZEOF_VOID_P == 4
1737 if (G_UNLIKELY ((size_t)location & 0x7)) {
1738 gint64 ret;
1739 mono_interlocked_lock ();
1740 (*location)--;
1741 ret = *location;
1742 mono_interlocked_unlock ();
1743 return ret;
1745 #endif
1746 return InterlockedDecrement64 (location);
1749 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1751 return InterlockedExchange(location, value);
1754 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1756 MonoObject *res;
1757 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1758 mono_gc_wbarrier_generic_nostore (location);
1759 return res;
1762 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1764 return InterlockedExchangePointer(location, value);
1767 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1769 IntFloatUnion val, ret;
1771 val.fval = value;
1772 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1774 return ret.fval;
1777 gint64
1778 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1780 #if SIZEOF_VOID_P == 4
1781 if (G_UNLIKELY ((size_t)location & 0x7)) {
1782 gint64 ret;
1783 mono_interlocked_lock ();
1784 ret = *location;
1785 *location = value;
1786 mono_interlocked_unlock ();
1787 return ret;
1789 #endif
1790 return InterlockedExchange64 (location, value);
1793 gdouble
1794 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1796 LongDoubleUnion val, ret;
1798 val.fval = value;
1799 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1801 return ret.fval;
1804 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1806 return InterlockedCompareExchange(location, value, comparand);
1809 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1811 gint32 r = InterlockedCompareExchange(location, value, comparand);
1812 *success = r == comparand;
1813 return r;
1816 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1818 MonoObject *res;
1819 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1820 mono_gc_wbarrier_generic_nostore (location);
1821 return res;
1824 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1826 return InterlockedCompareExchangePointer(location, value, comparand);
1829 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1831 IntFloatUnion val, ret, cmp;
1833 val.fval = value;
1834 cmp.fval = comparand;
1835 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1837 return ret.fval;
1840 gdouble
1841 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1843 #if SIZEOF_VOID_P == 8
1844 LongDoubleUnion val, comp, ret;
1846 val.fval = value;
1847 comp.fval = comparand;
1848 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1850 return ret.fval;
1851 #else
1852 gdouble old;
1854 mono_interlocked_lock ();
1855 old = *location;
1856 if (old == comparand)
1857 *location = value;
1858 mono_interlocked_unlock ();
1860 return old;
1861 #endif
1864 gint64
1865 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1867 #if SIZEOF_VOID_P == 4
1868 if (G_UNLIKELY ((size_t)location & 0x7)) {
1869 gint64 old;
1870 mono_interlocked_lock ();
1871 old = *location;
1872 if (old == comparand)
1873 *location = value;
1874 mono_interlocked_unlock ();
1875 return old;
1877 #endif
1878 return InterlockedCompareExchange64 (location, value, comparand);
1881 MonoObject*
1882 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1884 MonoObject *res;
1885 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1886 mono_gc_wbarrier_generic_nostore (location);
1887 return res;
1890 MonoObject*
1891 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1893 MonoObject *res;
1894 res = InterlockedExchangePointer ((gpointer *)location, value);
1895 mono_gc_wbarrier_generic_nostore (location);
1896 return res;
1899 gint32
1900 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1902 return InterlockedAdd (location, value);
1905 gint64
1906 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1908 #if SIZEOF_VOID_P == 4
1909 if (G_UNLIKELY ((size_t)location & 0x7)) {
1910 gint64 ret;
1911 mono_interlocked_lock ();
1912 *location += value;
1913 ret = *location;
1914 mono_interlocked_unlock ();
1915 return ret;
1917 #endif
1918 return InterlockedAdd64 (location, value);
1921 gint64
1922 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1924 #if SIZEOF_VOID_P == 4
1925 if (G_UNLIKELY ((size_t)location & 0x7)) {
1926 gint64 ret;
1927 mono_interlocked_lock ();
1928 ret = *location;
1929 mono_interlocked_unlock ();
1930 return ret;
1932 #endif
1933 return InterlockedRead64 (location);
1936 void
1937 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1939 mono_memory_barrier ();
1942 void
1943 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1945 mono_thread_clr_state (this, state);
1947 if (state & ThreadState_Background) {
1948 /* If the thread changes the background mode, the main thread has to
1949 * be notified, since it has to rebuild the list of threads to
1950 * wait for.
1952 SetEvent (background_change_event);
1956 void
1957 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1959 mono_thread_set_state (this, state);
1961 if (state & ThreadState_Background) {
1962 /* If the thread changes the background mode, the main thread has to
1963 * be notified, since it has to rebuild the list of threads to
1964 * wait for.
1966 SetEvent (background_change_event);
1970 guint32
1971 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1973 guint32 state;
1975 LOCK_THREAD (this);
1977 state = this->state;
1979 UNLOCK_THREAD (this);
1981 return state;
1984 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
1986 MonoInternalThread *current;
1987 gboolean throw;
1989 LOCK_THREAD (this);
1991 current = mono_thread_internal_current ();
1993 this->thread_interrupt_requested = TRUE;
1994 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
1996 UNLOCK_THREAD (this);
1998 if (throw) {
1999 abort_thread_internal (this, TRUE, FALSE);
2003 void mono_thread_current_check_pending_interrupt ()
2005 MonoInternalThread *thread = mono_thread_internal_current ();
2006 gboolean throw = FALSE;
2008 LOCK_THREAD (thread);
2010 if (thread->thread_interrupt_requested) {
2011 throw = TRUE;
2012 thread->thread_interrupt_requested = FALSE;
2015 UNLOCK_THREAD (thread);
2017 if (throw) {
2018 mono_raise_exception (mono_get_exception_thread_interrupted ());
2022 int
2023 mono_thread_get_abort_signal (void)
2025 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
2026 return -1;
2027 #elif defined(PLATFORM_ANDROID)
2028 return SIGUNUSED;
2029 #elif !defined (SIGRTMIN)
2030 #ifdef SIGUSR1
2031 return SIGUSR1;
2032 #else
2033 return -1;
2034 #endif /* SIGUSR1 */
2035 #else
2036 static int abort_signum = -1;
2037 int i;
2038 if (abort_signum != -1)
2039 return abort_signum;
2040 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
2041 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
2042 struct sigaction sinfo;
2043 sigaction (i, NULL, &sinfo);
2044 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
2045 abort_signum = i;
2046 return i;
2049 /* fallback to the old way */
2050 return SIGRTMIN;
2051 #endif /* HOST_WIN32 */
2054 #ifdef HOST_WIN32
2055 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2057 MonoException* exc = mono_thread_request_interruption (FALSE);
2058 if (exc) mono_raise_exception (exc);
2060 #endif /* HOST_WIN32 */
2063 * signal_thread_state_change
2065 * Tells the thread that his state has changed and it has to enter the new
2066 * state as soon as possible.
2068 static void signal_thread_state_change (MonoInternalThread *thread)
2070 #ifndef HOST_WIN32
2071 gpointer wait_handle;
2072 #endif
2074 if (thread == mono_thread_internal_current ()) {
2075 /* Do it synchronously */
2076 MonoException *exc = mono_thread_request_interruption (FALSE);
2077 if (exc)
2078 mono_raise_exception (exc);
2081 #ifdef HOST_WIN32
2082 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, (ULONG_PTR)NULL);
2083 #else
2085 * This will cause waits to be broken.
2086 * It will also prevent the thread from entering a wait, so if the thread returns
2087 * from the wait before it receives the abort signal, it will just spin in the wait
2088 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2089 * make it return.
2091 wait_handle = mono_thread_info_prepare_interrupt (thread->handle);
2093 /* fixme: store the state somewhere */
2094 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2096 mono_thread_info_finish_interrupt (wait_handle);
2097 #endif /* HOST_WIN32 */
2100 void
2101 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2103 LOCK_THREAD (thread);
2105 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2106 (thread->state & ThreadState_StopRequested) != 0 ||
2107 (thread->state & ThreadState_Stopped) != 0)
2109 UNLOCK_THREAD (thread);
2110 return;
2113 if ((thread->state & ThreadState_Unstarted) != 0) {
2114 thread->state |= ThreadState_Aborted;
2115 UNLOCK_THREAD (thread);
2116 return;
2119 thread->state |= ThreadState_AbortRequested;
2120 if (thread->abort_state_handle)
2121 mono_gchandle_free (thread->abort_state_handle);
2122 if (state) {
2123 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2124 g_assert (thread->abort_state_handle);
2125 } else {
2126 thread->abort_state_handle = 0;
2128 thread->abort_exc = NULL;
2131 * abort_exc is set in mono_thread_execute_interruption(),
2132 * triggered by the call to signal_thread_state_change(),
2133 * below. There's a point between where we have
2134 * abort_state_handle set, but abort_exc NULL, but that's not
2135 * a problem.
2138 UNLOCK_THREAD (thread);
2140 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2142 /* During shutdown, we can't wait for other threads */
2143 if (!shutting_down)
2144 /* Make sure the thread is awake */
2145 mono_thread_resume (thread);
2147 abort_thread_internal (thread, TRUE, TRUE);
2150 void
2151 ves_icall_System_Threading_Thread_ResetAbort (void)
2153 MonoInternalThread *thread = mono_thread_internal_current ();
2154 gboolean was_aborting;
2156 LOCK_THREAD (thread);
2157 was_aborting = thread->state & ThreadState_AbortRequested;
2158 thread->state &= ~ThreadState_AbortRequested;
2159 UNLOCK_THREAD (thread);
2161 if (!was_aborting) {
2162 const char *msg = "Unable to reset abort because no abort was requested";
2163 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2164 return;
2166 thread->abort_exc = NULL;
2167 if (thread->abort_state_handle) {
2168 mono_gchandle_free (thread->abort_state_handle);
2169 /* This is actually not necessary - the handle
2170 only counts if the exception is set */
2171 thread->abort_state_handle = 0;
2175 void
2176 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2178 LOCK_THREAD (thread);
2180 thread->state &= ~ThreadState_AbortRequested;
2182 if (thread->abort_exc) {
2183 thread->abort_exc = NULL;
2184 if (thread->abort_state_handle) {
2185 mono_gchandle_free (thread->abort_state_handle);
2186 /* This is actually not necessary - the handle
2187 only counts if the exception is set */
2188 thread->abort_state_handle = 0;
2192 UNLOCK_THREAD (thread);
2195 MonoObject*
2196 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2198 MonoInternalThread *thread = this->internal_thread;
2199 MonoObject *state, *deserialized = NULL, *exc;
2200 MonoDomain *domain;
2202 if (!thread->abort_state_handle)
2203 return NULL;
2205 state = mono_gchandle_get_target (thread->abort_state_handle);
2206 g_assert (state);
2208 domain = mono_domain_get ();
2209 if (mono_object_domain (state) == domain)
2210 return state;
2212 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2214 if (!deserialized) {
2215 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2216 if (exc)
2217 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2218 mono_set_pending_exception (invalid_op_exc);
2219 return NULL;
2222 return deserialized;
2225 static gboolean
2226 mono_thread_suspend (MonoInternalThread *thread)
2228 LOCK_THREAD (thread);
2230 if ((thread->state & ThreadState_Unstarted) != 0 ||
2231 (thread->state & ThreadState_Aborted) != 0 ||
2232 (thread->state & ThreadState_Stopped) != 0)
2234 UNLOCK_THREAD (thread);
2235 return FALSE;
2238 if ((thread->state & ThreadState_Suspended) != 0 ||
2239 (thread->state & ThreadState_SuspendRequested) != 0 ||
2240 (thread->state & ThreadState_StopRequested) != 0)
2242 UNLOCK_THREAD (thread);
2243 return TRUE;
2246 thread->state |= ThreadState_SuspendRequested;
2248 UNLOCK_THREAD (thread);
2250 suspend_thread_internal (thread, FALSE);
2251 return TRUE;
2254 void
2255 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2257 if (!mono_thread_suspend (thread)) {
2258 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2259 return;
2263 static gboolean
2264 mono_thread_resume (MonoInternalThread *thread)
2266 LOCK_THREAD (thread);
2268 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2269 thread->state &= ~ThreadState_SuspendRequested;
2270 UNLOCK_THREAD (thread);
2271 return TRUE;
2274 if ((thread->state & ThreadState_Suspended) == 0 ||
2275 (thread->state & ThreadState_Unstarted) != 0 ||
2276 (thread->state & ThreadState_Aborted) != 0 ||
2277 (thread->state & ThreadState_Stopped) != 0)
2279 UNLOCK_THREAD (thread);
2280 return FALSE;
2283 return resume_thread_internal (thread);
2286 void
2287 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2289 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2290 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2291 return;
2295 static gboolean
2296 mono_threads_is_critical_method (MonoMethod *method)
2298 switch (method->wrapper_type) {
2299 case MONO_WRAPPER_RUNTIME_INVOKE:
2300 case MONO_WRAPPER_XDOMAIN_INVOKE:
2301 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2302 return TRUE;
2304 return FALSE;
2307 static gboolean
2308 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2310 if (managed)
2311 return TRUE;
2313 if (mono_threads_is_critical_method (m)) {
2314 *((gboolean*)data) = TRUE;
2315 return TRUE;
2317 return FALSE;
2320 static gboolean
2321 is_running_protected_wrapper (void)
2323 gboolean found = FALSE;
2324 mono_stack_walk (find_wrapper, &found);
2325 return found;
2328 void mono_thread_internal_stop (MonoInternalThread *thread)
2330 LOCK_THREAD (thread);
2332 if ((thread->state & ThreadState_StopRequested) != 0 ||
2333 (thread->state & ThreadState_Stopped) != 0)
2335 UNLOCK_THREAD (thread);
2336 return;
2339 /* Make sure the thread is awake */
2340 mono_thread_resume (thread);
2342 thread->state |= ThreadState_StopRequested;
2343 thread->state &= ~ThreadState_AbortRequested;
2345 UNLOCK_THREAD (thread);
2347 abort_thread_internal (thread, TRUE, TRUE);
2350 void mono_thread_stop (MonoThread *thread)
2352 mono_thread_internal_stop (thread->internal_thread);
2355 gint8
2356 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2358 gint8 tmp;
2359 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2360 return tmp;
2363 gint16
2364 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2366 gint16 tmp;
2367 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2368 return tmp;
2371 gint32
2372 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2374 gint32 tmp;
2375 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2376 return tmp;
2379 gint64
2380 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2382 gint64 tmp;
2383 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2384 return tmp;
2387 void *
2388 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2390 volatile void *tmp;
2391 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2392 return (void *) tmp;
2395 void *
2396 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2398 volatile MonoObject *tmp;
2399 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2400 return (MonoObject *) tmp;
2403 double
2404 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2406 double tmp;
2407 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2408 return tmp;
2411 float
2412 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2414 float tmp;
2415 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2416 return tmp;
2419 gint8
2420 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2422 return InterlockedRead8 (ptr);
2425 gint16
2426 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2428 return InterlockedRead16 (ptr);
2431 gint32
2432 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2434 return InterlockedRead (ptr);
2437 gint64
2438 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2440 #if SIZEOF_VOID_P == 4
2441 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2442 gint64 val;
2443 mono_interlocked_lock ();
2444 val = *(gint64*)ptr;
2445 mono_interlocked_unlock ();
2446 return val;
2448 #endif
2449 return InterlockedRead64 (ptr);
2452 void *
2453 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2455 return InterlockedReadPointer (ptr);
2458 double
2459 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2461 LongDoubleUnion u;
2463 #if SIZEOF_VOID_P == 4
2464 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2465 double val;
2466 mono_interlocked_lock ();
2467 val = *(double*)ptr;
2468 mono_interlocked_unlock ();
2469 return val;
2471 #endif
2473 u.ival = InterlockedRead64 (ptr);
2475 return u.fval;
2478 float
2479 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2481 IntFloatUnion u;
2483 u.ival = InterlockedRead (ptr);
2485 return u.fval;
2488 MonoObject*
2489 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2491 return InterlockedReadPointer (ptr);
2494 void
2495 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2497 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2500 void
2501 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2503 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2506 void
2507 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2509 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2512 void
2513 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2515 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2518 void
2519 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2521 mono_atomic_store_release ((volatile void **) ptr, value);
2524 void
2525 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2527 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2530 void
2531 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2533 mono_atomic_store_release ((volatile double *) ptr, value);
2536 void
2537 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2539 mono_atomic_store_release ((volatile float *) ptr, value);
2542 void
2543 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2545 InterlockedWrite8 (ptr, value);
2548 void
2549 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2551 InterlockedWrite16 (ptr, value);
2554 void
2555 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2557 InterlockedWrite (ptr, value);
2560 void
2561 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2563 #if SIZEOF_VOID_P == 4
2564 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2565 mono_interlocked_lock ();
2566 *(gint64*)ptr = value;
2567 mono_interlocked_unlock ();
2568 return;
2570 #endif
2572 InterlockedWrite64 (ptr, value);
2575 void
2576 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2578 InterlockedWritePointer (ptr, value);
2581 void
2582 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2584 LongDoubleUnion u;
2586 #if SIZEOF_VOID_P == 4
2587 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2588 mono_interlocked_lock ();
2589 *(double*)ptr = value;
2590 mono_interlocked_unlock ();
2591 return;
2593 #endif
2595 u.fval = value;
2597 InterlockedWrite64 (ptr, u.ival);
2600 void
2601 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2603 IntFloatUnion u;
2605 u.fval = value;
2607 InterlockedWrite (ptr, u.ival);
2610 void
2611 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2613 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2616 void
2617 mono_thread_init_tls (void)
2619 MONO_FAST_TLS_INIT (tls_current_object);
2620 mono_native_tls_alloc (&current_object_key, NULL);
2623 void mono_thread_init (MonoThreadStartCB start_cb,
2624 MonoThreadAttachCB attach_cb)
2626 mono_mutex_init_recursive(&threads_mutex);
2627 mono_mutex_init_recursive(&interlocked_mutex);
2628 mono_mutex_init_recursive(&contexts_mutex);
2629 mono_mutex_init_recursive(&joinable_threads_mutex);
2631 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2632 g_assert(background_change_event != NULL);
2634 mono_init_static_data_info (&thread_static_info);
2635 mono_init_static_data_info (&context_static_info);
2637 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2639 mono_thread_start_cb = start_cb;
2640 mono_thread_attach_cb = attach_cb;
2642 /* Get a pseudo handle to the current process. This is just a
2643 * kludge so that wapi can build a process handle if needed.
2644 * As a pseudo handle is returned, we don't need to clean
2645 * anything up.
2647 GetCurrentProcess ();
2650 void mono_thread_cleanup (void)
2652 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2653 MonoThreadInfo *info;
2655 /* The main thread must abandon any held mutexes (particularly
2656 * important for named mutexes as they are shared across
2657 * processes, see bug 74680.) This will happen when the
2658 * thread exits, but if it's not running in a subthread it
2659 * won't exit in time.
2661 info = mono_thread_info_current ();
2662 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2663 #endif
2665 #if 0
2666 /* This stuff needs more testing, it seems one of these
2667 * critical sections can be locked when mono_thread_cleanup is
2668 * called.
2670 mono_mutex_destroy (&threads_mutex);
2671 mono_mutex_destroy (&interlocked_mutex);
2672 mono_mutex_destroy (&contexts_mutex);
2673 mono_mutex_destroy (&delayed_free_table_mutex);
2674 mono_mutex_destroy (&small_id_mutex);
2675 CloseHandle (background_change_event);
2676 #endif
2678 mono_native_tls_free (current_object_key);
2681 void
2682 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2684 mono_thread_cleanup_fn = func;
2687 void
2688 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2690 thread->internal_thread->manage_callback = func;
2693 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2695 mono_thread_notify_pending_exc_fn = func;
2698 G_GNUC_UNUSED
2699 static void print_tids (gpointer key, gpointer value, gpointer user)
2701 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2702 * sizeof(uint) and a cast to uint would overflow
2704 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2705 * print this as a pointer.
2707 g_message ("Waiting for: %p", key);
2710 struct wait_data
2712 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2713 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2714 guint32 num;
2717 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2719 guint32 i, ret;
2721 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2723 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2725 if(ret==WAIT_FAILED) {
2726 /* See the comment in build_wait_tids() */
2727 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2728 return;
2731 for(i=0; i<wait->num; i++)
2732 CloseHandle (wait->handles[i]);
2734 if (ret == WAIT_TIMEOUT)
2735 return;
2737 for(i=0; i<wait->num; i++) {
2738 gsize tid = wait->threads[i]->tid;
2741 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2742 * it can still run io-layer etc. code. So wait for it to really exit.
2743 * FIXME: This won't join threads which are not in the joinable_hash yet.
2745 mono_thread_join ((gpointer)tid);
2747 mono_threads_lock ();
2748 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2749 /* This thread must have been killed, because
2750 * it hasn't cleaned itself up. (It's just
2751 * possible that the thread exited before the
2752 * parent thread had a chance to store the
2753 * handle, and now there is another pointer to
2754 * the already-exited thread stored. In this
2755 * case, we'll just get two
2756 * mono_profiler_thread_end() calls for the
2757 * same thread.)
2760 mono_threads_unlock ();
2761 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2762 thread_cleanup (wait->threads[i]);
2763 } else {
2764 mono_threads_unlock ();
2769 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2771 guint32 i, ret, count;
2773 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2775 /* Add the thread state change event, so it wakes up if a thread changes
2776 * to background mode.
2778 count = wait->num;
2779 if (count < MAXIMUM_WAIT_OBJECTS) {
2780 wait->handles [count] = background_change_event;
2781 count++;
2784 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2786 if(ret==WAIT_FAILED) {
2787 /* See the comment in build_wait_tids() */
2788 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2789 return;
2792 for(i=0; i<wait->num; i++)
2793 CloseHandle (wait->handles[i]);
2795 if (ret == WAIT_TIMEOUT)
2796 return;
2798 if (ret < wait->num) {
2799 gsize tid = wait->threads[ret]->tid;
2800 mono_threads_lock ();
2801 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2802 /* See comment in wait_for_tids about thread cleanup */
2803 mono_threads_unlock ();
2804 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2805 thread_cleanup (wait->threads [ret]);
2806 } else
2807 mono_threads_unlock ();
2811 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2813 struct wait_data *wait=(struct wait_data *)user;
2815 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2816 HANDLE handle;
2817 MonoInternalThread *thread=(MonoInternalThread *)value;
2819 /* Ignore background threads, we abort them later */
2820 /* Do not lock here since it is not needed and the caller holds threads_lock */
2821 if (thread->state & ThreadState_Background) {
2822 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2823 return; /* just leave, ignore */
2826 if (mono_gc_is_finalizer_internal_thread (thread)) {
2827 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2828 return;
2831 if (thread == mono_thread_internal_current ()) {
2832 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2833 return;
2836 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2837 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2838 return;
2841 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2842 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2843 return;
2846 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2847 if (handle == NULL) {
2848 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2849 return;
2852 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2853 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2854 wait->handles[wait->num]=handle;
2855 wait->threads[wait->num]=thread;
2856 wait->num++;
2858 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2859 } else {
2860 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2864 } else {
2865 /* Just ignore the rest, we can't do anything with
2866 * them yet
2871 static gboolean
2872 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2874 struct wait_data *wait=(struct wait_data *)user;
2875 gsize self = GetCurrentThreadId ();
2876 MonoInternalThread *thread = value;
2877 HANDLE handle;
2879 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2880 return FALSE;
2882 /* The finalizer thread is not a background thread */
2883 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2884 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2886 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2887 if (handle == NULL)
2888 return FALSE;
2890 /* printf ("A: %d\n", wait->num); */
2891 wait->handles[wait->num]=thread->handle;
2892 wait->threads[wait->num]=thread;
2893 wait->num++;
2895 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2896 mono_thread_internal_stop (thread);
2897 return TRUE;
2900 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2903 /**
2904 * mono_threads_set_shutting_down:
2906 * Is called by a thread that wants to shut down Mono. If the runtime is already
2907 * shutting down, the calling thread is suspended/stopped, and this function never
2908 * returns.
2910 void
2911 mono_threads_set_shutting_down (void)
2913 MonoInternalThread *current_thread = mono_thread_internal_current ();
2915 mono_threads_lock ();
2917 if (shutting_down) {
2918 mono_threads_unlock ();
2920 /* Make sure we're properly suspended/stopped */
2922 LOCK_THREAD (current_thread);
2924 if ((current_thread->state & ThreadState_SuspendRequested) ||
2925 (current_thread->state & ThreadState_AbortRequested) ||
2926 (current_thread->state & ThreadState_StopRequested)) {
2927 UNLOCK_THREAD (current_thread);
2928 mono_thread_execute_interruption (current_thread);
2929 } else {
2930 current_thread->state |= ThreadState_Stopped;
2931 UNLOCK_THREAD (current_thread);
2934 /*since we're killing the thread, unset the current domain.*/
2935 mono_domain_unset ();
2937 /* Wake up other threads potentially waiting for us */
2938 mono_thread_info_exit ();
2939 } else {
2940 shutting_down = TRUE;
2942 /* Not really a background state change, but this will
2943 * interrupt the main thread if it is waiting for all
2944 * the other threads.
2946 SetEvent (background_change_event);
2948 mono_threads_unlock ();
2952 void mono_thread_manage (void)
2954 struct wait_data wait_data;
2955 struct wait_data *wait = &wait_data;
2957 memset (wait, 0, sizeof (struct wait_data));
2958 /* join each thread that's still running */
2959 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2961 mono_threads_lock ();
2962 if(threads==NULL) {
2963 THREAD_DEBUG (g_message("%s: No threads", __func__));
2964 mono_threads_unlock ();
2965 return;
2967 mono_threads_unlock ();
2969 do {
2970 mono_threads_lock ();
2971 if (shutting_down) {
2972 /* somebody else is shutting down */
2973 mono_threads_unlock ();
2974 break;
2976 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2977 mono_g_hash_table_foreach (threads, print_tids, NULL));
2979 ResetEvent (background_change_event);
2980 wait->num=0;
2981 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2982 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2983 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2984 mono_threads_unlock ();
2985 if(wait->num>0) {
2986 /* Something to wait for */
2987 wait_for_tids_or_state_change (wait, INFINITE);
2989 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2990 } while(wait->num>0);
2992 /* Mono is shutting down, so just wait for the end */
2993 if (!mono_runtime_try_shutdown ()) {
2994 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2995 mono_thread_suspend (mono_thread_internal_current ());
2996 mono_thread_execute_interruption (mono_thread_internal_current ());
3000 * Remove everything but the finalizer thread and self.
3001 * Also abort all the background threads
3002 * */
3003 do {
3004 mono_threads_lock ();
3006 wait->num = 0;
3007 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3008 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3009 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3011 mono_threads_unlock ();
3013 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3014 if(wait->num>0) {
3015 /* Something to wait for */
3016 wait_for_tids (wait, INFINITE);
3018 } while (wait->num > 0);
3021 * give the subthreads a chance to really quit (this is mainly needed
3022 * to get correct user and system times from getrusage/wait/time(1)).
3023 * This could be removed if we avoid pthread_detach() and use pthread_join().
3025 mono_thread_info_yield ();
3028 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3030 MonoInternalThread *thread=(MonoInternalThread *)value;
3032 if(thread->tid != (gsize)user) {
3033 /*TerminateThread (thread->handle, -1);*/
3037 void mono_thread_abort_all_other_threads (void)
3039 gsize self = GetCurrentThreadId ();
3041 mono_threads_lock ();
3042 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3043 mono_g_hash_table_size (threads));
3044 mono_g_hash_table_foreach (threads, print_tids, NULL));
3046 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3048 mono_threads_unlock ();
3051 static void
3052 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3054 MonoInternalThread *thread = (MonoInternalThread*)value;
3055 struct wait_data *wait = (struct wait_data*)user_data;
3056 HANDLE handle;
3059 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3060 * limitation.
3061 * This needs no locking.
3063 if ((thread->state & ThreadState_Suspended) != 0 ||
3064 (thread->state & ThreadState_Stopped) != 0)
3065 return;
3067 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3068 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3069 if (handle == NULL)
3070 return;
3072 wait->handles [wait->num] = handle;
3073 wait->threads [wait->num] = thread;
3074 wait->num++;
3079 * mono_thread_suspend_all_other_threads:
3081 * Suspend all managed threads except the finalizer thread and this thread. It is
3082 * not possible to resume them later.
3084 void mono_thread_suspend_all_other_threads (void)
3086 struct wait_data wait_data;
3087 struct wait_data *wait = &wait_data;
3088 int i;
3089 gsize self = GetCurrentThreadId ();
3090 gpointer *events;
3091 guint32 eventidx = 0;
3092 gboolean starting, finished;
3094 memset (wait, 0, sizeof (struct wait_data));
3096 * The other threads could be in an arbitrary state at this point, i.e.
3097 * they could be starting up, shutting down etc. This means that there could be
3098 * threads which are not even in the threads hash table yet.
3102 * First we set a barrier which will be checked by all threads before they
3103 * are added to the threads hash table, and they will exit if the flag is set.
3104 * This ensures that no threads could be added to the hash later.
3105 * We will use shutting_down as the barrier for now.
3107 g_assert (shutting_down);
3110 * We make multiple calls to WaitForMultipleObjects since:
3111 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3112 * - some threads could exit without becoming suspended
3114 finished = FALSE;
3115 while (!finished) {
3117 * Make a copy of the hashtable since we can't do anything with
3118 * threads while threads_mutex is held.
3120 wait->num = 0;
3121 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3122 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3123 mono_threads_lock ();
3124 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3125 mono_threads_unlock ();
3127 events = g_new0 (gpointer, wait->num);
3128 eventidx = 0;
3129 /* Get the suspended events that we'll be waiting for */
3130 for (i = 0; i < wait->num; ++i) {
3131 MonoInternalThread *thread = wait->threads [i];
3132 gboolean signal_suspend = FALSE;
3134 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3135 //CloseHandle (wait->handles [i]);
3136 wait->threads [i] = NULL; /* ignore this thread in next loop */
3137 continue;
3140 LOCK_THREAD (thread);
3142 if (thread->suspended_event == NULL) {
3143 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3144 if (thread->suspended_event == NULL) {
3145 /* Forget this one and go on to the next */
3146 UNLOCK_THREAD (thread);
3147 continue;
3151 if ((thread->state & ThreadState_Suspended) != 0 ||
3152 (thread->state & ThreadState_StopRequested) != 0 ||
3153 (thread->state & ThreadState_Stopped) != 0) {
3154 UNLOCK_THREAD (thread);
3155 CloseHandle (wait->handles [i]);
3156 wait->threads [i] = NULL; /* ignore this thread in next loop */
3157 continue;
3160 if ((thread->state & ThreadState_SuspendRequested) == 0)
3161 signal_suspend = TRUE;
3163 events [eventidx++] = thread->suspended_event;
3165 /* Convert abort requests into suspend requests */
3166 if ((thread->state & ThreadState_AbortRequested) != 0)
3167 thread->state &= ~ThreadState_AbortRequested;
3169 thread->state |= ThreadState_SuspendRequested;
3171 UNLOCK_THREAD (thread);
3173 /* Signal the thread to suspend */
3174 if (mono_thread_info_new_interrupt_enabled ())
3175 suspend_thread_internal (thread, TRUE);
3176 else if (signal_suspend)
3177 signal_thread_state_change (thread);
3180 /*Only wait on the suspend event if we are using the old path */
3181 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3182 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3183 for (i = 0; i < wait->num; ++i) {
3184 MonoInternalThread *thread = wait->threads [i];
3186 if (thread == NULL)
3187 continue;
3189 LOCK_THREAD (thread);
3190 if ((thread->state & ThreadState_Suspended) != 0) {
3191 CloseHandle (thread->suspended_event);
3192 thread->suspended_event = NULL;
3194 UNLOCK_THREAD (thread);
3198 if (eventidx <= 0) {
3200 * If there are threads which are starting up, we wait until they
3201 * are suspended when they try to register in the threads hash.
3202 * This is guaranteed to finish, since the threads which can create new
3203 * threads get suspended after a while.
3204 * FIXME: The finalizer thread can still create new threads.
3206 mono_threads_lock ();
3207 if (threads_starting_up)
3208 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3209 else
3210 starting = FALSE;
3211 mono_threads_unlock ();
3212 if (starting)
3213 Sleep (100);
3214 else
3215 finished = TRUE;
3218 g_free (events);
3222 static void
3223 collect_threads (gpointer key, gpointer value, gpointer user_data)
3225 MonoInternalThread *thread = (MonoInternalThread*)value;
3226 struct wait_data *wait = (struct wait_data*)user_data;
3227 HANDLE handle;
3229 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3230 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3231 if (handle == NULL)
3232 return;
3234 wait->handles [wait->num] = handle;
3235 wait->threads [wait->num] = thread;
3236 wait->num++;
3240 static gboolean thread_dump_requested;
3242 static G_GNUC_UNUSED gboolean
3243 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3245 GString *p = (GString*)data;
3246 MonoMethod *method = NULL;
3247 if (frame->ji)
3248 method = mono_jit_info_get_method (frame->ji);
3250 if (method) {
3251 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3252 g_string_append_printf (p, " %s\n", location);
3253 g_free (location);
3254 } else
3255 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3257 return FALSE;
3260 static SuspendThreadResult
3261 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3263 MonoInternalThread *thread = ud;
3264 GString* text = g_string_new (0);
3265 char *name;
3266 GError *error = NULL;
3268 if (thread->name) {
3269 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3270 g_assert (!error);
3271 g_string_append_printf (text, "\n\"%s\"", name);
3272 g_free (name);
3274 else if (thread->threadpool_thread)
3275 g_string_append (text, "\n\"<threadpool thread>\"");
3276 else
3277 g_string_append (text, "\n\"<unnamed thread>\"");
3279 #if 0
3280 /* This no longer works with remote unwinding */
3281 #ifndef HOST_WIN32
3282 wapi_desc = wapi_current_thread_desc ();
3283 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3284 free (wapi_desc);
3285 #endif
3286 #endif
3288 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, text);
3290 fprintf (stdout, "%s", text->str);
3292 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3293 OutputDebugStringA(text->str);
3294 #endif
3296 g_string_free (text, TRUE);
3297 fflush (stdout);
3298 return MonoResumeThread;
3301 static void
3302 dump_thread (gpointer key, gpointer value, gpointer user)
3304 MonoInternalThread *thread = (MonoInternalThread *)value;
3306 if (thread == mono_thread_internal_current ())
3307 return;
3310 FIXME This still can hang if we stop a thread during malloc.
3311 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3312 that takes a callback and runs it with the target suspended.
3313 We probably should loop a bit around trying to get it to either managed code
3314 or WSJ state.
3316 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
3319 void
3320 mono_threads_perform_thread_dump (void)
3322 if (!thread_dump_requested)
3323 return;
3325 printf ("Full thread dump:\n");
3327 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3328 something needs then in the process.
3330 mono_loader_lock ();
3331 mono_domain_lock (mono_get_root_domain ());
3333 mono_threads_lock ();
3334 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3335 mono_threads_unlock ();
3337 mono_domain_unlock (mono_get_root_domain ());
3338 mono_loader_unlock ();
3340 thread_dump_requested = FALSE;
3344 * mono_threads_request_thread_dump:
3346 * Ask all threads except the current to print their stacktrace to stdout.
3348 void
3349 mono_threads_request_thread_dump (void)
3351 struct wait_data wait_data;
3352 struct wait_data *wait = &wait_data;
3353 int i;
3355 /*The new thread dump code runs out of the finalizer thread. */
3356 if (mono_thread_info_new_interrupt_enabled ()) {
3357 thread_dump_requested = TRUE;
3358 mono_gc_finalize_notify ();
3359 return;
3363 memset (wait, 0, sizeof (struct wait_data));
3366 * Make a copy of the hashtable since we can't do anything with
3367 * threads while threads_mutex is held.
3369 mono_threads_lock ();
3370 mono_g_hash_table_foreach (threads, collect_threads, wait);
3371 mono_threads_unlock ();
3373 for (i = 0; i < wait->num; ++i) {
3374 MonoInternalThread *thread = wait->threads [i];
3376 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3377 (thread != mono_thread_internal_current ()) &&
3378 !thread->thread_dump_requested) {
3379 thread->thread_dump_requested = TRUE;
3381 signal_thread_state_change (thread);
3384 CloseHandle (wait->handles [i]);
3388 struct ref_stack {
3389 gpointer *refs;
3390 gint allocated; /* +1 so that refs [allocated] == NULL */
3391 gint bottom;
3394 typedef struct ref_stack RefStack;
3396 static RefStack *
3397 ref_stack_new (gint initial_size)
3399 RefStack *rs;
3401 initial_size = MAX (initial_size, 16) + 1;
3402 rs = g_new0 (RefStack, 1);
3403 rs->refs = g_new0 (gpointer, initial_size);
3404 rs->allocated = initial_size;
3405 return rs;
3408 static void
3409 ref_stack_destroy (gpointer ptr)
3411 RefStack *rs = ptr;
3413 if (rs != NULL) {
3414 g_free (rs->refs);
3415 g_free (rs);
3419 static void
3420 ref_stack_push (RefStack *rs, gpointer ptr)
3422 g_assert (rs != NULL);
3424 if (rs->bottom >= rs->allocated) {
3425 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3426 rs->allocated <<= 1;
3427 rs->refs [rs->allocated] = NULL;
3429 rs->refs [rs->bottom++] = ptr;
3432 static void
3433 ref_stack_pop (RefStack *rs)
3435 if (rs == NULL || rs->bottom == 0)
3436 return;
3438 rs->bottom--;
3439 rs->refs [rs->bottom] = NULL;
3442 static gboolean
3443 ref_stack_find (RefStack *rs, gpointer ptr)
3445 gpointer *refs;
3447 if (rs == NULL)
3448 return FALSE;
3450 for (refs = rs->refs; refs && *refs; refs++) {
3451 if (*refs == ptr)
3452 return TRUE;
3454 return FALSE;
3458 * mono_thread_push_appdomain_ref:
3460 * Register that the current thread may have references to objects in domain
3461 * @domain on its stack. Each call to this function should be paired with a
3462 * call to pop_appdomain_ref.
3464 void
3465 mono_thread_push_appdomain_ref (MonoDomain *domain)
3467 MonoInternalThread *thread = mono_thread_internal_current ();
3469 if (thread) {
3470 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3471 SPIN_LOCK (thread->lock_thread_id);
3472 if (thread->appdomain_refs == NULL)
3473 thread->appdomain_refs = ref_stack_new (16);
3474 ref_stack_push (thread->appdomain_refs, domain);
3475 SPIN_UNLOCK (thread->lock_thread_id);
3479 void
3480 mono_thread_pop_appdomain_ref (void)
3482 MonoInternalThread *thread = mono_thread_internal_current ();
3484 if (thread) {
3485 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3486 SPIN_LOCK (thread->lock_thread_id);
3487 ref_stack_pop (thread->appdomain_refs);
3488 SPIN_UNLOCK (thread->lock_thread_id);
3492 gboolean
3493 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3495 gboolean res;
3496 SPIN_LOCK (thread->lock_thread_id);
3497 res = ref_stack_find (thread->appdomain_refs, domain);
3498 SPIN_UNLOCK (thread->lock_thread_id);
3499 return res;
3502 gboolean
3503 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3505 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3508 typedef struct abort_appdomain_data {
3509 struct wait_data wait;
3510 MonoDomain *domain;
3511 } abort_appdomain_data;
3513 static void
3514 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3516 MonoInternalThread *thread = (MonoInternalThread*)value;
3517 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3518 MonoDomain *domain = data->domain;
3520 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3521 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3523 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3524 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3525 if (handle == NULL)
3526 return;
3527 data->wait.handles [data->wait.num] = handle;
3528 data->wait.threads [data->wait.num] = thread;
3529 data->wait.num++;
3530 } else {
3531 /* Just ignore the rest, we can't do anything with
3532 * them yet
3539 * mono_threads_abort_appdomain_threads:
3541 * Abort threads which has references to the given appdomain.
3543 gboolean
3544 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3546 #ifdef __native_client__
3547 return FALSE;
3548 #endif
3550 abort_appdomain_data user_data;
3551 guint32 start_time;
3552 int orig_timeout = timeout;
3553 int i;
3555 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3557 start_time = mono_msec_ticks ();
3558 do {
3559 mono_threads_lock ();
3561 user_data.domain = domain;
3562 user_data.wait.num = 0;
3563 /* This shouldn't take any locks */
3564 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3565 mono_threads_unlock ();
3567 if (user_data.wait.num > 0) {
3568 /* Abort the threads outside the threads lock */
3569 for (i = 0; i < user_data.wait.num; ++i)
3570 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3573 * We should wait for the threads either to abort, or to leave the
3574 * domain. We can't do the latter, so we wait with a timeout.
3576 wait_for_tids (&user_data.wait, 100);
3579 /* Update remaining time */
3580 timeout -= mono_msec_ticks () - start_time;
3581 start_time = mono_msec_ticks ();
3583 if (orig_timeout != -1 && timeout < 0)
3584 return FALSE;
3586 while (user_data.wait.num > 0);
3588 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3590 return TRUE;
3593 static void
3594 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3596 MonoInternalThread *thread = (MonoInternalThread*)value;
3597 MonoDomain *domain = (MonoDomain*)user_data;
3598 int i;
3600 /* No locking needed here */
3601 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3603 if (thread->cached_culture_info) {
3604 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3605 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3606 if (obj && obj->vtable->domain == domain)
3607 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3613 * mono_threads_clear_cached_culture:
3615 * Clear the cached_current_culture from all threads if it is in the
3616 * given appdomain.
3618 void
3619 mono_threads_clear_cached_culture (MonoDomain *domain)
3621 mono_threads_lock ();
3622 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3623 mono_threads_unlock ();
3627 * mono_thread_get_undeniable_exception:
3629 * Return an exception which needs to be raised when leaving a catch clause.
3630 * This is used for undeniable exception propagation.
3632 MonoException*
3633 mono_thread_get_undeniable_exception (void)
3635 MonoInternalThread *thread = mono_thread_internal_current ();
3637 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3639 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3640 * exception if the thread no longer references a dying appdomain.
3642 thread->abort_exc->trace_ips = NULL;
3643 thread->abort_exc->stack_trace = NULL;
3644 return thread->abort_exc;
3647 return NULL;
3650 #if MONO_SMALL_CONFIG
3651 #define NUM_STATIC_DATA_IDX 4
3652 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3653 64, 256, 1024, 4096
3655 #else
3656 #define NUM_STATIC_DATA_IDX 8
3657 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3658 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3660 #endif
3662 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3664 static void
3665 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3667 int i;
3668 gpointer *static_data = addr;
3669 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3670 int j, numwords;
3671 void **ptr;
3672 if (!static_data [i])
3673 continue;
3674 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3675 ptr = static_data [i];
3676 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3677 uintptr_t bmap = static_reference_bitmaps [i][j];
3678 void ** p = ptr;
3679 while (bmap) {
3680 if ((bmap & 1) && *p) {
3681 mark_func (p, gc_data);
3683 p++;
3684 bmap >>= 1;
3691 * mono_alloc_static_data
3693 * Allocate memory blocks for storing threads or context static data
3695 static void
3696 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3698 guint idx = (offset >> 24) - 1;
3699 int i;
3701 gpointer* static_data = *static_data_ptr;
3702 if (!static_data) {
3703 static void* tls_desc = NULL;
3704 if (mono_gc_user_markers_supported () && !tls_desc)
3705 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3706 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3707 *static_data_ptr = static_data;
3708 static_data [0] = static_data;
3711 for (i = 1; i <= idx; ++i) {
3712 if (static_data [i])
3713 continue;
3714 if (mono_gc_user_markers_supported () && threadlocal)
3715 static_data [i] = g_malloc0 (static_data_size [i]);
3716 else
3717 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3721 static void
3722 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3724 int i;
3725 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3726 gpointer p = static_data [i];
3727 if (!p)
3728 continue;
3730 * At this point, the static data pointer array is still registered with the
3731 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3732 * data. Freeing the individual arrays without first nulling their slots
3733 * would make it possible for mark_tls_slots() to encounter a pointer to
3734 * such an already freed array. See bug #13813.
3736 static_data [i] = NULL;
3737 mono_memory_write_barrier ();
3738 if (mono_gc_user_markers_supported () && threadlocal)
3739 g_free (p);
3740 else
3741 mono_gc_free_fixed (p);
3743 mono_gc_free_fixed (static_data);
3747 * mono_init_static_data_info
3749 * Initializes static data counters
3751 static void mono_init_static_data_info (StaticDataInfo *static_data)
3753 static_data->idx = 0;
3754 static_data->offset = 0;
3755 static_data->freelist = NULL;
3759 * mono_alloc_static_data_slot
3761 * Generates an offset for static data. static_data contains the counters
3762 * used to generate it.
3764 static guint32
3765 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3767 guint32 offset;
3769 if (!static_data->idx && !static_data->offset) {
3771 * we use the first chunk of the first allocation also as
3772 * an array for the rest of the data
3774 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3776 static_data->offset += align - 1;
3777 static_data->offset &= ~(align - 1);
3778 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3779 static_data->idx ++;
3780 g_assert (size <= static_data_size [static_data->idx]);
3781 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3782 static_data->offset = 0;
3784 offset = static_data->offset | ((static_data->idx + 1) << 24);
3785 static_data->offset += size;
3786 return offset;
3790 * ensure thread static fields already allocated are valid for thread
3791 * This function is called when a thread is created or on thread attach.
3793 static void
3794 thread_adjust_static_data (MonoInternalThread *thread)
3796 guint32 offset;
3798 mono_threads_lock ();
3799 if (thread_static_info.offset || thread_static_info.idx > 0) {
3800 /* get the current allocated size */
3801 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3802 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3804 mono_threads_unlock ();
3807 static void
3808 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3810 MonoInternalThread *thread = value;
3811 guint32 offset = GPOINTER_TO_UINT (user);
3813 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3816 static MonoThreadDomainTls*
3817 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3819 MonoThreadDomainTls* prev = NULL;
3820 MonoThreadDomainTls* tmp = static_data->freelist;
3821 while (tmp) {
3822 if (tmp->size == size) {
3823 if (prev)
3824 prev->next = tmp->next;
3825 else
3826 static_data->freelist = tmp->next;
3827 return tmp;
3829 prev = tmp;
3830 tmp = tmp->next;
3832 return NULL;
3835 #if SIZEOF_VOID_P == 4
3836 #define ONE_P 1
3837 #else
3838 #define ONE_P 1ll
3839 #endif
3841 static void
3842 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3844 int i;
3845 int idx = (offset >> 24) - 1;
3846 uintptr_t *rb;
3847 if (!static_reference_bitmaps [idx])
3848 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3849 rb = static_reference_bitmaps [idx];
3850 offset &= 0xffffff;
3851 offset /= sizeof (gpointer);
3852 /* offset is now the bitmap offset */
3853 for (i = 0; i < numbits; ++i) {
3854 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3855 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (ONE_P << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3859 static void
3860 clear_reference_bitmap (guint32 offset, guint32 size)
3862 int idx = (offset >> 24) - 1;
3863 uintptr_t *rb;
3864 rb = static_reference_bitmaps [idx];
3865 offset &= 0xffffff;
3866 offset /= sizeof (gpointer);
3867 size /= sizeof (gpointer);
3868 size += offset;
3869 /* offset is now the bitmap offset */
3870 for (; offset < size; ++offset)
3871 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3875 * The offset for a special static variable is composed of three parts:
3876 * a bit that indicates the type of static data (0:thread, 1:context),
3877 * an index in the array of chunks of memory for the thread (thread->static_data)
3878 * and an offset in that chunk of mem. This allows allocating less memory in the
3879 * common case.
3882 guint32
3883 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3885 guint32 offset;
3886 if (static_type == SPECIAL_STATIC_THREAD) {
3887 MonoThreadDomainTls *item;
3888 mono_threads_lock ();
3889 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3890 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3891 if (item) {
3892 offset = item->offset;
3893 g_free (item);
3894 } else {
3895 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3897 update_tls_reference_bitmap (offset, bitmap, numbits);
3898 /* This can be called during startup */
3899 if (threads != NULL)
3900 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3901 mono_threads_unlock ();
3902 } else {
3903 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3904 mono_contexts_lock ();
3905 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3906 mono_contexts_unlock ();
3907 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3909 return offset;
3912 gpointer
3913 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3915 /* The high bit means either thread (0) or static (1) data. */
3917 guint32 static_type = (offset & 0x80000000);
3918 int idx;
3920 offset &= 0x7fffffff;
3921 idx = (offset >> 24) - 1;
3923 if (static_type == 0) {
3924 return get_thread_static_data (thread, offset);
3925 } else {
3926 /* Allocate static data block under demand, since we don't have a list
3927 // of contexts
3929 MonoAppContext *context = mono_context_get ();
3930 if (!context->static_data || !context->static_data [idx]) {
3931 mono_contexts_lock ();
3932 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3933 mono_contexts_unlock ();
3935 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3939 gpointer
3940 mono_get_special_static_data (guint32 offset)
3942 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3945 typedef struct {
3946 guint32 offset;
3947 guint32 size;
3948 } TlsOffsetSize;
3950 static void
3951 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3953 MonoInternalThread *thread = value;
3954 TlsOffsetSize *data = user;
3955 int idx = (data->offset >> 24) - 1;
3956 char *ptr;
3958 if (!thread->static_data || !thread->static_data [idx])
3959 return;
3960 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3961 mono_gc_bzero_atomic (ptr, data->size);
3964 static void
3965 do_free_special_slot (guint32 offset, guint32 size)
3967 guint32 static_type = (offset & 0x80000000);
3968 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3969 if (static_type == 0) {
3970 TlsOffsetSize data;
3971 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3972 data.offset = offset & 0x7fffffff;
3973 data.size = size;
3974 clear_reference_bitmap (data.offset, data.size);
3975 if (threads != NULL)
3976 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3977 item->offset = offset;
3978 item->size = size;
3980 if (!mono_runtime_is_shutting_down ()) {
3981 item->next = thread_static_info.freelist;
3982 thread_static_info.freelist = item;
3983 } else {
3984 /* We could be called during shutdown after mono_thread_cleanup () is called */
3985 g_free (item);
3987 } else {
3988 /* FIXME: free context static data as well */
3992 static void
3993 do_free_special (gpointer key, gpointer value, gpointer data)
3995 MonoClassField *field = key;
3996 guint32 offset = GPOINTER_TO_UINT (value);
3997 gint32 align;
3998 guint32 size;
3999 size = mono_type_size (field->type, &align);
4000 do_free_special_slot (offset, size);
4003 void
4004 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4006 mono_threads_lock ();
4007 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4008 mono_threads_unlock ();
4011 void
4012 mono_special_static_data_free_slot (guint32 offset, guint32 size)
4014 mono_threads_lock ();
4015 do_free_special_slot (offset, size);
4016 mono_threads_unlock ();
4020 * allocates room in the thread local area for storing an instance of the struct type
4021 * the allocation is kept track of in domain->tlsrec_list.
4023 uint32_t
4024 mono_thread_alloc_tls (MonoReflectionType *type)
4026 MonoDomain *domain = mono_domain_get ();
4027 MonoClass *klass;
4028 MonoTlsDataRecord *tlsrec;
4029 int max_set = 0;
4030 gsize *bitmap;
4031 gsize default_bitmap [4] = {0};
4032 uint32_t tls_offset;
4033 guint32 size;
4034 gint32 align;
4036 klass = mono_class_from_mono_type (type->type);
4037 /* TlsDatum is a struct, so we subtract the object header size offset */
4038 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
4039 size = mono_type_size (type->type, &align);
4040 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
4041 if (bitmap != default_bitmap)
4042 g_free (bitmap);
4043 tlsrec = g_new0 (MonoTlsDataRecord, 1);
4044 tlsrec->tls_offset = tls_offset;
4045 tlsrec->size = size;
4046 mono_domain_lock (domain);
4047 tlsrec->next = domain->tlsrec_list;
4048 domain->tlsrec_list = tlsrec;
4049 mono_domain_unlock (domain);
4050 return tls_offset;
4053 static void
4054 destroy_tls (MonoDomain *domain, uint32_t tls_offset)
4056 MonoTlsDataRecord *prev = NULL;
4057 MonoTlsDataRecord *cur;
4058 guint32 size = 0;
4060 mono_domain_lock (domain);
4061 cur = domain->tlsrec_list;
4062 while (cur) {
4063 if (cur->tls_offset == tls_offset) {
4064 if (prev)
4065 prev->next = cur->next;
4066 else
4067 domain->tlsrec_list = cur->next;
4068 size = cur->size;
4069 g_free (cur);
4070 break;
4072 prev = cur;
4073 cur = cur->next;
4075 mono_domain_unlock (domain);
4076 if (size)
4077 mono_special_static_data_free_slot (tls_offset, size);
4080 void
4081 mono_thread_destroy_tls (uint32_t tls_offset)
4083 destroy_tls (mono_domain_get (), tls_offset);
4087 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
4089 void
4090 mono_thread_destroy_domain_tls (MonoDomain *domain)
4092 while (domain->tlsrec_list)
4093 destroy_tls (domain, domain->tlsrec_list->tls_offset);
4096 static MonoClassField *local_slots = NULL;
4098 typedef struct {
4099 /* local tls data to get locals_slot from a thread */
4100 guint32 offset;
4101 int idx;
4102 /* index in the locals_slot array */
4103 int slot;
4104 } LocalSlotID;
4106 static void
4107 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4109 LocalSlotID *sid = user_data;
4110 MonoInternalThread *thread = (MonoInternalThread*)value;
4111 MonoArray *slots_array;
4113 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4114 * it is for the right domain, so we need to check if it is allocated an initialized
4115 * for the current thread.
4117 /*g_print ("handling thread %p\n", thread);*/
4118 if (!thread->static_data || !thread->static_data [sid->idx])
4119 return;
4120 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4121 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4122 return;
4123 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4126 void
4127 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4129 MonoDomain *domain;
4130 LocalSlotID sid;
4131 sid.slot = slot;
4132 if (thread_local) {
4133 void *addr = NULL;
4134 if (!local_slots) {
4135 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4136 if (!local_slots) {
4137 g_warning ("local_slots field not found in Thread class");
4138 return;
4141 domain = mono_domain_get ();
4142 mono_domain_lock (domain);
4143 if (domain->special_static_fields)
4144 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4145 mono_domain_unlock (domain);
4146 if (!addr)
4147 return;
4148 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4149 sid.offset = GPOINTER_TO_UINT (addr);
4150 sid.offset &= 0x7fffffff;
4151 sid.idx = (sid.offset >> 24) - 1;
4152 mono_threads_lock ();
4153 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4154 mono_threads_unlock ();
4155 } else {
4156 /* FIXME: clear the slot for MonoAppContexts, too */
4160 #ifdef HOST_WIN32
4161 static void CALLBACK dummy_apc (ULONG_PTR param)
4164 #endif
4167 * mono_thread_execute_interruption
4169 * Performs the operation that the requested thread state requires (abort,
4170 * suspend or stop)
4172 static MonoException*
4173 mono_thread_execute_interruption (MonoInternalThread *thread)
4175 LOCK_THREAD (thread);
4177 /* MonoThread::interruption_requested can only be changed with atomics */
4178 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4179 /* this will consume pending APC calls */
4180 #ifdef HOST_WIN32
4181 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4182 #endif
4183 InterlockedDecrement (&thread_interruption_requested);
4184 /* Clear the interrupted flag of the thread so it can wait again */
4185 mono_thread_info_clear_interruption ();
4188 if ((thread->state & ThreadState_AbortRequested) != 0) {
4189 UNLOCK_THREAD (thread);
4190 if (thread->abort_exc == NULL) {
4192 * This might be racy, but it has to be called outside the lock
4193 * since it calls managed code.
4195 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4197 return thread->abort_exc;
4199 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4200 self_suspend_internal (thread);
4201 return NULL;
4203 else if ((thread->state & ThreadState_StopRequested) != 0) {
4204 /* FIXME: do this through the JIT? */
4206 UNLOCK_THREAD (thread);
4208 mono_thread_exit ();
4209 return NULL;
4210 } else if (thread->pending_exception) {
4211 MonoException *exc;
4213 exc = thread->pending_exception;
4214 thread->pending_exception = NULL;
4216 UNLOCK_THREAD (thread);
4217 return exc;
4218 } else if (thread->thread_interrupt_requested) {
4220 thread->thread_interrupt_requested = FALSE;
4221 UNLOCK_THREAD (thread);
4223 return(mono_get_exception_thread_interrupted ());
4226 UNLOCK_THREAD (thread);
4228 return NULL;
4232 * mono_thread_request_interruption
4234 * A signal handler can call this method to request the interruption of a
4235 * thread. The result of the interruption will depend on the current state of
4236 * the thread. If the result is an exception that needs to be throw, it is
4237 * provided as return value.
4239 MonoException*
4240 mono_thread_request_interruption (gboolean running_managed)
4242 MonoInternalThread *thread = mono_thread_internal_current ();
4244 /* The thread may already be stopping */
4245 if (thread == NULL)
4246 return NULL;
4248 #ifdef HOST_WIN32
4249 if (thread->interrupt_on_stop &&
4250 thread->state & ThreadState_StopRequested &&
4251 thread->state & ThreadState_Background)
4252 ExitThread (1);
4253 #endif
4255 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4256 return NULL;
4257 InterlockedIncrement (&thread_interruption_requested);
4259 if (!running_managed || is_running_protected_wrapper ()) {
4260 /* Can't stop while in unmanaged code. Increase the global interruption
4261 request count. When exiting the unmanaged method the count will be
4262 checked and the thread will be interrupted. */
4264 if (mono_thread_notify_pending_exc_fn && !running_managed)
4265 /* The JIT will notify the thread about the interruption */
4266 /* This shouldn't take any locks */
4267 mono_thread_notify_pending_exc_fn (NULL);
4269 /* this will awake the thread if it is in WaitForSingleObject
4270 or similar */
4271 /* Our implementation of this function ignores the func argument */
4272 #ifdef HOST_WIN32
4273 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4274 #else
4275 mono_thread_info_self_interrupt ();
4276 #endif
4277 return NULL;
4279 else {
4280 return mono_thread_execute_interruption (thread);
4284 /*This function should be called by a thread after it has exited all of
4285 * its handle blocks at interruption time.*/
4286 MonoException*
4287 mono_thread_resume_interruption (void)
4289 MonoInternalThread *thread = mono_thread_internal_current ();
4290 gboolean still_aborting;
4292 /* The thread may already be stopping */
4293 if (thread == NULL)
4294 return NULL;
4296 LOCK_THREAD (thread);
4297 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4298 UNLOCK_THREAD (thread);
4300 /*This can happen if the protected block called Thread::ResetAbort*/
4301 if (!still_aborting)
4302 return FALSE;
4304 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4305 return NULL;
4306 InterlockedIncrement (&thread_interruption_requested);
4308 mono_thread_info_self_interrupt ();
4310 return mono_thread_execute_interruption (thread);
4313 gboolean mono_thread_interruption_requested ()
4315 if (thread_interruption_requested) {
4316 MonoInternalThread *thread = mono_thread_internal_current ();
4317 /* The thread may already be stopping */
4318 if (thread != NULL)
4319 return (thread->interruption_requested);
4321 return FALSE;
4324 static MonoException*
4325 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4327 MonoInternalThread *thread = mono_thread_internal_current ();
4329 /* The thread may already be stopping */
4330 if (thread == NULL)
4331 return NULL;
4333 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4334 MonoException* exc = mono_thread_execute_interruption (thread);
4335 if (exc)
4336 return exc;
4338 return NULL;
4342 * Performs the interruption of the current thread, if one has been requested,
4343 * and the thread is not running a protected wrapper.
4344 * Return the exception which needs to be thrown, if any.
4346 MonoException*
4347 mono_thread_interruption_checkpoint (void)
4349 return mono_thread_interruption_checkpoint_request (FALSE);
4353 * Performs the interruption of the current thread, if one has been requested.
4354 * Return the exception which needs to be thrown, if any.
4356 MonoException*
4357 mono_thread_force_interruption_checkpoint_noraise (void)
4359 return mono_thread_interruption_checkpoint_request (TRUE);
4363 * Performs the interruption of the current thread, if one has been requested.
4364 * Throw the exception which needs to be thrown, if any.
4366 void
4367 mono_thread_force_interruption_checkpoint (void)
4369 MonoException *ex;
4371 ex = mono_thread_interruption_checkpoint_request (TRUE);
4372 if (ex)
4373 mono_raise_exception (ex);
4377 * mono_thread_get_and_clear_pending_exception:
4379 * Return any pending exceptions for the current thread and clear it as a side effect.
4381 MonoException*
4382 mono_thread_get_and_clear_pending_exception (void)
4384 MonoInternalThread *thread = mono_thread_internal_current ();
4386 /* The thread may already be stopping */
4387 if (thread == NULL)
4388 return NULL;
4390 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4391 return mono_thread_execute_interruption (thread);
4394 if (thread->pending_exception) {
4395 MonoException *exc = thread->pending_exception;
4397 thread->pending_exception = NULL;
4398 return exc;
4401 return NULL;
4405 * mono_set_pending_exception:
4407 * Set the pending exception of the current thread to EXC.
4408 * The exception will be thrown when execution returns to managed code.
4410 void
4411 mono_set_pending_exception (MonoException *exc)
4413 MonoInternalThread *thread = mono_thread_internal_current ();
4415 /* The thread may already be stopping */
4416 if (thread == NULL)
4417 return;
4419 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4421 mono_thread_request_interruption (FALSE);
4425 * mono_thread_interruption_request_flag:
4427 * Returns the address of a flag that will be non-zero if an interruption has
4428 * been requested for a thread. The thread to interrupt may not be the current
4429 * thread, so an additional call to mono_thread_interruption_requested() or
4430 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4431 * zero.
4433 gint32* mono_thread_interruption_request_flag ()
4435 return &thread_interruption_requested;
4438 void
4439 mono_thread_init_apartment_state (void)
4441 #ifdef HOST_WIN32
4442 MonoInternalThread* thread = mono_thread_internal_current ();
4444 /* Positive return value indicates success, either
4445 * S_OK if this is first CoInitialize call, or
4446 * S_FALSE if CoInitialize already called, but with same
4447 * threading model. A negative value indicates failure,
4448 * probably due to trying to change the threading model.
4450 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4451 ? COINIT_APARTMENTTHREADED
4452 : COINIT_MULTITHREADED) < 0) {
4453 thread->apartment_state = ThreadApartmentState_Unknown;
4455 #endif
4458 void
4459 mono_thread_cleanup_apartment_state (void)
4461 #ifdef HOST_WIN32
4462 MonoInternalThread* thread = mono_thread_internal_current ();
4464 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4465 CoUninitialize ();
4467 #endif
4470 void
4471 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4473 LOCK_THREAD (thread);
4474 thread->state |= state;
4475 UNLOCK_THREAD (thread);
4478 void
4479 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4481 LOCK_THREAD (thread);
4482 thread->state &= ~state;
4483 UNLOCK_THREAD (thread);
4486 gboolean
4487 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4489 gboolean ret = FALSE;
4491 LOCK_THREAD (thread);
4493 if ((thread->state & test) != 0) {
4494 ret = TRUE;
4497 UNLOCK_THREAD (thread);
4499 return ret;
4502 //static MonoClassField *execution_context_field;
4504 static MonoObject**
4505 get_execution_context_addr (void)
4507 MonoDomain *domain = mono_domain_get ();
4508 guint32 offset = domain->execution_context_field_offset;
4510 if (!offset) {
4511 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4512 g_assert (field);
4514 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4516 mono_domain_lock (domain);
4517 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4518 mono_domain_unlock (domain);
4519 g_assert (offset);
4521 domain->execution_context_field_offset = offset;
4524 return (MonoObject**) mono_get_special_static_data (offset);
4527 MonoObject*
4528 mono_thread_get_execution_context (void)
4530 return *get_execution_context_addr ();
4533 void
4534 mono_thread_set_execution_context (MonoObject *ec)
4536 *get_execution_context_addr () = ec;
4539 static gboolean has_tls_get = FALSE;
4541 void
4542 mono_runtime_set_has_tls_get (gboolean val)
4544 has_tls_get = val;
4547 gboolean
4548 mono_runtime_has_tls_get (void)
4550 return has_tls_get;
4554 mono_thread_kill (MonoInternalThread *thread, int signal)
4556 #ifdef __native_client__
4557 /* Workaround pthread_kill abort() in NaCl glibc. */
4558 return -1;
4559 #endif
4560 #if defined (HOST_WIN32) || !defined (HAVE_SIGACTION)
4561 /* Win32 uses QueueUserAPC and callers of this are guarded */
4562 g_assert_not_reached ();
4563 #else
4564 # ifdef PTHREAD_POINTER_ID
4565 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4566 # else
4567 # ifdef USE_TKILL_ON_ANDROID
4568 if (thread->android_tid != 0) {
4569 int ret;
4570 int old_errno = errno;
4572 ret = tkill ((pid_t) thread->android_tid, signal);
4573 if (ret < 0) {
4574 ret = errno;
4575 errno = old_errno;
4578 return ret;
4580 else
4581 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4582 # else
4583 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4584 # endif
4585 # endif
4586 #endif
4589 static void
4590 self_interrupt_thread (void *_unused)
4592 MonoThreadInfo *info = mono_thread_info_current ();
4593 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4594 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4595 mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
4596 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4599 static gboolean
4600 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4602 if (!ji)
4603 return FALSE;
4604 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4607 static gboolean
4608 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4610 MonoJitInfo **dest = data;
4611 *dest = frame->ji;
4612 return TRUE;
4615 static MonoJitInfo*
4616 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4618 MonoJitInfo *ji = NULL;
4619 if (!info)
4620 return NULL;
4621 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4622 return ji;
4625 typedef struct {
4626 MonoInternalThread *thread;
4627 gboolean install_async_abort;
4628 gpointer interrupt_handle;
4629 } AbortThreadData;
4631 static SuspendThreadResult
4632 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4634 AbortThreadData *data = ud;
4635 MonoInternalThread *thread = data->thread;
4636 MonoJitInfo *ji = NULL;
4637 gboolean protected_wrapper;
4638 gboolean running_managed;
4640 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4641 return MonoResumeThread;
4643 /*someone is already interrupting it*/
4644 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4645 return MonoResumeThread;
4647 InterlockedIncrement (&thread_interruption_requested);
4649 ji = mono_thread_info_get_last_managed (info);
4650 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4651 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4653 if (!protected_wrapper && running_managed) {
4654 /*We are in managed code*/
4655 /*Set the thread to call */
4656 if (data->install_async_abort)
4657 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4658 return MonoResumeThread;
4659 } else {
4660 if (mono_thread_notify_pending_exc_fn)
4661 /* The JIT will notify the thread about the interruption */
4662 mono_thread_notify_pending_exc_fn (info);
4665 * This will cause waits to be broken.
4666 * It will also prevent the thread from entering a wait, so if the thread returns
4667 * from the wait before it receives the abort signal, it will just spin in the wait
4668 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4669 * make it return.
4671 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4672 return MonoResumeThread;
4676 static void
4677 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4679 AbortThreadData data = { 0 };
4680 data.thread = thread;
4681 data.install_async_abort = install_async_abort;
4683 if (!mono_thread_info_new_interrupt_enabled ()) {
4684 signal_thread_state_change (thread);
4685 return;
4689 FIXME this is insanely broken, it doesn't cause interruption to happen
4690 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4692 if (thread == mono_thread_internal_current ()) {
4693 /* Do it synchronously */
4694 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4695 if (exc)
4696 mono_raise_exception (exc);
4697 mono_thread_info_interrupt (thread->handle);
4698 return;
4701 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
4702 if (data.interrupt_handle)
4703 mono_thread_info_finish_interrupt (data.interrupt_handle);
4704 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4707 typedef struct{
4708 MonoInternalThread *thread;
4709 gboolean interrupt;
4710 gpointer interrupt_handle;
4711 } SuspendThreadData;
4713 static SuspendThreadResult
4714 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4716 SuspendThreadData *data = ud;
4717 MonoInternalThread *thread = data->thread;
4718 MonoJitInfo *ji = NULL;
4719 gboolean protected_wrapper;
4720 gboolean running_managed;
4722 ji = mono_thread_info_get_last_managed (info);
4723 protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4724 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4726 if (running_managed && !protected_wrapper) {
4727 thread->state &= ~ThreadState_SuspendRequested;
4728 thread->state |= ThreadState_Suspended;
4729 return KeepSuspended;
4730 } else {
4731 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4732 InterlockedIncrement (&thread_interruption_requested);
4733 if (data->interrupt)
4734 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4736 if (mono_thread_notify_pending_exc_fn && !running_managed)
4737 /* The JIT will notify the thread about the interruption */
4738 mono_thread_notify_pending_exc_fn (info);
4739 return MonoResumeThread;
4743 static void
4744 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4746 if (!mono_thread_info_new_interrupt_enabled ()) {
4747 signal_thread_state_change (thread);
4748 return;
4751 LOCK_THREAD (thread);
4752 if (thread == mono_thread_internal_current ()) {
4753 mono_thread_info_begin_self_suspend ();
4754 //XXX replace this with better named functions
4755 thread->state &= ~ThreadState_SuspendRequested;
4756 thread->state |= ThreadState_Suspended;
4757 UNLOCK_THREAD (thread);
4758 mono_thread_info_end_self_suspend ();
4759 } else {
4760 SuspendThreadData data = { 0 };
4761 data.thread = thread;
4762 data.interrupt = interrupt;
4764 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
4765 if (data.interrupt_handle)
4766 mono_thread_info_finish_interrupt (data.interrupt_handle);
4767 UNLOCK_THREAD (thread);
4771 /*This is called with @thread synch_cs held and it must release it*/
4772 static void
4773 self_suspend_internal (MonoInternalThread *thread)
4775 if (!mono_thread_info_new_interrupt_enabled ()) {
4776 thread->state &= ~ThreadState_SuspendRequested;
4777 thread->state |= ThreadState_Suspended;
4778 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4779 if (thread->suspend_event == NULL) {
4780 UNLOCK_THREAD (thread);
4781 return;
4783 if (thread->suspended_event)
4784 SetEvent (thread->suspended_event);
4786 UNLOCK_THREAD (thread);
4788 if (shutting_down) {
4789 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4790 for (;;)
4791 Sleep (1000);
4794 WaitForSingleObject (thread->suspend_event, INFINITE);
4796 LOCK_THREAD (thread);
4798 CloseHandle (thread->suspend_event);
4799 thread->suspend_event = NULL;
4800 thread->state &= ~ThreadState_Suspended;
4802 /* The thread that requested the resume will have replaced this event
4803 * and will be waiting for it
4805 SetEvent (thread->resume_event);
4807 UNLOCK_THREAD (thread);
4808 return;
4811 mono_thread_info_begin_self_suspend ();
4812 thread->state &= ~ThreadState_SuspendRequested;
4813 thread->state |= ThreadState_Suspended;
4814 UNLOCK_THREAD (thread);
4815 mono_thread_info_end_self_suspend ();
4818 /*This is called with @thread synch_cs held and it must release it*/
4819 static gboolean
4820 resume_thread_internal (MonoInternalThread *thread)
4822 if (!mono_thread_info_new_interrupt_enabled ()) {
4823 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4824 if (thread->resume_event == NULL) {
4825 UNLOCK_THREAD (thread);
4826 return FALSE;
4829 /* Awake the thread */
4830 SetEvent (thread->suspend_event);
4832 UNLOCK_THREAD (thread);
4834 /* Wait for the thread to awake */
4835 WaitForSingleObject (thread->resume_event, INFINITE);
4836 CloseHandle (thread->resume_event);
4837 thread->resume_event = NULL;
4838 return TRUE;
4841 UNLOCK_THREAD (thread);
4842 /* Awake the thread */
4843 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4844 return FALSE;
4845 LOCK_THREAD (thread);
4846 thread->state &= ~ThreadState_Suspended;
4847 UNLOCK_THREAD (thread);
4848 return TRUE;
4853 * mono_thread_is_foreign:
4854 * @thread: the thread to query
4856 * This function allows one to determine if a thread was created by the mono runtime and has
4857 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4859 * Returns: true if @thread was not created by the runtime.
4861 mono_bool
4862 mono_thread_is_foreign (MonoThread *thread)
4864 MonoThreadInfo *info = thread->internal_thread->thread_info;
4865 return info->runtime_thread == FALSE;
4869 * mono_add_joinable_thread:
4871 * Add TID to the list of joinable threads.
4872 * LOCKING: Acquires the threads lock.
4874 void
4875 mono_threads_add_joinable_thread (gpointer tid)
4877 #ifndef HOST_WIN32
4879 * We cannot detach from threads because it causes problems like
4880 * 2fd16f60/r114307. So we collect them and join them when
4881 * we have time (in he finalizer thread).
4883 joinable_threads_lock ();
4884 if (!joinable_threads)
4885 joinable_threads = g_hash_table_new (NULL, NULL);
4886 g_hash_table_insert (joinable_threads, tid, tid);
4887 joinable_thread_count ++;
4888 joinable_threads_unlock ();
4890 mono_gc_finalize_notify ();
4891 #endif
4895 * mono_threads_join_threads:
4897 * Join all joinable threads. This is called from the finalizer thread.
4898 * LOCKING: Acquires the threads lock.
4900 void
4901 mono_threads_join_threads (void)
4903 #ifndef HOST_WIN32
4904 GHashTableIter iter;
4905 gpointer key;
4906 gpointer tid;
4907 pthread_t thread;
4908 gboolean found;
4910 /* Fastpath */
4911 if (!joinable_thread_count)
4912 return;
4914 while (TRUE) {
4915 joinable_threads_lock ();
4916 found = FALSE;
4917 if (g_hash_table_size (joinable_threads)) {
4918 g_hash_table_iter_init (&iter, joinable_threads);
4919 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4920 thread = (pthread_t)tid;
4921 g_hash_table_remove (joinable_threads, key);
4922 joinable_thread_count --;
4923 found = TRUE;
4925 joinable_threads_unlock ();
4926 if (found) {
4927 if (thread != pthread_self ())
4928 /* This shouldn't block */
4929 pthread_join (thread, NULL);
4930 } else {
4931 break;
4934 #endif
4938 * mono_thread_join:
4940 * Wait for thread TID to exit.
4941 * LOCKING: Acquires the threads lock.
4943 void
4944 mono_thread_join (gpointer tid)
4946 #ifndef HOST_WIN32
4947 pthread_t thread;
4948 gboolean found = FALSE;
4950 joinable_threads_lock ();
4951 if (!joinable_threads)
4952 joinable_threads = g_hash_table_new (NULL, NULL);
4953 if (g_hash_table_lookup (joinable_threads, tid)) {
4954 g_hash_table_remove (joinable_threads, tid);
4955 joinable_thread_count --;
4956 found = TRUE;
4958 joinable_threads_unlock ();
4959 if (!found)
4960 return;
4961 thread = (pthread_t)tid;
4962 pthread_join (thread, NULL);
4963 #endif