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