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