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