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