[sgen] Untag the vtable during concurrent mark
[mono.git] / mono / metadata / threads.c
1 /*
2  * threads.c: Thread support internal calls
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *      Paolo Molaro (lupus@ximian.com)
7  *      Patrik Torstensson (patrik.torstensson@labs2.com)
8  *
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)
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14
15 #include <config.h>
16
17 #include <glib.h>
18 #include <string.h>
19
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/threads.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-internals.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/monobitset.h>
35 #include <mono/utils/mono-compiler.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-membar.h>
38 #include <mono/utils/mono-time.h>
39 #include <mono/utils/mono-threads.h>
40 #include <mono/utils/mono-threads-coop.h>
41 #include <mono/utils/hazard-pointer.h>
42 #include <mono/utils/mono-tls.h>
43 #include <mono/utils/atomic.h>
44 #include <mono/utils/mono-memory-model.h>
45 #include <mono/utils/mono-threads-coop.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/w32handle.h>
48 #include <mono/metadata/w32event.h>
49
50 #include <mono/metadata/gc-internals.h>
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/abi-details.h>
53
54 #ifdef HAVE_SIGNAL_H
55 #include <signal.h>
56 #endif
57
58 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
59 #define USE_TKILL_ON_ANDROID 1
60 #endif
61
62 #ifdef PLATFORM_ANDROID
63 #include <errno.h>
64
65 #ifdef USE_TKILL_ON_ANDROID
66 extern int tkill (pid_t tid, int signal);
67 #endif
68 #endif
69
70 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
71 #define THREAD_DEBUG(a)
72 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
73 #define THREAD_WAIT_DEBUG(a)
74 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
75 #define LIBGC_DEBUG(a)
76
77 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
78 #define SPIN_LOCK(i) do { \
79                                 if (SPIN_TRYLOCK (i)) \
80                                         break; \
81                         } while (1)
82
83 #define SPIN_UNLOCK(i) i = 0
84
85 #define LOCK_THREAD(thread) lock_thread((thread))
86 #define UNLOCK_THREAD(thread) unlock_thread((thread))
87
88 typedef union {
89         gint32 ival;
90         gfloat fval;
91 } IntFloatUnion;
92
93 typedef union {
94         gint64 ival;
95         gdouble fval;
96 } LongDoubleUnion;
97  
98 typedef struct _StaticDataFreeList StaticDataFreeList;
99 struct _StaticDataFreeList {
100         StaticDataFreeList *next;
101         guint32 offset;
102         guint32 size;
103 };
104
105 typedef struct {
106         int idx;
107         int offset;
108         StaticDataFreeList *freelist;
109 } StaticDataInfo;
110
111 /* Number of cached culture objects in the MonoThread->cached_culture_info array
112  * (per-type): we use the first NUM entries for CultureInfo and the last for
113  * UICultureInfo. So the size of the array is really NUM_CACHED_CULTURES * 2.
114  */
115 #define NUM_CACHED_CULTURES 4
116 #define CULTURES_START_IDX 0
117 #define UICULTURES_START_IDX NUM_CACHED_CULTURES
118
119 /* Controls access to the 'threads' hash table */
120 static void mono_threads_lock (void);
121 static void mono_threads_unlock (void);
122 static MonoCoopMutex threads_mutex;
123
124 /* Controls access to the 'joinable_threads' hash table */
125 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
126 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
127 static mono_mutex_t joinable_threads_mutex;
128
129 /* Holds current status of static data heap */
130 static StaticDataInfo thread_static_info;
131 static StaticDataInfo context_static_info;
132
133 /* The hash of existing threads (key is thread ID, value is
134  * MonoInternalThread*) that need joining before exit
135  */
136 static MonoGHashTable *threads=NULL;
137
138 /* List of app context GC handles.
139  * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
140  */
141 static GHashTable *contexts = NULL;
142
143 /* Cleanup queue for contexts. */
144 static MonoReferenceQueue *context_queue;
145
146 /*
147  * Threads which are starting up and they are not in the 'threads' hash yet.
148  * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
149  * Protected by mono_threads_lock ().
150  */
151 static MonoGHashTable *threads_starting_up = NULL;
152
153 /* The TLS key that holds the MonoObject assigned to each thread */
154 static MonoNativeTlsKey current_object_key;
155
156 /* Contains tids */
157 /* Protected by the threads lock */
158 static GHashTable *joinable_threads;
159 static int joinable_thread_count;
160
161 #ifdef MONO_HAVE_FAST_TLS
162 /* we need to use both the Tls* functions and __thread because
163  * the gc needs to see all the threads 
164  */
165 MONO_FAST_TLS_DECLARE(tls_current_object);
166 #define SET_CURRENT_OBJECT(x) do { \
167         MONO_FAST_TLS_SET (tls_current_object, x); \
168         mono_native_tls_set_value (current_object_key, x); \
169 } while (FALSE)
170 #define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
171 #else
172 #define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
173 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
174 #endif
175
176 /* function called at thread start */
177 static MonoThreadStartCB mono_thread_start_cb = NULL;
178
179 /* function called at thread attach */
180 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
181
182 /* function called at thread cleanup */
183 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
184
185 /* The default stack size for each thread */
186 static guint32 default_stacksize = 0;
187 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
188
189 static void context_adjust_static_data (MonoAppContext *ctx);
190 static void mono_free_static_data (gpointer* static_data);
191 static void mono_init_static_data_info (StaticDataInfo *static_data);
192 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
193 static gboolean mono_thread_resume (MonoInternalThread* thread);
194 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
195 static void self_abort_internal (MonoError *error);
196 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
197 static void self_suspend_internal (void);
198
199 static MonoException* mono_thread_execute_interruption (void);
200 static void ref_stack_destroy (gpointer rs);
201
202 /* Spin lock for InterlockedXXX 64 bit functions */
203 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
204 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
205 static mono_mutex_t interlocked_mutex;
206
207 /* global count of thread interruptions requested */
208 static gint32 thread_interruption_requested = 0;
209
210 /* Event signaled when a thread changes its background mode */
211 static HANDLE background_change_event;
212
213 static gboolean shutting_down = FALSE;
214
215 static gint32 managed_thread_id_counter = 0;
216
217 /* Class lazy loading functions */
218 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, System, AppDomainUnloadedException)
219
220 static void
221 mono_threads_lock (void)
222 {
223         mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
224 }
225
226 static void
227 mono_threads_unlock (void)
228 {
229         mono_locks_coop_release (&threads_mutex, ThreadsLock);
230 }
231
232
233 static guint32
234 get_next_managed_thread_id (void)
235 {
236         return InterlockedIncrement (&managed_thread_id_counter);
237 }
238
239 MonoNativeTlsKey
240 mono_thread_get_tls_key (void)
241 {
242         return current_object_key;
243 }
244
245 gint32
246 mono_thread_get_tls_offset (void)
247 {
248         int offset = -1;
249
250 #ifdef HOST_WIN32
251         if (current_object_key)
252                 offset = current_object_key;
253 #else
254         MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
255 #endif
256         return offset;
257 }
258
259 static inline MonoNativeThreadId
260 thread_get_tid (MonoInternalThread *thread)
261 {
262         /* We store the tid as a guint64 to keep the object layout constant between platforms */
263         return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
264 }
265
266 static void ensure_synch_cs_set (MonoInternalThread *thread)
267 {
268         MonoCoopMutex *synch_cs;
269
270         if (thread->synch_cs != NULL) {
271                 return;
272         }
273
274         synch_cs = g_new0 (MonoCoopMutex, 1);
275         mono_coop_mutex_init_recursive (synch_cs);
276
277         if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
278                                                synch_cs, NULL) != NULL) {
279                 /* Another thread must have installed this CS */
280                 mono_coop_mutex_destroy (synch_cs);
281                 g_free (synch_cs);
282         }
283 }
284
285 static inline void
286 lock_thread (MonoInternalThread *thread)
287 {
288         if (!thread->synch_cs)
289                 ensure_synch_cs_set (thread);
290
291         g_assert (thread->synch_cs);
292
293         mono_coop_mutex_lock (thread->synch_cs);
294 }
295
296 static inline void
297 unlock_thread (MonoInternalThread *thread)
298 {
299         mono_coop_mutex_unlock (thread->synch_cs);
300 }
301
302 static inline gboolean
303 is_appdomainunloaded_exception (MonoClass *klass)
304 {
305         return klass == mono_class_get_appdomain_unloaded_exception_class ();
306 }
307
308 static inline gboolean
309 is_threadabort_exception (MonoClass *klass)
310 {
311         return klass == mono_defaults.threadabortexception_class;
312 }
313
314 /*
315  * NOTE: this function can be called also for threads different from the current one:
316  * make sure no code called from it will ever assume it is run on the thread that is
317  * getting cleaned up.
318  */
319 static void thread_cleanup (MonoInternalThread *thread)
320 {
321         gboolean ret;
322
323         g_assert (thread != NULL);
324
325         if (thread->abort_state_handle) {
326                 mono_gchandle_free (thread->abort_state_handle);
327                 thread->abort_state_handle = 0;
328         }
329         thread->abort_exc = NULL;
330         thread->current_appcontext = NULL;
331
332         /*
333          * This is necessary because otherwise we might have
334          * cross-domain references which will not get cleaned up when
335          * the target domain is unloaded.
336          */
337         if (thread->cached_culture_info) {
338                 int i;
339                 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
340                         mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
341         }
342
343         /*
344          * thread->synch_cs can be NULL if this was called after
345          * ves_icall_System_Threading_InternalThread_Thread_free_internal.
346          * This can happen only during shutdown.
347          * The shutting_down flag is not always set, so we can't assert on it.
348          */
349         if (thread->synch_cs)
350                 LOCK_THREAD (thread);
351
352         thread->state |= ThreadState_Stopped;
353         thread->state &= ~ThreadState_Background;
354
355         if (thread->synch_cs)
356                 UNLOCK_THREAD (thread);
357
358         /*
359         An interruption request has leaked to cleanup. Adjust the global counter.
360
361         This can happen is the abort source thread finds the abortee (this) thread
362         in unmanaged code. If this thread never trips back to managed code or check
363         the local flag it will be left set and positively unbalance the global counter.
364         
365         Leaving the counter unbalanced will cause a performance degradation since all threads
366         will now keep checking their local flags all the time.
367         */
368         if (InterlockedExchange (&thread->interruption_requested, 0))
369                 InterlockedDecrement (&thread_interruption_requested);
370
371         mono_threads_lock ();
372
373         if (!threads) {
374                 ret = FALSE;
375         } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
376                 /* We have to check whether the thread object for the
377                  * tid is still the same in the table because the
378                  * thread might have been destroyed and the tid reused
379                  * in the meantime, in which case the tid would be in
380                  * the table, but with another thread object.
381                  */
382                 ret = FALSE;
383         } else {
384                 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
385                 ret = TRUE;
386         }
387
388         mono_threads_unlock ();
389
390         /* Don't close the handle here, wait for the object finalizer
391          * to do it. Otherwise, the following race condition applies:
392          *
393          * 1) Thread exits (and thread_cleanup() closes the handle)
394          *
395          * 2) Some other handle is reassigned the same slot
396          *
397          * 3) Another thread tries to join the first thread, and
398          * blocks waiting for the reassigned handle to be signalled
399          * (which might never happen).  This is possible, because the
400          * thread calling Join() still has a reference to the first
401          * thread's object.
402          */
403
404         /* if the thread is not in the hash it has been removed already */
405         if (!ret) {
406                 if (thread == mono_thread_internal_current ()) {
407                         mono_domain_unset ();
408                         mono_memory_barrier ();
409                 }
410                 if (mono_thread_cleanup_fn)
411                         mono_thread_cleanup_fn (thread_get_tid (thread));
412                 return;
413         }
414         mono_release_type_locks (thread);
415
416         /* Can happen when we attach the profiler helper thread in order to heapshot. */
417         if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
418                 mono_profiler_thread_end (thread->tid);
419
420         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
421
422         if (thread == mono_thread_internal_current ()) {
423                 /*
424                  * This will signal async signal handlers that the thread has exited.
425                  * The profiler callback needs this to be set, so it cannot be done earlier.
426                  */
427                 mono_domain_unset ();
428                 mono_memory_barrier ();
429         }
430
431         if (thread == mono_thread_internal_current ())
432                 mono_thread_pop_appdomain_ref ();
433
434         thread->cached_culture_info = NULL;
435
436         mono_free_static_data (thread->static_data);
437         thread->static_data = NULL;
438         ref_stack_destroy (thread->appdomain_refs);
439         thread->appdomain_refs = NULL;
440
441         if (mono_thread_cleanup_fn)
442                 mono_thread_cleanup_fn (thread_get_tid (thread));
443
444         if (mono_gc_is_moving ()) {
445                 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
446                 thread->thread_pinning_ref = NULL;
447         }
448
449 }
450
451 /*
452  * A special static data offset (guint32) consists of 3 parts:
453  *
454  * [0]   6-bit index into the array of chunks.
455  * [6]   25-bit offset into the array.
456  * [31]  Bit indicating thread or context static.
457  */
458
459 typedef union {
460         struct {
461 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
462                 guint32 type : 1;
463                 guint32 offset : 25;
464                 guint32 index : 6;
465 #else
466                 guint32 index : 6;
467                 guint32 offset : 25;
468                 guint32 type : 1;
469 #endif
470         } fields;
471         guint32 raw;
472 } SpecialStaticOffset;
473
474 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
475 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
476
477 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
478         ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
479 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
480         (((SpecialStaticOffset *) &(x))->fields.f)
481
482 static gpointer
483 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
484 {
485         g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
486
487         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
488         int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
489
490         return ((char *) thread->static_data [idx]) + off;
491 }
492
493 static gpointer
494 get_context_static_data (MonoAppContext *ctx, guint32 offset)
495 {
496         g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
497
498         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
499         int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
500
501         return ((char *) ctx->static_data [idx]) + off;
502 }
503
504 static MonoThread**
505 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
506 {
507         static MonoClassField *current_thread_field = NULL;
508
509         guint32 offset;
510
511         if (!current_thread_field) {
512                 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
513                 g_assert (current_thread_field);
514         }
515
516         mono_class_vtable (domain, mono_defaults.thread_class);
517         mono_domain_lock (domain);
518         offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
519         mono_domain_unlock (domain);
520         g_assert (offset);
521
522         return (MonoThread **)get_thread_static_data (thread, offset);
523 }
524
525 static void
526 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
527 {
528         MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
529
530         g_assert (current->obj.vtable->domain == domain);
531
532         g_assert (!*current_thread_ptr);
533         *current_thread_ptr = current;
534 }
535
536 static MonoThread*
537 create_thread_object (MonoDomain *domain)
538 {
539         MonoError error;
540         MonoVTable *vt = mono_class_vtable (domain, mono_defaults.thread_class);
541         MonoThread *t = (MonoThread*)mono_object_new_mature (vt, &error);
542         /* only possible failure mode is OOM, from which we don't expect to recover. */
543         mono_error_assert_ok (&error);
544         return t;
545 }
546
547 static MonoThread*
548 new_thread_with_internal (MonoDomain *domain, MonoInternalThread *internal)
549 {
550         MonoThread *thread;
551
552         thread = create_thread_object (domain);
553
554         MONO_OBJECT_SETREF (thread, internal_thread, internal);
555
556         return thread;
557 }
558
559 static MonoInternalThread*
560 create_internal_thread (void)
561 {
562         MonoError error;
563         MonoInternalThread *thread;
564         MonoVTable *vt;
565
566         vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
567         thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
568         /* only possible failure mode is OOM, from which we don't exect to recover */
569         mono_error_assert_ok (&error);
570
571         thread->synch_cs = g_new0 (MonoCoopMutex, 1);
572         mono_coop_mutex_init_recursive (thread->synch_cs);
573
574         thread->apartment_state = ThreadApartmentState_Unknown;
575         thread->managed_id = get_next_managed_thread_id ();
576         if (mono_gc_is_moving ()) {
577                 thread->thread_pinning_ref = thread;
578                 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
579         }
580
581         thread->priority = MONO_THREAD_PRIORITY_NORMAL;
582
583         return thread;
584 }
585
586 static void
587 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
588 {
589         g_assert (internal);
590         g_assert (internal->handle);
591
592         g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
593         g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
594         g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
595
596 #ifdef HOST_WIN32
597         BOOL res;
598
599         res = SetThreadPriority (internal->handle, priority - 2);
600         if (!res)
601                 g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
602 #else /* HOST_WIN32 */
603         pthread_t tid;
604         int policy;
605         struct sched_param param;
606         gint res;
607
608         tid = thread_get_tid (internal);
609
610         res = pthread_getschedparam (tid, &policy, &param);
611         if (res != 0)
612                 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
613
614 #ifdef _POSIX_PRIORITY_SCHEDULING
615         int max, min;
616
617         /* Necessary to get valid priority range */
618
619         min = sched_get_priority_min (policy);
620         max = sched_get_priority_max (policy);
621
622         if (max > 0 && min >= 0 && max > min) {
623                 double srange, drange, sposition, dposition;
624                 srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
625                 drange = max - min;
626                 sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
627                 dposition = (sposition / srange) * drange;
628                 param.sched_priority = (int)(dposition + min);
629         } else
630 #endif
631         {
632                 switch (policy) {
633                 case SCHED_FIFO:
634                 case SCHED_RR:
635                         param.sched_priority = 50;
636                         break;
637 #ifdef SCHED_BATCH
638                 case SCHED_BATCH:
639 #endif
640                 case SCHED_OTHER:
641                         param.sched_priority = 0;
642                         break;
643                 default:
644                         g_error ("%s: unknown policy %d", __func__, policy);
645                 }
646         }
647
648         res = pthread_setschedparam (tid, policy, &param);
649         if (res != 0) {
650                 if (res == EPERM) {
651                         g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
652                         return;
653                 }
654                 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
655         }
656 #endif /* HOST_WIN32 */
657 }
658
659 static void 
660 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
661
662 static gboolean
663 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain, gsize *stack_ptr)
664 {
665         MonoThreadInfo *info;
666         MonoInternalThread *internal;
667         MonoDomain *domain, *root_domain;
668
669         g_assert (thread);
670
671         info = mono_thread_info_current ();
672
673         internal = thread->internal_thread;
674         internal->handle = mono_thread_info_duplicate_handle (info);
675         internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
676         internal->thread_info = info;
677         internal->small_id = info->small_id;
678         internal->stack_ptr = stack_ptr;
679
680         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
681
682         SET_CURRENT_OBJECT (internal);
683
684         domain = mono_object_domain (thread);
685
686         mono_thread_push_appdomain_ref (domain);
687         if (!mono_domain_set (domain, force_domain)) {
688                 mono_thread_pop_appdomain_ref ();
689                 return FALSE;
690         }
691
692         mono_threads_lock ();
693
694         if (threads_starting_up)
695                 mono_g_hash_table_remove (threads_starting_up, thread);
696
697         if (shutting_down && !force_attach) {
698                 mono_threads_unlock ();
699                 return FALSE;
700         }
701
702         if (!threads) {
703                 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
704                 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
705         }
706
707         /* We don't need to duplicate thread->handle, because it is
708          * only closed when the thread object is finalized by the GC. */
709         mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
710
711         /* We have to do this here because mono_thread_start_cb
712          * requires that root_domain_thread is set up. */
713         if (thread_static_info.offset || thread_static_info.idx > 0) {
714                 /* get the current allocated size */
715                 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
716                 mono_alloc_static_data (&internal->static_data, offset, TRUE);
717         }
718
719         mono_threads_unlock ();
720
721         root_domain = mono_get_root_domain ();
722
723         g_assert (!internal->root_domain_thread);
724         if (domain != root_domain)
725                 MONO_OBJECT_SETREF (internal, root_domain_thread, new_thread_with_internal (root_domain, internal));
726         else
727                 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
728
729         if (domain != root_domain)
730                 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
731
732         set_current_thread_for_domain (domain, internal, thread);
733
734         THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
735
736         return TRUE;
737 }
738
739 typedef struct {
740         gint32 ref;
741         MonoThread *thread;
742         MonoObject *start_delegate;
743         MonoObject *start_delegate_arg;
744         MonoThreadStart start_func;
745         gpointer start_func_arg;
746         gboolean failed;
747         MonoCoopSem registered;
748 } StartInfo;
749
750 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
751 {
752         MonoError error;
753         MonoThreadStart start_func;
754         void *start_func_arg;
755         gsize tid;
756         /* 
757          * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
758          * GC stack walk.
759          */
760         MonoThread *thread;
761         MonoInternalThread *internal;
762         MonoObject *start_delegate;
763         MonoObject *start_delegate_arg;
764         MonoDomain *domain;
765
766         thread = start_info->thread;
767         internal = thread->internal_thread;
768         domain = mono_object_domain (start_info->thread);
769
770         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
771
772         if (!mono_thread_attach_internal (thread, FALSE, FALSE, stack_ptr)) {
773                 start_info->failed = TRUE;
774
775                 mono_coop_sem_post (&start_info->registered);
776
777                 if (InterlockedDecrement (&start_info->ref) == 0) {
778                         mono_coop_sem_destroy (&start_info->registered);
779                         g_free (start_info);
780                 }
781
782                 return 0;
783         }
784
785         mono_thread_internal_set_priority (internal, internal->priority);
786
787         tid = internal->tid;
788
789         start_delegate = start_info->start_delegate;
790         start_delegate_arg = start_info->start_delegate_arg;
791         start_func = start_info->start_func;
792         start_func_arg = start_info->start_func_arg;
793
794         /* This MUST be called before any managed code can be
795          * executed, as it calls the callback function that (for the
796          * jit) sets the lmf marker.
797          */
798
799         if (mono_thread_start_cb)
800                 mono_thread_start_cb (tid, stack_ptr, start_func);
801
802         /* On 2.0 profile (and higher), set explicitly since state might have been
803            Unknown */
804         if (internal->apartment_state == ThreadApartmentState_Unknown)
805                 internal->apartment_state = ThreadApartmentState_MTA;
806
807         mono_thread_init_apartment_state ();
808
809         /* Let the thread that called Start() know we're ready */
810         mono_coop_sem_post (&start_info->registered);
811
812         if (InterlockedDecrement (&start_info->ref) == 0) {
813                 mono_coop_sem_destroy (&start_info->registered);
814                 g_free (start_info);
815         }
816
817         /* start_info is not valid anymore */
818         start_info = NULL;
819
820         /* 
821          * Call this after calling start_notify, since the profiler callback might want
822          * to lock the thread, and the lock is held by thread_start () which waits for
823          * start_notify.
824          */
825         mono_profiler_thread_start (tid);
826
827         /* if the name was set before starting, we didn't invoke the profiler callback */
828         if (internal->name) {
829                 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
830                 mono_profiler_thread_name (internal->tid, tname);
831                 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
832                 g_free (tname);
833         }
834
835         /* start_func is set only for unmanaged start functions */
836         if (start_func) {
837                 start_func (start_func_arg);
838         } else {
839                 void *args [1];
840
841                 g_assert (start_delegate != NULL);
842
843                 /* we may want to handle the exception here. See comment below on unhandled exceptions */
844                 args [0] = (gpointer) start_delegate_arg;
845                 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
846
847                 if (!mono_error_ok (&error)) {
848                         MonoException *ex = mono_error_convert_to_exception (&error);
849
850                         g_assert (ex != NULL);
851                         MonoClass *klass = mono_object_get_class (&ex->object);
852                         if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
853                             !is_threadabort_exception (klass)) {
854                                 mono_unhandled_exception (&ex->object);
855                                 mono_invoke_unhandled_exception_hook (&ex->object);
856                                 g_assert_not_reached ();
857                         }
858                 } else {
859                         mono_error_cleanup (&error);
860                 }
861         }
862
863         /* If the thread calls ExitThread at all, this remaining code
864          * will not be executed, but the main thread will eventually
865          * call thread_cleanup() on this thread's behalf.
866          */
867
868         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
869
870         /* Do any cleanup needed for apartment state. This
871          * cannot be done in thread_cleanup since thread_cleanup could be 
872          * called for a thread other than the current thread.
873          * mono_thread_cleanup_apartment_state cleans up apartment
874          * for the current thead */
875         mono_thread_cleanup_apartment_state ();
876
877         mono_thread_detach_internal (internal);
878
879         internal->tid = 0;
880
881         return(0);
882 }
883
884 static gsize WINAPI start_wrapper(void *data)
885 {
886         volatile gsize dummy;
887
888         /* Avoid scanning the frames above this frame during a GC */
889         mono_gc_set_stack_end ((void*)&dummy);
890
891         return start_wrapper_internal ((StartInfo*) data, (gsize*) &dummy);
892 }
893
894 /*
895  * create_thread:
896  *
897  *   Common thread creation code.
898  * LOCKING: Acquires the threads lock.
899  */
900 static gboolean
901 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
902         gboolean threadpool_thread, guint32 stack_size, MonoError *error)
903 {
904         StartInfo *start_info = NULL;
905         HANDLE thread_handle;
906         MonoNativeThreadId tid;
907         gboolean ret;
908
909         if (start_delegate)
910                 g_assert (!start_func && !start_func_arg);
911         if (start_func)
912                 g_assert (!start_delegate);
913
914         /*
915          * Join joinable threads to prevent running out of threads since the finalizer
916          * thread might be blocked/backlogged.
917          */
918         mono_threads_join_threads ();
919
920         mono_error_init (error);
921
922         mono_threads_lock ();
923         if (shutting_down) {
924                 mono_threads_unlock ();
925                 return FALSE;
926         }
927         if (threads_starting_up == NULL) {
928                 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
929                 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
930         }
931         mono_g_hash_table_insert (threads_starting_up, thread, thread);
932         mono_threads_unlock ();
933
934         internal->threadpool_thread = threadpool_thread;
935         if (threadpool_thread)
936                 mono_thread_set_state (internal, ThreadState_Background);
937
938         start_info = g_new0 (StartInfo, 1);
939         start_info->ref = 2;
940         start_info->thread = thread;
941         start_info->start_delegate = start_delegate;
942         start_info->start_delegate_arg = thread->start_obj;
943         start_info->start_func = start_func;
944         start_info->start_func_arg = start_func_arg;
945         start_info->failed = FALSE;
946         mono_coop_sem_init (&start_info->registered, 0);
947
948         if (stack_size == 0)
949                 stack_size = default_stacksize_for_thread (internal);
950
951         thread_handle = mono_threads_create_thread (start_wrapper, start_info, stack_size, &tid);
952
953         if (thread_handle == NULL) {
954                 /* The thread couldn't be created, so set an exception */
955                 mono_threads_lock ();
956                 mono_g_hash_table_remove (threads_starting_up, thread);
957                 mono_threads_unlock ();
958                 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
959                 /* ref is not going to be decremented in start_wrapper_internal */
960                 InterlockedDecrement (&start_info->ref);
961                 ret = FALSE;
962                 goto done;
963         }
964
965         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
966
967         /*
968          * Wait for the thread to set up its TLS data etc, so
969          * theres no potential race condition if someone tries
970          * to look up the data believing the thread has
971          * started
972          */
973
974         mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
975
976         mono_threads_close_thread_handle (thread_handle);
977
978         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
979
980         ret = !start_info->failed;
981
982 done:
983         if (InterlockedDecrement (&start_info->ref) == 0) {
984                 mono_coop_sem_destroy (&start_info->registered);
985                 g_free (start_info);
986         }
987
988         return ret;
989 }
990
991 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
992 {
993         if (mono_thread_start_cb) {
994                 mono_thread_start_cb (tid, stack_start, func);
995         }
996 }
997
998 void mono_threads_set_default_stacksize (guint32 stacksize)
999 {
1000         default_stacksize = stacksize;
1001 }
1002
1003 guint32 mono_threads_get_default_stacksize (void)
1004 {
1005         return default_stacksize;
1006 }
1007
1008 /*
1009  * mono_thread_create_internal:
1010  *
1011  *   ARG should not be a GC reference.
1012  */
1013 MonoInternalThread*
1014 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
1015 {
1016         MonoThread *thread;
1017         MonoInternalThread *internal;
1018         gboolean res;
1019
1020         mono_error_init (error);
1021
1022         thread = create_thread_object (domain);
1023
1024         internal = create_internal_thread ();
1025
1026         MONO_OBJECT_SETREF (thread, internal_thread, internal);
1027
1028         LOCK_THREAD (internal);
1029
1030         res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
1031         return_val_if_nok (error, NULL);
1032
1033         UNLOCK_THREAD (internal);
1034
1035         return internal;
1036 }
1037
1038 void
1039 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1040 {
1041         MonoError error;
1042         if (!mono_thread_create_checked (domain, func, arg, &error))
1043                 mono_error_cleanup (&error);
1044 }
1045
1046 gboolean
1047 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1048 {
1049         return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
1050 }
1051
1052 MonoThread *
1053 mono_thread_attach (MonoDomain *domain)
1054 {
1055         MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1056
1057         return thread;
1058 }
1059
1060 MonoThread *
1061 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1062 {
1063         MonoInternalThread *internal;
1064         MonoThread *thread;
1065         MonoNativeThreadId tid;
1066         gsize stack_ptr;
1067
1068         if (mono_thread_internal_current_is_attached ()) {
1069                 if (domain != mono_domain_get ())
1070                         mono_domain_set (domain, TRUE);
1071                 /* Already attached */
1072                 return mono_thread_current ();
1073         }
1074
1075         if (!mono_gc_register_thread (&domain)) {
1076                 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.", mono_native_thread_id_get ());
1077         }
1078
1079         tid=mono_native_thread_id_get ();
1080
1081         internal = create_internal_thread ();
1082
1083         thread = new_thread_with_internal (domain, internal);
1084
1085         if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
1086                 /* Mono is shutting down, so just wait for the end */
1087                 for (;;)
1088                         mono_thread_info_sleep (10000, NULL);
1089         }
1090
1091         THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1092
1093         if (mono_thread_attach_cb) {
1094                 guint8 *staddr;
1095                 size_t stsize;
1096
1097                 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1098
1099                 if (staddr == NULL)
1100                         mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1101                 else
1102                         mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1103         }
1104
1105         /* Can happen when we attach the profiler helper thread in order to heapshot. */
1106         if (!mono_thread_info_current ()->tools_thread)
1107                 // FIXME: Need a separate callback
1108                 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1109
1110         return thread;
1111 }
1112
1113 void
1114 mono_thread_detach_internal (MonoInternalThread *thread)
1115 {
1116         g_return_if_fail (thread != NULL);
1117
1118         THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1119
1120         thread_cleanup (thread);
1121
1122         SET_CURRENT_OBJECT (NULL);
1123         mono_domain_unset ();
1124
1125         /* Don't need to close the handle to this thread, even though we took a
1126          * reference in mono_thread_attach (), because the GC will do it
1127          * when the Thread object is finalised.
1128          */
1129 }
1130
1131 void
1132 mono_thread_detach (MonoThread *thread)
1133 {
1134         if (thread)
1135                 mono_thread_detach_internal (thread->internal_thread);
1136 }
1137
1138 /*
1139  * mono_thread_detach_if_exiting:
1140  *
1141  *   Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1142  * This should be used at the end of embedding code which calls into managed code, and which
1143  * can be called from pthread dtors, like dealloc: implementations in objective-c.
1144  */
1145 mono_bool
1146 mono_thread_detach_if_exiting (void)
1147 {
1148         if (mono_thread_info_is_exiting ()) {
1149                 MonoInternalThread *thread;
1150
1151                 thread = mono_thread_internal_current ();
1152                 if (thread) {
1153                         mono_thread_detach_internal (thread);
1154                         mono_thread_info_detach ();
1155                         return TRUE;
1156                 }
1157         }
1158         return FALSE;
1159 }
1160
1161 gboolean
1162 mono_thread_internal_current_is_attached (void)
1163 {
1164         MonoInternalThread *internal;
1165
1166         internal = GET_CURRENT_OBJECT ();
1167         if (!internal)
1168                 return FALSE;
1169
1170         return TRUE;
1171 }
1172
1173 void
1174 mono_thread_exit (void)
1175 {
1176         MonoInternalThread *thread = mono_thread_internal_current ();
1177
1178         THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1179
1180         mono_thread_detach_internal (thread);
1181
1182         /* we could add a callback here for embedders to use. */
1183         if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1184                 exit (mono_environment_exitcode_get ());
1185
1186         mono_thread_info_exit ();
1187 }
1188
1189 void
1190 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1191 {
1192         MonoInternalThread *internal;
1193
1194         internal = create_internal_thread ();
1195
1196         internal->state = ThreadState_Unstarted;
1197
1198         InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1199 }
1200
1201 HANDLE
1202 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1203                                                                                                    MonoObject *start)
1204 {
1205         MonoError error;
1206         MonoInternalThread *internal;
1207         gboolean res;
1208
1209         THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1210
1211         if (!this_obj->internal_thread)
1212                 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1213         internal = this_obj->internal_thread;
1214
1215         LOCK_THREAD (internal);
1216
1217         if ((internal->state & ThreadState_Unstarted) == 0) {
1218                 UNLOCK_THREAD (internal);
1219                 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1220                 return NULL;
1221         }
1222
1223         if ((internal->state & ThreadState_Aborted) != 0) {
1224                 UNLOCK_THREAD (internal);
1225                 return this_obj;
1226         }
1227
1228         res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1229         if (!res) {
1230                 mono_error_cleanup (&error);
1231                 UNLOCK_THREAD (internal);
1232                 return NULL;
1233         }
1234
1235         internal->state &= ~ThreadState_Unstarted;
1236
1237         THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1238
1239         UNLOCK_THREAD (internal);
1240         return internal->handle;
1241 }
1242
1243 /*
1244  * This is called from the finalizer of the internal thread object.
1245  */
1246 void
1247 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj, HANDLE thread)
1248 {
1249         THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, thread));
1250
1251         /*
1252          * Since threads keep a reference to their thread object while running, by the time this function is called,
1253          * the thread has already exited/detached, i.e. thread_cleanup () has ran. The exception is during shutdown,
1254          * when thread_cleanup () can be called after this.
1255          */
1256         if (thread)
1257                 mono_threads_close_thread_handle (thread);
1258
1259         if (this_obj->synch_cs) {
1260                 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1261                 this_obj->synch_cs = NULL;
1262                 mono_coop_mutex_destroy (synch_cs);
1263                 g_free (synch_cs);
1264         }
1265
1266         if (this_obj->name) {
1267                 void *name = this_obj->name;
1268                 this_obj->name = NULL;
1269                 g_free (name);
1270         }
1271 }
1272
1273 void
1274 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1275 {
1276         guint32 res;
1277         MonoInternalThread *thread = mono_thread_internal_current ();
1278
1279         THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1280
1281         if (mono_thread_current_check_pending_interrupt ())
1282                 return;
1283
1284         while (TRUE) {
1285                 gboolean alerted = FALSE;
1286
1287                 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1288
1289                 res = mono_thread_info_sleep (ms, &alerted);
1290
1291                 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1292
1293                 if (alerted) {
1294                         MonoException* exc = mono_thread_execute_interruption ();
1295                         if (exc) {
1296                                 mono_raise_exception (exc);
1297                         } else {
1298                                 // FIXME: !INFINITE
1299                                 if (ms != INFINITE)
1300                                         break;
1301                         }
1302                 } else {
1303                         break;
1304                 }
1305         }
1306 }
1307
1308 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1309 {
1310 }
1311
1312 gint32
1313 ves_icall_System_Threading_Thread_GetDomainID (void) 
1314 {
1315         return mono_domain_get()->domain_id;
1316 }
1317
1318 gboolean 
1319 ves_icall_System_Threading_Thread_Yield (void)
1320 {
1321         return mono_thread_info_yield ();
1322 }
1323
1324 /*
1325  * mono_thread_get_name:
1326  *
1327  *   Return the name of the thread. NAME_LEN is set to the length of the name.
1328  * Return NULL if the thread has no name. The returned memory is owned by the
1329  * caller.
1330  */
1331 gunichar2*
1332 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1333 {
1334         gunichar2 *res;
1335
1336         LOCK_THREAD (this_obj);
1337         
1338         if (!this_obj->name) {
1339                 *name_len = 0;
1340                 res = NULL;
1341         } else {
1342                 *name_len = this_obj->name_len;
1343                 res = g_new (gunichar2, this_obj->name_len);
1344                 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1345         }
1346         
1347         UNLOCK_THREAD (this_obj);
1348
1349         return res;
1350 }
1351
1352 /*
1353  * mono_thread_get_name_utf8:
1354  *
1355  * Return the name of the thread in UTF-8.
1356  * Return NULL if the thread has no name.
1357  * The returned memory is owned by the caller.
1358  */
1359 char *
1360 mono_thread_get_name_utf8 (MonoThread *thread)
1361 {
1362         if (thread == NULL)
1363                 return NULL;
1364
1365         MonoInternalThread *internal = thread->internal_thread;
1366         if (internal == NULL)
1367                 return NULL;
1368
1369         LOCK_THREAD (internal);
1370
1371         char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1372
1373         UNLOCK_THREAD (internal);
1374
1375         return tname;
1376 }
1377
1378 /*
1379  * mono_thread_get_managed_id:
1380  *
1381  * Return the Thread.ManagedThreadId value of `thread`.
1382  * Returns -1 if `thread` is NULL.
1383  */
1384 int32_t
1385 mono_thread_get_managed_id (MonoThread *thread)
1386 {
1387         if (thread == NULL)
1388                 return -1;
1389
1390         MonoInternalThread *internal = thread->internal_thread;
1391         if (internal == NULL)
1392                 return -1;
1393
1394         int32_t id = internal->managed_id;
1395
1396         return id;
1397 }
1398
1399 MonoString* 
1400 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1401 {
1402         MonoError error;
1403         MonoString* str;
1404
1405         mono_error_init (&error);
1406
1407         LOCK_THREAD (this_obj);
1408         
1409         if (!this_obj->name)
1410                 str = NULL;
1411         else
1412                 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1413         
1414         UNLOCK_THREAD (this_obj);
1415
1416         if (mono_error_set_pending_exception (&error))
1417                 return NULL;
1418         
1419         return str;
1420 }
1421
1422 void 
1423 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1424 {
1425         LOCK_THREAD (this_obj);
1426
1427         mono_error_init (error);
1428
1429         if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1430                 UNLOCK_THREAD (this_obj);
1431                 
1432                 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1433                 return;
1434         }
1435         if (this_obj->name) {
1436                 g_free (this_obj->name);
1437                 this_obj->name_len = 0;
1438         }
1439         if (name) {
1440                 this_obj->name = g_new (gunichar2, mono_string_length (name));
1441                 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
1442                 this_obj->name_len = mono_string_length (name);
1443
1444                 if (permanent)
1445                         this_obj->flags |= MONO_THREAD_FLAG_NAME_SET;
1446         }
1447         else
1448                 this_obj->name = NULL;
1449
1450         
1451         UNLOCK_THREAD (this_obj);
1452
1453         if (this_obj->name && this_obj->tid) {
1454                 char *tname = mono_string_to_utf8_checked (name, error);
1455                 return_if_nok (error);
1456                 mono_profiler_thread_name (this_obj->tid, tname);
1457                 mono_native_thread_set_name (thread_get_tid (this_obj), tname);
1458                 mono_free (tname);
1459         }
1460 }
1461
1462 void 
1463 ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
1464 {
1465         MonoError error;
1466         mono_thread_set_name_internal (this_obj, name, TRUE, &error);
1467         mono_error_set_pending_exception (&error);
1468 }
1469
1470 /*
1471  * ves_icall_System_Threading_Thread_GetPriority_internal:
1472  * @param this_obj: The MonoInternalThread on which to operate.
1473  *
1474  * Gets the priority of the given thread.
1475  * @return: The priority of the given thread.
1476  */
1477 int
1478 ves_icall_System_Threading_Thread_GetPriority (MonoThread *this_obj)
1479 {
1480         gint32 priority;
1481         MonoInternalThread *internal = this_obj->internal_thread;
1482
1483         LOCK_THREAD (internal);
1484         priority = internal->priority;
1485         UNLOCK_THREAD (internal);
1486
1487         return priority;
1488 }
1489
1490 /* 
1491  * ves_icall_System_Threading_Thread_SetPriority_internal:
1492  * @param this_obj: The MonoInternalThread on which to operate.
1493  * @param priority: The priority to set.
1494  *
1495  * Sets the priority of the given thread.
1496  */
1497 void
1498 ves_icall_System_Threading_Thread_SetPriority (MonoThread *this_obj, int priority)
1499 {
1500         MonoInternalThread *internal = this_obj->internal_thread;
1501
1502         LOCK_THREAD (internal);
1503         internal->priority = priority;
1504         if (internal->handle != NULL)
1505                 mono_thread_internal_set_priority (internal, priority);
1506         UNLOCK_THREAD (internal);
1507 }
1508
1509 /* If the array is already in the requested domain, we just return it,
1510    otherwise we return a copy in that domain. */
1511 static MonoArray*
1512 byte_array_to_domain (MonoArray *arr, MonoDomain *domain, MonoError *error)
1513 {
1514         MonoArray *copy;
1515
1516         mono_error_init (error);
1517         if (!arr)
1518                 return NULL;
1519
1520         if (mono_object_domain (arr) == domain)
1521                 return arr;
1522
1523         copy = mono_array_new_checked (domain, mono_defaults.byte_class, arr->max_length, error);
1524         memmove (mono_array_addr (copy, guint8, 0), mono_array_addr (arr, guint8, 0), arr->max_length);
1525         return copy;
1526 }
1527
1528 MonoArray*
1529 ves_icall_System_Threading_Thread_ByteArrayToRootDomain (MonoArray *arr)
1530 {
1531         MonoError error;
1532         MonoArray *result = byte_array_to_domain (arr, mono_get_root_domain (), &error);
1533         mono_error_set_pending_exception (&error);
1534         return result;
1535 }
1536
1537 MonoArray*
1538 ves_icall_System_Threading_Thread_ByteArrayToCurrentDomain (MonoArray *arr)
1539 {
1540         MonoError error;
1541         MonoArray *result = byte_array_to_domain (arr, mono_domain_get (), &error);
1542         mono_error_set_pending_exception (&error);
1543         return result;
1544 }
1545
1546 MonoThread *
1547 mono_thread_current (void)
1548 {
1549         MonoDomain *domain = mono_domain_get ();
1550         MonoInternalThread *internal = mono_thread_internal_current ();
1551         MonoThread **current_thread_ptr;
1552
1553         g_assert (internal);
1554         current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1555
1556         if (!*current_thread_ptr) {
1557                 g_assert (domain != mono_get_root_domain ());
1558                 *current_thread_ptr = new_thread_with_internal (domain, internal);
1559         }
1560         return *current_thread_ptr;
1561 }
1562
1563 /* Return the thread object belonging to INTERNAL in the current domain */
1564 static MonoThread *
1565 mono_thread_current_for_thread (MonoInternalThread *internal)
1566 {
1567         MonoDomain *domain = mono_domain_get ();
1568         MonoThread **current_thread_ptr;
1569
1570         g_assert (internal);
1571         current_thread_ptr = get_current_thread_ptr_for_domain (domain, internal);
1572
1573         if (!*current_thread_ptr) {
1574                 g_assert (domain != mono_get_root_domain ());
1575                 *current_thread_ptr = new_thread_with_internal (domain, internal);
1576         }
1577         return *current_thread_ptr;
1578 }
1579
1580 MonoInternalThread*
1581 mono_thread_internal_current (void)
1582 {
1583         MonoInternalThread *res = GET_CURRENT_OBJECT ();
1584         THREAD_DEBUG (g_message ("%s: returning %p", __func__, res));
1585         return res;
1586 }
1587
1588 gboolean
1589 ves_icall_System_Threading_Thread_Join_internal(MonoThread *this_obj, int ms)
1590 {
1591         MonoInternalThread *thread = this_obj->internal_thread;
1592         HANDLE handle = thread->handle;
1593         MonoInternalThread *cur_thread = mono_thread_internal_current ();
1594         gboolean ret;
1595
1596         if (mono_thread_current_check_pending_interrupt ())
1597                 return FALSE;
1598
1599         LOCK_THREAD (thread);
1600         
1601         if ((thread->state & ThreadState_Unstarted) != 0) {
1602                 UNLOCK_THREAD (thread);
1603                 
1604                 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1605                 return FALSE;
1606         }
1607
1608         UNLOCK_THREAD (thread);
1609
1610         if(ms== -1) {
1611                 ms=INFINITE;
1612         }
1613         THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1614         
1615         mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1616
1617         MONO_ENTER_GC_SAFE;
1618         ret=WaitForSingleObjectEx (handle, ms, TRUE);
1619         MONO_EXIT_GC_SAFE;
1620
1621         mono_thread_clr_state (cur_thread, ThreadState_WaitSleepJoin);
1622         
1623         if(ret==WAIT_OBJECT_0) {
1624                 THREAD_DEBUG (g_message ("%s: join successful", __func__));
1625
1626                 return(TRUE);
1627         }
1628         
1629         THREAD_DEBUG (g_message ("%s: join failed", __func__));
1630
1631         return(FALSE);
1632 }
1633
1634 #define MANAGED_WAIT_FAILED 0x7fffffff
1635
1636 static gint32
1637 map_native_wait_result_to_managed (gint32 val)
1638 {
1639         /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1640         return val == WAIT_FAILED ? MANAGED_WAIT_FAILED : val;
1641 }
1642
1643 static gint32
1644 mono_wait_uninterrupted (MonoInternalThread *thread, guint32 numhandles, gpointer *handles, gboolean waitall, gint32 ms, MonoError *error)
1645 {
1646         MonoException *exc;
1647         guint32 ret;
1648         gint64 start;
1649         gint32 diff_ms;
1650         gint32 wait = ms;
1651
1652         mono_error_init (error);
1653
1654         start = (ms == -1) ? 0 : mono_100ns_ticks ();
1655         do {
1656                 MONO_ENTER_GC_SAFE;
1657                 if (numhandles != 1)
1658                         ret = WaitForMultipleObjectsEx (numhandles, handles, waitall, wait, TRUE);
1659                 else
1660                         ret = WaitForSingleObjectEx (handles [0], ms, TRUE);
1661                 MONO_EXIT_GC_SAFE;
1662
1663                 if (ret != WAIT_IO_COMPLETION)
1664                         break;
1665
1666                 exc = mono_thread_execute_interruption ();
1667                 if (exc) {
1668                         mono_error_set_exception_instance (error, exc);
1669                         break;
1670                 }
1671
1672                 if (ms == -1)
1673                         continue;
1674
1675                 /* Re-calculate ms according to the time passed */
1676                 diff_ms = (gint32)((mono_100ns_ticks () - start) / 10000);
1677                 if (diff_ms >= ms) {
1678                         ret = WAIT_TIMEOUT;
1679                         break;
1680                 }
1681                 wait = ms - diff_ms;
1682         } while (TRUE);
1683         
1684         return ret;
1685 }
1686
1687 gint32 ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms)
1688 {
1689         MonoError error;
1690         HANDLE *handles;
1691         guint32 numhandles;
1692         guint32 ret;
1693         guint32 i;
1694         MonoObject *waitHandle;
1695         MonoInternalThread *thread = mono_thread_internal_current ();
1696
1697         /* Do this WaitSleepJoin check before creating objects */
1698         if (mono_thread_current_check_pending_interrupt ())
1699                 return map_native_wait_result_to_managed (WAIT_FAILED);
1700
1701         /* We fail in managed if the array has more than 64 elements */
1702         numhandles = (guint32)mono_array_length(mono_handles);
1703         handles = g_new0(HANDLE, numhandles);
1704
1705         for(i = 0; i < numhandles; i++) {       
1706                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1707                 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1708         }
1709         
1710         if(ms== -1) {
1711                 ms=INFINITE;
1712         }
1713
1714         mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1715
1716         ret = mono_wait_uninterrupted (thread, numhandles, handles, TRUE, ms, &error);
1717
1718         mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1719
1720         g_free(handles);
1721
1722         mono_error_set_pending_exception (&error);
1723
1724         /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1725         return map_native_wait_result_to_managed (ret);
1726 }
1727
1728 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms)
1729 {
1730         MonoError error;
1731         HANDLE handles [MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
1732         uintptr_t numhandles;
1733         guint32 ret;
1734         guint32 i;
1735         MonoObject *waitHandle;
1736         MonoInternalThread *thread = mono_thread_internal_current ();
1737
1738         /* Do this WaitSleepJoin check before creating objects */
1739         if (mono_thread_current_check_pending_interrupt ())
1740                 return map_native_wait_result_to_managed (WAIT_FAILED);
1741
1742         numhandles = mono_array_length(mono_handles);
1743         if (numhandles > MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
1744                 return map_native_wait_result_to_managed (WAIT_FAILED);
1745
1746         for(i = 0; i < numhandles; i++) {       
1747                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);
1748                 handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
1749         }
1750         
1751         if(ms== -1) {
1752                 ms=INFINITE;
1753         }
1754
1755         mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1756
1757         ret = mono_wait_uninterrupted (thread, numhandles, handles, FALSE, ms, &error);
1758
1759         mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1760
1761         THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") returning %d", __func__, mono_native_thread_id_get (), ret));
1762
1763         mono_error_set_pending_exception (&error);
1764
1765         /* WAIT_FAILED in waithandle.cs is different from WAIT_FAILED in Win32 API */
1766         return map_native_wait_result_to_managed (ret);
1767 }
1768
1769 gint32 ves_icall_System_Threading_WaitHandle_WaitOne_internal(HANDLE handle, gint32 ms)
1770 {
1771         MonoError error;
1772         guint32 ret;
1773         MonoInternalThread *thread = mono_thread_internal_current ();
1774
1775         THREAD_WAIT_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") waiting for %p, %d ms", __func__, mono_native_thread_id_get (), handle, ms));
1776         
1777         if(ms== -1) {
1778                 ms=INFINITE;
1779         }
1780         
1781         if (mono_thread_current_check_pending_interrupt ())
1782                 return map_native_wait_result_to_managed (WAIT_FAILED);
1783
1784         mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1785         
1786         ret = mono_wait_uninterrupted (thread, 1, &handle, FALSE, ms, &error);
1787         
1788         mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1789
1790         mono_error_set_pending_exception (&error);
1791         return map_native_wait_result_to_managed (ret);
1792 }
1793
1794 gint32
1795 ves_icall_System_Threading_WaitHandle_SignalAndWait_Internal (HANDLE toSignal, HANDLE toWait, gint32 ms)
1796 {
1797         guint32 ret;
1798         MonoInternalThread *thread = mono_thread_internal_current ();
1799
1800         if (ms == -1)
1801                 ms = INFINITE;
1802
1803         if (mono_thread_current_check_pending_interrupt ())
1804                 return map_native_wait_result_to_managed (WAIT_FAILED);
1805
1806         mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1807         
1808         MONO_ENTER_GC_SAFE;
1809         ret = SignalObjectAndWait (toSignal, toWait, ms, TRUE);
1810         MONO_EXIT_GC_SAFE;
1811         
1812         mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1813
1814         return map_native_wait_result_to_managed (ret);
1815 }
1816
1817 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1818 {
1819         return InterlockedIncrement (location);
1820 }
1821
1822 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1823 {
1824 #if SIZEOF_VOID_P == 4
1825         if (G_UNLIKELY ((size_t)location & 0x7)) {
1826                 gint64 ret;
1827                 mono_interlocked_lock ();
1828                 (*location)++;
1829                 ret = *location;
1830                 mono_interlocked_unlock ();
1831                 return ret;
1832         }
1833 #endif
1834         return InterlockedIncrement64 (location);
1835 }
1836
1837 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1838 {
1839         return InterlockedDecrement(location);
1840 }
1841
1842 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1843 {
1844 #if SIZEOF_VOID_P == 4
1845         if (G_UNLIKELY ((size_t)location & 0x7)) {
1846                 gint64 ret;
1847                 mono_interlocked_lock ();
1848                 (*location)--;
1849                 ret = *location;
1850                 mono_interlocked_unlock ();
1851                 return ret;
1852         }
1853 #endif
1854         return InterlockedDecrement64 (location);
1855 }
1856
1857 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1858 {
1859         return InterlockedExchange(location, value);
1860 }
1861
1862 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1863 {
1864         MonoObject *res;
1865         res = (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1866         mono_gc_wbarrier_generic_nostore (location);
1867         return res;
1868 }
1869
1870 gpointer ves_icall_System_Threading_Interlocked_Exchange_IntPtr (gpointer *location, gpointer value)
1871 {
1872         return InterlockedExchangePointer(location, value);
1873 }
1874
1875 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1876 {
1877         IntFloatUnion val, ret;
1878
1879         val.fval = value;
1880         ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1881
1882         return ret.fval;
1883 }
1884
1885 gint64 
1886 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1887 {
1888 #if SIZEOF_VOID_P == 4
1889         if (G_UNLIKELY ((size_t)location & 0x7)) {
1890                 gint64 ret;
1891                 mono_interlocked_lock ();
1892                 ret = *location;
1893                 *location = value;
1894                 mono_interlocked_unlock ();
1895                 return ret;
1896         }
1897 #endif
1898         return InterlockedExchange64 (location, value);
1899 }
1900
1901 gdouble 
1902 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1903 {
1904         LongDoubleUnion val, ret;
1905
1906         val.fval = value;
1907         ret.ival = (gint64)InterlockedExchange64((gint64 *) location, val.ival);
1908
1909         return ret.fval;
1910 }
1911
1912 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1913 {
1914         return InterlockedCompareExchange(location, value, comparand);
1915 }
1916
1917 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int_Success(gint32 *location, gint32 value, gint32 comparand, MonoBoolean *success)
1918 {
1919         gint32 r = InterlockedCompareExchange(location, value, comparand);
1920         *success = r == comparand;
1921         return r;
1922 }
1923
1924 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1925 {
1926         MonoObject *res;
1927         res = (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1928         mono_gc_wbarrier_generic_nostore (location);
1929         return res;
1930 }
1931
1932 gpointer ves_icall_System_Threading_Interlocked_CompareExchange_IntPtr(gpointer *location, gpointer value, gpointer comparand)
1933 {
1934         return InterlockedCompareExchangePointer(location, value, comparand);
1935 }
1936
1937 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1938 {
1939         IntFloatUnion val, ret, cmp;
1940
1941         val.fval = value;
1942         cmp.fval = comparand;
1943         ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1944
1945         return ret.fval;
1946 }
1947
1948 gdouble
1949 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1950 {
1951 #if SIZEOF_VOID_P == 8
1952         LongDoubleUnion val, comp, ret;
1953
1954         val.fval = value;
1955         comp.fval = comparand;
1956         ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1957
1958         return ret.fval;
1959 #else
1960         gdouble old;
1961
1962         mono_interlocked_lock ();
1963         old = *location;
1964         if (old == comparand)
1965                 *location = value;
1966         mono_interlocked_unlock ();
1967
1968         return old;
1969 #endif
1970 }
1971
1972 gint64 
1973 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1974 {
1975 #if SIZEOF_VOID_P == 4
1976         if (G_UNLIKELY ((size_t)location & 0x7)) {
1977                 gint64 old;
1978                 mono_interlocked_lock ();
1979                 old = *location;
1980                 if (old == comparand)
1981                         *location = value;
1982                 mono_interlocked_unlock ();
1983                 return old;
1984         }
1985 #endif
1986         return InterlockedCompareExchange64 (location, value, comparand);
1987 }
1988
1989 MonoObject*
1990 ves_icall_System_Threading_Interlocked_CompareExchange_T (MonoObject **location, MonoObject *value, MonoObject *comparand)
1991 {
1992         MonoObject *res;
1993         res = (MonoObject *)InterlockedCompareExchangePointer ((volatile gpointer *)location, value, comparand);
1994         mono_gc_wbarrier_generic_nostore (location);
1995         return res;
1996 }
1997
1998 MonoObject*
1999 ves_icall_System_Threading_Interlocked_Exchange_T (MonoObject **location, MonoObject *value)
2000 {
2001         MonoObject *res;
2002         MONO_CHECK_NULL (location, NULL);
2003         res = (MonoObject *)InterlockedExchangePointer ((volatile gpointer *)location, value);
2004         mono_gc_wbarrier_generic_nostore (location);
2005         return res;
2006 }
2007
2008 gint32 
2009 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
2010 {
2011         return InterlockedAdd (location, value);
2012 }
2013
2014 gint64 
2015 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
2016 {
2017 #if SIZEOF_VOID_P == 4
2018         if (G_UNLIKELY ((size_t)location & 0x7)) {
2019                 gint64 ret;
2020                 mono_interlocked_lock ();
2021                 *location += value;
2022                 ret = *location;
2023                 mono_interlocked_unlock ();
2024                 return ret;
2025         }
2026 #endif
2027         return InterlockedAdd64 (location, value);
2028 }
2029
2030 gint64 
2031 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
2032 {
2033 #if SIZEOF_VOID_P == 4
2034         if (G_UNLIKELY ((size_t)location & 0x7)) {
2035                 gint64 ret;
2036                 mono_interlocked_lock ();
2037                 ret = *location;
2038                 mono_interlocked_unlock ();
2039                 return ret;
2040         }
2041 #endif
2042         return InterlockedRead64 (location);
2043 }
2044
2045 void
2046 ves_icall_System_Threading_Thread_MemoryBarrier (void)
2047 {
2048         mono_memory_barrier ();
2049 }
2050
2051 void
2052 ves_icall_System_Threading_Thread_ClrState (MonoInternalThread* this_obj, guint32 state)
2053 {
2054         mono_thread_clr_state (this_obj, (MonoThreadState)state);
2055
2056         if (state & ThreadState_Background) {
2057                 /* If the thread changes the background mode, the main thread has to
2058                  * be notified, since it has to rebuild the list of threads to
2059                  * wait for.
2060                  */
2061                 mono_w32event_set (background_change_event);
2062         }
2063 }
2064
2065 void
2066 ves_icall_System_Threading_Thread_SetState (MonoInternalThread* this_obj, guint32 state)
2067 {
2068         mono_thread_set_state (this_obj, (MonoThreadState)state);
2069         
2070         if (state & ThreadState_Background) {
2071                 /* If the thread changes the background mode, the main thread has to
2072                  * be notified, since it has to rebuild the list of threads to
2073                  * wait for.
2074                  */
2075                 mono_w32event_set (background_change_event);
2076         }
2077 }
2078
2079 guint32
2080 ves_icall_System_Threading_Thread_GetState (MonoInternalThread* this_obj)
2081 {
2082         guint32 state;
2083
2084         LOCK_THREAD (this_obj);
2085         
2086         state = this_obj->state;
2087
2088         UNLOCK_THREAD (this_obj);
2089         
2090         return state;
2091 }
2092
2093 void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this_obj)
2094 {
2095         MonoInternalThread *current;
2096         gboolean throw_;
2097         MonoInternalThread *thread = this_obj->internal_thread;
2098
2099         LOCK_THREAD (thread);
2100
2101         current = mono_thread_internal_current ();
2102
2103         thread->thread_interrupt_requested = TRUE;
2104         throw_ = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2105
2106         UNLOCK_THREAD (thread);
2107
2108         if (throw_) {
2109                 async_abort_internal (thread, FALSE);
2110         }
2111 }
2112
2113 /**
2114  * mono_thread_current_check_pending_interrupt:
2115  *
2116  * Checks if there's a interruption request and set the pending exception if so.
2117  *
2118  * @returns true if a pending exception was set
2119  */
2120 gboolean
2121 mono_thread_current_check_pending_interrupt (void)
2122 {
2123         MonoInternalThread *thread = mono_thread_internal_current ();
2124         gboolean throw_ = FALSE;
2125
2126         LOCK_THREAD (thread);
2127         
2128         if (thread->thread_interrupt_requested) {
2129                 throw_ = TRUE;
2130                 thread->thread_interrupt_requested = FALSE;
2131         }
2132         
2133         UNLOCK_THREAD (thread);
2134
2135         if (throw_)
2136                 mono_set_pending_exception (mono_get_exception_thread_interrupted ());
2137         return throw_;
2138 }
2139
2140 static gboolean
2141 request_thread_abort (MonoInternalThread *thread, MonoObject *state)
2142 {
2143         LOCK_THREAD (thread);
2144         
2145         if ((thread->state & ThreadState_AbortRequested) != 0 || 
2146                 (thread->state & ThreadState_StopRequested) != 0 ||
2147                 (thread->state & ThreadState_Stopped) != 0)
2148         {
2149                 UNLOCK_THREAD (thread);
2150                 return FALSE;
2151         }
2152
2153         if ((thread->state & ThreadState_Unstarted) != 0) {
2154                 thread->state |= ThreadState_Aborted;
2155                 UNLOCK_THREAD (thread);
2156                 return FALSE;
2157         }
2158
2159         thread->state |= ThreadState_AbortRequested;
2160         if (thread->abort_state_handle)
2161                 mono_gchandle_free (thread->abort_state_handle);
2162         if (state) {
2163                 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2164                 g_assert (thread->abort_state_handle);
2165         } else {
2166                 thread->abort_state_handle = 0;
2167         }
2168         thread->abort_exc = NULL;
2169
2170         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), thread, (gsize)thread->tid));
2171
2172         /* During shutdown, we can't wait for other threads */
2173         if (!shutting_down)
2174                 /* Make sure the thread is awake */
2175                 mono_thread_resume (thread);
2176
2177         UNLOCK_THREAD (thread);
2178         return TRUE;
2179 }
2180
2181 void
2182 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2183 {
2184         if (!request_thread_abort (thread, state))
2185                 return;
2186
2187         if (thread == mono_thread_internal_current ()) {
2188                 MonoError error;
2189                 self_abort_internal (&error);
2190                 mono_error_set_pending_exception (&error);
2191         } else {
2192                 async_abort_internal (thread, TRUE);
2193         }
2194 }
2195
2196 /**
2197  * mono_thread_internal_abort:
2198  *
2199  * Request thread @thread to be aborted.
2200  *
2201  * @thread MUST NOT be the current thread.
2202  */
2203 void
2204 mono_thread_internal_abort (MonoInternalThread *thread)
2205 {
2206         g_assert (thread != mono_thread_internal_current ());
2207
2208         if (!request_thread_abort (thread, NULL))
2209                 return;
2210         async_abort_internal (thread, TRUE);
2211 }
2212
2213 void
2214 ves_icall_System_Threading_Thread_ResetAbort (MonoThread *this_obj)
2215 {
2216         MonoInternalThread *thread = mono_thread_internal_current ();
2217         gboolean was_aborting;
2218
2219         LOCK_THREAD (thread);
2220         was_aborting = thread->state & ThreadState_AbortRequested;
2221         thread->state &= ~ThreadState_AbortRequested;
2222         UNLOCK_THREAD (thread);
2223
2224         if (!was_aborting) {
2225                 const char *msg = "Unable to reset abort because no abort was requested";
2226                 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2227                 return;
2228         }
2229         thread->abort_exc = NULL;
2230         if (thread->abort_state_handle) {
2231                 mono_gchandle_free (thread->abort_state_handle);
2232                 /* This is actually not necessary - the handle
2233                    only counts if the exception is set */
2234                 thread->abort_state_handle = 0;
2235         }
2236 }
2237
2238 void
2239 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2240 {
2241         LOCK_THREAD (thread);
2242
2243         thread->state &= ~ThreadState_AbortRequested;
2244
2245         if (thread->abort_exc) {
2246                 thread->abort_exc = NULL;
2247                 if (thread->abort_state_handle) {
2248                         mono_gchandle_free (thread->abort_state_handle);
2249                         /* This is actually not necessary - the handle
2250                            only counts if the exception is set */
2251                         thread->abort_state_handle = 0;
2252                 }
2253         }
2254
2255         UNLOCK_THREAD (thread);
2256 }
2257
2258 MonoObject*
2259 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this_obj)
2260 {
2261         MonoError error;
2262         MonoInternalThread *thread = this_obj->internal_thread;
2263         MonoObject *state, *deserialized = NULL;
2264         MonoDomain *domain;
2265
2266         if (!thread->abort_state_handle)
2267                 return NULL;
2268
2269         state = mono_gchandle_get_target (thread->abort_state_handle);
2270         g_assert (state);
2271
2272         domain = mono_domain_get ();
2273         if (mono_object_domain (state) == domain)
2274                 return state;
2275
2276         deserialized = mono_object_xdomain_representation (state, domain, &error);
2277
2278         if (!deserialized) {
2279                 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2280                 if (!is_ok (&error)) {
2281                         MonoObject *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2282                         MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2283                 }
2284                 mono_set_pending_exception (invalid_op_exc);
2285                 return NULL;
2286         }
2287
2288         return deserialized;
2289 }
2290
2291 static gboolean
2292 mono_thread_suspend (MonoInternalThread *thread)
2293 {
2294         LOCK_THREAD (thread);
2295
2296         if ((thread->state & ThreadState_Unstarted) != 0 || 
2297                 (thread->state & ThreadState_Aborted) != 0 || 
2298                 (thread->state & ThreadState_Stopped) != 0)
2299         {
2300                 UNLOCK_THREAD (thread);
2301                 return FALSE;
2302         }
2303
2304         if ((thread->state & ThreadState_Suspended) != 0 || 
2305                 (thread->state & ThreadState_SuspendRequested) != 0 ||
2306                 (thread->state & ThreadState_StopRequested) != 0) 
2307         {
2308                 UNLOCK_THREAD (thread);
2309                 return TRUE;
2310         }
2311         
2312         thread->state |= ThreadState_SuspendRequested;
2313
2314         if (thread == mono_thread_internal_current ()) {
2315                 /* calls UNLOCK_THREAD (thread) */
2316                 self_suspend_internal ();
2317         } else {
2318                 /* calls UNLOCK_THREAD (thread) */
2319                 async_suspend_internal (thread, FALSE);
2320         }
2321
2322         return TRUE;
2323 }
2324
2325 void
2326 ves_icall_System_Threading_Thread_Suspend (MonoThread *this_obj)
2327 {
2328         if (!mono_thread_suspend (this_obj->internal_thread)) {
2329                 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2330                 return;
2331         }
2332 }
2333
2334 /* LOCKING: LOCK_THREAD(thread) must be held */
2335 static gboolean
2336 mono_thread_resume (MonoInternalThread *thread)
2337 {
2338         if ((thread->state & ThreadState_SuspendRequested) != 0) {
2339                 thread->state &= ~ThreadState_SuspendRequested;
2340                 return TRUE;
2341         }
2342
2343         if ((thread->state & ThreadState_Suspended) == 0 ||
2344                 (thread->state & ThreadState_Unstarted) != 0 || 
2345                 (thread->state & ThreadState_Aborted) != 0 || 
2346                 (thread->state & ThreadState_Stopped) != 0)
2347         {
2348                 return FALSE;
2349         }
2350
2351         UNLOCK_THREAD (thread);
2352
2353         /* Awake the thread */
2354         if (!mono_thread_info_resume (thread_get_tid (thread)))
2355                 return FALSE;
2356
2357         LOCK_THREAD (thread);
2358
2359         thread->state &= ~ThreadState_Suspended;
2360
2361         return TRUE;
2362 }
2363
2364 void
2365 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2366 {
2367         if (!thread->internal_thread) {
2368                 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2369         } else {
2370                 LOCK_THREAD (thread->internal_thread);
2371                 if (!mono_thread_resume (thread->internal_thread))
2372                         mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2373                 UNLOCK_THREAD (thread->internal_thread);
2374         }
2375 }
2376
2377 static gboolean
2378 mono_threads_is_critical_method (MonoMethod *method)
2379 {
2380         switch (method->wrapper_type) {
2381         case MONO_WRAPPER_RUNTIME_INVOKE:
2382         case MONO_WRAPPER_XDOMAIN_INVOKE:
2383         case MONO_WRAPPER_XDOMAIN_DISPATCH:     
2384                 return TRUE;
2385         }
2386         return FALSE;
2387 }
2388
2389 static gboolean
2390 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2391 {
2392         if (managed)
2393                 return TRUE;
2394
2395         if (mono_threads_is_critical_method (m)) {
2396                 *((gboolean*)data) = TRUE;
2397                 return TRUE;
2398         }
2399         return FALSE;
2400 }
2401
2402 static gboolean 
2403 is_running_protected_wrapper (void)
2404 {
2405         gboolean found = FALSE;
2406         mono_stack_walk (find_wrapper, &found);
2407         return found;
2408 }
2409
2410 static gboolean
2411 request_thread_stop (MonoInternalThread *thread)
2412 {
2413         LOCK_THREAD (thread);
2414
2415         if ((thread->state & ThreadState_StopRequested) != 0 ||
2416                 (thread->state & ThreadState_Stopped) != 0)
2417         {
2418                 UNLOCK_THREAD (thread);
2419                 return FALSE;
2420         }
2421         
2422         /* Make sure the thread is awake */
2423         mono_thread_resume (thread);
2424
2425         thread->state |= ThreadState_StopRequested;
2426         thread->state &= ~ThreadState_AbortRequested;
2427         
2428         UNLOCK_THREAD (thread);
2429         return TRUE;
2430 }
2431
2432 /**
2433  * mono_thread_internal_stop:
2434  *
2435  * Request thread @thread to stop.
2436  *
2437  * @thread MUST NOT be the current thread.
2438  */
2439 void
2440 mono_thread_internal_stop (MonoInternalThread *thread)
2441 {
2442         g_assert (thread != mono_thread_internal_current ());
2443
2444         if (!request_thread_stop (thread))
2445                 return;
2446         
2447         async_abort_internal (thread, TRUE);
2448 }
2449
2450 void mono_thread_stop (MonoThread *thread)
2451 {
2452         MonoInternalThread *internal = thread->internal_thread;
2453
2454         if (!request_thread_stop (internal))
2455                 return;
2456         
2457         if (internal == mono_thread_internal_current ()) {
2458                 MonoError error;
2459                 self_abort_internal (&error);
2460                 /*
2461                 This function is part of the embeding API and has no way to return the exception
2462                 to be thrown. So what we do is keep the old behavior and raise the exception.
2463                 */
2464                 mono_error_raise_exception (&error); /* OK to throw, see note */
2465         } else {
2466                 async_abort_internal (internal, TRUE);
2467         }
2468 }
2469
2470 gint8
2471 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2472 {
2473         gint8 tmp = *(volatile gint8 *)ptr;
2474         mono_memory_barrier ();
2475         return tmp;
2476 }
2477
2478 gint16
2479 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2480 {
2481         gint16 tmp = *(volatile gint16 *)ptr;
2482         mono_memory_barrier ();
2483         return tmp;
2484 }
2485
2486 gint32
2487 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2488 {
2489         gint32 tmp = *(volatile gint32 *)ptr;
2490         mono_memory_barrier ();
2491         return tmp;
2492 }
2493
2494 gint64
2495 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2496 {
2497         gint64 tmp = *(volatile gint64 *)ptr;
2498         mono_memory_barrier ();
2499         return tmp;
2500 }
2501
2502 void *
2503 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2504 {
2505         volatile void *tmp = *(volatile void **)ptr;
2506         mono_memory_barrier ();
2507         return (void *) tmp;
2508 }
2509
2510 void *
2511 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2512 {
2513         volatile MonoObject *tmp = *(volatile MonoObject **)ptr;
2514         mono_memory_barrier ();
2515         return (MonoObject *) tmp;
2516 }
2517
2518 double
2519 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2520 {
2521         double tmp = *(volatile double *)ptr;
2522         mono_memory_barrier ();
2523         return tmp;
2524 }
2525
2526 float
2527 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2528 {
2529         float tmp = *(volatile float *)ptr;
2530         mono_memory_barrier ();
2531         return tmp;
2532 }
2533
2534 gint8
2535 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2536 {
2537         return InterlockedRead8 ((volatile gint8 *)ptr);
2538 }
2539
2540 gint16
2541 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2542 {
2543         return InterlockedRead16 ((volatile gint16 *)ptr);
2544 }
2545
2546 gint32
2547 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2548 {
2549         return InterlockedRead ((volatile gint32 *)ptr);
2550 }
2551
2552 gint64
2553 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2554 {
2555 #if SIZEOF_VOID_P == 4
2556         if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2557                 gint64 val;
2558                 mono_interlocked_lock ();
2559                 val = *(gint64*)ptr;
2560                 mono_interlocked_unlock ();
2561                 return val;
2562         }
2563 #endif
2564         return InterlockedRead64 ((volatile gint64 *)ptr);
2565 }
2566
2567 void *
2568 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2569 {
2570         return InterlockedReadPointer ((volatile gpointer *)ptr);
2571 }
2572
2573 double
2574 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2575 {
2576         LongDoubleUnion u;
2577
2578 #if SIZEOF_VOID_P == 4
2579         if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2580                 double val;
2581                 mono_interlocked_lock ();
2582                 val = *(double*)ptr;
2583                 mono_interlocked_unlock ();
2584                 return val;
2585         }
2586 #endif
2587
2588         u.ival = InterlockedRead64 ((volatile gint64 *)ptr);
2589
2590         return u.fval;
2591 }
2592
2593 float
2594 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2595 {
2596         IntFloatUnion u;
2597
2598         u.ival = InterlockedRead ((volatile gint32 *)ptr);
2599
2600         return u.fval;
2601 }
2602
2603 MonoObject*
2604 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2605 {
2606         return (MonoObject *)InterlockedReadPointer ((volatile gpointer *)ptr);
2607 }
2608
2609 void
2610 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2611 {
2612         mono_memory_barrier ();
2613         *(volatile gint8 *)ptr = value;
2614 }
2615
2616 void
2617 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2618 {
2619         mono_memory_barrier ();
2620         *(volatile gint16 *)ptr = value;
2621 }
2622
2623 void
2624 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2625 {
2626         mono_memory_barrier ();
2627         *(volatile gint32 *)ptr = value;
2628 }
2629
2630 void
2631 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2632 {
2633         mono_memory_barrier ();
2634         *(volatile gint64 *)ptr = value;
2635 }
2636
2637 void
2638 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2639 {
2640         mono_memory_barrier ();
2641         *(volatile void **)ptr = value;
2642 }
2643
2644 void
2645 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2646 {
2647         mono_memory_barrier ();
2648         mono_gc_wbarrier_generic_store (ptr, value);
2649 }
2650
2651 void
2652 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2653 {
2654         mono_memory_barrier ();
2655         *(volatile double *)ptr = value;
2656 }
2657
2658 void
2659 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2660 {
2661         mono_memory_barrier ();
2662         *(volatile float *)ptr = value;
2663 }
2664
2665 void
2666 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2667 {
2668         InterlockedWrite8 ((volatile gint8 *)ptr, value);
2669 }
2670
2671 void
2672 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2673 {
2674         InterlockedWrite16 ((volatile gint16 *)ptr, value);
2675 }
2676
2677 void
2678 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2679 {
2680         InterlockedWrite ((volatile gint32 *)ptr, value);
2681 }
2682
2683 void
2684 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2685 {
2686 #if SIZEOF_VOID_P == 4
2687         if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2688                 mono_interlocked_lock ();
2689                 *(gint64*)ptr = value;
2690                 mono_interlocked_unlock ();
2691                 return;
2692         }
2693 #endif
2694
2695         InterlockedWrite64 ((volatile gint64 *)ptr, value);
2696 }
2697
2698 void
2699 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2700 {
2701         InterlockedWritePointer ((volatile gpointer *)ptr, value);
2702 }
2703
2704 void
2705 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2706 {
2707         LongDoubleUnion u;
2708
2709 #if SIZEOF_VOID_P == 4
2710         if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2711                 mono_interlocked_lock ();
2712                 *(double*)ptr = value;
2713                 mono_interlocked_unlock ();
2714                 return;
2715         }
2716 #endif
2717
2718         u.fval = value;
2719
2720         InterlockedWrite64 ((volatile gint64 *)ptr, u.ival);
2721 }
2722
2723 void
2724 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2725 {
2726         IntFloatUnion u;
2727
2728         u.fval = value;
2729
2730         InterlockedWrite ((volatile gint32 *)ptr, u.ival);
2731 }
2732
2733 void
2734 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2735 {
2736         mono_gc_wbarrier_generic_store_atomic (ptr, value);
2737 }
2738
2739 static void
2740 free_context (void *user_data)
2741 {
2742         ContextStaticData *data = user_data;
2743
2744         mono_threads_lock ();
2745
2746         /*
2747          * There is no guarantee that, by the point this reference queue callback
2748          * has been invoked, the GC handle associated with the object will fail to
2749          * resolve as one might expect. So if we don't free and remove the GC
2750          * handle here, free_context_static_data_helper () could end up resolving
2751          * a GC handle to an actually-dead context which would contain a pointer
2752          * to an already-freed static data segment, resulting in a crash when
2753          * accessing it.
2754          */
2755         g_hash_table_remove (contexts, GUINT_TO_POINTER (data->gc_handle));
2756
2757         mono_threads_unlock ();
2758
2759         mono_gchandle_free (data->gc_handle);
2760         mono_free_static_data (data->static_data);
2761         g_free (data);
2762 }
2763
2764 void
2765 ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext (MonoAppContext *ctx)
2766 {
2767         mono_threads_lock ();
2768
2769         //g_print ("Registering context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2770
2771         if (!contexts)
2772                 contexts = g_hash_table_new (NULL, NULL);
2773
2774         if (!context_queue)
2775                 context_queue = mono_gc_reference_queue_new (free_context);
2776
2777         gpointer gch = GUINT_TO_POINTER (mono_gchandle_new_weakref (&ctx->obj, FALSE));
2778         g_hash_table_insert (contexts, gch, gch);
2779
2780         /*
2781          * We use this intermediate structure to contain a duplicate pointer to
2782          * the static data because we can't rely on being able to resolve the GC
2783          * handle in the reference queue callback.
2784          */
2785         ContextStaticData *data = g_new0 (ContextStaticData, 1);
2786         data->gc_handle = GPOINTER_TO_UINT (gch);
2787         ctx->data = data;
2788
2789         context_adjust_static_data (ctx);
2790         mono_gc_reference_queue_add (context_queue, &ctx->obj, data);
2791
2792         mono_threads_unlock ();
2793
2794         mono_profiler_context_loaded (ctx);
2795 }
2796
2797 void
2798 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2799 {
2800         /*
2801          * NOTE: Since finalizers are unreliable for the purposes of ensuring
2802          * cleanup in exceptional circumstances, we don't actually do any
2803          * cleanup work here. We instead do this via a reference queue.
2804          */
2805
2806         //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2807
2808         mono_profiler_context_unloaded (ctx);
2809 }
2810
2811 void
2812 mono_thread_init_tls (void)
2813 {
2814         MONO_FAST_TLS_INIT (tls_current_object);
2815         mono_native_tls_alloc (&current_object_key, NULL);
2816 }
2817
2818 void mono_thread_init (MonoThreadStartCB start_cb,
2819                        MonoThreadAttachCB attach_cb)
2820 {
2821         mono_coop_mutex_init_recursive (&threads_mutex);
2822
2823         mono_os_mutex_init_recursive(&interlocked_mutex);
2824         mono_os_mutex_init_recursive(&joinable_threads_mutex);
2825         
2826         background_change_event = mono_w32event_create (TRUE, FALSE);
2827         g_assert(background_change_event != NULL);
2828         
2829         mono_init_static_data_info (&thread_static_info);
2830         mono_init_static_data_info (&context_static_info);
2831
2832         THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2833
2834         mono_thread_start_cb = start_cb;
2835         mono_thread_attach_cb = attach_cb;
2836
2837         /* Get a pseudo handle to the current process.  This is just a
2838          * kludge so that wapi can build a process handle if needed.
2839          * As a pseudo handle is returned, we don't need to clean
2840          * anything up.
2841          */
2842         GetCurrentProcess ();
2843 }
2844
2845 void mono_thread_cleanup (void)
2846 {
2847 #if !defined(RUN_IN_SUBTHREAD)
2848         /* The main thread must abandon any held mutexes (particularly
2849          * important for named mutexes as they are shared across
2850          * processes, see bug 74680.)  This will happen when the
2851          * thread exits, but if it's not running in a subthread it
2852          * won't exit in time.
2853          */
2854         mono_thread_info_set_exited (mono_thread_info_current ());
2855 #endif
2856
2857 #if 0
2858         /* This stuff needs more testing, it seems one of these
2859          * critical sections can be locked when mono_thread_cleanup is
2860          * called.
2861          */
2862         mono_coop_mutex_destroy (&threads_mutex);
2863         mono_os_mutex_destroy (&interlocked_mutex);
2864         mono_os_mutex_destroy (&delayed_free_table_mutex);
2865         mono_os_mutex_destroy (&small_id_mutex);
2866         CloseHandle (background_change_event);
2867 #endif
2868
2869         mono_native_tls_free (current_object_key);
2870 }
2871
2872 void
2873 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2874 {
2875         mono_thread_cleanup_fn = func;
2876 }
2877
2878 void
2879 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2880 {
2881         thread->internal_thread->manage_callback = func;
2882 }
2883
2884 G_GNUC_UNUSED
2885 static void print_tids (gpointer key, gpointer value, gpointer user)
2886 {
2887         /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2888          * sizeof(uint) and a cast to uint would overflow
2889          */
2890         /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2891          * print this as a pointer.
2892          */
2893         g_message ("Waiting for: %p", key);
2894 }
2895
2896 struct wait_data 
2897 {
2898         HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2899         MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2900         guint32 num;
2901 };
2902
2903 static void
2904 wait_for_tids (struct wait_data *wait, guint32 timeout)
2905 {
2906         guint32 i, ret;
2907         
2908         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2909
2910         MONO_ENTER_GC_SAFE;
2911         ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2912         MONO_EXIT_GC_SAFE;
2913
2914         if(ret==WAIT_FAILED) {
2915                 /* See the comment in build_wait_tids() */
2916                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2917                 return;
2918         }
2919         
2920         for(i=0; i<wait->num; i++)
2921                 mono_threads_close_thread_handle (wait->handles [i]);
2922
2923         if (ret == WAIT_TIMEOUT)
2924                 return;
2925
2926         for(i=0; i<wait->num; i++) {
2927                 gsize tid = wait->threads[i]->tid;
2928
2929                 /*
2930                  * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2931                  * it can still run io-layer etc. code. So wait for it to really exit.
2932                  * FIXME: This won't join threads which are not in the joinable_hash yet.
2933                  */
2934                 mono_thread_join ((gpointer)tid);
2935
2936                 mono_threads_lock ();
2937                 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2938                         /* This thread must have been killed, because
2939                          * it hasn't cleaned itself up. (It's just
2940                          * possible that the thread exited before the
2941                          * parent thread had a chance to store the
2942                          * handle, and now there is another pointer to
2943                          * the already-exited thread stored.  In this
2944                          * case, we'll just get two
2945                          * mono_profiler_thread_end() calls for the
2946                          * same thread.)
2947                          */
2948         
2949                         mono_threads_unlock ();
2950                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2951                         thread_cleanup (wait->threads[i]);
2952                 } else {
2953                         mono_threads_unlock ();
2954                 }
2955         }
2956 }
2957
2958 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2959 {
2960         guint32 i, ret, count;
2961         
2962         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2963
2964         /* Add the thread state change event, so it wakes up if a thread changes
2965          * to background mode.
2966          */
2967         count = wait->num;
2968         if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
2969                 wait->handles [count] = background_change_event;
2970                 count++;
2971         }
2972
2973         MONO_ENTER_GC_SAFE;
2974         ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2975         MONO_EXIT_GC_SAFE;
2976
2977         if(ret==WAIT_FAILED) {
2978                 /* See the comment in build_wait_tids() */
2979                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2980                 return;
2981         }
2982         
2983         for(i=0; i<wait->num; i++)
2984                 mono_threads_close_thread_handle (wait->handles [i]);
2985
2986         if (ret == WAIT_TIMEOUT)
2987                 return;
2988         
2989         if (ret < wait->num) {
2990                 gsize tid = wait->threads[ret]->tid;
2991                 mono_threads_lock ();
2992                 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2993                         /* See comment in wait_for_tids about thread cleanup */
2994                         mono_threads_unlock ();
2995                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2996                         thread_cleanup (wait->threads [ret]);
2997                 } else
2998                         mono_threads_unlock ();
2999         }
3000 }
3001
3002 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3003 {
3004         struct wait_data *wait=(struct wait_data *)user;
3005
3006         if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3007                 HANDLE handle;
3008                 MonoInternalThread *thread=(MonoInternalThread *)value;
3009
3010                 /* Ignore background threads, we abort them later */
3011                 /* Do not lock here since it is not needed and the caller holds threads_lock */
3012                 if (thread->state & ThreadState_Background) {
3013                         THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3014                         return; /* just leave, ignore */
3015                 }
3016                 
3017                 if (mono_gc_is_finalizer_internal_thread (thread)) {
3018                         THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3019                         return;
3020                 }
3021
3022                 if (thread == mono_thread_internal_current ()) {
3023                         THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3024                         return;
3025                 }
3026
3027                 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3028                         THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3029                         return;
3030                 }
3031
3032                 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3033                         THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3034                         return;
3035                 }
3036
3037                 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3038                 if (handle == NULL) {
3039                         THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3040                         return;
3041                 }
3042                 
3043                 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3044                 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3045                         wait->handles[wait->num]=handle;
3046                         wait->threads[wait->num]=thread;
3047                         wait->num++;
3048
3049                         THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3050                 } else {
3051                         THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3052                 }
3053                 
3054                 
3055         } else {
3056                 /* Just ignore the rest, we can't do anything with
3057                  * them yet
3058                  */
3059         }
3060 }
3061
3062 static gboolean
3063 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3064 {
3065         struct wait_data *wait=(struct wait_data *)user;
3066         MonoNativeThreadId self = mono_native_thread_id_get ();
3067         MonoInternalThread *thread = (MonoInternalThread *)value;
3068         HANDLE handle;
3069
3070         if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3071                 return FALSE;
3072
3073         /* The finalizer thread is not a background thread */
3074         if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3075              && (thread->state & ThreadState_Background) != 0
3076              && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3077         ) {
3078                 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3079                 if (handle == NULL)
3080                         return FALSE;
3081
3082                 wait->handles[wait->num] = handle;
3083                 wait->threads[wait->num] = thread;
3084                 wait->num++;
3085
3086                 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3087                 mono_thread_internal_abort (thread);
3088                 return TRUE;
3089         }
3090
3091         return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3092                 && !mono_gc_is_finalizer_internal_thread (thread);
3093 }
3094
3095 /** 
3096  * mono_threads_set_shutting_down:
3097  *
3098  * Is called by a thread that wants to shut down Mono. If the runtime is already
3099  * shutting down, the calling thread is suspended/stopped, and this function never
3100  * returns.
3101  */
3102 void
3103 mono_threads_set_shutting_down (void)
3104 {
3105         MonoInternalThread *current_thread = mono_thread_internal_current ();
3106
3107         mono_threads_lock ();
3108
3109         if (shutting_down) {
3110                 mono_threads_unlock ();
3111
3112                 /* Make sure we're properly suspended/stopped */
3113
3114                 LOCK_THREAD (current_thread);
3115
3116                 if ((current_thread->state & ThreadState_SuspendRequested) ||
3117                     (current_thread->state & ThreadState_AbortRequested) ||
3118                     (current_thread->state & ThreadState_StopRequested)) {
3119                         UNLOCK_THREAD (current_thread);
3120                         mono_thread_execute_interruption ();
3121                 } else {
3122                         current_thread->state |= ThreadState_Stopped;
3123                         UNLOCK_THREAD (current_thread);
3124                 }
3125
3126                 /*since we're killing the thread, detach it.*/
3127                 mono_thread_detach_internal (current_thread);
3128
3129                 /* Wake up other threads potentially waiting for us */
3130                 mono_thread_info_exit ();
3131         } else {
3132                 shutting_down = TRUE;
3133
3134                 /* Not really a background state change, but this will
3135                  * interrupt the main thread if it is waiting for all
3136                  * the other threads.
3137                  */
3138                 mono_w32event_set (background_change_event);
3139                 
3140                 mono_threads_unlock ();
3141         }
3142 }
3143
3144 void mono_thread_manage (void)
3145 {
3146         struct wait_data wait_data;
3147         struct wait_data *wait = &wait_data;
3148
3149         memset (wait, 0, sizeof (struct wait_data));
3150         /* join each thread that's still running */
3151         THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3152         
3153         mono_threads_lock ();
3154         if(threads==NULL) {
3155                 THREAD_DEBUG (g_message("%s: No threads", __func__));
3156                 mono_threads_unlock ();
3157                 return;
3158         }
3159         mono_threads_unlock ();
3160         
3161         do {
3162                 mono_threads_lock ();
3163                 if (shutting_down) {
3164                         /* somebody else is shutting down */
3165                         mono_threads_unlock ();
3166                         break;
3167                 }
3168                 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3169                         mono_g_hash_table_foreach (threads, print_tids, NULL));
3170         
3171                 mono_w32event_reset (background_change_event);
3172                 wait->num=0;
3173                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3174                 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3175                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3176                 mono_threads_unlock ();
3177                 if(wait->num>0) {
3178                         /* Something to wait for */
3179                         wait_for_tids_or_state_change (wait, INFINITE);
3180                 }
3181                 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3182         } while(wait->num>0);
3183
3184         /* Mono is shutting down, so just wait for the end */
3185         if (!mono_runtime_try_shutdown ()) {
3186                 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3187                 mono_thread_suspend (mono_thread_internal_current ());
3188                 mono_thread_execute_interruption ();
3189         }
3190
3191         /* 
3192          * Remove everything but the finalizer thread and self.
3193          * Also abort all the background threads
3194          * */
3195         do {
3196                 mono_threads_lock ();
3197
3198                 wait->num = 0;
3199                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3200                 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3201                 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3202
3203                 mono_threads_unlock ();
3204
3205                 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3206                 if(wait->num>0) {
3207                         /* Something to wait for */
3208                         wait_for_tids (wait, INFINITE);
3209                 }
3210         } while (wait->num > 0);
3211         
3212         /* 
3213          * give the subthreads a chance to really quit (this is mainly needed
3214          * to get correct user and system times from getrusage/wait/time(1)).
3215          * This could be removed if we avoid pthread_detach() and use pthread_join().
3216          */
3217         mono_thread_info_yield ();
3218 }
3219
3220 static void
3221 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3222 {
3223         MonoInternalThread *thread = (MonoInternalThread*)value;
3224         struct wait_data *wait = (struct wait_data*)user_data;
3225         HANDLE handle;
3226
3227         /* 
3228          * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3229          * limitation.
3230          * This needs no locking.
3231          */
3232         if ((thread->state & ThreadState_Suspended) != 0 || 
3233                 (thread->state & ThreadState_Stopped) != 0)
3234                 return;
3235
3236         if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3237                 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3238                 if (handle == NULL)
3239                         return;
3240
3241                 wait->handles [wait->num] = handle;
3242                 wait->threads [wait->num] = thread;
3243                 wait->num++;
3244         }
3245 }
3246
3247 /*
3248  * mono_thread_suspend_all_other_threads:
3249  *
3250  *  Suspend all managed threads except the finalizer thread and this thread. It is
3251  * not possible to resume them later.
3252  */
3253 void mono_thread_suspend_all_other_threads (void)
3254 {
3255         struct wait_data wait_data;
3256         struct wait_data *wait = &wait_data;
3257         int i;
3258         MonoNativeThreadId self = mono_native_thread_id_get ();
3259         guint32 eventidx = 0;
3260         gboolean starting, finished;
3261
3262         memset (wait, 0, sizeof (struct wait_data));
3263         /*
3264          * The other threads could be in an arbitrary state at this point, i.e.
3265          * they could be starting up, shutting down etc. This means that there could be
3266          * threads which are not even in the threads hash table yet.
3267          */
3268
3269         /* 
3270          * First we set a barrier which will be checked by all threads before they
3271          * are added to the threads hash table, and they will exit if the flag is set.
3272          * This ensures that no threads could be added to the hash later.
3273          * We will use shutting_down as the barrier for now.
3274          */
3275         g_assert (shutting_down);
3276
3277         /*
3278          * We make multiple calls to WaitForMultipleObjects since:
3279          * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3280          * - some threads could exit without becoming suspended
3281          */
3282         finished = FALSE;
3283         while (!finished) {
3284                 /*
3285                  * Make a copy of the hashtable since we can't do anything with
3286                  * threads while threads_mutex is held.
3287                  */
3288                 wait->num = 0;
3289                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3290                 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3291                 mono_threads_lock ();
3292                 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3293                 mono_threads_unlock ();
3294
3295                 eventidx = 0;
3296                 /* Get the suspended events that we'll be waiting for */
3297                 for (i = 0; i < wait->num; ++i) {
3298                         MonoInternalThread *thread = wait->threads [i];
3299
3300                         if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3301                              || mono_gc_is_finalizer_internal_thread (thread)
3302                              || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3303                         ) {
3304                                 //mono_threads_close_thread_handle (wait->handles [i]);
3305                                 wait->threads [i] = NULL; /* ignore this thread in next loop */
3306                                 continue;
3307                         }
3308
3309                         LOCK_THREAD (thread);
3310
3311                         if ((thread->state & ThreadState_Suspended) != 0 || 
3312                                 (thread->state & ThreadState_StopRequested) != 0 ||
3313                                 (thread->state & ThreadState_Stopped) != 0) {
3314                                 UNLOCK_THREAD (thread);
3315                                 mono_threads_close_thread_handle (wait->handles [i]);
3316                                 wait->threads [i] = NULL; /* ignore this thread in next loop */
3317                                 continue;
3318                         }
3319
3320                         ++eventidx;
3321
3322                         /* Convert abort requests into suspend requests */
3323                         if ((thread->state & ThreadState_AbortRequested) != 0)
3324                                 thread->state &= ~ThreadState_AbortRequested;
3325                         
3326                         thread->state |= ThreadState_SuspendRequested;
3327
3328                         /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3329                         async_suspend_internal (thread, TRUE);
3330                 }
3331                 if (eventidx <= 0) {
3332                         /* 
3333                          * If there are threads which are starting up, we wait until they
3334                          * are suspended when they try to register in the threads hash.
3335                          * This is guaranteed to finish, since the threads which can create new
3336                          * threads get suspended after a while.
3337                          * FIXME: The finalizer thread can still create new threads.
3338                          */
3339                         mono_threads_lock ();
3340                         if (threads_starting_up)
3341                                 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3342                         else
3343                                 starting = FALSE;
3344                         mono_threads_unlock ();
3345                         if (starting)
3346                                 mono_thread_info_sleep (100, NULL);
3347                         else
3348                                 finished = TRUE;
3349                 }
3350         }
3351 }
3352
3353 typedef struct {
3354         MonoInternalThread *thread;
3355         MonoStackFrameInfo *frames;
3356         int nframes, max_frames;
3357         int nthreads, max_threads;
3358         MonoInternalThread **threads;
3359 } ThreadDumpUserData;
3360
3361 static gboolean thread_dump_requested;
3362
3363 /* This needs to be async safe */
3364 static gboolean
3365 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3366 {
3367         ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3368
3369         if (ud->nframes < ud->max_frames) {
3370                 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3371                 ud->nframes ++;
3372         }
3373
3374         return FALSE;
3375 }
3376
3377 /* This needs to be async safe */
3378 static SuspendThreadResult
3379 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3380 {
3381         ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3382         MonoInternalThread *thread = user_data->thread;
3383
3384 #if 0
3385 /* This no longer works with remote unwinding */
3386         g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3387         mono_thread_internal_describe (thread, text);
3388         g_string_append (text, "\n");
3389 #endif
3390
3391         if (thread == mono_thread_internal_current ())
3392                 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3393         else
3394                 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3395
3396         return MonoResumeThread;
3397 }
3398
3399 typedef struct {
3400         int nthreads, max_threads;
3401         MonoInternalThread **threads;
3402 } CollectThreadsUserData;
3403
3404 static void
3405 collect_thread (gpointer key, gpointer value, gpointer user)
3406 {
3407         CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3408         MonoInternalThread *thread = (MonoInternalThread *)value;
3409
3410         if (ud->nthreads < ud->max_threads)
3411                 ud->threads [ud->nthreads ++] = thread;
3412 }
3413
3414 /*
3415  * Collect running threads into the THREADS array.
3416  * THREADS should be an array allocated on the stack.
3417  */
3418 static int
3419 collect_threads (MonoInternalThread **thread_array, int max_threads)
3420 {
3421         CollectThreadsUserData ud;
3422
3423         memset (&ud, 0, sizeof (ud));
3424         /* This array contains refs, but its on the stack, so its ok */
3425         ud.threads = thread_array;
3426         ud.max_threads = max_threads;
3427
3428         mono_threads_lock ();
3429         mono_g_hash_table_foreach (threads, collect_thread, &ud);
3430         mono_threads_unlock ();
3431
3432         return ud.nthreads;
3433 }
3434
3435 static void
3436 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3437 {
3438         GString* text = g_string_new (0);
3439         char *name;
3440         GError *error = NULL;
3441         int i;
3442
3443         ud->thread = thread;
3444         ud->nframes = 0;
3445
3446         /* Collect frames for the thread */
3447         if (thread == mono_thread_internal_current ()) {
3448                 get_thread_dump (mono_thread_info_current (), ud);
3449         } else {
3450                 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3451         }
3452
3453         /*
3454          * Do all the non async-safe work outside of get_thread_dump.
3455          */
3456         if (thread->name) {
3457                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3458                 g_assert (!error);
3459                 g_string_append_printf (text, "\n\"%s\"", name);
3460                 g_free (name);
3461         }
3462         else if (thread->threadpool_thread) {
3463                 g_string_append (text, "\n\"<threadpool thread>\"");
3464         } else {
3465                 g_string_append (text, "\n\"<unnamed thread>\"");
3466         }
3467
3468         for (i = 0; i < ud->nframes; ++i) {
3469                 MonoStackFrameInfo *frame = &ud->frames [i];
3470                 MonoMethod *method = NULL;
3471
3472                 if (frame->type == FRAME_TYPE_MANAGED)
3473                         method = mono_jit_info_get_method (frame->ji);
3474
3475                 if (method) {
3476                         gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3477                         g_string_append_printf (text, "  %s\n", location);
3478                         g_free (location);
3479                 } else {
3480                         g_string_append_printf (text, "  at <unknown> <0x%05x>\n", frame->native_offset);
3481                 }
3482         }
3483
3484         fprintf (stdout, "%s", text->str);
3485
3486 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3487         OutputDebugStringA(text->str);
3488 #endif
3489
3490         g_string_free (text, TRUE);
3491         fflush (stdout);
3492 }
3493
3494 void
3495 mono_threads_perform_thread_dump (void)
3496 {
3497         ThreadDumpUserData ud;
3498         MonoInternalThread *thread_array [128];
3499         int tindex, nthreads;
3500
3501         if (!thread_dump_requested)
3502                 return;
3503
3504         printf ("Full thread dump:\n");
3505
3506         /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3507         nthreads = collect_threads (thread_array, 128);
3508
3509         memset (&ud, 0, sizeof (ud));
3510         ud.frames = g_new0 (MonoStackFrameInfo, 256);
3511         ud.max_frames = 256;
3512
3513         for (tindex = 0; tindex < nthreads; ++tindex)
3514                 dump_thread (thread_array [tindex], &ud);
3515
3516         g_free (ud.frames);
3517
3518         thread_dump_requested = FALSE;
3519 }
3520
3521 /* Obtain the thread dump of all threads */
3522 static gboolean
3523 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3524 {
3525
3526         ThreadDumpUserData ud;
3527         MonoInternalThread *thread_array [128];
3528         MonoDomain *domain = mono_domain_get ();
3529         MonoDebugSourceLocation *location;
3530         int tindex, nthreads;
3531
3532         mono_error_init (error);
3533         
3534         *out_threads = NULL;
3535         *out_stack_frames = NULL;
3536
3537         /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3538         nthreads = collect_threads (thread_array, 128);
3539
3540         memset (&ud, 0, sizeof (ud));
3541         ud.frames = g_new0 (MonoStackFrameInfo, 256);
3542         ud.max_frames = 256;
3543
3544         *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3545         if (!is_ok (error))
3546                 goto leave;
3547         *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3548         if (!is_ok (error))
3549                 goto leave;
3550
3551         for (tindex = 0; tindex < nthreads; ++tindex) {
3552                 MonoInternalThread *thread = thread_array [tindex];
3553                 MonoArray *thread_frames;
3554                 int i;
3555
3556                 ud.thread = thread;
3557                 ud.nframes = 0;
3558
3559                 /* Collect frames for the thread */
3560                 if (thread == mono_thread_internal_current ()) {
3561                         get_thread_dump (mono_thread_info_current (), &ud);
3562                 } else {
3563                         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3564                 }
3565
3566                 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3567
3568                 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3569                 if (!is_ok (error))
3570                         goto leave;
3571                 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3572
3573                 for (i = 0; i < ud.nframes; ++i) {
3574                         MonoStackFrameInfo *frame = &ud.frames [i];
3575                         MonoMethod *method = NULL;
3576                         MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3577                         if (!is_ok (error))
3578                                 goto leave;
3579
3580                         sf->native_offset = frame->native_offset;
3581
3582                         if (frame->type == FRAME_TYPE_MANAGED)
3583                                 method = mono_jit_info_get_method (frame->ji);
3584
3585                         if (method) {
3586                                 sf->method_address = (gsize) frame->ji->code_start;
3587
3588                                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3589                                 if (!is_ok (error))
3590                                         goto leave;
3591                                 MONO_OBJECT_SETREF (sf, method, rm);
3592
3593                                 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3594                                 if (location) {
3595                                         sf->il_offset = location->il_offset;
3596
3597                                         if (location && location->source_file) {
3598                                                 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3599                                                 sf->line = location->row;
3600                                                 sf->column = location->column;
3601                                         }
3602                                         mono_debug_free_source_location (location);
3603                                 } else {
3604                                         sf->il_offset = -1;
3605                                 }
3606                         }
3607                         mono_array_setref (thread_frames, i, sf);
3608                 }
3609         }
3610
3611 leave:
3612         g_free (ud.frames);
3613         return is_ok (error);
3614 }
3615
3616 /**
3617  * mono_threads_request_thread_dump:
3618  *
3619  *   Ask all threads except the current to print their stacktrace to stdout.
3620  */
3621 void
3622 mono_threads_request_thread_dump (void)
3623 {
3624         /*The new thread dump code runs out of the finalizer thread. */
3625         thread_dump_requested = TRUE;
3626         mono_gc_finalize_notify ();
3627 }
3628
3629 struct ref_stack {
3630         gpointer *refs;
3631         gint allocated; /* +1 so that refs [allocated] == NULL */
3632         gint bottom;
3633 };
3634
3635 typedef struct ref_stack RefStack;
3636
3637 static RefStack *
3638 ref_stack_new (gint initial_size)
3639 {
3640         RefStack *rs;
3641
3642         initial_size = MAX (initial_size, 16) + 1;
3643         rs = g_new0 (RefStack, 1);
3644         rs->refs = g_new0 (gpointer, initial_size);
3645         rs->allocated = initial_size;
3646         return rs;
3647 }
3648
3649 static void
3650 ref_stack_destroy (gpointer ptr)
3651 {
3652         RefStack *rs = (RefStack *)ptr;
3653
3654         if (rs != NULL) {
3655                 g_free (rs->refs);
3656                 g_free (rs);
3657         }
3658 }
3659
3660 static void
3661 ref_stack_push (RefStack *rs, gpointer ptr)
3662 {
3663         g_assert (rs != NULL);
3664
3665         if (rs->bottom >= rs->allocated) {
3666                 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3667                 rs->allocated <<= 1;
3668                 rs->refs [rs->allocated] = NULL;
3669         }
3670         rs->refs [rs->bottom++] = ptr;
3671 }
3672
3673 static void
3674 ref_stack_pop (RefStack *rs)
3675 {
3676         if (rs == NULL || rs->bottom == 0)
3677                 return;
3678
3679         rs->bottom--;
3680         rs->refs [rs->bottom] = NULL;
3681 }
3682
3683 static gboolean
3684 ref_stack_find (RefStack *rs, gpointer ptr)
3685 {
3686         gpointer *refs;
3687
3688         if (rs == NULL)
3689                 return FALSE;
3690
3691         for (refs = rs->refs; refs && *refs; refs++) {
3692                 if (*refs == ptr)
3693                         return TRUE;
3694         }
3695         return FALSE;
3696 }
3697
3698 /*
3699  * mono_thread_push_appdomain_ref:
3700  *
3701  *   Register that the current thread may have references to objects in domain 
3702  * @domain on its stack. Each call to this function should be paired with a 
3703  * call to pop_appdomain_ref.
3704  */
3705 void 
3706 mono_thread_push_appdomain_ref (MonoDomain *domain)
3707 {
3708         MonoInternalThread *thread = mono_thread_internal_current ();
3709
3710         if (thread) {
3711                 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3712                 SPIN_LOCK (thread->lock_thread_id);
3713                 if (thread->appdomain_refs == NULL)
3714                         thread->appdomain_refs = ref_stack_new (16);
3715                 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3716                 SPIN_UNLOCK (thread->lock_thread_id);
3717         }
3718 }
3719
3720 void
3721 mono_thread_pop_appdomain_ref (void)
3722 {
3723         MonoInternalThread *thread = mono_thread_internal_current ();
3724
3725         if (thread) {
3726                 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3727                 SPIN_LOCK (thread->lock_thread_id);
3728                 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3729                 SPIN_UNLOCK (thread->lock_thread_id);
3730         }
3731 }
3732
3733 gboolean
3734 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3735 {
3736         gboolean res;
3737         SPIN_LOCK (thread->lock_thread_id);
3738         res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3739         SPIN_UNLOCK (thread->lock_thread_id);
3740         return res;
3741 }
3742
3743 gboolean
3744 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3745 {
3746         return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3747 }
3748
3749 typedef struct abort_appdomain_data {
3750         struct wait_data wait;
3751         MonoDomain *domain;
3752 } abort_appdomain_data;
3753
3754 static void
3755 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3756 {
3757         MonoInternalThread *thread = (MonoInternalThread*)value;
3758         abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3759         MonoDomain *domain = data->domain;
3760
3761         if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3762                 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3763
3764                 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3765                         HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3766                         if (handle == NULL)
3767                                 return;
3768                         data->wait.handles [data->wait.num] = handle;
3769                         data->wait.threads [data->wait.num] = thread;
3770                         data->wait.num++;
3771                 } else {
3772                         /* Just ignore the rest, we can't do anything with
3773                          * them yet
3774                          */
3775                 }
3776         }
3777 }
3778
3779 /*
3780  * mono_threads_abort_appdomain_threads:
3781  *
3782  *   Abort threads which has references to the given appdomain.
3783  */
3784 gboolean
3785 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3786 {
3787 #ifdef __native_client__
3788         return FALSE;
3789 #endif
3790
3791         abort_appdomain_data user_data;
3792         gint64 start_time;
3793         int orig_timeout = timeout;
3794         int i;
3795
3796         THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3797
3798         start_time = mono_msec_ticks ();
3799         do {
3800                 mono_threads_lock ();
3801
3802                 user_data.domain = domain;
3803                 user_data.wait.num = 0;
3804                 /* This shouldn't take any locks */
3805                 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3806                 mono_threads_unlock ();
3807
3808                 if (user_data.wait.num > 0) {
3809                         /* Abort the threads outside the threads lock */
3810                         for (i = 0; i < user_data.wait.num; ++i)
3811                                 mono_thread_internal_abort (user_data.wait.threads [i]);
3812
3813                         /*
3814                          * We should wait for the threads either to abort, or to leave the
3815                          * domain. We can't do the latter, so we wait with a timeout.
3816                          */
3817                         wait_for_tids (&user_data.wait, 100);
3818                 }
3819
3820                 /* Update remaining time */
3821                 timeout -= mono_msec_ticks () - start_time;
3822                 start_time = mono_msec_ticks ();
3823
3824                 if (orig_timeout != -1 && timeout < 0)
3825                         return FALSE;
3826         }
3827         while (user_data.wait.num > 0);
3828
3829         THREAD_DEBUG (g_message ("%s: abort done", __func__));
3830
3831         return TRUE;
3832 }
3833
3834 static void
3835 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3836 {
3837         MonoInternalThread *thread = (MonoInternalThread*)value;
3838         MonoDomain *domain = (MonoDomain*)user_data;
3839         int i;
3840
3841         /* No locking needed here */
3842         /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3843
3844         if (thread->cached_culture_info) {
3845                 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3846                         MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3847                         if (obj && obj->vtable->domain == domain)
3848                                 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3849                 }
3850         }
3851 }
3852         
3853 /*
3854  * mono_threads_clear_cached_culture:
3855  *
3856  *   Clear the cached_current_culture from all threads if it is in the
3857  * given appdomain.
3858  */
3859 void
3860 mono_threads_clear_cached_culture (MonoDomain *domain)
3861 {
3862         mono_threads_lock ();
3863         mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3864         mono_threads_unlock ();
3865 }
3866
3867 /*
3868  * mono_thread_get_undeniable_exception:
3869  *
3870  *   Return an exception which needs to be raised when leaving a catch clause.
3871  * This is used for undeniable exception propagation.
3872  */
3873 MonoException*
3874 mono_thread_get_undeniable_exception (void)
3875 {
3876         MonoInternalThread *thread = mono_thread_internal_current ();
3877
3878         if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3879                 /*
3880                  * FIXME: Clear the abort exception and return an AppDomainUnloaded 
3881                  * exception if the thread no longer references a dying appdomain.
3882                  */
3883                 thread->abort_exc->trace_ips = NULL;
3884                 thread->abort_exc->stack_trace = NULL;
3885                 return thread->abort_exc;
3886         }
3887
3888         return NULL;
3889 }
3890
3891 #if MONO_SMALL_CONFIG
3892 #define NUM_STATIC_DATA_IDX 4
3893 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3894         64, 256, 1024, 4096
3895 };
3896 #else
3897 #define NUM_STATIC_DATA_IDX 8
3898 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3899         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3900 };
3901 #endif
3902
3903 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3904 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3905
3906 static void
3907 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3908 {
3909         gpointer *static_data = (gpointer *)addr;
3910
3911         for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3912                 void **ptr = (void **)static_data [i];
3913
3914                 if (!ptr)
3915                         continue;
3916
3917                 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3918                         void **p = ptr + idx;
3919
3920                         if (*p)
3921                                 mark_func ((MonoObject**)p, gc_data);
3922                 });
3923         }
3924 }
3925
3926 static void
3927 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3928 {
3929         mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3930 }
3931
3932 static void
3933 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3934 {
3935         mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3936 }
3937
3938 /*
3939  *  mono_alloc_static_data
3940  *
3941  *   Allocate memory blocks for storing threads or context static data
3942  */
3943 static void 
3944 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3945 {
3946         guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3947         int i;
3948
3949         gpointer* static_data = *static_data_ptr;
3950         if (!static_data) {
3951                 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3952                 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3953
3954                 if (mono_gc_user_markers_supported ()) {
3955                         if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3956                                 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3957
3958                         if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3959                                 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3960                 }
3961
3962                 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3963                         threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3964                         threadlocal ? "managed thread-static variables" : "managed context-static variables");
3965                 *static_data_ptr = static_data;
3966                 static_data [0] = static_data;
3967         }
3968
3969         for (i = 1; i <= idx; ++i) {
3970                 if (static_data [i])
3971                         continue;
3972
3973                 if (mono_gc_user_markers_supported ())
3974                         static_data [i] = g_malloc0 (static_data_size [i]);
3975                 else
3976                         static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3977                                 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3978                                 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3979         }
3980 }
3981
3982 static void 
3983 mono_free_static_data (gpointer* static_data)
3984 {
3985         int i;
3986         for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3987                 gpointer p = static_data [i];
3988                 if (!p)
3989                         continue;
3990                 /*
3991                  * At this point, the static data pointer array is still registered with the
3992                  * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3993                  * data.  Freeing the individual arrays without first nulling their slots
3994                  * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3995                  * such an already freed array.  See bug #13813.
3996                  */
3997                 static_data [i] = NULL;
3998                 mono_memory_write_barrier ();
3999                 if (mono_gc_user_markers_supported ())
4000                         g_free (p);
4001                 else
4002                         mono_gc_free_fixed (p);
4003         }
4004         mono_gc_free_fixed (static_data);
4005 }
4006
4007 /*
4008  *  mono_init_static_data_info
4009  *
4010  *   Initializes static data counters
4011  */
4012 static void mono_init_static_data_info (StaticDataInfo *static_data)
4013 {
4014         static_data->idx = 0;
4015         static_data->offset = 0;
4016         static_data->freelist = NULL;
4017 }
4018
4019 /*
4020  *  mono_alloc_static_data_slot
4021  *
4022  *   Generates an offset for static data. static_data contains the counters
4023  *  used to generate it.
4024  */
4025 static guint32
4026 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4027 {
4028         if (!static_data->idx && !static_data->offset) {
4029                 /* 
4030                  * we use the first chunk of the first allocation also as
4031                  * an array for the rest of the data 
4032                  */
4033                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4034         }
4035         static_data->offset += align - 1;
4036         static_data->offset &= ~(align - 1);
4037         if (static_data->offset + size >= static_data_size [static_data->idx]) {
4038                 static_data->idx ++;
4039                 g_assert (size <= static_data_size [static_data->idx]);
4040                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4041                 static_data->offset = 0;
4042         }
4043         guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4044         static_data->offset += size;
4045         return offset;
4046 }
4047
4048 /*
4049  * LOCKING: requires that threads_mutex is held
4050  */
4051 static void
4052 context_adjust_static_data (MonoAppContext *ctx)
4053 {
4054         if (context_static_info.offset || context_static_info.idx > 0) {
4055                 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4056                 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4057                 ctx->data->static_data = ctx->static_data;
4058         }
4059 }
4060
4061 /*
4062  * LOCKING: requires that threads_mutex is held
4063  */
4064 static void 
4065 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4066 {
4067         MonoInternalThread *thread = (MonoInternalThread *)value;
4068         guint32 offset = GPOINTER_TO_UINT (user);
4069
4070         mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4071 }
4072
4073 /*
4074  * LOCKING: requires that threads_mutex is held
4075  */
4076 static void
4077 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4078 {
4079         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4080
4081         if (!ctx)
4082                 return;
4083
4084         guint32 offset = GPOINTER_TO_UINT (user);
4085         mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4086         ctx->data->static_data = ctx->static_data;
4087 }
4088
4089 static StaticDataFreeList*
4090 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4091 {
4092         StaticDataFreeList* prev = NULL;
4093         StaticDataFreeList* tmp = static_data->freelist;
4094         while (tmp) {
4095                 if (tmp->size == size) {
4096                         if (prev)
4097                                 prev->next = tmp->next;
4098                         else
4099                                 static_data->freelist = tmp->next;
4100                         return tmp;
4101                 }
4102                 prev = tmp;
4103                 tmp = tmp->next;
4104         }
4105         return NULL;
4106 }
4107
4108 #if SIZEOF_VOID_P == 4
4109 #define ONE_P 1
4110 #else
4111 #define ONE_P 1ll
4112 #endif
4113
4114 static void
4115 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4116 {
4117         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4118         if (!sets [idx])
4119                 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4120         MonoBitSet *rb = sets [idx];
4121         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4122         offset /= sizeof (uintptr_t);
4123         /* offset is now the bitmap offset */
4124         for (int i = 0; i < numbits; ++i) {
4125                 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4126                         mono_bitset_set_fast (rb, offset + i);
4127         }
4128 }
4129
4130 static void
4131 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4132 {
4133         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4134         MonoBitSet *rb = sets [idx];
4135         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4136         offset /= sizeof (uintptr_t);
4137         /* offset is now the bitmap offset */
4138         for (int i = 0; i < size / sizeof (uintptr_t); i++)
4139                 mono_bitset_clear_fast (rb, offset + i);
4140 }
4141
4142 guint32
4143 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4144 {
4145         g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4146
4147         StaticDataInfo *info;
4148         MonoBitSet **sets;
4149
4150         if (static_type == SPECIAL_STATIC_THREAD) {
4151                 info = &thread_static_info;
4152                 sets = thread_reference_bitmaps;
4153         } else {
4154                 info = &context_static_info;
4155                 sets = context_reference_bitmaps;
4156         }
4157
4158         mono_threads_lock ();
4159
4160         StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4161         guint32 offset;
4162
4163         if (item) {
4164                 offset = item->offset;
4165                 g_free (item);
4166         } else {
4167                 offset = mono_alloc_static_data_slot (info, size, align);
4168         }
4169
4170         update_reference_bitmap (sets, offset, bitmap, numbits);
4171
4172         if (static_type == SPECIAL_STATIC_THREAD) {
4173                 /* This can be called during startup */
4174                 if (threads != NULL)
4175                         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4176         } else {
4177                 if (contexts != NULL)
4178                         g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4179
4180                 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4181         }
4182
4183         mono_threads_unlock ();
4184
4185         return offset;
4186 }
4187
4188 gpointer
4189 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4190 {
4191         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4192
4193         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4194                 return get_thread_static_data (thread, offset);
4195         } else {
4196                 return get_context_static_data (thread->current_appcontext, offset);
4197         }
4198 }
4199
4200 gpointer
4201 mono_get_special_static_data (guint32 offset)
4202 {
4203         return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4204 }
4205
4206 typedef struct {
4207         guint32 offset;
4208         guint32 size;
4209 } OffsetSize;
4210
4211 /*
4212  * LOCKING: requires that threads_mutex is held
4213  */
4214 static void 
4215 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4216 {
4217         MonoInternalThread *thread = (MonoInternalThread *)value;
4218         OffsetSize *data = (OffsetSize *)user;
4219         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4220         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4221         char *ptr;
4222
4223         if (!thread->static_data || !thread->static_data [idx])
4224                 return;
4225         ptr = ((char*) thread->static_data [idx]) + off;
4226         mono_gc_bzero_atomic (ptr, data->size);
4227 }
4228
4229 /*
4230  * LOCKING: requires that threads_mutex is held
4231  */
4232 static void
4233 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4234 {
4235         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4236
4237         if (!ctx)
4238                 return;
4239
4240         OffsetSize *data = (OffsetSize *)user;
4241         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4242         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4243         char *ptr;
4244
4245         if (!ctx->static_data || !ctx->static_data [idx])
4246                 return;
4247
4248         ptr = ((char*) ctx->static_data [idx]) + off;
4249         mono_gc_bzero_atomic (ptr, data->size);
4250 }
4251
4252 static void
4253 do_free_special_slot (guint32 offset, guint32 size)
4254 {
4255         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4256         MonoBitSet **sets;
4257         StaticDataInfo *info;
4258
4259         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4260                 info = &thread_static_info;
4261                 sets = thread_reference_bitmaps;
4262         } else {
4263                 info = &context_static_info;
4264                 sets = context_reference_bitmaps;
4265         }
4266
4267         guint32 data_offset = offset;
4268         ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4269         OffsetSize data = { data_offset, size };
4270
4271         clear_reference_bitmap (sets, data.offset, data.size);
4272
4273         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4274                 if (threads != NULL)
4275                         mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4276         } else {
4277                 if (contexts != NULL)
4278                         g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4279         }
4280
4281         if (!mono_runtime_is_shutting_down ()) {
4282                 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4283
4284                 item->offset = offset;
4285                 item->size = size;
4286
4287                 item->next = info->freelist;
4288                 info->freelist = item;
4289         }
4290 }
4291
4292 static void
4293 do_free_special (gpointer key, gpointer value, gpointer data)
4294 {
4295         MonoClassField *field = (MonoClassField *)key;
4296         guint32 offset = GPOINTER_TO_UINT (value);
4297         gint32 align;
4298         guint32 size;
4299         size = mono_type_size (field->type, &align);
4300         do_free_special_slot (offset, size);
4301 }
4302
4303 void
4304 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4305 {
4306         mono_threads_lock ();
4307
4308         g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4309
4310         mono_threads_unlock ();
4311 }
4312
4313 #ifdef HOST_WIN32
4314 static void CALLBACK dummy_apc (ULONG_PTR param)
4315 {
4316 }
4317 #endif
4318
4319 /*
4320  * mono_thread_execute_interruption
4321  * 
4322  * Performs the operation that the requested thread state requires (abort,
4323  * suspend or stop)
4324  */
4325 static MonoException*
4326 mono_thread_execute_interruption (void)
4327 {
4328         MonoInternalThread *thread = mono_thread_internal_current ();
4329         MonoThread *sys_thread = mono_thread_current ();
4330
4331         LOCK_THREAD (thread);
4332
4333         /* MonoThread::interruption_requested can only be changed with atomics */
4334         if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4335                 /* this will consume pending APC calls */
4336 #ifdef HOST_WIN32
4337                 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4338 #endif
4339                 InterlockedDecrement (&thread_interruption_requested);
4340
4341                 /* Clear the interrupted flag of the thread so it can wait again */
4342                 mono_thread_info_clear_self_interrupt ();
4343         }
4344
4345         /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4346         if (sys_thread->pending_exception) {
4347                 MonoException *exc;
4348
4349                 exc = sys_thread->pending_exception;
4350                 sys_thread->pending_exception = NULL;
4351
4352                 UNLOCK_THREAD (thread);
4353                 return exc;
4354         } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4355                 UNLOCK_THREAD (thread);
4356                 g_assert (sys_thread->pending_exception == NULL);
4357                 if (thread->abort_exc == NULL) {
4358                         /* 
4359                          * This might be racy, but it has to be called outside the lock
4360                          * since it calls managed code.
4361                          */
4362                         MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4363                 }
4364                 return thread->abort_exc;
4365         }
4366         else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4367                 /* calls UNLOCK_THREAD (thread) */
4368                 self_suspend_internal ();
4369                 return NULL;
4370         }
4371         else if ((thread->state & ThreadState_StopRequested) != 0) {
4372                 /* FIXME: do this through the JIT? */
4373
4374                 UNLOCK_THREAD (thread);
4375                 
4376                 mono_thread_exit ();
4377                 return NULL;
4378         } else if (thread->thread_interrupt_requested) {
4379
4380                 thread->thread_interrupt_requested = FALSE;
4381                 UNLOCK_THREAD (thread);
4382                 
4383                 return(mono_get_exception_thread_interrupted ());
4384         }
4385         
4386         UNLOCK_THREAD (thread);
4387         
4388         return NULL;
4389 }
4390
4391 /*
4392  * mono_thread_request_interruption
4393  *
4394  * A signal handler can call this method to request the interruption of a
4395  * thread. The result of the interruption will depend on the current state of
4396  * the thread. If the result is an exception that needs to be throw, it is 
4397  * provided as return value.
4398  */
4399 MonoException*
4400 mono_thread_request_interruption (gboolean running_managed)
4401 {
4402         MonoInternalThread *thread = mono_thread_internal_current ();
4403
4404         /* The thread may already be stopping */
4405         if (thread == NULL) 
4406                 return NULL;
4407
4408 #ifdef HOST_WIN32
4409         if (thread->interrupt_on_stop && 
4410                 thread->state & ThreadState_StopRequested && 
4411                 thread->state & ThreadState_Background)
4412                 ExitThread (1);
4413 #endif
4414         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4415                 return NULL;
4416         InterlockedIncrement (&thread_interruption_requested);
4417
4418         if (!running_managed || is_running_protected_wrapper ()) {
4419                 /* Can't stop while in unmanaged code. Increase the global interruption
4420                    request count. When exiting the unmanaged method the count will be
4421                    checked and the thread will be interrupted. */
4422
4423                 /* this will awake the thread if it is in WaitForSingleObject 
4424                    or similar */
4425                 /* Our implementation of this function ignores the func argument */
4426 #ifdef HOST_WIN32
4427                 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4428 #else
4429                 mono_thread_info_self_interrupt ();
4430 #endif
4431                 return NULL;
4432         }
4433         else {
4434                 return mono_thread_execute_interruption ();
4435         }
4436 }
4437
4438 /*This function should be called by a thread after it has exited all of
4439  * its handle blocks at interruption time.*/
4440 MonoException*
4441 mono_thread_resume_interruption (void)
4442 {
4443         MonoInternalThread *thread = mono_thread_internal_current ();
4444         gboolean still_aborting;
4445
4446         /* The thread may already be stopping */
4447         if (thread == NULL)
4448                 return NULL;
4449
4450         LOCK_THREAD (thread);
4451         still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4452         UNLOCK_THREAD (thread);
4453
4454         /*This can happen if the protected block called Thread::ResetAbort*/
4455         if (!still_aborting)
4456                 return FALSE;
4457
4458         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4459                 return NULL;
4460         InterlockedIncrement (&thread_interruption_requested);
4461
4462         mono_thread_info_self_interrupt ();
4463
4464         return mono_thread_execute_interruption ();
4465 }
4466
4467 gboolean mono_thread_interruption_requested ()
4468 {
4469         if (thread_interruption_requested) {
4470                 MonoInternalThread *thread = mono_thread_internal_current ();
4471                 /* The thread may already be stopping */
4472                 if (thread != NULL) 
4473                         return (thread->interruption_requested);
4474         }
4475         return FALSE;
4476 }
4477
4478 static MonoException*
4479 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4480 {
4481         MonoInternalThread *thread = mono_thread_internal_current ();
4482
4483         /* The thread may already be stopping */
4484         if (thread == NULL)
4485                 return NULL;
4486
4487         if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4488                 MonoException* exc = mono_thread_execute_interruption ();
4489                 if (exc)
4490                         return exc;
4491         }
4492         return NULL;
4493 }
4494
4495 /*
4496  * Performs the interruption of the current thread, if one has been requested,
4497  * and the thread is not running a protected wrapper.
4498  * Return the exception which needs to be thrown, if any.
4499  */
4500 MonoException*
4501 mono_thread_interruption_checkpoint (void)
4502 {
4503         return mono_thread_interruption_checkpoint_request (FALSE);
4504 }
4505
4506 /*
4507  * Performs the interruption of the current thread, if one has been requested.
4508  * Return the exception which needs to be thrown, if any.
4509  */
4510 MonoException*
4511 mono_thread_force_interruption_checkpoint_noraise (void)
4512 {
4513         return mono_thread_interruption_checkpoint_request (TRUE);
4514 }
4515
4516 /*
4517  * mono_set_pending_exception:
4518  *
4519  *   Set the pending exception of the current thread to EXC.
4520  * The exception will be thrown when execution returns to managed code.
4521  */
4522 void
4523 mono_set_pending_exception (MonoException *exc)
4524 {
4525         MonoThread *thread = mono_thread_current ();
4526
4527         /* The thread may already be stopping */
4528         if (thread == NULL)
4529                 return;
4530
4531         MONO_OBJECT_SETREF (thread, pending_exception, exc);
4532
4533     mono_thread_request_interruption (FALSE);
4534 }
4535
4536 /**
4537  * mono_thread_interruption_request_flag:
4538  *
4539  * Returns the address of a flag that will be non-zero if an interruption has
4540  * been requested for a thread. The thread to interrupt may not be the current
4541  * thread, so an additional call to mono_thread_interruption_requested() or
4542  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4543  * zero.
4544  */
4545 gint32* mono_thread_interruption_request_flag ()
4546 {
4547         return &thread_interruption_requested;
4548 }
4549
4550 void 
4551 mono_thread_init_apartment_state (void)
4552 {
4553 #ifdef HOST_WIN32
4554         MonoInternalThread* thread = mono_thread_internal_current ();
4555
4556         /* Positive return value indicates success, either
4557          * S_OK if this is first CoInitialize call, or
4558          * S_FALSE if CoInitialize already called, but with same
4559          * threading model. A negative value indicates failure,
4560          * probably due to trying to change the threading model.
4561          */
4562         if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA) 
4563                         ? COINIT_APARTMENTTHREADED 
4564                         : COINIT_MULTITHREADED) < 0) {
4565                 thread->apartment_state = ThreadApartmentState_Unknown;
4566         }
4567 #endif
4568 }
4569
4570 void 
4571 mono_thread_cleanup_apartment_state (void)
4572 {
4573 #ifdef HOST_WIN32
4574         MonoInternalThread* thread = mono_thread_internal_current ();
4575
4576         if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4577                 CoUninitialize ();
4578         }
4579 #endif
4580 }
4581
4582 void
4583 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4584 {
4585         LOCK_THREAD (thread);
4586         thread->state |= state;
4587         UNLOCK_THREAD (thread);
4588 }
4589
4590 /**
4591  * mono_thread_test_and_set_state:
4592  *
4593  * Test if current state of @thread include @test. If it does not, OR @set into the state.
4594  *
4595  * Returns TRUE is @set was OR'd in.
4596  */
4597 gboolean
4598 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4599 {
4600         LOCK_THREAD (thread);
4601
4602         if ((thread->state & test) != 0) {
4603                 UNLOCK_THREAD (thread);
4604                 return FALSE;
4605         }
4606
4607         thread->state |= set;
4608         UNLOCK_THREAD (thread);
4609
4610         return TRUE;
4611 }
4612
4613 void
4614 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4615 {
4616         LOCK_THREAD (thread);
4617         thread->state &= ~state;
4618         UNLOCK_THREAD (thread);
4619 }
4620
4621 gboolean
4622 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4623 {
4624         gboolean ret = FALSE;
4625
4626         LOCK_THREAD (thread);
4627
4628         if ((thread->state & test) != 0) {
4629                 ret = TRUE;
4630         }
4631         
4632         UNLOCK_THREAD (thread);
4633         
4634         return ret;
4635 }
4636
4637 static gboolean has_tls_get = FALSE;
4638
4639 void
4640 mono_runtime_set_has_tls_get (gboolean val)
4641 {
4642         has_tls_get = val;
4643 }
4644
4645 gboolean
4646 mono_runtime_has_tls_get (void)
4647 {
4648         return has_tls_get;
4649 }
4650
4651 static void
4652 self_interrupt_thread (void *_unused)
4653 {
4654         MonoThreadInfo *info = mono_thread_info_current ();
4655         MonoException *exc = mono_thread_execute_interruption ();
4656         if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4657                 mono_raise_exception_with_context (exc, &info->thread_saved_state [ASYNC_SUSPEND_STATE_INDEX].ctx); /* FIXME using thread_saved_state [ASYNC_SUSPEND_STATE_INDEX] can race with another suspend coming in. */
4658         g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4659 }
4660
4661 static gboolean
4662 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4663 {
4664         if (!ji)
4665                 return FALSE;
4666         return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4667 }
4668
4669 static gboolean
4670 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4671 {
4672         MonoJitInfo **dest = (MonoJitInfo **)data;
4673         *dest = frame->ji;
4674         return TRUE;
4675 }
4676
4677 static MonoJitInfo*
4678 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4679 {
4680         MonoJitInfo *ji = NULL;
4681         if (!info)
4682                 return NULL;
4683
4684         /*
4685          * The suspended thread might be holding runtime locks. Make sure we don't try taking
4686          * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4687          * where we hold runtime locks.
4688          */
4689         if (!mono_threads_is_coop_enabled ())
4690                 mono_thread_info_set_is_async_context (TRUE);
4691         mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4692         if (!mono_threads_is_coop_enabled ())
4693                 mono_thread_info_set_is_async_context (FALSE);
4694         return ji;
4695 }
4696
4697 typedef struct {
4698         MonoInternalThread *thread;
4699         gboolean install_async_abort;
4700         MonoThreadInfoInterruptToken *interrupt_token;
4701 } AbortThreadData;
4702
4703 static SuspendThreadResult
4704 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4705 {
4706         AbortThreadData *data = (AbortThreadData *)ud;
4707         MonoInternalThread *thread = data->thread;
4708         MonoJitInfo *ji = NULL;
4709         gboolean protected_wrapper;
4710         gboolean running_managed;
4711
4712         if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4713                 return MonoResumeThread;
4714
4715         /*
4716         The target thread is running at least one protected block, which must not be interrupted, so we give up.
4717         The protected block code will give them a chance when appropriate.
4718         */
4719         if (thread->abort_protected_block_count)
4720                 return MonoResumeThread;
4721
4722         /*someone is already interrupting it*/
4723         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4724                 return MonoResumeThread;
4725
4726         InterlockedIncrement (&thread_interruption_requested);
4727
4728         ji = mono_thread_info_get_last_managed (info);
4729         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4730         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4731
4732         if (!protected_wrapper && running_managed) {
4733                 /*We are in managed code*/
4734                 /*Set the thread to call */
4735                 if (data->install_async_abort)
4736                         mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4737                 return MonoResumeThread;
4738         } else {
4739                 /* 
4740                  * This will cause waits to be broken.
4741                  * It will also prevent the thread from entering a wait, so if the thread returns
4742                  * from the wait before it receives the abort signal, it will just spin in the wait
4743                  * functions in the io-layer until the signal handler calls QueueUserAPC which will
4744                  * make it return.
4745                  */
4746                 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4747
4748                 return MonoResumeThread;
4749         }
4750 }
4751
4752 static void
4753 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4754 {
4755         AbortThreadData data;
4756
4757         g_assert (thread != mono_thread_internal_current ());
4758
4759         data.thread = thread;
4760         data.install_async_abort = install_async_abort;
4761         data.interrupt_token = NULL;
4762
4763         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4764         if (data.interrupt_token)
4765                 mono_thread_info_finish_interrupt (data.interrupt_token);
4766         /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4767 }
4768
4769 static void
4770 self_abort_internal (MonoError *error)
4771 {
4772         MonoException *exc;
4773
4774         mono_error_init (error);
4775
4776         /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4777          * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4778
4779         /*
4780         Self aborts ignore the protected block logic and raise the TAE regardless. This is verified by one of the tests in mono/tests/abort-cctor.cs.
4781         */
4782         exc = mono_thread_request_interruption (TRUE);
4783         if (exc)
4784                 mono_error_set_exception_instance (error, exc);
4785         else
4786                 mono_thread_info_self_interrupt ();
4787 }
4788
4789 typedef struct {
4790         MonoInternalThread *thread;
4791         gboolean interrupt;
4792         MonoThreadInfoInterruptToken *interrupt_token;
4793 } SuspendThreadData;
4794
4795 static SuspendThreadResult
4796 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4797 {
4798         SuspendThreadData *data = (SuspendThreadData *)ud;
4799         MonoInternalThread *thread = data->thread;
4800         MonoJitInfo *ji = NULL;
4801         gboolean protected_wrapper;
4802         gboolean running_managed;
4803
4804         ji = mono_thread_info_get_last_managed (info);
4805         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4806         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4807
4808         if (running_managed && !protected_wrapper) {
4809                 thread->state &= ~ThreadState_SuspendRequested;
4810                 thread->state |= ThreadState_Suspended;
4811                 return KeepSuspended;
4812         } else {
4813                 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4814                         InterlockedIncrement (&thread_interruption_requested);
4815                 if (data->interrupt)
4816                         data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4817
4818                 return MonoResumeThread;
4819         }
4820 }
4821
4822 /* LOCKING: called with @thread synch_cs held, and releases it */
4823 static void
4824 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4825 {
4826         SuspendThreadData data;
4827
4828         g_assert (thread != mono_thread_internal_current ());
4829
4830         data.thread = thread;
4831         data.interrupt = interrupt;
4832         data.interrupt_token = NULL;
4833
4834         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4835         if (data.interrupt_token)
4836                 mono_thread_info_finish_interrupt (data.interrupt_token);
4837
4838         UNLOCK_THREAD (thread);
4839 }
4840
4841 /* LOCKING: called with @thread synch_cs held, and releases it */
4842 static void
4843 self_suspend_internal (void)
4844 {
4845         MonoInternalThread *thread;
4846
4847         thread = mono_thread_internal_current ();
4848
4849         mono_thread_info_begin_self_suspend ();
4850         thread->state &= ~ThreadState_SuspendRequested;
4851         thread->state |= ThreadState_Suspended;
4852
4853         UNLOCK_THREAD (thread);
4854
4855         mono_thread_info_end_self_suspend ();
4856 }
4857
4858 /*
4859  * mono_thread_is_foreign:
4860  * @thread: the thread to query
4861  *
4862  * This function allows one to determine if a thread was created by the mono runtime and has
4863  * a well defined lifecycle or it's a foreigh one, created by the native environment.
4864  *
4865  * Returns: TRUE if @thread was not created by the runtime.
4866  */
4867 mono_bool
4868 mono_thread_is_foreign (MonoThread *thread)
4869 {
4870         MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4871         return info->runtime_thread == FALSE;
4872 }
4873
4874 /*
4875  * mono_add_joinable_thread:
4876  *
4877  *   Add TID to the list of joinable threads.
4878  * LOCKING: Acquires the threads lock.
4879  */
4880 void
4881 mono_threads_add_joinable_thread (gpointer tid)
4882 {
4883 #ifndef HOST_WIN32
4884         /*
4885          * We cannot detach from threads because it causes problems like
4886          * 2fd16f60/r114307. So we collect them and join them when
4887          * we have time (in he finalizer thread).
4888          */
4889         joinable_threads_lock ();
4890         if (!joinable_threads)
4891                 joinable_threads = g_hash_table_new (NULL, NULL);
4892         g_hash_table_insert (joinable_threads, tid, tid);
4893         joinable_thread_count ++;
4894         joinable_threads_unlock ();
4895
4896         mono_gc_finalize_notify ();
4897 #endif
4898 }
4899
4900 /*
4901  * mono_threads_join_threads:
4902  *
4903  *   Join all joinable threads. This is called from the finalizer thread.
4904  * LOCKING: Acquires the threads lock.
4905  */
4906 void
4907 mono_threads_join_threads (void)
4908 {
4909 #ifndef HOST_WIN32
4910         GHashTableIter iter;
4911         gpointer key;
4912         gpointer tid;
4913         pthread_t thread;
4914         gboolean found;
4915
4916         /* Fastpath */
4917         if (!joinable_thread_count)
4918                 return;
4919
4920         while (TRUE) {
4921                 joinable_threads_lock ();
4922                 found = FALSE;
4923                 if (g_hash_table_size (joinable_threads)) {
4924                         g_hash_table_iter_init (&iter, joinable_threads);
4925                         g_hash_table_iter_next (&iter, &key, (void**)&tid);
4926                         thread = (pthread_t)tid;
4927                         g_hash_table_remove (joinable_threads, key);
4928                         joinable_thread_count --;
4929                         found = TRUE;
4930                 }
4931                 joinable_threads_unlock ();
4932                 if (found) {
4933                         if (thread != pthread_self ()) {
4934                                 MONO_ENTER_GC_SAFE;
4935                                 /* This shouldn't block */
4936                                 pthread_join (thread, NULL);
4937                                 MONO_EXIT_GC_SAFE;
4938                         }
4939                 } else {
4940                         break;
4941                 }
4942         }
4943 #endif
4944 }
4945
4946 /*
4947  * mono_thread_join:
4948  *
4949  *   Wait for thread TID to exit.
4950  * LOCKING: Acquires the threads lock.
4951  */
4952 void
4953 mono_thread_join (gpointer tid)
4954 {
4955 #ifndef HOST_WIN32
4956         pthread_t thread;
4957         gboolean found = FALSE;
4958
4959         joinable_threads_lock ();
4960         if (!joinable_threads)
4961                 joinable_threads = g_hash_table_new (NULL, NULL);
4962         if (g_hash_table_lookup (joinable_threads, tid)) {
4963                 g_hash_table_remove (joinable_threads, tid);
4964                 joinable_thread_count --;
4965                 found = TRUE;
4966         }
4967         joinable_threads_unlock ();
4968         if (!found)
4969                 return;
4970         thread = (pthread_t)tid;
4971         MONO_ENTER_GC_SAFE;
4972         pthread_join (thread, NULL);
4973         MONO_EXIT_GC_SAFE;
4974 #endif
4975 }
4976
4977 void
4978 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4979 {
4980         if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4981                 mono_thread_interruption_checkpoint ();
4982 }
4983
4984 void
4985 mono_thread_internal_unhandled_exception (MonoObject* exc)
4986 {
4987         MonoClass *klass = exc->vtable->klass;
4988         if (is_threadabort_exception (klass)) {
4989                 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4990         } else if (!is_appdomainunloaded_exception (klass)
4991                 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4992                 mono_unhandled_exception (exc);
4993                 if (mono_environment_exitcode_get () == 1) {
4994                         mono_environment_exitcode_set (255);
4995                         mono_invoke_unhandled_exception_hook (exc);
4996                         g_assert_not_reached ();
4997                 }
4998         }
4999 }
5000
5001 void
5002 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5003 {
5004         MonoError error;
5005         mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5006         mono_error_set_pending_exception (&error);
5007 }
5008
5009 /*
5010  * mono_threads_attach_coop: called by native->managed wrappers
5011  *
5012  * In non-coop mode:
5013  *  - @dummy: is NULL
5014  *  - @return: the original domain which needs to be restored, or NULL.
5015  *
5016  * In coop mode:
5017  *  - @dummy: contains the original domain
5018  *  - @return: a cookie containing current MonoThreadInfo*.
5019  */
5020 gpointer
5021 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5022 {
5023         MonoDomain *orig;
5024         gboolean fresh_thread = FALSE;
5025
5026         if (!domain) {
5027                 /* Happens when called from AOTed code which is only used in the root domain. */
5028                 domain = mono_get_root_domain ();
5029         }
5030
5031         g_assert (domain);
5032
5033         /* On coop, when we detached, we moved the thread from  RUNNING->BLOCKING.
5034          * If we try to reattach we do a BLOCKING->RUNNING transition.  If the thread
5035          * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5036          * we're only responsible for making the cookie. */
5037         if (mono_threads_is_coop_enabled ()) {
5038                 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5039                 fresh_thread = !info || !mono_thread_info_is_live (info);
5040         }
5041
5042         if (!mono_thread_internal_current ()) {
5043                 mono_thread_attach_full (domain, FALSE);
5044
5045                 // #678164
5046                 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5047         }
5048
5049         orig = mono_domain_get ();
5050         if (orig != domain)
5051                 mono_domain_set (domain, TRUE);
5052
5053         if (!mono_threads_is_coop_enabled ())
5054                 return orig != domain ? orig : NULL;
5055
5056         if (fresh_thread) {
5057                 *dummy = NULL;
5058                 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5059                  * return the right cookie. */
5060                 return mono_threads_enter_gc_unsafe_region_cookie ();
5061         } else {
5062                 *dummy = orig;
5063                 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5064                 return mono_threads_enter_gc_unsafe_region (dummy);
5065         }
5066 }
5067
5068 /*
5069  * mono_threads_detach_coop: called by native->managed wrappers
5070  *
5071  * In non-coop mode:
5072  *  - @cookie: the original domain which needs to be restored, or NULL.
5073  *  - @dummy: is NULL
5074  *
5075  * In coop mode:
5076  *  - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5077  *  - @dummy: contains the original domain
5078  */
5079 void
5080 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5081 {
5082         MonoDomain *domain, *orig;
5083
5084         if (!mono_threads_is_coop_enabled ()) {
5085                 orig = (MonoDomain*) cookie;
5086                 if (orig)
5087                         mono_domain_set (orig, TRUE);
5088         } else {
5089                 orig = (MonoDomain*) *dummy;
5090
5091                 domain = mono_domain_get ();
5092                 g_assert (domain);
5093
5094                 /* it won't do anything if cookie is NULL
5095                  * thread state RUNNING -> (RUNNING|BLOCKING) */
5096                 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5097
5098                 if (orig != domain) {
5099                         if (!orig)
5100                                 mono_domain_unset ();
5101                         else
5102                                 mono_domain_set (orig, TRUE);
5103                 }
5104         }
5105 }
5106
5107 void
5108 mono_threads_begin_abort_protected_block (void)
5109 {
5110         MonoInternalThread *thread;
5111
5112         thread = mono_thread_internal_current ();
5113         ++thread->abort_protected_block_count;
5114         mono_memory_barrier ();
5115 }
5116
5117 void
5118 mono_threads_end_abort_protected_block (void)
5119 {
5120         MonoInternalThread *thread;
5121
5122         thread = mono_thread_internal_current ();
5123
5124         mono_memory_barrier ();
5125         --thread->abort_protected_block_count;
5126 }
5127
5128 MonoException*
5129 mono_thread_try_resume_interruption (void)
5130 {
5131         MonoInternalThread *thread;
5132
5133         thread = mono_thread_internal_current ();
5134         if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5135                 return NULL;
5136
5137         return mono_thread_resume_interruption ();
5138 }
5139
5140 /* Returns TRUE if the current thread is ready to be interrupted. */
5141 gboolean
5142 mono_threads_is_ready_to_be_interrupted (void)
5143 {
5144         MonoInternalThread *thread;
5145
5146         thread = mono_thread_internal_current ();
5147         LOCK_THREAD (thread);
5148         if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5149                 UNLOCK_THREAD (thread);
5150                 return FALSE;
5151         }
5152
5153         if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5154                 UNLOCK_THREAD (thread);
5155                 return FALSE;
5156         }
5157
5158         UNLOCK_THREAD (thread);
5159         return TRUE;
5160 }
5161
5162 void
5163 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5164 {
5165         MonoThreadInfo *info;
5166
5167         g_string_append_printf (text, ", thread handle : %p", internal->handle);
5168
5169         info = (MonoThreadInfo*) internal->thread_info;
5170         if (!info)
5171                 return;
5172
5173         g_string_append (text, ", state : ");
5174         mono_thread_info_describe_interrupt_token (info, text);
5175
5176         if (info->owned_mutexes) {
5177                 int i;
5178
5179                 g_string_append (text, ", owns : [");
5180                 for (i = 0; i < info->owned_mutexes->len; i++)
5181                         g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (info->owned_mutexes, i));
5182                 g_string_append (text, "]");
5183         }
5184 }