Sorry for breaking linux.
[mono-project.git] / mono / metadata / threads.c
blobeb1e92dbb438d94381ad5e503f302d87144d2540
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)
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 #define mono_threads_lock() mono_mutex_lock (&threads_mutex)
130 #define mono_threads_unlock() mono_mutex_unlock (&threads_mutex)
131 static mono_mutex_t threads_mutex;
133 /* Controls access to context static data */
134 #define mono_contexts_lock() mono_mutex_lock (&contexts_mutex)
135 #define mono_contexts_unlock() mono_mutex_unlock (&contexts_mutex)
136 static mono_mutex_t contexts_mutex;
138 /* Controls access to the 'joinable_threads' hash table */
139 #define joinable_threads_lock() mono_mutex_lock (&joinable_threads_mutex)
140 #define joinable_threads_unlock() mono_mutex_unlock (&joinable_threads_mutex)
141 static mono_mutex_t joinable_threads_mutex;
143 /* Holds current status of static data heap */
144 static StaticDataInfo thread_static_info;
145 static StaticDataInfo context_static_info;
147 /* The hash of existing threads (key is thread ID, value is
148 * MonoInternalThread*) that need joining before exit
150 static MonoGHashTable *threads=NULL;
153 * Threads which are starting up and they are not in the 'threads' hash yet.
154 * When handle_store is called for a thread, it will be removed from this hash table.
155 * Protected by mono_threads_lock ().
157 static MonoGHashTable *threads_starting_up = NULL;
159 /* Maps a MonoThread to its start argument */
160 /* Protected by mono_threads_lock () */
161 static MonoGHashTable *thread_start_args = NULL;
163 /* The TLS key that holds the MonoObject assigned to each thread */
164 static MonoNativeTlsKey current_object_key;
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;
231 static guint32
232 get_next_managed_thread_id (void)
234 return InterlockedIncrement (&managed_thread_id_counter);
237 MonoNativeTlsKey
238 mono_thread_get_tls_key (void)
240 return current_object_key;
243 gint32
244 mono_thread_get_tls_offset (void)
246 int offset;
247 MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
248 return offset;
251 static inline MonoNativeThreadId
252 thread_get_tid (MonoInternalThread *thread)
254 /* We store the tid as a guint64 to keep the object layout constant between platforms */
255 return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
258 /* handle_store() and handle_remove() manage the array of threads that
259 * still need to be waited for when the main thread exits.
261 * If handle_store() returns FALSE the thread must not be started
262 * because Mono is shutting down.
264 static gboolean handle_store(MonoThread *thread, gboolean force_attach)
266 mono_threads_lock ();
268 THREAD_DEBUG (g_message ("%s: thread %p ID %"G_GSIZE_FORMAT, __func__, thread, (gsize)thread->internal_thread->tid));
270 if (threads_starting_up)
271 mono_g_hash_table_remove (threads_starting_up, thread);
273 if (shutting_down && !force_attach) {
274 mono_threads_unlock ();
275 return FALSE;
278 if(threads==NULL) {
279 MONO_GC_REGISTER_ROOT_FIXED (threads);
280 threads=mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC);
283 /* We don't need to duplicate thread->handle, because it is
284 * only closed when the thread object is finalized by the GC.
286 g_assert (thread->internal_thread);
287 mono_g_hash_table_insert(threads, (gpointer)(gsize)(thread->internal_thread->tid),
288 thread->internal_thread);
290 mono_threads_unlock ();
292 return TRUE;
295 static gboolean handle_remove(MonoInternalThread *thread)
297 gboolean ret;
298 gsize tid = thread->tid;
300 THREAD_DEBUG (g_message ("%s: thread ID %"G_GSIZE_FORMAT, __func__, tid));
302 mono_threads_lock ();
304 if (threads) {
305 /* We have to check whether the thread object for the
306 * tid is still the same in the table because the
307 * thread might have been destroyed and the tid reused
308 * in the meantime, in which case the tid would be in
309 * the table, but with another thread object.
311 if (mono_g_hash_table_lookup (threads, (gpointer)tid) == thread) {
312 mono_g_hash_table_remove (threads, (gpointer)tid);
313 ret = TRUE;
314 } else {
315 ret = FALSE;
318 else
319 ret = FALSE;
321 mono_threads_unlock ();
323 /* Don't close the handle here, wait for the object finalizer
324 * to do it. Otherwise, the following race condition applies:
326 * 1) Thread exits (and handle_remove() closes the handle)
328 * 2) Some other handle is reassigned the same slot
330 * 3) Another thread tries to join the first thread, and
331 * blocks waiting for the reassigned handle to be signalled
332 * (which might never happen). This is possible, because the
333 * thread calling Join() still has a reference to the first
334 * thread's object.
336 return ret;
339 static void ensure_synch_cs_set (MonoInternalThread *thread)
341 mono_mutex_t *synch_cs;
343 if (thread->synch_cs != NULL) {
344 return;
347 synch_cs = g_new0 (mono_mutex_t, 1);
348 mono_mutex_init_recursive (synch_cs);
350 if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
351 synch_cs, NULL) != NULL) {
352 /* Another thread must have installed this CS */
353 mono_mutex_destroy (synch_cs);
354 g_free (synch_cs);
358 static inline void
359 lock_thread (MonoInternalThread *thread)
361 if (!thread->synch_cs)
362 ensure_synch_cs_set (thread);
364 g_assert (thread->synch_cs);
365 mono_mutex_lock (thread->synch_cs);
368 static inline void
369 unlock_thread (MonoInternalThread *thread)
371 mono_mutex_unlock (thread->synch_cs);
375 * NOTE: this function can be called also for threads different from the current one:
376 * make sure no code called from it will ever assume it is run on the thread that is
377 * getting cleaned up.
379 static void thread_cleanup (MonoInternalThread *thread)
381 g_assert (thread != NULL);
383 if (thread->abort_state_handle) {
384 mono_gchandle_free (thread->abort_state_handle);
385 thread->abort_state_handle = 0;
387 thread->abort_exc = NULL;
388 thread->current_appcontext = NULL;
391 * This is necessary because otherwise we might have
392 * cross-domain references which will not get cleaned up when
393 * the target domain is unloaded.
395 if (thread->cached_culture_info) {
396 int i;
397 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
398 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
402 * thread->synch_cs can be NULL if this was called after
403 * ves_icall_System_Threading_InternalThread_Thread_free_internal.
404 * This can happen only during shutdown.
405 * The shutting_down flag is not always set, so we can't assert on it.
407 if (thread->synch_cs)
408 LOCK_THREAD (thread);
410 thread->state |= ThreadState_Stopped;
411 thread->state &= ~ThreadState_Background;
413 if (thread->synch_cs)
414 UNLOCK_THREAD (thread);
417 An interruption request has leaked to cleanup. Adjust the global counter.
419 This can happen is the abort source thread finds the abortee (this) thread
420 in unmanaged code. If this thread never trips back to managed code or check
421 the local flag it will be left set and positively unbalance the global counter.
423 Leaving the counter unbalanced will cause a performance degradation since all threads
424 will now keep checking their local flags all the time.
426 if (InterlockedExchange (&thread->interruption_requested, 0))
427 InterlockedDecrement (&thread_interruption_requested);
429 /* if the thread is not in the hash it has been removed already */
430 if (!handle_remove (thread)) {
431 if (thread == mono_thread_internal_current ()) {
432 mono_domain_unset ();
433 mono_memory_barrier ();
435 /* This needs to be called even if handle_remove () fails */
436 if (mono_thread_cleanup_fn)
437 mono_thread_cleanup_fn (thread);
438 return;
440 mono_release_type_locks (thread);
442 mono_profiler_thread_end (thread->tid);
444 if (thread == mono_thread_internal_current ()) {
446 * This will signal async signal handlers that the thread has exited.
447 * The profiler callback needs this to be set, so it cannot be done earlier.
449 mono_domain_unset ();
450 mono_memory_barrier ();
453 if (thread == mono_thread_internal_current ())
454 mono_thread_pop_appdomain_ref ();
456 thread->cached_culture_info = NULL;
458 mono_free_static_data (thread->static_data, TRUE);
459 thread->static_data = NULL;
460 ref_stack_destroy (thread->appdomain_refs);
461 thread->appdomain_refs = NULL;
463 if (mono_thread_cleanup_fn)
464 mono_thread_cleanup_fn (thread);
466 if (mono_gc_is_moving ()) {
467 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
468 thread->thread_pinning_ref = NULL;
472 static gpointer
473 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
475 int idx;
476 g_assert ((offset & 0x80000000) == 0);
477 offset &= 0x7fffffff;
478 idx = (offset >> 24) - 1;
479 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
482 static MonoThread**
483 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
485 static MonoClassField *current_thread_field = NULL;
487 guint32 offset;
489 if (!current_thread_field) {
490 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
491 g_assert (current_thread_field);
494 mono_class_vtable (domain, mono_defaults.thread_class);
495 mono_domain_lock (domain);
496 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
497 mono_domain_unlock (domain);
498 g_assert (offset);
500 return get_thread_static_data (thread, offset);
503 static void
504 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
506 MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
508 g_assert (current->obj.vtable->domain == domain);
510 g_assert (!*current_thread_ptr);
511 *current_thread_ptr = current;
514 static MonoThread*
515 create_thread_object (MonoDomain *domain)
517 MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
518 return (MonoThread*)mono_gc_alloc_mature (vt);
521 static MonoThread*
522 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
524 MonoThread *thread = create_thread_object (domain);
525 MONO_OBJECT_SETREF (thread, internal_thread, internal);
526 return thread;
529 static MonoInternalThread*
530 create_internal_thread (void)
532 MonoInternalThread *thread;
533 MonoVTable *vt;
535 vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
536 thread = (MonoInternalThread*)mono_gc_alloc_mature (vt);
538 thread->synch_cs = g_new0 (mono_mutex_t, 1);
539 mono_mutex_init_recursive (thread->synch_cs);
541 thread->apartment_state = ThreadApartmentState_Unknown;
542 thread->managed_id = get_next_managed_thread_id ();
543 if (mono_gc_is_moving ()) {
544 thread->thread_pinning_ref = thread;
545 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref);
548 return thread;
551 static void
552 init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
554 MonoDomain *domain = mono_get_root_domain ();
556 if (!candidate || candidate->obj.vtable->domain != domain)
557 candidate = new_thread_with_internal (domain, thread);
558 set_current_thread_for_domain (domain, thread, candidate);
559 g_assert (!thread->root_domain_thread);
560 MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
563 static guint32 WINAPI start_wrapper_internal(void *data)
565 MonoThreadInfo *info;
566 StartInfo *start_info = (StartInfo *)data;
567 guint32 (*start_func)(void *);
568 void *start_arg;
569 gsize tid;
571 * We don't create a local to hold start_info->obj, so hopefully it won't get pinned during a
572 * GC stack walk.
574 MonoInternalThread *internal = start_info->obj->internal_thread;
575 MonoObject *start_delegate = start_info->delegate;
576 MonoDomain *domain = start_info->obj->obj.vtable->domain;
578 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, GetCurrentThreadId ()));
580 /* We can be sure start_info->obj->tid and
581 * start_info->obj->handle have been set, because the thread
582 * was created suspended, and these values were set before the
583 * thread resumed
586 info = mono_thread_info_current ();
587 g_assert (info);
588 internal->thread_info = info;
591 tid=internal->tid;
593 SET_CURRENT_OBJECT (internal);
595 mono_monitor_init_tls ();
597 /* Every thread references the appdomain which created it */
598 mono_thread_push_appdomain_ref (domain);
600 if (!mono_domain_set (domain, FALSE)) {
601 /* No point in raising an appdomain_unloaded exception here */
602 /* FIXME: Cleanup here */
603 mono_thread_pop_appdomain_ref ();
604 return 0;
607 start_func = start_info->func;
608 start_arg = start_info->start_arg;
610 /* We have to do this here because mono_thread_new_init()
611 requires that root_domain_thread is set up. */
612 thread_adjust_static_data (internal);
613 init_root_domain_thread (internal, start_info->obj);
615 /* This MUST be called before any managed code can be
616 * executed, as it calls the callback function that (for the
617 * jit) sets the lmf marker.
619 mono_thread_new_init (tid, &tid, start_func);
620 internal->stack_ptr = &tid;
622 LIBGC_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT",%d) Setting thread stack to %p", __func__, GetCurrentThreadId (), getpid (), thread->stack_ptr));
624 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), internal));
626 /* On 2.0 profile (and higher), set explicitly since state might have been
627 Unknown */
628 if (internal->apartment_state == ThreadApartmentState_Unknown)
629 internal->apartment_state = ThreadApartmentState_MTA;
631 mono_thread_init_apartment_state ();
633 if(internal->start_notify!=NULL) {
634 /* Let the thread that called Start() know we're
635 * ready
637 ReleaseSemaphore (internal->start_notify, 1, NULL);
640 mono_threads_lock ();
641 mono_g_hash_table_remove (thread_start_args, start_info->obj);
642 mono_threads_unlock ();
644 mono_thread_set_execution_context (start_info->obj->ec_to_set);
645 start_info->obj->ec_to_set = NULL;
647 g_free (start_info);
648 THREAD_DEBUG (g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
649 internal->tid));
652 * Call this after calling start_notify, since the profiler callback might want
653 * to lock the thread, and the lock is held by thread_start () which waits for
654 * start_notify.
656 mono_profiler_thread_start (tid);
658 /* if the name was set before starting, we didn't invoke the profiler callback */
659 if (internal->name && (internal->flags & MONO_THREAD_FLAG_NAME_SET)) {
660 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
661 mono_profiler_thread_name (internal->tid, tname);
662 g_free (tname);
664 /* start_func is set only for unmanaged start functions */
665 if (start_func) {
666 start_func (start_arg);
667 } else {
668 void *args [1];
669 g_assert (start_delegate != NULL);
670 args [0] = start_arg;
671 /* we may want to handle the exception here. See comment below on unhandled exceptions */
672 mono_runtime_delegate_invoke (start_delegate, args, NULL);
675 /* If the thread calls ExitThread at all, this remaining code
676 * will not be executed, but the main thread will eventually
677 * call thread_cleanup() on this thread's behalf.
680 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, GetCurrentThreadId ()));
682 /* Do any cleanup needed for apartment state. This
683 * cannot be done in thread_cleanup since thread_cleanup could be
684 * called for a thread other than the current thread.
685 * mono_thread_cleanup_apartment_state cleans up apartment
686 * for the current thead */
687 mono_thread_cleanup_apartment_state ();
689 thread_cleanup (internal);
691 internal->tid = 0;
693 /* Remove the reference to the thread object in the TLS data,
694 * so the thread object can be finalized. This won't be
695 * reached if the thread threw an uncaught exception, so those
696 * thread handles will stay referenced :-( (This is due to
697 * missing support for scanning thread-specific data in the
698 * Boehm GC - the io-layer keeps a GC-visible hash of pointers
699 * to TLS data.)
701 SET_CURRENT_OBJECT (NULL);
703 return(0);
706 static guint32 WINAPI start_wrapper(void *data)
708 volatile int dummy;
710 /* Avoid scanning the frames above this frame during a GC */
711 mono_gc_set_stack_end ((void*)&dummy);
713 return start_wrapper_internal (data);
717 * create_thread:
719 * Common thread creation code.
720 * LOCKING: Acquires the threads lock.
722 static gboolean
723 create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
724 gboolean throw_on_failure)
726 HANDLE thread_handle;
727 MonoNativeThreadId tid;
728 guint32 create_flags;
731 * Join joinable threads to prevent running out of threads since the finalizer
732 * thread might be blocked/backlogged.
734 mono_threads_join_threads ();
736 mono_threads_lock ();
737 if (shutting_down) {
738 g_free (start_info);
739 mono_threads_unlock ();
740 return FALSE;
743 * The thread start argument may be an object reference, and there is
744 * no ref to keep it alive when the new thread is started but not yet
745 * registered with the collector. So we store it in a GC tracked hash
746 * table.
748 if (thread_start_args == NULL) {
749 MONO_GC_REGISTER_ROOT_FIXED (thread_start_args);
750 thread_start_args = mono_g_hash_table_new (NULL, NULL);
752 mono_g_hash_table_insert (thread_start_args, thread, start_info->start_arg);
753 if (threads_starting_up == NULL) {
754 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up);
755 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC);
757 mono_g_hash_table_insert (threads_starting_up, thread, thread);
758 mono_threads_unlock ();
760 internal->start_notify = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
761 if (!internal->start_notify) {
762 mono_threads_lock ();
763 mono_g_hash_table_remove (threads_starting_up, thread);
764 mono_threads_unlock ();
765 g_warning ("%s: CreateSemaphore error 0x%x", __func__, GetLastError ());
766 g_free (start_info);
767 return FALSE;
770 if (stack_size == 0)
771 stack_size = default_stacksize_for_thread (internal);
773 /* Create suspended, so we can do some housekeeping before the thread
774 * starts
776 create_flags = CREATE_SUSPENDED;
777 thread_handle = mono_threads_create_thread ((LPTHREAD_START_ROUTINE)start_wrapper, start_info,
778 stack_size, create_flags, &tid);
779 if (thread_handle == NULL) {
780 /* The thread couldn't be created, so throw an exception */
781 mono_threads_lock ();
782 mono_g_hash_table_remove (threads_starting_up, thread);
783 mono_threads_unlock ();
784 g_free (start_info);
785 if (throw_on_failure)
786 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
787 else
788 g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
789 return FALSE;
791 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
793 internal->handle = thread_handle;
794 internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (tid);
796 internal->threadpool_thread = threadpool_thread;
797 if (threadpool_thread)
798 mono_thread_set_state (internal, ThreadState_Background);
800 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
802 /* Only store the handle when the thread is about to be
803 * launched, to avoid the main thread deadlocking while trying
804 * to clean up a thread that will never be signalled.
806 if (!handle_store (thread, FALSE))
807 return FALSE;
809 mono_thread_info_resume (tid);
811 if (internal->start_notify) {
813 * Wait for the thread to set up its TLS data etc, so
814 * theres no potential race condition if someone tries
815 * to look up the data believing the thread has
816 * started
818 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for thread %p (%"G_GSIZE_FORMAT") to start", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
820 WaitForSingleObjectEx (internal->start_notify, INFINITE, FALSE);
821 CloseHandle (internal->start_notify);
822 internal->start_notify = NULL;
825 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), internal, (gsize)internal->tid));
827 return TRUE;
830 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
832 if (mono_thread_start_cb) {
833 mono_thread_start_cb (tid, stack_start, func);
837 void mono_threads_set_default_stacksize (guint32 stacksize)
839 default_stacksize = stacksize;
842 guint32 mono_threads_get_default_stacksize (void)
844 return default_stacksize;
848 * mono_thread_create_internal:
851 MonoInternalThread*
852 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size)
854 MonoThread *thread;
855 MonoInternalThread *internal;
856 StartInfo *start_info;
857 gboolean res;
859 thread = create_thread_object (domain);
860 internal = create_internal_thread ();
861 MONO_OBJECT_SETREF (thread, internal_thread, internal);
863 start_info = g_new0 (StartInfo, 1);
864 start_info->func = func;
865 start_info->obj = thread;
866 start_info->start_arg = arg;
868 res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
869 if (!res)
870 return NULL;
872 /* Check that the managed and unmanaged layout of MonoInternalThread matches */
873 if (mono_check_corlib_version () == NULL)
874 g_assert (((char*)&internal->unused2 - (char*)internal) == mono_defaults.internal_thread_class->fields [mono_defaults.internal_thread_class->field.count - 1].offset);
876 return internal;
879 void
880 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
882 mono_thread_create_internal (domain, func, arg, FALSE, 0);
885 MonoThread *
886 mono_thread_attach (MonoDomain *domain)
888 return mono_thread_attach_full (domain, FALSE);
891 MonoThread *
892 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
894 MonoThreadInfo *info;
895 MonoInternalThread *thread;
896 MonoThread *current_thread;
897 HANDLE thread_handle;
898 gsize tid;
900 if ((thread = mono_thread_internal_current ())) {
901 if (domain != mono_domain_get ())
902 mono_domain_set (domain, TRUE);
903 /* Already attached */
904 return mono_thread_current ();
907 if (!mono_gc_register_thread (&domain)) {
908 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 ());
911 thread = create_internal_thread ();
913 thread_handle = mono_thread_info_open_handle ();
914 g_assert (thread_handle);
916 tid=GetCurrentThreadId ();
918 thread->handle=thread_handle;
919 thread->tid=tid;
920 #ifdef PLATFORM_ANDROID
921 thread->android_tid = (gpointer) gettid ();
922 #endif
923 thread->stack_ptr = &tid;
925 THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
927 info = mono_thread_info_current ();
928 g_assert (info);
929 thread->thread_info = info;
931 current_thread = new_thread_with_internal (domain, thread);
933 if (!handle_store (current_thread, force_attach)) {
934 /* Mono is shutting down, so just wait for the end */
935 for (;;)
936 Sleep (10000);
939 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, GetCurrentThreadId (), thread));
941 SET_CURRENT_OBJECT (thread);
942 mono_domain_set (domain, TRUE);
944 mono_monitor_init_tls ();
946 thread_adjust_static_data (thread);
948 init_root_domain_thread (thread, current_thread);
949 if (domain != mono_get_root_domain ())
950 set_current_thread_for_domain (domain, thread, current_thread);
953 if (mono_thread_attach_cb) {
954 guint8 *staddr;
955 size_t stsize;
957 mono_thread_info_get_stack_bounds (&staddr, &stsize);
959 if (staddr == NULL)
960 mono_thread_attach_cb (tid, &tid);
961 else
962 mono_thread_attach_cb (tid, staddr + stsize);
965 // FIXME: Need a separate callback
966 mono_profiler_thread_start (tid);
968 return current_thread;
971 void
972 mono_thread_detach_internal (MonoInternalThread *thread)
974 g_return_if_fail (thread != NULL);
976 THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
978 thread_cleanup (thread);
980 SET_CURRENT_OBJECT (NULL);
981 mono_domain_unset ();
983 /* Don't need to CloseHandle this thread, even though we took a
984 * reference in mono_thread_attach (), because the GC will do it
985 * when the Thread object is finalised.
989 void
990 mono_thread_detach (MonoThread *thread)
992 if (thread)
993 mono_thread_detach_internal (thread->internal_thread);
997 * mono_thread_detach_if_exiting:
999 * Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1000 * This should be used at the end of embedding code which calls into managed code, and which
1001 * can be called from pthread dtors, like dealloc: implementations in objective-c.
1003 void
1004 mono_thread_detach_if_exiting (void)
1006 if (mono_thread_info_is_exiting ()) {
1007 MonoInternalThread *thread;
1009 thread = mono_thread_internal_current ();
1010 if (thread) {
1011 mono_thread_detach_internal (thread);
1012 mono_thread_info_detach ();
1017 void
1018 mono_thread_exit ()
1020 MonoInternalThread *thread = mono_thread_internal_current ();
1022 THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1024 thread_cleanup (thread);
1025 SET_CURRENT_OBJECT (NULL);
1026 mono_domain_unset ();
1028 /* we could add a callback here for embedders to use. */
1029 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1030 exit (mono_environment_exitcode_get ());
1031 mono_thread_info_exit ();
1034 void
1035 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this)
1037 MonoInternalThread *internal = create_internal_thread ();
1039 internal->state = ThreadState_Unstarted;
1041 InterlockedCompareExchangePointer ((gpointer)&this->internal_thread, internal, NULL);
1044 HANDLE
1045 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this,
1046 MonoObject *start)
1048 StartInfo *start_info;
1049 MonoInternalThread *internal;
1050 gboolean res;
1052 THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this, start));
1054 if (!this->internal_thread)
1055 ves_icall_System_Threading_Thread_ConstructInternalThread (this);
1056 internal = this->internal_thread;
1058 LOCK_THREAD (internal);
1060 if ((internal->state & ThreadState_Unstarted) == 0) {
1061 UNLOCK_THREAD (internal);
1062 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
1063 return NULL;
1066 if ((internal->state & ThreadState_Aborted) != 0) {
1067 UNLOCK_THREAD (internal);
1068 return this;
1070 /* This is freed in start_wrapper */
1071 start_info = g_new0 (StartInfo, 1);
1072 start_info->func = NULL;
1073 start_info->start_arg = this->start_obj; /* FIXME: GC object stored in unmanaged memory */
1074 start_info->delegate = start;
1075 start_info->obj = this;
1076 g_assert (this->obj.vtable->domain == mono_domain_get ());
1078 res = create_thread (this, internal, start_info, FALSE, 0, FALSE);
1079 if (!res) {
1080 UNLOCK_THREAD (internal);
1081 return NULL;
1084 internal->state &= ~ThreadState_Unstarted;
1086 THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1088 UNLOCK_THREAD (internal);
1089 return internal->handle;
1093 * This is called from the finalizer of the internal thread object.
1095 void
1096 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this, HANDLE thread)
1098 THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1101 * Since threads keep a reference to their thread object while running, by the time this function is called,
1102 * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1103 * when thread_cleanup () can be called after this.
1105 if (thread)
1106 CloseHandle (thread);
1108 if (this->synch_cs) {
1109 mono_mutex_t *synch_cs = this->synch_cs;
1110 this->synch_cs = NULL;
1111 mono_mutex_destroy (synch_cs);
1112 g_free (synch_cs);
1115 if (this->name) {
1116 void *name = this->name;
1117 this->name = NULL;
1118 g_free (name);
1122 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1124 guint32 res;
1125 MonoInternalThread *thread = mono_thread_internal_current ();
1127 THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1129 mono_thread_current_check_pending_interrupt ();
1131 while (TRUE) {
1132 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1134 res = SleepEx(ms,TRUE);
1136 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1138 if (res == WAIT_IO_COMPLETION) { /* we might have been interrupted */
1139 MonoException* exc = mono_thread_execute_interruption (thread);
1140 if (exc) {
1141 mono_raise_exception (exc);
1142 } else {
1143 // FIXME: !INFINITE
1144 if (ms != INFINITE)
1145 break;
1147 } else {
1148 break;
1153 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1157 gint32
1158 ves_icall_System_Threading_Thread_GetDomainID (void)
1160 return mono_domain_get()->domain_id;
1163 gboolean
1164 ves_icall_System_Threading_Thread_Yield (void)
1166 return mono_thread_info_yield ();
1170 * mono_thread_get_name:
1172 * Return the name of the thread. NAME_LEN is set to the length of the name.
1173 * Return NULL if the thread has no name. The returned memory is owned by the
1174 * caller.
1176 gunichar2*
1177 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1179 gunichar2 *res;
1181 LOCK_THREAD (this_obj);
1183 if (!this_obj->name) {
1184 *name_len = 0;
1185 res = NULL;
1186 } else {
1187 *name_len = this_obj->name_len;
1188 res = g_new (gunichar2, this_obj->name_len);
1189 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1192 UNLOCK_THREAD (this_obj);
1194 return res;
1197 MonoString*
1198 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1200 MonoString* str;
1202 LOCK_THREAD (this_obj);
1204 if (!this_obj->name)
1205 str = NULL;
1206 else
1207 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
1209 UNLOCK_THREAD (this_obj);
1211 return str;
1214 void
1215 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
1217 LOCK_THREAD (this_obj);
1219 if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
1220 UNLOCK_THREAD (this_obj);
1222 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
1223 return;
1225 if (this_obj->name) {
1226 g_free (this_obj->name);
1227 this_obj->name_len = 0;
1229 if (name) {
1230 this_obj->name = g_new (gunichar2, mono_string_length (name));
1231 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1232 this_obj->name_len = mono_string_length (name);
1234 else
1235 this_obj->name = NULL;
1237 if (managed)
1238 this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1240 UNLOCK_THREAD (this_obj);
1242 if (this_obj->name && this_obj->tid) {
1243 char *tname = mono_string_to_utf8 (name);
1244 mono_profiler_thread_name (this_obj->tid, tname);
1245 mono_thread_info_set_name (thread_get_tid (this_obj), tname);
1246 mono_free (tname);
1250 void
1251 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1253 mono_thread_set_name_internal (this_obj, name, TRUE);
1256 /* If the array is already in the requested domain, we just return it,
1257 otherwise we return a copy in that domain. */
1258 static MonoArray*
1259 byte_array_to_domain (MonoArray *arr, MonoDomain *domain)
1261 MonoArray *copy;
1263 if (!arr)
1264 return NULL;
1266 if (mono_object_domain (arr) == domain)
1267 return arr;
1269 copy = mono_array_new (domain, mono_defaults.byte_class, arr->max_length);
1270 memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1271 return copy;
1274 MonoArray*
1275 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1277 return byte_array_to_domain (arr, mono_get_root_domain ());
1280 MonoArray*
1281 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1283 return byte_array_to_domain (arr, mono_domain_get ());
1286 MonoThread *
1287 mono_thread_current (void)
1289 MonoDomain *domain = mono_domain_get ();
1290 MonoInternalThread *internal = mono_thread_internal_current ();
1291 MonoThread **current_thread_ptr;
1293 g_assert (internal);
1294 current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1296 if (!*current_thread_ptr) {
1297 g_assert (domain != mono_get_root_domain ());
1298 *current_thread_ptr = new_thread_with_internal (domain, internal);
1300 return *current_thread_ptr;
1303 MonoInternalThread*
1304 mono_thread_internal_current (void)
1306 MonoInternalThread *res = GET_CURRENT_OBJECT ();
1307 THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1308 return res;
1311 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoInternalThread *this,
1312 int ms, HANDLE thread)
1314 MonoInternalThread *cur_thread = mono_thread_internal_current ();
1315 gboolean ret;
1317 mono_thread_current_check_pending_interrupt ();
1319 LOCK_THREAD (this);
1321 if ((this->state & ThreadState_Unstarted) != 0) {
1322 UNLOCK_THREAD (this);
1324 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
1325 return FALSE;
1328 UNLOCK_THREAD (this);
1330 if(ms== -1) {
1331 ms=INFINITE;
1333 THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, thread, ms));
1335 mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1337 ret=WaitForSingleObjectEx (thread, ms, TRUE);
1339 mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1341 if(ret==WAIT_OBJECT_0) {
1342 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1344 return(TRUE);
1347 THREAD_DEBUG (g_message ("%s: join failed", __func__));
1349 return(FALSE);
1352 static gint32
1353 mono_wait_uninterrupted (MonoInternalThread *thread, gboolean multiple, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, gboolean alertable)
1355 MonoException *exc;
1356 guint32 ret;
1357 gint64 start;
1358 gint32 diff_ms;
1359 gint32 wait = ms;
1361 start = (ms == -1) ? 0 : mono_100ns_ticks ();
1362 do {
1363 if (multiple)
1364 ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, alertable);
1365 else
1366 ret = WaitForSingleObjectEx (handles [0], ms, alertable);
1368 if (ret != WAIT_IO_COMPLETION)
1369 break;
1371 exc = mono_thread_execute_interruption (thread);
1372 if (exc)
1373 mono_raise_exception (exc);
1375 if (ms == -1)
1376 continue;
1378 /* Re-calculate ms according to the time passed */
1379 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1380 if (diff_ms >= ms) {
1381 ret = WAIT_TIMEOUT;
1382 break;
1384 wait = ms - diff_ms;
1385 } while (TRUE);
1387 return ret;
1390 /* FIXME: exitContext isnt documented */
1391 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1393 HANDLE *handles;
1394 guint32 numhandles;
1395 guint32 ret;
1396 guint32 i;
1397 MonoObject *waitHandle;
1398 MonoInternalThread *thread = mono_thread_internal_current ();
1400 /* Do this WaitSleepJoin check before creating objects */
1401 mono_thread_current_check_pending_interrupt ();
1403 /* We fail in managed if the array has more than 64 elements */
1404 numhandles = (guint32)mono_array_length(mono_handles);
1405 handles = g_new0(HANDLE, numhandles);
1407 for(i = 0; i < numhandles; i++) {
1408 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1409 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1412 if(ms== -1) {
1413 ms=INFINITE;
1416 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1418 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, TRUE, ms, TRUE);
1420 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1422 g_free(handles);
1424 if(ret==WAIT_FAILED) {
1425 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1426 return(FALSE);
1427 } else if(ret==WAIT_TIMEOUT) {
1428 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1429 return(FALSE);
1432 return(TRUE);
1435 /* FIXME: exitContext isnt documented */
1436 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
1438 HANDLE handles [MAXIMUM_WAIT_OBJECTS];
1439 uintptr_t numhandles;
1440 guint32 ret;
1441 guint32 i;
1442 MonoObject *waitHandle;
1443 MonoInternalThread *thread = mono_thread_internal_current ();
1445 /* Do this WaitSleepJoin check before creating objects */
1446 mono_thread_current_check_pending_interrupt ();
1448 numhandles = mono_array_length(mono_handles);
1449 if (numhandles > MAXIMUM_WAIT_OBJECTS)
1450 return WAIT_FAILED;
1452 for(i = 0; i < numhandles; i++) {
1453 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1454 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1457 if(ms== -1) {
1458 ms=INFINITE;
1461 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1463 ret = mono_wait_uninterrupted (thread, TRUE, numhandles, handles, FALSE, ms, TRUE);
1465 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1467 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, GetCurrentThreadId (), ret));
1470 * These need to be here. See MSDN dos on WaitForMultipleObjects.
1472 if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
1473 return ret - WAIT_OBJECT_0;
1475 else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
1476 return ret - WAIT_ABANDONED_0;
1478 else {
1479 return ret;
1483 /* FIXME: exitContext isnt documented */
1484 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
1486 guint32 ret;
1487 MonoInternalThread *thread = mono_thread_internal_current ();
1489 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, GetCurrentThreadId (), handle, ms));
1491 if(ms== -1) {
1492 ms=INFINITE;
1495 mono_thread_current_check_pending_interrupt ();
1497 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1499 ret = mono_wait_uninterrupted (thread, FALSE, 1, &handle, FALSE, ms, TRUE);
1501 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1503 if(ret==WAIT_FAILED) {
1504 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait failed", __func__, GetCurrentThreadId ()));
1505 return(FALSE);
1506 } else if(ret==WAIT_TIMEOUT) {
1507 THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Wait timed out", __func__, GetCurrentThreadId ()));
1508 return(FALSE);
1511 return(TRUE);
1514 gboolean
1515 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms, gboolean exitContext)
1517 guint32 ret;
1518 MonoInternalThread *thread = mono_thread_internal_current ();
1520 if (ms == -1)
1521 ms = INFINITE;
1523 mono_thread_current_check_pending_interrupt ();
1525 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1527 ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1529 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1531 return (!(ret == WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION || ret == WAIT_FAILED));
1534 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1536 HANDLE mutex;
1538 *created = TRUE;
1540 if (name == NULL) {
1541 mutex = CreateMutex (NULL, owned, NULL);
1542 } else {
1543 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1545 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1546 *created = FALSE;
1550 return(mutex);
1553 MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
1554 return(ReleaseMutex (handle));
1557 HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
1558 gint32 rights,
1559 gint32 *error)
1561 HANDLE ret;
1563 *error = ERROR_SUCCESS;
1565 ret = OpenMutex (rights, FALSE, mono_string_chars (name));
1566 if (ret == NULL) {
1567 *error = GetLastError ();
1570 return(ret);
1574 HANDLE ves_icall_System_Threading_Semaphore_CreateSemaphore_internal (gint32 initialCount, gint32 maximumCount, MonoString *name, MonoBoolean *created)
1576 HANDLE sem;
1578 *created = TRUE;
1580 if (name == NULL) {
1581 sem = CreateSemaphore (NULL, initialCount, maximumCount, NULL);
1582 } else {
1583 sem = CreateSemaphore (NULL, initialCount, maximumCount,
1584 mono_string_chars (name));
1586 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1587 *created = FALSE;
1591 return(sem);
1594 gint32 ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (HANDLE handle, gint32 releaseCount, MonoBoolean *fail)
1596 gint32 prevcount;
1598 *fail = !ReleaseSemaphore (handle, releaseCount, &prevcount);
1600 return (prevcount);
1603 HANDLE ves_icall_System_Threading_Semaphore_OpenSemaphore_internal (MonoString *name, gint32 rights, gint32 *error)
1605 HANDLE ret;
1607 *error = ERROR_SUCCESS;
1609 ret = OpenSemaphore (rights, FALSE, mono_string_chars (name));
1610 if (ret == NULL) {
1611 *error = GetLastError ();
1614 return(ret);
1617 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name, MonoBoolean *created)
1619 HANDLE event;
1621 *created = TRUE;
1623 if (name == NULL) {
1624 event = CreateEvent (NULL, manual, initial, NULL);
1625 } else {
1626 event = CreateEvent (NULL, manual, initial,
1627 mono_string_chars (name));
1629 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1630 *created = FALSE;
1634 return(event);
1637 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1638 return (SetEvent(handle));
1641 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1642 return (ResetEvent(handle));
1645 void
1646 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1647 CloseHandle (handle);
1650 HANDLE ves_icall_System_Threading_Events_OpenEvent_internal (MonoString *name,
1651 gint32 rights,
1652 gint32 *error)
1654 HANDLE ret;
1656 *error = ERROR_SUCCESS;
1658 ret = OpenEvent (rights, FALSE, mono_string_chars (name));
1659 if (ret == NULL) {
1660 *error = GetLastError ();
1663 return(ret);
1666 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1668 return InterlockedIncrement (location);
1671 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1673 #if SIZEOF_VOID_P == 4
1674 if (G_UNLIKELY ((size_t)location & 0x7)) {
1675 gint64 ret;
1676 mono_interlocked_lock ();
1677 (*location)++;
1678 ret = *location;
1679 mono_interlocked_unlock ();
1680 return ret;
1682 #endif
1683 return InterlockedIncrement64 (location);
1686 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1688 return InterlockedDecrement(location);
1691 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1693 #if SIZEOF_VOID_P == 4
1694 if (G_UNLIKELY ((size_t)location & 0x7)) {
1695 gint64 ret;
1696 mono_interlocked_lock ();
1697 (*location)--;
1698 ret = *location;
1699 mono_interlocked_unlock ();
1700 return ret;
1702 #endif
1703 return InterlockedDecrement64 (location);
1706 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1708 return InterlockedExchange(location, value);
1711 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1713 MonoObject *res;
1714 res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1715 mono_gc_wbarrier_generic_nostore (location);
1716 return res;
1719 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1721 return InterlockedExchangePointer(location, value);
1724 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1726 IntFloatUnion val, ret;
1728 val.fval = value;
1729 ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1731 return ret.fval;
1734 gint64
1735 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1737 #if SIZEOF_VOID_P == 4
1738 if (G_UNLIKELY ((size_t)location & 0x7)) {
1739 gint64 ret;
1740 mono_interlocked_lock ();
1741 ret = *location;
1742 *location = value;
1743 mono_interlocked_unlock ();
1744 return ret;
1746 #endif
1747 return InterlockedExchange64 (location, value);
1750 gdouble
1751 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1753 LongDoubleUnion val, ret;
1755 val.fval = value;
1756 ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1758 return ret.fval;
1761 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1763 return InterlockedCompareExchange(location, value, comparand);
1766 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1768 MonoObject *res;
1769 res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1770 mono_gc_wbarrier_generic_nostore (location);
1771 return res;
1774 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1776 return InterlockedCompareExchangePointer(location, value, comparand);
1779 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1781 IntFloatUnion val, ret, cmp;
1783 val.fval = value;
1784 cmp.fval = comparand;
1785 ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1787 return ret.fval;
1790 gdouble
1791 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1793 #if SIZEOF_VOID_P == 8
1794 LongDoubleUnion val, comp, ret;
1796 val.fval = value;
1797 comp.fval = comparand;
1798 ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1800 return ret.fval;
1801 #else
1802 gdouble old;
1804 mono_interlocked_lock ();
1805 old = *location;
1806 if (old == comparand)
1807 *location = value;
1808 mono_interlocked_unlock ();
1810 return old;
1811 #endif
1814 gint64
1815 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1817 #if SIZEOF_VOID_P == 4
1818 if (G_UNLIKELY ((size_t)location & 0x7)) {
1819 gint64 old;
1820 mono_interlocked_lock ();
1821 old = *location;
1822 if (old == comparand)
1823 *location = value;
1824 mono_interlocked_unlock ();
1825 return old;
1827 #endif
1828 return InterlockedCompareExchange64 (location, value, comparand);
1831 MonoObject*
1832 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1834 MonoObject *res;
1835 res = InterlockedCompareExchangePointer ((gpointer *)location, value, comparand);
1836 mono_gc_wbarrier_generic_nostore (location);
1837 return res;
1840 MonoObject*
1841 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
1843 MonoObject *res;
1844 res = InterlockedExchangePointer ((gpointer *)location, value);
1845 mono_gc_wbarrier_generic_nostore (location);
1846 return res;
1849 gint32
1850 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1852 return InterlockedAdd (location, value);
1855 gint64
1856 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1858 #if SIZEOF_VOID_P == 4
1859 if (G_UNLIKELY ((size_t)location & 0x7)) {
1860 gint64 ret;
1861 mono_interlocked_lock ();
1862 *location += value;
1863 ret = *location;
1864 mono_interlocked_unlock ();
1865 return ret;
1867 #endif
1868 return InterlockedAdd64 (location, value);
1871 gint64
1872 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1874 #if SIZEOF_VOID_P == 4
1875 if (G_UNLIKELY ((size_t)location & 0x7)) {
1876 gint64 ret;
1877 mono_interlocked_lock ();
1878 ret = *location;
1879 mono_interlocked_unlock ();
1880 return ret;
1882 #endif
1883 return InterlockedRead64 (location);
1886 void
1887 ves_icall_System_Threading_Thread_MemoryBarrier (void)
1889 mono_memory_barrier ();
1892 void
1893 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this, guint32 state)
1895 mono_thread_clr_state (this, state);
1897 if (state & ThreadState_Background) {
1898 /* If the thread changes the background mode, the main thread has to
1899 * be notified, since it has to rebuild the list of threads to
1900 * wait for.
1902 SetEvent (background_change_event);
1906 void
1907 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this, guint32 state)
1909 mono_thread_set_state (this, state);
1911 if (state & ThreadState_Background) {
1912 /* If the thread changes the background mode, the main thread has to
1913 * be notified, since it has to rebuild the list of threads to
1914 * wait for.
1916 SetEvent (background_change_event);
1920 guint32
1921 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this)
1923 guint32 state;
1925 LOCK_THREAD (this);
1927 state = this->state;
1929 UNLOCK_THREAD (this);
1931 return state;
1934 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
1936 MonoInternalThread *current;
1937 gboolean throw;
1939 LOCK_THREAD (this);
1941 current = mono_thread_internal_current ();
1943 this->thread_interrupt_requested = TRUE;
1944 throw = current != this && (this->state & ThreadState_WaitSleepJoin);
1946 UNLOCK_THREAD (this);
1948 if (throw) {
1949 abort_thread_internal (this, TRUE, FALSE);
1953 void mono_thread_current_check_pending_interrupt ()
1955 MonoInternalThread *thread = mono_thread_internal_current ();
1956 gboolean throw = FALSE;
1958 LOCK_THREAD (thread);
1960 if (thread->thread_interrupt_requested) {
1961 throw = TRUE;
1962 thread->thread_interrupt_requested = FALSE;
1965 UNLOCK_THREAD (thread);
1967 if (throw) {
1968 mono_raise_exception (mono_get_exception_thread_interrupted ());
1972 int
1973 mono_thread_get_abort_signal (void)
1975 #ifdef HOST_WIN32
1976 return -1;
1977 #elif defined(PLATFORM_ANDROID)
1978 return SIGUNUSED;
1979 #elif !defined (SIGRTMIN)
1980 #ifdef SIGUSR1
1981 return SIGUSR1;
1982 #else
1983 return -1;
1984 #endif /* SIGUSR1 */
1985 #else
1986 static int abort_signum = -1;
1987 int i;
1988 if (abort_signum != -1)
1989 return abort_signum;
1990 /* we try to avoid SIGRTMIN and any one that might have been set already, see bug #75387 */
1991 for (i = SIGRTMIN + 1; i < SIGRTMAX; ++i) {
1992 struct sigaction sinfo;
1993 sigaction (i, NULL, &sinfo);
1994 if (sinfo.sa_handler == SIG_DFL && (void*)sinfo.sa_sigaction == (void*)SIG_DFL) {
1995 abort_signum = i;
1996 return i;
1999 /* fallback to the old way */
2000 return SIGRTMIN;
2001 #endif /* HOST_WIN32 */
2004 #ifdef HOST_WIN32
2005 static void CALLBACK interruption_request_apc (ULONG_PTR param)
2007 MonoException* exc = mono_thread_request_interruption (FALSE);
2008 if (exc) mono_raise_exception (exc);
2010 #endif /* HOST_WIN32 */
2013 * signal_thread_state_change
2015 * Tells the thread that his state has changed and it has to enter the new
2016 * state as soon as possible.
2018 static void signal_thread_state_change (MonoInternalThread *thread)
2020 #ifndef HOST_WIN32
2021 gpointer wait_handle;
2022 #endif
2024 if (thread == mono_thread_internal_current ()) {
2025 /* Do it synchronously */
2026 MonoException *exc = mono_thread_request_interruption (FALSE);
2027 if (exc)
2028 mono_raise_exception (exc);
2031 #ifdef HOST_WIN32
2032 QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, (ULONG_PTR)NULL);
2033 #else
2035 * This will cause waits to be broken.
2036 * It will also prevent the thread from entering a wait, so if the thread returns
2037 * from the wait before it receives the abort signal, it will just spin in the wait
2038 * functions in the io-layer until the signal handler calls QueueUserAPC which will
2039 * make it return.
2041 wait_handle = mono_thread_info_prepare_interrupt (thread->handle);
2043 /* fixme: store the state somewhere */
2044 mono_thread_kill (thread, mono_thread_get_abort_signal ());
2046 mono_thread_info_finish_interrupt (wait_handle);
2047 #endif /* HOST_WIN32 */
2050 void
2051 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2053 LOCK_THREAD (thread);
2055 if ((thread->state & ThreadState_AbortRequested) != 0 ||
2056 (thread->state & ThreadState_StopRequested) != 0 ||
2057 (thread->state & ThreadState_Stopped) != 0)
2059 UNLOCK_THREAD (thread);
2060 return;
2063 if ((thread->state & ThreadState_Unstarted) != 0) {
2064 thread->state |= ThreadState_Aborted;
2065 UNLOCK_THREAD (thread);
2066 return;
2069 thread->state |= ThreadState_AbortRequested;
2070 if (thread->abort_state_handle)
2071 mono_gchandle_free (thread->abort_state_handle);
2072 if (state) {
2073 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2074 g_assert (thread->abort_state_handle);
2075 } else {
2076 thread->abort_state_handle = 0;
2078 thread->abort_exc = NULL;
2081 * abort_exc is set in mono_thread_execute_interruption(),
2082 * triggered by the call to signal_thread_state_change(),
2083 * below. There's a point between where we have
2084 * abort_state_handle set, but abort_exc NULL, but that's not
2085 * a problem.
2088 UNLOCK_THREAD (thread);
2090 THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2092 /* During shutdown, we can't wait for other threads */
2093 if (!shutting_down)
2094 /* Make sure the thread is awake */
2095 mono_thread_resume (thread);
2097 abort_thread_internal (thread, TRUE, TRUE);
2100 void
2101 ves_icall_System_Threading_Thread_ResetAbort (void)
2103 MonoInternalThread *thread = mono_thread_internal_current ();
2104 gboolean was_aborting;
2106 LOCK_THREAD (thread);
2107 was_aborting = thread->state & ThreadState_AbortRequested;
2108 thread->state &= ~ThreadState_AbortRequested;
2109 UNLOCK_THREAD (thread);
2111 if (!was_aborting) {
2112 const char *msg = "Unable to reset abort because no abort was requested";
2113 mono_raise_exception (mono_get_exception_thread_state (msg));
2115 thread->abort_exc = NULL;
2116 if (thread->abort_state_handle) {
2117 mono_gchandle_free (thread->abort_state_handle);
2118 /* This is actually not necessary - the handle
2119 only counts if the exception is set */
2120 thread->abort_state_handle = 0;
2124 void
2125 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2127 LOCK_THREAD (thread);
2129 thread->state &= ~ThreadState_AbortRequested;
2131 if (thread->abort_exc) {
2132 thread->abort_exc = NULL;
2133 if (thread->abort_state_handle) {
2134 mono_gchandle_free (thread->abort_state_handle);
2135 /* This is actually not necessary - the handle
2136 only counts if the exception is set */
2137 thread->abort_state_handle = 0;
2141 UNLOCK_THREAD (thread);
2144 MonoObject*
2145 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2147 MonoInternalThread *thread = this->internal_thread;
2148 MonoObject *state, *deserialized = NULL, *exc;
2149 MonoDomain *domain;
2151 if (!thread->abort_state_handle)
2152 return NULL;
2154 state = mono_gchandle_get_target (thread->abort_state_handle);
2155 g_assert (state);
2157 domain = mono_domain_get ();
2158 if (mono_object_domain (state) == domain)
2159 return state;
2161 deserialized = mono_object_xdomain_representation (state, domain, &exc);
2163 if (!deserialized) {
2164 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2165 if (exc)
2166 MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2167 mono_raise_exception (invalid_op_exc);
2170 return deserialized;
2173 static gboolean
2174 mono_thread_suspend (MonoInternalThread *thread)
2176 LOCK_THREAD (thread);
2178 if ((thread->state & ThreadState_Unstarted) != 0 ||
2179 (thread->state & ThreadState_Aborted) != 0 ||
2180 (thread->state & ThreadState_Stopped) != 0)
2182 UNLOCK_THREAD (thread);
2183 return FALSE;
2186 if ((thread->state & ThreadState_Suspended) != 0 ||
2187 (thread->state & ThreadState_SuspendRequested) != 0 ||
2188 (thread->state & ThreadState_StopRequested) != 0)
2190 UNLOCK_THREAD (thread);
2191 return TRUE;
2194 thread->state |= ThreadState_SuspendRequested;
2196 UNLOCK_THREAD (thread);
2198 suspend_thread_internal (thread, FALSE);
2199 return TRUE;
2202 void
2203 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2205 if (!mono_thread_suspend (thread))
2206 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2209 static gboolean
2210 mono_thread_resume (MonoInternalThread *thread)
2212 LOCK_THREAD (thread);
2214 if ((thread->state & ThreadState_SuspendRequested) != 0) {
2215 thread->state &= ~ThreadState_SuspendRequested;
2216 UNLOCK_THREAD (thread);
2217 return TRUE;
2220 if ((thread->state & ThreadState_Suspended) == 0 ||
2221 (thread->state & ThreadState_Unstarted) != 0 ||
2222 (thread->state & ThreadState_Aborted) != 0 ||
2223 (thread->state & ThreadState_Stopped) != 0)
2225 UNLOCK_THREAD (thread);
2226 return FALSE;
2229 return resume_thread_internal (thread);
2232 void
2233 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2235 if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread))
2236 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2239 static gboolean
2240 mono_threads_is_critical_method (MonoMethod *method)
2242 switch (method->wrapper_type) {
2243 case MONO_WRAPPER_RUNTIME_INVOKE:
2244 case MONO_WRAPPER_XDOMAIN_INVOKE:
2245 case MONO_WRAPPER_XDOMAIN_DISPATCH:
2246 return TRUE;
2248 return FALSE;
2251 static gboolean
2252 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2254 if (managed)
2255 return TRUE;
2257 if (mono_threads_is_critical_method (m)) {
2258 *((gboolean*)data) = TRUE;
2259 return TRUE;
2261 return FALSE;
2264 static gboolean
2265 is_running_protected_wrapper (void)
2267 gboolean found = FALSE;
2268 mono_stack_walk (find_wrapper, &found);
2269 return found;
2272 void mono_thread_internal_stop (MonoInternalThread *thread)
2274 LOCK_THREAD (thread);
2276 if ((thread->state & ThreadState_StopRequested) != 0 ||
2277 (thread->state & ThreadState_Stopped) != 0)
2279 UNLOCK_THREAD (thread);
2280 return;
2283 /* Make sure the thread is awake */
2284 mono_thread_resume (thread);
2286 thread->state |= ThreadState_StopRequested;
2287 thread->state &= ~ThreadState_AbortRequested;
2289 UNLOCK_THREAD (thread);
2291 abort_thread_internal (thread, TRUE, TRUE);
2294 void mono_thread_stop (MonoThread *thread)
2296 mono_thread_internal_stop (thread->internal_thread);
2299 gint8
2300 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2302 gint8 tmp;
2303 mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2304 return tmp;
2307 gint16
2308 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2310 gint16 tmp;
2311 mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2312 return tmp;
2315 gint32
2316 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2318 gint32 tmp;
2319 mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2320 return tmp;
2323 gint64
2324 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2326 gint64 tmp;
2327 mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2328 return tmp;
2331 void *
2332 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2334 volatile void *tmp;
2335 mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2336 return (void *) tmp;
2339 void *
2340 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2342 volatile MonoObject *tmp;
2343 mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2344 return (MonoObject *) tmp;
2347 double
2348 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2350 double tmp;
2351 mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2352 return tmp;
2355 float
2356 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2358 float tmp;
2359 mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2360 return tmp;
2363 gint8
2364 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2366 return InterlockedRead8 (ptr);
2369 gint16
2370 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2372 return InterlockedRead16 (ptr);
2375 gint32
2376 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2378 return InterlockedRead (ptr);
2381 gint64
2382 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2384 #if SIZEOF_VOID_P == 4
2385 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2386 gint64 val;
2387 mono_interlocked_lock ();
2388 val = *(gint64*)ptr;
2389 mono_interlocked_unlock ();
2390 return val;
2392 #endif
2393 return InterlockedRead64 (ptr);
2396 void *
2397 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2399 return InterlockedReadPointer (ptr);
2402 double
2403 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2405 LongDoubleUnion u;
2407 #if SIZEOF_VOID_P == 4
2408 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2409 double val;
2410 mono_interlocked_lock ();
2411 val = *(double*)ptr;
2412 mono_interlocked_unlock ();
2413 return val;
2415 #endif
2417 u.ival = InterlockedRead64 (ptr);
2419 return u.fval;
2422 float
2423 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2425 IntFloatUnion u;
2427 u.ival = InterlockedRead (ptr);
2429 return u.fval;
2432 MonoObject*
2433 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2435 return InterlockedReadPointer (ptr);
2438 void
2439 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2441 mono_atomic_store_release ((volatile gint8 *) ptr, value);
2444 void
2445 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2447 mono_atomic_store_release ((volatile gint16 *) ptr, value);
2450 void
2451 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2453 mono_atomic_store_release ((volatile gint32 *) ptr, value);
2456 void
2457 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2459 mono_atomic_store_release ((volatile gint64 *) ptr, value);
2462 void
2463 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2465 mono_atomic_store_release ((volatile void **) ptr, value);
2468 void
2469 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2471 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2474 void
2475 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2477 mono_atomic_store_release ((volatile double *) ptr, value);
2480 void
2481 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2483 mono_atomic_store_release ((volatile float *) ptr, value);
2486 void
2487 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2489 InterlockedWrite8 (ptr, value);
2492 void
2493 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2495 InterlockedWrite16 (ptr, value);
2498 void
2499 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2501 InterlockedWrite (ptr, value);
2504 void
2505 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2507 #if SIZEOF_VOID_P == 4
2508 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2509 mono_interlocked_lock ();
2510 *(gint64*)ptr = value;
2511 mono_interlocked_unlock ();
2512 return;
2514 #endif
2516 InterlockedWrite64 (ptr, value);
2519 void
2520 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2522 InterlockedWritePointer (ptr, value);
2525 void
2526 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2528 LongDoubleUnion u;
2530 #if SIZEOF_VOID_P == 4
2531 if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2532 mono_interlocked_lock ();
2533 *(double*)ptr = value;
2534 mono_interlocked_unlock ();
2535 return;
2537 #endif
2539 u.fval = value;
2541 InterlockedWrite64 (ptr, u.ival);
2544 void
2545 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2547 IntFloatUnion u;
2549 u.fval = value;
2551 InterlockedWrite (ptr, u.ival);
2554 void
2555 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2557 mono_gc_wbarrier_generic_store_atomic (ptr, value);
2560 void
2561 mono_thread_init_tls (void)
2563 MONO_FAST_TLS_INIT (tls_current_object);
2564 mono_native_tls_alloc (&current_object_key, NULL);
2567 void mono_thread_init (MonoThreadStartCB start_cb,
2568 MonoThreadAttachCB attach_cb)
2570 mono_mutex_init_recursive(&threads_mutex);
2571 mono_mutex_init_recursive(&interlocked_mutex);
2572 mono_mutex_init_recursive(&contexts_mutex);
2573 mono_mutex_init_recursive(&joinable_threads_mutex);
2575 background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2576 g_assert(background_change_event != NULL);
2578 mono_init_static_data_info (&thread_static_info);
2579 mono_init_static_data_info (&context_static_info);
2581 THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2583 mono_thread_start_cb = start_cb;
2584 mono_thread_attach_cb = attach_cb;
2586 /* Get a pseudo handle to the current process. This is just a
2587 * kludge so that wapi can build a process handle if needed.
2588 * As a pseudo handle is returned, we don't need to clean
2589 * anything up.
2591 GetCurrentProcess ();
2594 void mono_thread_cleanup (void)
2596 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2597 MonoThreadInfo *info;
2599 /* The main thread must abandon any held mutexes (particularly
2600 * important for named mutexes as they are shared across
2601 * processes, see bug 74680.) This will happen when the
2602 * thread exits, but if it's not running in a subthread it
2603 * won't exit in time.
2605 info = mono_thread_info_current ();
2606 wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2607 #endif
2609 #if 0
2610 /* This stuff needs more testing, it seems one of these
2611 * critical sections can be locked when mono_thread_cleanup is
2612 * called.
2614 mono_mutex_destroy (&threads_mutex);
2615 mono_mutex_destroy (&interlocked_mutex);
2616 mono_mutex_destroy (&contexts_mutex);
2617 mono_mutex_destroy (&delayed_free_table_mutex);
2618 mono_mutex_destroy (&small_id_mutex);
2619 CloseHandle (background_change_event);
2620 #endif
2622 mono_native_tls_free (current_object_key);
2625 void
2626 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2628 mono_thread_cleanup_fn = func;
2631 void
2632 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2634 thread->internal_thread->manage_callback = func;
2637 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2639 mono_thread_notify_pending_exc_fn = func;
2642 G_GNUC_UNUSED
2643 static void print_tids (gpointer key, gpointer value, gpointer user)
2645 /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2646 * sizeof(uint) and a cast to uint would overflow
2648 /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2649 * print this as a pointer.
2651 g_message ("Waiting for: %p", key);
2654 struct wait_data
2656 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2657 MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2658 guint32 num;
2661 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2663 guint32 i, ret;
2665 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2667 ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2669 if(ret==WAIT_FAILED) {
2670 /* See the comment in build_wait_tids() */
2671 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2672 return;
2675 for(i=0; i<wait->num; i++)
2676 CloseHandle (wait->handles[i]);
2678 if (ret == WAIT_TIMEOUT)
2679 return;
2681 for(i=0; i<wait->num; i++) {
2682 gsize tid = wait->threads[i]->tid;
2685 * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2686 * it can still run io-layer etc. code. So wait for it to really exit.
2687 * FIXME: This won't join threads which are not in the joinable_hash yet.
2689 mono_thread_join ((gpointer)tid);
2691 mono_threads_lock ();
2692 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2693 /* This thread must have been killed, because
2694 * it hasn't cleaned itself up. (It's just
2695 * possible that the thread exited before the
2696 * parent thread had a chance to store the
2697 * handle, and now there is another pointer to
2698 * the already-exited thread stored. In this
2699 * case, we'll just get two
2700 * mono_profiler_thread_end() calls for the
2701 * same thread.)
2704 mono_threads_unlock ();
2705 THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2706 thread_cleanup (wait->threads[i]);
2707 } else {
2708 mono_threads_unlock ();
2713 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2715 guint32 i, ret, count;
2717 THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2719 /* Add the thread state change event, so it wakes up if a thread changes
2720 * to background mode.
2722 count = wait->num;
2723 if (count < MAXIMUM_WAIT_OBJECTS) {
2724 wait->handles [count] = background_change_event;
2725 count++;
2728 ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2730 if(ret==WAIT_FAILED) {
2731 /* See the comment in build_wait_tids() */
2732 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2733 return;
2736 for(i=0; i<wait->num; i++)
2737 CloseHandle (wait->handles[i]);
2739 if (ret == WAIT_TIMEOUT)
2740 return;
2742 if (ret < wait->num) {
2743 gsize tid = wait->threads[ret]->tid;
2744 mono_threads_lock ();
2745 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2746 /* See comment in wait_for_tids about thread cleanup */
2747 mono_threads_unlock ();
2748 THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2749 thread_cleanup (wait->threads [ret]);
2750 } else
2751 mono_threads_unlock ();
2755 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2757 struct wait_data *wait=(struct wait_data *)user;
2759 if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2760 HANDLE handle;
2761 MonoInternalThread *thread=(MonoInternalThread *)value;
2763 /* Ignore background threads, we abort them later */
2764 /* Do not lock here since it is not needed and the caller holds threads_lock */
2765 if (thread->state & ThreadState_Background) {
2766 THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2767 return; /* just leave, ignore */
2770 if (mono_gc_is_finalizer_internal_thread (thread)) {
2771 THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2772 return;
2775 if (thread == mono_thread_internal_current ()) {
2776 THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2777 return;
2780 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2781 THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2782 return;
2785 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2786 THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2787 return;
2790 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2791 if (handle == NULL) {
2792 THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2793 return;
2796 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2797 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2798 wait->handles[wait->num]=handle;
2799 wait->threads[wait->num]=thread;
2800 wait->num++;
2802 THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2803 } else {
2804 THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2808 } else {
2809 /* Just ignore the rest, we can't do anything with
2810 * them yet
2815 static gboolean
2816 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2818 struct wait_data *wait=(struct wait_data *)user;
2819 gsize self = GetCurrentThreadId ();
2820 MonoInternalThread *thread = value;
2821 HANDLE handle;
2823 if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2824 return FALSE;
2826 /* The finalizer thread is not a background thread */
2827 if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2828 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2830 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2831 if (handle == NULL)
2832 return FALSE;
2834 /* printf ("A: %d\n", wait->num); */
2835 wait->handles[wait->num]=thread->handle;
2836 wait->threads[wait->num]=thread;
2837 wait->num++;
2839 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2840 mono_thread_internal_stop (thread);
2841 return TRUE;
2844 return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread));
2847 /**
2848 * mono_threads_set_shutting_down:
2850 * Is called by a thread that wants to shut down Mono. If the runtime is already
2851 * shutting down, the calling thread is suspended/stopped, and this function never
2852 * returns.
2854 void
2855 mono_threads_set_shutting_down (void)
2857 MonoInternalThread *current_thread = mono_thread_internal_current ();
2859 mono_threads_lock ();
2861 if (shutting_down) {
2862 mono_threads_unlock ();
2864 /* Make sure we're properly suspended/stopped */
2866 LOCK_THREAD (current_thread);
2868 if ((current_thread->state & ThreadState_SuspendRequested) ||
2869 (current_thread->state & ThreadState_AbortRequested) ||
2870 (current_thread->state & ThreadState_StopRequested)) {
2871 UNLOCK_THREAD (current_thread);
2872 mono_thread_execute_interruption (current_thread);
2873 } else {
2874 current_thread->state |= ThreadState_Stopped;
2875 UNLOCK_THREAD (current_thread);
2878 /*since we're killing the thread, unset the current domain.*/
2879 mono_domain_unset ();
2881 /* Wake up other threads potentially waiting for us */
2882 mono_thread_info_exit ();
2883 } else {
2884 shutting_down = TRUE;
2886 /* Not really a background state change, but this will
2887 * interrupt the main thread if it is waiting for all
2888 * the other threads.
2890 SetEvent (background_change_event);
2892 mono_threads_unlock ();
2896 void mono_thread_manage (void)
2898 struct wait_data wait_data;
2899 struct wait_data *wait = &wait_data;
2901 memset (wait, 0, sizeof (struct wait_data));
2902 /* join each thread that's still running */
2903 THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2905 mono_threads_lock ();
2906 if(threads==NULL) {
2907 THREAD_DEBUG (g_message("%s: No threads", __func__));
2908 mono_threads_unlock ();
2909 return;
2911 mono_threads_unlock ();
2913 do {
2914 mono_threads_lock ();
2915 if (shutting_down) {
2916 /* somebody else is shutting down */
2917 mono_threads_unlock ();
2918 break;
2920 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2921 mono_g_hash_table_foreach (threads, print_tids, NULL));
2923 ResetEvent (background_change_event);
2924 wait->num=0;
2925 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2926 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2927 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2928 mono_threads_unlock ();
2929 if(wait->num>0) {
2930 /* Something to wait for */
2931 wait_for_tids_or_state_change (wait, INFINITE);
2933 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2934 } while(wait->num>0);
2936 /* Mono is shutting down, so just wait for the end */
2937 if (!mono_runtime_try_shutdown ()) {
2938 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2939 mono_thread_suspend (mono_thread_internal_current ());
2940 mono_thread_execute_interruption (mono_thread_internal_current ());
2944 * Remove everything but the finalizer thread and self.
2945 * Also abort all the background threads
2946 * */
2947 do {
2948 mono_threads_lock ();
2950 wait->num = 0;
2951 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2952 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2953 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2955 mono_threads_unlock ();
2957 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2958 if(wait->num>0) {
2959 /* Something to wait for */
2960 wait_for_tids (wait, INFINITE);
2962 } while (wait->num > 0);
2965 * give the subthreads a chance to really quit (this is mainly needed
2966 * to get correct user and system times from getrusage/wait/time(1)).
2967 * This could be removed if we avoid pthread_detach() and use pthread_join().
2969 mono_thread_info_yield ();
2972 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2974 MonoInternalThread *thread=(MonoInternalThread *)value;
2976 if(thread->tid != (gsize)user) {
2977 /*TerminateThread (thread->handle, -1);*/
2981 void mono_thread_abort_all_other_threads (void)
2983 gsize self = GetCurrentThreadId ();
2985 mono_threads_lock ();
2986 THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2987 mono_g_hash_table_size (threads));
2988 mono_g_hash_table_foreach (threads, print_tids, NULL));
2990 mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2992 mono_threads_unlock ();
2995 static void
2996 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2998 MonoInternalThread *thread = (MonoInternalThread*)value;
2999 struct wait_data *wait = (struct wait_data*)user_data;
3000 HANDLE handle;
3003 * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3004 * limitation.
3005 * This needs no locking.
3007 if ((thread->state & ThreadState_Suspended) != 0 ||
3008 (thread->state & ThreadState_Stopped) != 0)
3009 return;
3011 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3012 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3013 if (handle == NULL)
3014 return;
3016 wait->handles [wait->num] = handle;
3017 wait->threads [wait->num] = thread;
3018 wait->num++;
3023 * mono_thread_suspend_all_other_threads:
3025 * Suspend all managed threads except the finalizer thread and this thread. It is
3026 * not possible to resume them later.
3028 void mono_thread_suspend_all_other_threads (void)
3030 struct wait_data wait_data;
3031 struct wait_data *wait = &wait_data;
3032 int i;
3033 gsize self = GetCurrentThreadId ();
3034 gpointer *events;
3035 guint32 eventidx = 0;
3036 gboolean starting, finished;
3038 memset (wait, 0, sizeof (struct wait_data));
3040 * The other threads could be in an arbitrary state at this point, i.e.
3041 * they could be starting up, shutting down etc. This means that there could be
3042 * threads which are not even in the threads hash table yet.
3046 * First we set a barrier which will be checked by all threads before they
3047 * are added to the threads hash table, and they will exit if the flag is set.
3048 * This ensures that no threads could be added to the hash later.
3049 * We will use shutting_down as the barrier for now.
3051 g_assert (shutting_down);
3054 * We make multiple calls to WaitForMultipleObjects since:
3055 * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3056 * - some threads could exit without becoming suspended
3058 finished = FALSE;
3059 while (!finished) {
3061 * Make a copy of the hashtable since we can't do anything with
3062 * threads while threads_mutex is held.
3064 wait->num = 0;
3065 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3066 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3067 mono_threads_lock ();
3068 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3069 mono_threads_unlock ();
3071 events = g_new0 (gpointer, wait->num);
3072 eventidx = 0;
3073 /* Get the suspended events that we'll be waiting for */
3074 for (i = 0; i < wait->num; ++i) {
3075 MonoInternalThread *thread = wait->threads [i];
3076 gboolean signal_suspend = FALSE;
3078 if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3079 //CloseHandle (wait->handles [i]);
3080 wait->threads [i] = NULL; /* ignore this thread in next loop */
3081 continue;
3084 LOCK_THREAD (thread);
3086 if (thread->suspended_event == NULL) {
3087 thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
3088 if (thread->suspended_event == NULL) {
3089 /* Forget this one and go on to the next */
3090 UNLOCK_THREAD (thread);
3091 continue;
3095 if ((thread->state & ThreadState_Suspended) != 0 ||
3096 (thread->state & ThreadState_StopRequested) != 0 ||
3097 (thread->state & ThreadState_Stopped) != 0) {
3098 UNLOCK_THREAD (thread);
3099 CloseHandle (wait->handles [i]);
3100 wait->threads [i] = NULL; /* ignore this thread in next loop */
3101 continue;
3104 if ((thread->state & ThreadState_SuspendRequested) == 0)
3105 signal_suspend = TRUE;
3107 events [eventidx++] = thread->suspended_event;
3109 /* Convert abort requests into suspend requests */
3110 if ((thread->state & ThreadState_AbortRequested) != 0)
3111 thread->state &= ~ThreadState_AbortRequested;
3113 thread->state |= ThreadState_SuspendRequested;
3115 UNLOCK_THREAD (thread);
3117 /* Signal the thread to suspend */
3118 if (mono_thread_info_new_interrupt_enabled ())
3119 suspend_thread_internal (thread, TRUE);
3120 else if (signal_suspend)
3121 signal_thread_state_change (thread);
3124 /*Only wait on the suspend event if we are using the old path */
3125 if (eventidx > 0 && !mono_thread_info_new_interrupt_enabled ()) {
3126 WaitForMultipleObjectsEx (eventidx, events, TRUE, 100, FALSE);
3127 for (i = 0; i < wait->num; ++i) {
3128 MonoInternalThread *thread = wait->threads [i];
3130 if (thread == NULL)
3131 continue;
3133 LOCK_THREAD (thread);
3134 if ((thread->state & ThreadState_Suspended) != 0) {
3135 CloseHandle (thread->suspended_event);
3136 thread->suspended_event = NULL;
3138 UNLOCK_THREAD (thread);
3142 if (eventidx <= 0) {
3144 * If there are threads which are starting up, we wait until they
3145 * are suspended when they try to register in the threads hash.
3146 * This is guaranteed to finish, since the threads which can create new
3147 * threads get suspended after a while.
3148 * FIXME: The finalizer thread can still create new threads.
3150 mono_threads_lock ();
3151 if (threads_starting_up)
3152 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3153 else
3154 starting = FALSE;
3155 mono_threads_unlock ();
3156 if (starting)
3157 Sleep (100);
3158 else
3159 finished = TRUE;
3162 g_free (events);
3166 static void
3167 collect_threads (gpointer key, gpointer value, gpointer user_data)
3169 MonoInternalThread *thread = (MonoInternalThread*)value;
3170 struct wait_data *wait = (struct wait_data*)user_data;
3171 HANDLE handle;
3173 if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3174 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3175 if (handle == NULL)
3176 return;
3178 wait->handles [wait->num] = handle;
3179 wait->threads [wait->num] = thread;
3180 wait->num++;
3184 static gboolean thread_dump_requested;
3186 static G_GNUC_UNUSED gboolean
3187 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3189 GString *p = (GString*)data;
3190 MonoMethod *method = NULL;
3191 if (frame->ji)
3192 method = mono_jit_info_get_method (frame->ji);
3194 if (method) {
3195 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3196 g_string_append_printf (p, " %s\n", location);
3197 g_free (location);
3198 } else
3199 g_string_append_printf (p, " at <unknown> <0x%05x>\n", frame->native_offset);
3201 return FALSE;
3204 static void
3205 print_thread_dump (MonoInternalThread *thread, MonoThreadInfo *info)
3207 GString* text = g_string_new (0);
3208 char *name;
3209 GError *error = NULL;
3211 if (thread->name) {
3212 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3213 g_assert (!error);
3214 g_string_append_printf (text, "\n\"%s\"", name);
3215 g_free (name);
3217 else if (thread->threadpool_thread)
3218 g_string_append (text, "\n\"<threadpool thread>\"");
3219 else
3220 g_string_append (text, "\n\"<unnamed thread>\"");
3222 #if 0
3223 /* This no longer works with remote unwinding */
3224 #ifndef HOST_WIN32
3225 wapi_desc = wapi_current_thread_desc ();
3226 g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread, wapi_desc);
3227 free (wapi_desc);
3228 #endif
3229 #endif
3231 mono_get_eh_callbacks ()->mono_walk_stack_with_state (print_stack_frame_to_string, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, text);
3232 mono_thread_info_finish_suspend_and_resume (info);
3234 fprintf (stdout, "%s", text->str);
3236 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3237 OutputDebugStringA(text->str);
3238 #endif
3240 g_string_free (text, TRUE);
3241 fflush (stdout);
3244 static void
3245 dump_thread (gpointer key, gpointer value, gpointer user)
3247 MonoInternalThread *thread = (MonoInternalThread *)value;
3248 MonoThreadInfo *info;
3250 if (thread == mono_thread_internal_current ())
3251 return;
3254 FIXME This still can hang if we stop a thread during malloc.
3255 FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3256 that takes a callback and runs it with the target suspended.
3257 We probably should loop a bit around trying to get it to either managed code
3258 or WSJ state.
3260 info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gpointer)(gsize)thread->tid, FALSE);
3262 if (!info)
3263 return;
3265 print_thread_dump (thread, info);
3268 void
3269 mono_threads_perform_thread_dump (void)
3271 if (!thread_dump_requested)
3272 return;
3274 printf ("Full thread dump:\n");
3276 /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3277 something needs then in the process.
3279 mono_loader_lock ();
3280 mono_domain_lock (mono_get_root_domain ());
3282 mono_threads_lock ();
3283 mono_g_hash_table_foreach (threads, dump_thread, NULL);
3284 mono_threads_unlock ();
3286 mono_domain_unlock (mono_get_root_domain ());
3287 mono_loader_unlock ();
3289 thread_dump_requested = FALSE;
3293 * mono_threads_request_thread_dump:
3295 * Ask all threads except the current to print their stacktrace to stdout.
3297 void
3298 mono_threads_request_thread_dump (void)
3300 struct wait_data wait_data;
3301 struct wait_data *wait = &wait_data;
3302 int i;
3304 /*The new thread dump code runs out of the finalizer thread. */
3305 if (mono_thread_info_new_interrupt_enabled ()) {
3306 thread_dump_requested = TRUE;
3307 mono_gc_finalize_notify ();
3308 return;
3312 memset (wait, 0, sizeof (struct wait_data));
3315 * Make a copy of the hashtable since we can't do anything with
3316 * threads while threads_mutex is held.
3318 mono_threads_lock ();
3319 mono_g_hash_table_foreach (threads, collect_threads, wait);
3320 mono_threads_unlock ();
3322 for (i = 0; i < wait->num; ++i) {
3323 MonoInternalThread *thread = wait->threads [i];
3325 if (!mono_gc_is_finalizer_internal_thread (thread) &&
3326 (thread != mono_thread_internal_current ()) &&
3327 !thread->thread_dump_requested) {
3328 thread->thread_dump_requested = TRUE;
3330 signal_thread_state_change (thread);
3333 CloseHandle (wait->handles [i]);
3337 struct ref_stack {
3338 gpointer *refs;
3339 gint allocated; /* +1 so that refs [allocated] == NULL */
3340 gint bottom;
3343 typedef struct ref_stack RefStack;
3345 static RefStack *
3346 ref_stack_new (gint initial_size)
3348 RefStack *rs;
3350 initial_size = MAX (initial_size, 16) + 1;
3351 rs = g_new0 (RefStack, 1);
3352 rs->refs = g_new0 (gpointer, initial_size);
3353 rs->allocated = initial_size;
3354 return rs;
3357 static void
3358 ref_stack_destroy (gpointer ptr)
3360 RefStack *rs = ptr;
3362 if (rs != NULL) {
3363 g_free (rs->refs);
3364 g_free (rs);
3368 static void
3369 ref_stack_push (RefStack *rs, gpointer ptr)
3371 g_assert (rs != NULL);
3373 if (rs->bottom >= rs->allocated) {
3374 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3375 rs->allocated <<= 1;
3376 rs->refs [rs->allocated] = NULL;
3378 rs->refs [rs->bottom++] = ptr;
3381 static void
3382 ref_stack_pop (RefStack *rs)
3384 if (rs == NULL || rs->bottom == 0)
3385 return;
3387 rs->bottom--;
3388 rs->refs [rs->bottom] = NULL;
3391 static gboolean
3392 ref_stack_find (RefStack *rs, gpointer ptr)
3394 gpointer *refs;
3396 if (rs == NULL)
3397 return FALSE;
3399 for (refs = rs->refs; refs && *refs; refs++) {
3400 if (*refs == ptr)
3401 return TRUE;
3403 return FALSE;
3407 * mono_thread_push_appdomain_ref:
3409 * Register that the current thread may have references to objects in domain
3410 * @domain on its stack. Each call to this function should be paired with a
3411 * call to pop_appdomain_ref.
3413 void
3414 mono_thread_push_appdomain_ref (MonoDomain *domain)
3416 MonoInternalThread *thread = mono_thread_internal_current ();
3418 if (thread) {
3419 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3420 SPIN_LOCK (thread->lock_thread_id);
3421 if (thread->appdomain_refs == NULL)
3422 thread->appdomain_refs = ref_stack_new (16);
3423 ref_stack_push (thread->appdomain_refs, domain);
3424 SPIN_UNLOCK (thread->lock_thread_id);
3428 void
3429 mono_thread_pop_appdomain_ref (void)
3431 MonoInternalThread *thread = mono_thread_internal_current ();
3433 if (thread) {
3434 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3435 SPIN_LOCK (thread->lock_thread_id);
3436 ref_stack_pop (thread->appdomain_refs);
3437 SPIN_UNLOCK (thread->lock_thread_id);
3441 gboolean
3442 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3444 gboolean res;
3445 SPIN_LOCK (thread->lock_thread_id);
3446 res = ref_stack_find (thread->appdomain_refs, domain);
3447 SPIN_UNLOCK (thread->lock_thread_id);
3448 return res;
3451 gboolean
3452 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3454 return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3457 typedef struct abort_appdomain_data {
3458 struct wait_data wait;
3459 MonoDomain *domain;
3460 } abort_appdomain_data;
3462 static void
3463 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3465 MonoInternalThread *thread = (MonoInternalThread*)value;
3466 abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3467 MonoDomain *domain = data->domain;
3469 if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3470 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3472 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3473 HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3474 if (handle == NULL)
3475 return;
3476 data->wait.handles [data->wait.num] = handle;
3477 data->wait.threads [data->wait.num] = thread;
3478 data->wait.num++;
3479 } else {
3480 /* Just ignore the rest, we can't do anything with
3481 * them yet
3488 * mono_threads_abort_appdomain_threads:
3490 * Abort threads which has references to the given appdomain.
3492 gboolean
3493 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3495 #ifdef __native_client__
3496 return FALSE;
3497 #endif
3499 abort_appdomain_data user_data;
3500 guint32 start_time;
3501 int orig_timeout = timeout;
3502 int i;
3504 THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3506 start_time = mono_msec_ticks ();
3507 do {
3508 mono_threads_lock ();
3510 user_data.domain = domain;
3511 user_data.wait.num = 0;
3512 /* This shouldn't take any locks */
3513 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3514 mono_threads_unlock ();
3516 if (user_data.wait.num > 0) {
3517 /* Abort the threads outside the threads lock */
3518 for (i = 0; i < user_data.wait.num; ++i)
3519 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3522 * We should wait for the threads either to abort, or to leave the
3523 * domain. We can't do the latter, so we wait with a timeout.
3525 wait_for_tids (&user_data.wait, 100);
3528 /* Update remaining time */
3529 timeout -= mono_msec_ticks () - start_time;
3530 start_time = mono_msec_ticks ();
3532 if (orig_timeout != -1 && timeout < 0)
3533 return FALSE;
3535 while (user_data.wait.num > 0);
3537 THREAD_DEBUG (g_message ("%s: abort done", __func__));
3539 return TRUE;
3542 static void
3543 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3545 MonoInternalThread *thread = (MonoInternalThread*)value;
3546 MonoDomain *domain = (MonoDomain*)user_data;
3547 int i;
3549 /* No locking needed here */
3550 /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3552 if (thread->cached_culture_info) {
3553 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3554 MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3555 if (obj && obj->vtable->domain == domain)
3556 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3562 * mono_threads_clear_cached_culture:
3564 * Clear the cached_current_culture from all threads if it is in the
3565 * given appdomain.
3567 void
3568 mono_threads_clear_cached_culture (MonoDomain *domain)
3570 mono_threads_lock ();
3571 mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3572 mono_threads_unlock ();
3576 * mono_thread_get_undeniable_exception:
3578 * Return an exception which needs to be raised when leaving a catch clause.
3579 * This is used for undeniable exception propagation.
3581 MonoException*
3582 mono_thread_get_undeniable_exception (void)
3584 MonoInternalThread *thread = mono_thread_internal_current ();
3586 if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3588 * FIXME: Clear the abort exception and return an AppDomainUnloaded
3589 * exception if the thread no longer references a dying appdomain.
3591 thread->abort_exc->trace_ips = NULL;
3592 thread->abort_exc->stack_trace = NULL;
3593 return thread->abort_exc;
3596 return NULL;
3599 #if MONO_SMALL_CONFIG
3600 #define NUM_STATIC_DATA_IDX 4
3601 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3602 64, 256, 1024, 4096
3604 #else
3605 #define NUM_STATIC_DATA_IDX 8
3606 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3607 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3609 #endif
3611 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3613 static void
3614 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3616 int i;
3617 gpointer *static_data = addr;
3618 for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3619 int j, numwords;
3620 void **ptr;
3621 if (!static_data [i])
3622 continue;
3623 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3624 ptr = static_data [i];
3625 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3626 uintptr_t bmap = static_reference_bitmaps [i][j];
3627 void ** p = ptr;
3628 while (bmap) {
3629 if ((bmap & 1) && *p) {
3630 mark_func (p, gc_data);
3632 p++;
3633 bmap >>= 1;
3640 * mono_alloc_static_data
3642 * Allocate memory blocks for storing threads or context static data
3644 static void
3645 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3647 guint idx = (offset >> 24) - 1;
3648 int i;
3650 gpointer* static_data = *static_data_ptr;
3651 if (!static_data) {
3652 static void* tls_desc = NULL;
3653 if (mono_gc_user_markers_supported () && !tls_desc)
3654 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3655 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3656 *static_data_ptr = static_data;
3657 static_data [0] = static_data;
3660 for (i = 1; i <= idx; ++i) {
3661 if (static_data [i])
3662 continue;
3663 if (mono_gc_user_markers_supported () && threadlocal)
3664 static_data [i] = g_malloc0 (static_data_size [i]);
3665 else
3666 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3670 static void
3671 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3673 int i;
3674 for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3675 gpointer p = static_data [i];
3676 if (!p)
3677 continue;
3679 * At this point, the static data pointer array is still registered with the
3680 * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3681 * data. Freeing the individual arrays without first nulling their slots
3682 * would make it possible for mark_tls_slots() to encounter a pointer to
3683 * such an already freed array. See bug #13813.
3685 static_data [i] = NULL;
3686 mono_memory_write_barrier ();
3687 if (mono_gc_user_markers_supported () && threadlocal)
3688 g_free (p);
3689 else
3690 mono_gc_free_fixed (p);
3692 mono_gc_free_fixed (static_data);
3696 * mono_init_static_data_info
3698 * Initializes static data counters
3700 static void mono_init_static_data_info (StaticDataInfo *static_data)
3702 static_data->idx = 0;
3703 static_data->offset = 0;
3704 static_data->freelist = NULL;
3708 * mono_alloc_static_data_slot
3710 * Generates an offset for static data. static_data contains the counters
3711 * used to generate it.
3713 static guint32
3714 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3716 guint32 offset;
3718 if (!static_data->idx && !static_data->offset) {
3720 * we use the first chunk of the first allocation also as
3721 * an array for the rest of the data
3723 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3725 static_data->offset += align - 1;
3726 static_data->offset &= ~(align - 1);
3727 if (static_data->offset + size >= static_data_size [static_data->idx]) {
3728 static_data->idx ++;
3729 g_assert (size <= static_data_size [static_data->idx]);
3730 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3731 static_data->offset = 0;
3733 offset = static_data->offset | ((static_data->idx + 1) << 24);
3734 static_data->offset += size;
3735 return offset;
3739 * ensure thread static fields already allocated are valid for thread
3740 * This function is called when a thread is created or on thread attach.
3742 static void
3743 thread_adjust_static_data (MonoInternalThread *thread)
3745 guint32 offset;
3747 mono_threads_lock ();
3748 if (thread_static_info.offset || thread_static_info.idx > 0) {
3749 /* get the current allocated size */
3750 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3751 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3753 mono_threads_unlock ();
3756 static void
3757 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3759 MonoInternalThread *thread = value;
3760 guint32 offset = GPOINTER_TO_UINT (user);
3762 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3765 static MonoThreadDomainTls*
3766 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3768 MonoThreadDomainTls* prev = NULL;
3769 MonoThreadDomainTls* tmp = static_data->freelist;
3770 while (tmp) {
3771 if (tmp->size == size) {
3772 if (prev)
3773 prev->next = tmp->next;
3774 else
3775 static_data->freelist = tmp->next;
3776 return tmp;
3778 prev = tmp;
3779 tmp = tmp->next;
3781 return NULL;
3784 #if SIZEOF_VOID_P == 4
3785 #define ONE_P 1
3786 #else
3787 #define ONE_P 1ll
3788 #endif
3790 static void
3791 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3793 int i;
3794 int idx = (offset >> 24) - 1;
3795 uintptr_t *rb;
3796 if (!static_reference_bitmaps [idx])
3797 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3798 rb = static_reference_bitmaps [idx];
3799 offset &= 0xffffff;
3800 offset /= sizeof (gpointer);
3801 /* offset is now the bitmap offset */
3802 for (i = 0; i < numbits; ++i) {
3803 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3804 rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (ONE_P << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3808 static void
3809 clear_reference_bitmap (guint32 offset, guint32 size)
3811 int idx = (offset >> 24) - 1;
3812 uintptr_t *rb;
3813 rb = static_reference_bitmaps [idx];
3814 offset &= 0xffffff;
3815 offset /= sizeof (gpointer);
3816 size /= sizeof (gpointer);
3817 size += offset;
3818 /* offset is now the bitmap offset */
3819 for (; offset < size; ++offset)
3820 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3824 * The offset for a special static variable is composed of three parts:
3825 * a bit that indicates the type of static data (0:thread, 1:context),
3826 * an index in the array of chunks of memory for the thread (thread->static_data)
3827 * and an offset in that chunk of mem. This allows allocating less memory in the
3828 * common case.
3831 guint32
3832 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3834 guint32 offset;
3835 if (static_type == SPECIAL_STATIC_THREAD) {
3836 MonoThreadDomainTls *item;
3837 mono_threads_lock ();
3838 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3839 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3840 if (item) {
3841 offset = item->offset;
3842 g_free (item);
3843 } else {
3844 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3846 update_tls_reference_bitmap (offset, bitmap, numbits);
3847 /* This can be called during startup */
3848 if (threads != NULL)
3849 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3850 mono_threads_unlock ();
3851 } else {
3852 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3853 mono_contexts_lock ();
3854 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3855 mono_contexts_unlock ();
3856 offset |= 0x80000000; /* Set the high bit to indicate context static data */
3858 return offset;
3861 gpointer
3862 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3864 /* The high bit means either thread (0) or static (1) data. */
3866 guint32 static_type = (offset & 0x80000000);
3867 int idx;
3869 offset &= 0x7fffffff;
3870 idx = (offset >> 24) - 1;
3872 if (static_type == 0) {
3873 return get_thread_static_data (thread, offset);
3874 } else {
3875 /* Allocate static data block under demand, since we don't have a list
3876 // of contexts
3878 MonoAppContext *context = mono_context_get ();
3879 if (!context->static_data || !context->static_data [idx]) {
3880 mono_contexts_lock ();
3881 mono_alloc_static_data (&(context->static_data), offset, FALSE);
3882 mono_contexts_unlock ();
3884 return ((char*) context->static_data [idx]) + (offset & 0xffffff);
3888 gpointer
3889 mono_get_special_static_data (guint32 offset)
3891 return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3894 typedef struct {
3895 guint32 offset;
3896 guint32 size;
3897 } TlsOffsetSize;
3899 static void
3900 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3902 MonoInternalThread *thread = value;
3903 TlsOffsetSize *data = user;
3904 int idx = (data->offset >> 24) - 1;
3905 char *ptr;
3907 if (!thread->static_data || !thread->static_data [idx])
3908 return;
3909 ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3910 mono_gc_bzero_atomic (ptr, data->size);
3913 static void
3914 do_free_special_slot (guint32 offset, guint32 size)
3916 guint32 static_type = (offset & 0x80000000);
3917 /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3918 if (static_type == 0) {
3919 TlsOffsetSize data;
3920 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3921 data.offset = offset & 0x7fffffff;
3922 data.size = size;
3923 clear_reference_bitmap (data.offset, data.size);
3924 if (threads != NULL)
3925 mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3926 item->offset = offset;
3927 item->size = size;
3929 if (!mono_runtime_is_shutting_down ()) {
3930 item->next = thread_static_info.freelist;
3931 thread_static_info.freelist = item;
3932 } else {
3933 /* We could be called during shutdown after mono_thread_cleanup () is called */
3934 g_free (item);
3936 } else {
3937 /* FIXME: free context static data as well */
3941 static void
3942 do_free_special (gpointer key, gpointer value, gpointer data)
3944 MonoClassField *field = key;
3945 guint32 offset = GPOINTER_TO_UINT (value);
3946 gint32 align;
3947 guint32 size;
3948 size = mono_type_size (field->type, &align);
3949 do_free_special_slot (offset, size);
3952 void
3953 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3955 mono_threads_lock ();
3956 g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3957 mono_threads_unlock ();
3960 void
3961 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3963 mono_threads_lock ();
3964 do_free_special_slot (offset, size);
3965 mono_threads_unlock ();
3969 * allocates room in the thread local area for storing an instance of the struct type
3970 * the allocation is kept track of in domain->tlsrec_list.
3972 uint32_t
3973 mono_thread_alloc_tls (MonoReflectionType *type)
3975 MonoDomain *domain = mono_domain_get ();
3976 MonoClass *klass;
3977 MonoTlsDataRecord *tlsrec;
3978 int max_set = 0;
3979 gsize *bitmap;
3980 gsize default_bitmap [4] = {0};
3981 uint32_t tls_offset;
3982 guint32 size;
3983 gint32 align;
3985 klass = mono_class_from_mono_type (type->type);
3986 /* TlsDatum is a struct, so we subtract the object header size offset */
3987 bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3988 size = mono_type_size (type->type, &align);
3989 tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3990 if (bitmap != default_bitmap)
3991 g_free (bitmap);
3992 tlsrec = g_new0 (MonoTlsDataRecord, 1);
3993 tlsrec->tls_offset = tls_offset;
3994 tlsrec->size = size;
3995 mono_domain_lock (domain);
3996 tlsrec->next = domain->tlsrec_list;
3997 domain->tlsrec_list = tlsrec;
3998 mono_domain_unlock (domain);
3999 return tls_offset;
4002 static void
4003 destroy_tls (MonoDomain *domain, uint32_t tls_offset)
4005 MonoTlsDataRecord *prev = NULL;
4006 MonoTlsDataRecord *cur;
4007 guint32 size = 0;
4009 mono_domain_lock (domain);
4010 cur = domain->tlsrec_list;
4011 while (cur) {
4012 if (cur->tls_offset == tls_offset) {
4013 if (prev)
4014 prev->next = cur->next;
4015 else
4016 domain->tlsrec_list = cur->next;
4017 size = cur->size;
4018 g_free (cur);
4019 break;
4021 prev = cur;
4022 cur = cur->next;
4024 mono_domain_unlock (domain);
4025 if (size)
4026 mono_special_static_data_free_slot (tls_offset, size);
4029 void
4030 mono_thread_destroy_tls (uint32_t tls_offset)
4032 destroy_tls (mono_domain_get (), tls_offset);
4036 * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
4038 void
4039 mono_thread_destroy_domain_tls (MonoDomain *domain)
4041 while (domain->tlsrec_list)
4042 destroy_tls (domain, domain->tlsrec_list->tls_offset);
4045 static MonoClassField *local_slots = NULL;
4047 typedef struct {
4048 /* local tls data to get locals_slot from a thread */
4049 guint32 offset;
4050 int idx;
4051 /* index in the locals_slot array */
4052 int slot;
4053 } LocalSlotID;
4055 static void
4056 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4058 LocalSlotID *sid = user_data;
4059 MonoInternalThread *thread = (MonoInternalThread*)value;
4060 MonoArray *slots_array;
4062 * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4063 * it is for the right domain, so we need to check if it is allocated an initialized
4064 * for the current thread.
4066 /*g_print ("handling thread %p\n", thread);*/
4067 if (!thread->static_data || !thread->static_data [sid->idx])
4068 return;
4069 slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4070 if (!slots_array || sid->slot >= mono_array_length (slots_array))
4071 return;
4072 mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4075 void
4076 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4078 MonoDomain *domain;
4079 LocalSlotID sid;
4080 sid.slot = slot;
4081 if (thread_local) {
4082 void *addr = NULL;
4083 if (!local_slots) {
4084 local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4085 if (!local_slots) {
4086 g_warning ("local_slots field not found in Thread class");
4087 return;
4090 domain = mono_domain_get ();
4091 mono_domain_lock (domain);
4092 if (domain->special_static_fields)
4093 addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4094 mono_domain_unlock (domain);
4095 if (!addr)
4096 return;
4097 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4098 sid.offset = GPOINTER_TO_UINT (addr);
4099 sid.offset &= 0x7fffffff;
4100 sid.idx = (sid.offset >> 24) - 1;
4101 mono_threads_lock ();
4102 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4103 mono_threads_unlock ();
4104 } else {
4105 /* FIXME: clear the slot for MonoAppContexts, too */
4109 #ifdef HOST_WIN32
4110 static void CALLBACK dummy_apc (ULONG_PTR param)
4113 #endif
4116 * mono_thread_execute_interruption
4118 * Performs the operation that the requested thread state requires (abort,
4119 * suspend or stop)
4121 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4123 LOCK_THREAD (thread);
4125 /* MonoThread::interruption_requested can only be changed with atomics */
4126 if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4127 /* this will consume pending APC calls */
4128 #ifdef HOST_WIN32
4129 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4130 #endif
4131 InterlockedDecrement (&thread_interruption_requested);
4132 /* Clear the interrupted flag of the thread so it can wait again */
4133 mono_thread_info_clear_interruption ();
4136 if ((thread->state & ThreadState_AbortRequested) != 0) {
4137 UNLOCK_THREAD (thread);
4138 if (thread->abort_exc == NULL) {
4140 * This might be racy, but it has to be called outside the lock
4141 * since it calls managed code.
4143 MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4145 return thread->abort_exc;
4147 else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4148 self_suspend_internal (thread);
4149 return NULL;
4151 else if ((thread->state & ThreadState_StopRequested) != 0) {
4152 /* FIXME: do this through the JIT? */
4154 UNLOCK_THREAD (thread);
4156 mono_thread_exit ();
4157 return NULL;
4158 } else if (thread->pending_exception) {
4159 MonoException *exc;
4161 exc = thread->pending_exception;
4162 thread->pending_exception = NULL;
4164 UNLOCK_THREAD (thread);
4165 return exc;
4166 } else if (thread->thread_interrupt_requested) {
4168 thread->thread_interrupt_requested = FALSE;
4169 UNLOCK_THREAD (thread);
4171 return(mono_get_exception_thread_interrupted ());
4174 UNLOCK_THREAD (thread);
4176 return NULL;
4180 * mono_thread_request_interruption
4182 * A signal handler can call this method to request the interruption of a
4183 * thread. The result of the interruption will depend on the current state of
4184 * the thread. If the result is an exception that needs to be throw, it is
4185 * provided as return value.
4187 MonoException*
4188 mono_thread_request_interruption (gboolean running_managed)
4190 MonoInternalThread *thread = mono_thread_internal_current ();
4192 /* The thread may already be stopping */
4193 if (thread == NULL)
4194 return NULL;
4196 #ifdef HOST_WIN32
4197 if (thread->interrupt_on_stop &&
4198 thread->state & ThreadState_StopRequested &&
4199 thread->state & ThreadState_Background)
4200 ExitThread (1);
4201 #endif
4203 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4204 return NULL;
4205 InterlockedIncrement (&thread_interruption_requested);
4207 if (!running_managed || is_running_protected_wrapper ()) {
4208 /* Can't stop while in unmanaged code. Increase the global interruption
4209 request count. When exiting the unmanaged method the count will be
4210 checked and the thread will be interrupted. */
4212 if (mono_thread_notify_pending_exc_fn && !running_managed)
4213 /* The JIT will notify the thread about the interruption */
4214 /* This shouldn't take any locks */
4215 mono_thread_notify_pending_exc_fn (NULL);
4217 /* this will awake the thread if it is in WaitForSingleObject
4218 or similar */
4219 /* Our implementation of this function ignores the func argument */
4220 #ifdef HOST_WIN32
4221 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4222 #else
4223 mono_thread_info_self_interrupt ();
4224 #endif
4225 return NULL;
4227 else {
4228 return mono_thread_execute_interruption (thread);
4232 /*This function should be called by a thread after it has exited all of
4233 * its handle blocks at interruption time.*/
4234 MonoException*
4235 mono_thread_resume_interruption (void)
4237 MonoInternalThread *thread = mono_thread_internal_current ();
4238 gboolean still_aborting;
4240 /* The thread may already be stopping */
4241 if (thread == NULL)
4242 return NULL;
4244 LOCK_THREAD (thread);
4245 still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4246 UNLOCK_THREAD (thread);
4248 /*This can happen if the protected block called Thread::ResetAbort*/
4249 if (!still_aborting)
4250 return FALSE;
4252 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4253 return NULL;
4254 InterlockedIncrement (&thread_interruption_requested);
4256 mono_thread_info_self_interrupt ();
4258 return mono_thread_execute_interruption (thread);
4261 gboolean mono_thread_interruption_requested ()
4263 if (thread_interruption_requested) {
4264 MonoInternalThread *thread = mono_thread_internal_current ();
4265 /* The thread may already be stopping */
4266 if (thread != NULL)
4267 return (thread->interruption_requested);
4269 return FALSE;
4272 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4274 MonoInternalThread *thread = mono_thread_internal_current ();
4276 /* The thread may already be stopping */
4277 if (thread == NULL)
4278 return;
4280 if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4281 MonoException* exc = mono_thread_execute_interruption (thread);
4282 if (exc) mono_raise_exception (exc);
4287 * Performs the interruption of the current thread, if one has been requested,
4288 * and the thread is not running a protected wrapper.
4290 void mono_thread_interruption_checkpoint ()
4292 mono_thread_interruption_checkpoint_request (FALSE);
4296 * Performs the interruption of the current thread, if one has been requested.
4298 void mono_thread_force_interruption_checkpoint ()
4300 mono_thread_interruption_checkpoint_request (TRUE);
4304 * mono_thread_get_and_clear_pending_exception:
4306 * Return any pending exceptions for the current thread and clear it as a side effect.
4308 MonoException*
4309 mono_thread_get_and_clear_pending_exception (void)
4311 MonoInternalThread *thread = mono_thread_internal_current ();
4313 /* The thread may already be stopping */
4314 if (thread == NULL)
4315 return NULL;
4317 if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4318 return mono_thread_execute_interruption (thread);
4321 if (thread->pending_exception) {
4322 MonoException *exc = thread->pending_exception;
4324 thread->pending_exception = NULL;
4325 return exc;
4328 return NULL;
4332 * mono_set_pending_exception:
4334 * Set the pending exception of the current thread to EXC.
4335 * The exception will be thrown when execution returns to managed code.
4337 void
4338 mono_set_pending_exception (MonoException *exc)
4340 MonoInternalThread *thread = mono_thread_internal_current ();
4342 /* The thread may already be stopping */
4343 if (thread == NULL)
4344 return;
4346 MONO_OBJECT_SETREF (thread, pending_exception, exc);
4348 mono_thread_request_interruption (FALSE);
4352 * mono_thread_interruption_request_flag:
4354 * Returns the address of a flag that will be non-zero if an interruption has
4355 * been requested for a thread. The thread to interrupt may not be the current
4356 * thread, so an additional call to mono_thread_interruption_requested() or
4357 * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4358 * zero.
4360 gint32* mono_thread_interruption_request_flag ()
4362 return &thread_interruption_requested;
4365 void
4366 mono_thread_init_apartment_state (void)
4368 #ifdef HOST_WIN32
4369 MonoInternalThread* thread = mono_thread_internal_current ();
4371 /* Positive return value indicates success, either
4372 * S_OK if this is first CoInitialize call, or
4373 * S_FALSE if CoInitialize already called, but with same
4374 * threading model. A negative value indicates failure,
4375 * probably due to trying to change the threading model.
4377 if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA)
4378 ? COINIT_APARTMENTTHREADED
4379 : COINIT_MULTITHREADED) < 0) {
4380 thread->apartment_state = ThreadApartmentState_Unknown;
4382 #endif
4385 void
4386 mono_thread_cleanup_apartment_state (void)
4388 #ifdef HOST_WIN32
4389 MonoInternalThread* thread = mono_thread_internal_current ();
4391 if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4392 CoUninitialize ();
4394 #endif
4397 void
4398 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4400 LOCK_THREAD (thread);
4401 thread->state |= state;
4402 UNLOCK_THREAD (thread);
4405 void
4406 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4408 LOCK_THREAD (thread);
4409 thread->state &= ~state;
4410 UNLOCK_THREAD (thread);
4413 gboolean
4414 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4416 gboolean ret = FALSE;
4418 LOCK_THREAD (thread);
4420 if ((thread->state & test) != 0) {
4421 ret = TRUE;
4424 UNLOCK_THREAD (thread);
4426 return ret;
4429 //static MonoClassField *execution_context_field;
4431 static MonoObject**
4432 get_execution_context_addr (void)
4434 MonoDomain *domain = mono_domain_get ();
4435 guint32 offset = domain->execution_context_field_offset;
4437 if (!offset) {
4438 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4439 g_assert (field);
4441 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4443 mono_domain_lock (domain);
4444 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4445 mono_domain_unlock (domain);
4446 g_assert (offset);
4448 domain->execution_context_field_offset = offset;
4451 return (MonoObject**) mono_get_special_static_data (offset);
4454 MonoObject*
4455 mono_thread_get_execution_context (void)
4457 return *get_execution_context_addr ();
4460 void
4461 mono_thread_set_execution_context (MonoObject *ec)
4463 *get_execution_context_addr () = ec;
4466 static gboolean has_tls_get = FALSE;
4468 void
4469 mono_runtime_set_has_tls_get (gboolean val)
4471 has_tls_get = val;
4474 gboolean
4475 mono_runtime_has_tls_get (void)
4477 return has_tls_get;
4481 mono_thread_kill (MonoInternalThread *thread, int signal)
4483 #ifdef __native_client__
4484 /* Workaround pthread_kill abort() in NaCl glibc. */
4485 return -1;
4486 #endif
4487 #ifdef HOST_WIN32
4488 /* Win32 uses QueueUserAPC and callers of this are guarded */
4489 g_assert_not_reached ();
4490 #else
4491 # ifdef PTHREAD_POINTER_ID
4492 return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4493 # else
4494 # ifdef USE_TKILL_ON_ANDROID
4495 if (thread->android_tid != 0) {
4496 int ret;
4497 int old_errno = errno;
4499 ret = tkill ((pid_t) thread->android_tid, signal);
4500 if (ret < 0) {
4501 ret = errno;
4502 errno = old_errno;
4505 return ret;
4507 else
4508 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4509 # else
4510 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4511 # endif
4512 # endif
4513 #endif
4516 static void
4517 self_interrupt_thread (void *_unused)
4519 MonoThreadInfo *info = mono_thread_info_current ();
4520 MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ());
4521 if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4522 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4523 g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4526 static gboolean
4527 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4529 if (!ji)
4530 return FALSE;
4531 return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4534 static gboolean
4535 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4537 MonoJitInfo **dest = data;
4538 *dest = frame->ji;
4539 return TRUE;
4542 static MonoJitInfo*
4543 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4545 MonoJitInfo *ji = NULL;
4546 if (!info)
4547 return NULL;
4548 mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4549 return ji;
4552 static void
4553 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4555 MonoJitInfo *ji;
4556 MonoThreadInfo *info = NULL;
4557 gboolean protected_wrapper;
4558 gboolean running_managed;
4560 if (!mono_thread_info_new_interrupt_enabled ()) {
4561 signal_thread_state_change (thread);
4562 return;
4566 FIXME this is insanely broken, it doesn't cause interruption to happen
4567 synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4569 if (thread == mono_thread_internal_current ()) {
4570 /* Do it synchronously */
4571 MonoException *exc = mono_thread_request_interruption (can_raise_exception);
4572 if (exc)
4573 mono_raise_exception (exc);
4574 mono_thread_info_interrupt (thread->handle);
4575 return;
4578 /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4579 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4580 return;
4583 if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4584 mono_thread_info_finish_suspend_and_resume (info);
4585 return;
4588 /*someone is already interrupting it*/
4589 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4590 mono_thread_info_finish_suspend_and_resume (info);
4591 return;
4593 InterlockedIncrement (&thread_interruption_requested);
4595 ji = mono_thread_info_get_last_managed (info);
4596 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4597 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4599 if (!protected_wrapper && running_managed) {
4600 /*We are in managed code*/
4601 /*Set the thread to call */
4602 if (install_async_abort)
4603 mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4604 mono_thread_info_finish_suspend_and_resume (info);
4605 } else {
4607 * This will cause waits to be broken.
4608 * It will also prevent the thread from entering a wait, so if the thread returns
4609 * from the wait before it receives the abort signal, it will just spin in the wait
4610 * functions in the io-layer until the signal handler calls QueueUserAPC which will
4611 * make it return.
4613 gpointer interrupt_handle;
4615 if (mono_thread_notify_pending_exc_fn)
4616 /* The JIT will notify the thread about the interruption */
4617 mono_thread_notify_pending_exc_fn (info);
4619 interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4620 mono_thread_info_finish_suspend_and_resume (info);
4621 mono_thread_info_finish_interrupt (interrupt_handle);
4623 /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4626 static void
4627 transition_to_suspended (MonoInternalThread *thread, MonoThreadInfo *info)
4629 if ((thread->state & ThreadState_SuspendRequested) == 0) {
4630 g_assert (0); /*FIXME we should not reach this */
4631 /*Make sure we balance the suspend count.*/
4632 if (info)
4633 mono_thread_info_finish_suspend_and_resume (info);
4634 } else {
4635 thread->state &= ~ThreadState_SuspendRequested;
4636 thread->state |= ThreadState_Suspended;
4637 if (info)
4638 mono_thread_info_finish_suspend (info);
4640 UNLOCK_THREAD (thread);
4643 static void
4644 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4646 if (!mono_thread_info_new_interrupt_enabled ()) {
4647 signal_thread_state_change (thread);
4648 return;
4651 LOCK_THREAD (thread);
4652 if (thread == mono_thread_internal_current ()) {
4653 transition_to_suspended (thread, NULL);
4654 mono_thread_info_self_suspend ();
4655 } else {
4656 MonoThreadInfo *info;
4657 MonoJitInfo *ji;
4658 gboolean protected_wrapper;
4659 gboolean running_managed;
4661 /*A null info usually means the thread is already dead. */
4662 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
4663 UNLOCK_THREAD (thread);
4664 return;
4667 ji = mono_thread_info_get_last_managed (info);
4668 protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4669 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4671 if (running_managed && !protected_wrapper) {
4672 transition_to_suspended (thread, info);
4673 } else {
4674 gpointer interrupt_handle;
4676 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4677 InterlockedIncrement (&thread_interruption_requested);
4678 if (interrupt)
4679 interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4680 if (mono_thread_notify_pending_exc_fn && !running_managed)
4681 /* The JIT will notify the thread about the interruption */
4682 mono_thread_notify_pending_exc_fn (info);
4683 mono_thread_info_finish_suspend_and_resume (info);
4684 if (interrupt)
4685 mono_thread_info_finish_interrupt (interrupt_handle);
4686 UNLOCK_THREAD (thread);
4691 /*This is called with @thread synch_cs held and it must release it*/
4692 static void
4693 self_suspend_internal (MonoInternalThread *thread)
4695 if (!mono_thread_info_new_interrupt_enabled ()) {
4696 thread->state &= ~ThreadState_SuspendRequested;
4697 thread->state |= ThreadState_Suspended;
4698 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4699 if (thread->suspend_event == NULL) {
4700 UNLOCK_THREAD (thread);
4701 return;
4703 if (thread->suspended_event)
4704 SetEvent (thread->suspended_event);
4706 UNLOCK_THREAD (thread);
4708 if (shutting_down) {
4709 /* After we left the lock, the runtime might shut down so everything becomes invalid */
4710 for (;;)
4711 Sleep (1000);
4714 WaitForSingleObject (thread->suspend_event, INFINITE);
4716 LOCK_THREAD (thread);
4718 CloseHandle (thread->suspend_event);
4719 thread->suspend_event = NULL;
4720 thread->state &= ~ThreadState_Suspended;
4722 /* The thread that requested the resume will have replaced this event
4723 * and will be waiting for it
4725 SetEvent (thread->resume_event);
4727 UNLOCK_THREAD (thread);
4728 return;
4731 transition_to_suspended (thread, NULL);
4732 mono_thread_info_self_suspend ();
4735 /*This is called with @thread synch_cs held and it must release it*/
4736 static gboolean
4737 resume_thread_internal (MonoInternalThread *thread)
4739 if (!mono_thread_info_new_interrupt_enabled ()) {
4740 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4741 if (thread->resume_event == NULL) {
4742 UNLOCK_THREAD (thread);
4743 return FALSE;
4746 /* Awake the thread */
4747 SetEvent (thread->suspend_event);
4749 UNLOCK_THREAD (thread);
4751 /* Wait for the thread to awake */
4752 WaitForSingleObject (thread->resume_event, INFINITE);
4753 CloseHandle (thread->resume_event);
4754 thread->resume_event = NULL;
4755 return TRUE;
4758 UNLOCK_THREAD (thread);
4759 /* Awake the thread */
4760 if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4761 return FALSE;
4762 LOCK_THREAD (thread);
4763 thread->state &= ~ThreadState_Suspended;
4764 UNLOCK_THREAD (thread);
4765 return TRUE;
4770 * mono_thread_is_foreign:
4771 * @thread: the thread to query
4773 * This function allows one to determine if a thread was created by the mono runtime and has
4774 * a well defined lifecycle or it's a foreigh one, created by the native environment.
4776 * Returns: true if @thread was not created by the runtime.
4778 mono_bool
4779 mono_thread_is_foreign (MonoThread *thread)
4781 MonoThreadInfo *info = thread->internal_thread->thread_info;
4782 return info->runtime_thread == FALSE;
4786 * mono_add_joinable_thread:
4788 * Add TID to the list of joinable threads.
4789 * LOCKING: Acquires the threads lock.
4791 void
4792 mono_threads_add_joinable_thread (gpointer tid)
4794 #ifndef HOST_WIN32
4796 * We cannot detach from threads because it causes problems like
4797 * 2fd16f60/r114307. So we collect them and join them when
4798 * we have time (in he finalizer thread).
4800 joinable_threads_lock ();
4801 if (!joinable_threads)
4802 joinable_threads = g_hash_table_new (NULL, NULL);
4803 g_hash_table_insert (joinable_threads, tid, tid);
4804 joinable_thread_count ++;
4805 joinable_threads_unlock ();
4807 mono_gc_finalize_notify ();
4808 #endif
4812 * mono_threads_join_threads:
4814 * Join all joinable threads. This is called from the finalizer thread.
4815 * LOCKING: Acquires the threads lock.
4817 void
4818 mono_threads_join_threads (void)
4820 #ifndef HOST_WIN32
4821 GHashTableIter iter;
4822 gpointer key;
4823 gpointer tid;
4824 pthread_t thread;
4825 gboolean found;
4827 /* Fastpath */
4828 if (!joinable_thread_count)
4829 return;
4831 while (TRUE) {
4832 joinable_threads_lock ();
4833 found = FALSE;
4834 if (g_hash_table_size (joinable_threads)) {
4835 g_hash_table_iter_init (&iter, joinable_threads);
4836 g_hash_table_iter_next (&iter, &key, (void**)&tid);
4837 thread = (pthread_t)tid;
4838 g_hash_table_remove (joinable_threads, key);
4839 joinable_thread_count --;
4840 found = TRUE;
4842 joinable_threads_unlock ();
4843 if (found) {
4844 if (thread != pthread_self ())
4845 /* This shouldn't block */
4846 pthread_join (thread, NULL);
4847 } else {
4848 break;
4851 #endif
4855 * mono_thread_join:
4857 * Wait for thread TID to exit.
4858 * LOCKING: Acquires the threads lock.
4860 void
4861 mono_thread_join (gpointer tid)
4863 #ifndef HOST_WIN32
4864 pthread_t thread;
4865 gboolean found = FALSE;
4867 joinable_threads_lock ();
4868 if (!joinable_threads)
4869 joinable_threads = g_hash_table_new (NULL, NULL);
4870 if (g_hash_table_lookup (joinable_threads, tid)) {
4871 g_hash_table_remove (joinable_threads, tid);
4872 joinable_thread_count --;
4873 found = TRUE;
4875 joinable_threads_unlock ();
4876 if (!found)
4877 return;
4878 thread = (pthread_t)tid;
4879 pthread_join (thread, NULL);
4880 #endif