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