Merge pull request #1840 from ludovic-henry/iolayer-thread-interrupt
[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_obj)
1098 {
1099         MonoInternalThread *internal = create_internal_thread ();
1100
1101         internal->state = ThreadState_Unstarted;
1102
1103         InterlockedCompareExchangePointer ((gpointer)&this_obj->internal_thread, internal, NULL);
1104 }
1105
1106 HANDLE
1107 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
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_obj, start));
1115
1116         if (!this_obj->internal_thread)
1117                 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1118         internal = this_obj->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_obj;
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_obj->start_obj; /* FIXME: GC object stored in unmanaged memory */
1136         start_info->delegate = start;
1137         start_info->obj = this_obj;
1138         g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
1139
1140         res = create_thread (this_obj, 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_obj, 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_obj->synch_cs) {
1171                 mono_mutex_t *synch_cs = this_obj->synch_cs;
1172                 this_obj->synch_cs = NULL;
1173                 mono_mutex_destroy (synch_cs);
1174                 g_free (synch_cs);
1175         }
1176
1177         if (this_obj->name) {
1178                 void *name = this_obj->name;
1179                 this_obj->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_obj, 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_obj, int ms)
1389 {
1390         MonoInternalThread *thread = this_obj->internal_thread;
1391         HANDLE handle = thread->handle;
1392         MonoInternalThread *cur_thread = mono_thread_internal_current ();
1393         gboolean ret;
1394
1395         mono_thread_current_check_pending_interrupt ();
1396
1397         LOCK_THREAD (thread);
1398         
1399         if ((thread->state & ThreadState_Unstarted) != 0) {
1400                 UNLOCK_THREAD (thread);
1401                 
1402                 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started."));
1403                 return FALSE;
1404         }
1405
1406         UNLOCK_THREAD (thread);
1407
1408         if(ms== -1) {
1409                 ms=INFINITE;
1410         }
1411         THREAD_DEBUG (g_message ("%s: joining thread handle %p, %d ms", __func__, handle, ms));
1412         
1413         mono_thread_set_state (cur_thread, ThreadState_WaitSleepJoin);
1414
1415         MONO_PREPARE_BLOCKING
1416         ret=WaitForSingleObjectEx (handle, 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_obj, 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_obj)
2026 {
2027         MonoInternalThread *current;
2028         gboolean throw;
2029         MonoInternalThread *thread = this_obj->internal_thread;
2030
2031         LOCK_THREAD (thread);
2032
2033         current = mono_thread_internal_current ();
2034
2035         thread->thread_interrupt_requested = TRUE;
2036         throw = current != thread && (thread->state & ThreadState_WaitSleepJoin);
2037
2038         UNLOCK_THREAD (thread);
2039         
2040         if (throw) {
2041                 abort_thread_internal (thread, 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_obj)
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_obj)
2153 {
2154         MonoInternalThread *thread = this_obj->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_obj)
2212 {
2213         if (!mono_thread_suspend (this_obj->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         mono_profiler_context_loaded (ctx);
2589 }
2590
2591 void
2592 ves_icall_System_Runtime_Remoting_Contexts_Context_ReleaseContext (MonoAppContext *ctx)
2593 {
2594         /*
2595          * NOTE: Since finalizers are unreliable for the purposes of ensuring
2596          * cleanup in exceptional circumstances, we don't actually do any
2597          * cleanup work here. We instead do this when we iterate the `contexts`
2598          * hash table. The only purpose of this finalizer, at the moment, is to
2599          * notify the profiler.
2600          */
2601
2602         //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id);
2603
2604         mono_profiler_context_unloaded (ctx);
2605 }
2606
2607 void
2608 mono_thread_init_tls (void)
2609 {
2610         MONO_FAST_TLS_INIT (tls_current_object);
2611         mono_native_tls_alloc (&current_object_key, NULL);
2612 }
2613
2614 void mono_thread_init (MonoThreadStartCB start_cb,
2615                        MonoThreadAttachCB attach_cb)
2616 {
2617         mono_mutex_init_recursive(&threads_mutex);
2618         mono_mutex_init_recursive(&interlocked_mutex);
2619         mono_mutex_init_recursive(&joinable_threads_mutex);
2620         
2621         background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2622         g_assert(background_change_event != NULL);
2623         
2624         mono_init_static_data_info (&thread_static_info);
2625         mono_init_static_data_info (&context_static_info);
2626
2627         THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2628
2629         mono_thread_start_cb = start_cb;
2630         mono_thread_attach_cb = attach_cb;
2631
2632         /* Get a pseudo handle to the current process.  This is just a
2633          * kludge so that wapi can build a process handle if needed.
2634          * As a pseudo handle is returned, we don't need to clean
2635          * anything up.
2636          */
2637         GetCurrentProcess ();
2638 }
2639
2640 void mono_thread_cleanup (void)
2641 {
2642 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2643         MonoThreadInfo *info;
2644
2645         /* The main thread must abandon any held mutexes (particularly
2646          * important for named mutexes as they are shared across
2647          * processes, see bug 74680.)  This will happen when the
2648          * thread exits, but if it's not running in a subthread it
2649          * won't exit in time.
2650          */
2651         info = mono_thread_info_current ();
2652         wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2653 #endif
2654
2655 #if 0
2656         /* This stuff needs more testing, it seems one of these
2657          * critical sections can be locked when mono_thread_cleanup is
2658          * called.
2659          */
2660         mono_mutex_destroy (&threads_mutex);
2661         mono_mutex_destroy (&interlocked_mutex);
2662         mono_mutex_destroy (&delayed_free_table_mutex);
2663         mono_mutex_destroy (&small_id_mutex);
2664         CloseHandle (background_change_event);
2665 #endif
2666
2667         mono_native_tls_free (current_object_key);
2668 }
2669
2670 void
2671 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2672 {
2673         mono_thread_cleanup_fn = func;
2674 }
2675
2676 void
2677 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2678 {
2679         thread->internal_thread->manage_callback = func;
2680 }
2681
2682 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2683 {
2684         mono_thread_notify_pending_exc_fn = func;
2685 }
2686
2687 G_GNUC_UNUSED
2688 static void print_tids (gpointer key, gpointer value, gpointer user)
2689 {
2690         /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2691          * sizeof(uint) and a cast to uint would overflow
2692          */
2693         /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2694          * print this as a pointer.
2695          */
2696         g_message ("Waiting for: %p", key);
2697 }
2698
2699 struct wait_data 
2700 {
2701         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2702         MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2703         guint32 num;
2704 };
2705
2706 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2707 {
2708         guint32 i, ret;
2709         
2710         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2711
2712         MONO_PREPARE_BLOCKING
2713         ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2714         MONO_FINISH_BLOCKING
2715
2716         if(ret==WAIT_FAILED) {
2717                 /* See the comment in build_wait_tids() */
2718                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2719                 return;
2720         }
2721         
2722         for(i=0; i<wait->num; i++)
2723                 CloseHandle (wait->handles[i]);
2724
2725         if (ret == WAIT_TIMEOUT)
2726                 return;
2727
2728         for(i=0; i<wait->num; i++) {
2729                 gsize tid = wait->threads[i]->tid;
2730
2731                 /*
2732                  * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2733                  * it can still run io-layer etc. code. So wait for it to really exit.
2734                  * FIXME: This won't join threads which are not in the joinable_hash yet.
2735                  */
2736                 mono_thread_join ((gpointer)tid);
2737
2738                 mono_threads_lock ();
2739                 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2740                         /* This thread must have been killed, because
2741                          * it hasn't cleaned itself up. (It's just
2742                          * possible that the thread exited before the
2743                          * parent thread had a chance to store the
2744                          * handle, and now there is another pointer to
2745                          * the already-exited thread stored.  In this
2746                          * case, we'll just get two
2747                          * mono_profiler_thread_end() calls for the
2748                          * same thread.)
2749                          */
2750         
2751                         mono_threads_unlock ();
2752                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2753                         thread_cleanup (wait->threads[i]);
2754                 } else {
2755                         mono_threads_unlock ();
2756                 }
2757         }
2758 }
2759
2760 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2761 {
2762         guint32 i, ret, count;
2763         
2764         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2765
2766         /* Add the thread state change event, so it wakes up if a thread changes
2767          * to background mode.
2768          */
2769         count = wait->num;
2770         if (count < MAXIMUM_WAIT_OBJECTS) {
2771                 wait->handles [count] = background_change_event;
2772                 count++;
2773         }
2774
2775         MONO_PREPARE_BLOCKING
2776         ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2777         MONO_FINISH_BLOCKING
2778
2779         if(ret==WAIT_FAILED) {
2780                 /* See the comment in build_wait_tids() */
2781                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2782                 return;
2783         }
2784         
2785         for(i=0; i<wait->num; i++)
2786                 CloseHandle (wait->handles[i]);
2787
2788         if (ret == WAIT_TIMEOUT)
2789                 return;
2790         
2791         if (ret < wait->num) {
2792                 gsize tid = wait->threads[ret]->tid;
2793                 mono_threads_lock ();
2794                 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2795                         /* See comment in wait_for_tids about thread cleanup */
2796                         mono_threads_unlock ();
2797                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2798                         thread_cleanup (wait->threads [ret]);
2799                 } else
2800                         mono_threads_unlock ();
2801         }
2802 }
2803
2804 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2805 {
2806         struct wait_data *wait=(struct wait_data *)user;
2807
2808         if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2809                 HANDLE handle;
2810                 MonoInternalThread *thread=(MonoInternalThread *)value;
2811
2812                 /* Ignore background threads, we abort them later */
2813                 /* Do not lock here since it is not needed and the caller holds threads_lock */
2814                 if (thread->state & ThreadState_Background) {
2815                         THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2816                         return; /* just leave, ignore */
2817                 }
2818                 
2819                 if (mono_gc_is_finalizer_internal_thread (thread)) {
2820                         THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2821                         return;
2822                 }
2823
2824                 if (thread == mono_thread_internal_current ()) {
2825                         THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2826                         return;
2827                 }
2828
2829                 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2830                         THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2831                         return;
2832                 }
2833
2834                 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2835                         THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2836                         return;
2837                 }
2838
2839                 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2840                 if (handle == NULL) {
2841                         THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2842                         return;
2843                 }
2844                 
2845                 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2846                 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2847                         wait->handles[wait->num]=handle;
2848                         wait->threads[wait->num]=thread;
2849                         wait->num++;
2850
2851                         THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2852                 } else {
2853                         THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2854                 }
2855                 
2856                 
2857         } else {
2858                 /* Just ignore the rest, we can't do anything with
2859                  * them yet
2860                  */
2861         }
2862 }
2863
2864 static gboolean
2865 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2866 {
2867         struct wait_data *wait=(struct wait_data *)user;
2868         gsize self = GetCurrentThreadId ();
2869         MonoInternalThread *thread = value;
2870         HANDLE handle;
2871
2872         if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2873                 return FALSE;
2874
2875         /* The finalizer thread is not a background thread */
2876         if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2877                 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2878         
2879                 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2880                 if (handle == NULL)
2881                         return FALSE;
2882
2883                 /* printf ("A: %d\n", wait->num); */
2884                 wait->handles[wait->num]=thread->handle;
2885                 wait->threads[wait->num]=thread;
2886                 wait->num++;
2887
2888                 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2889                 mono_thread_internal_stop (thread);
2890                 return TRUE;
2891         }
2892
2893         return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread)); 
2894 }
2895
2896 /** 
2897  * mono_threads_set_shutting_down:
2898  *
2899  * Is called by a thread that wants to shut down Mono. If the runtime is already
2900  * shutting down, the calling thread is suspended/stopped, and this function never
2901  * returns.
2902  */
2903 void
2904 mono_threads_set_shutting_down (void)
2905 {
2906         MonoInternalThread *current_thread = mono_thread_internal_current ();
2907
2908         mono_threads_lock ();
2909
2910         if (shutting_down) {
2911                 mono_threads_unlock ();
2912
2913                 /* Make sure we're properly suspended/stopped */
2914
2915                 LOCK_THREAD (current_thread);
2916
2917                 if ((current_thread->state & ThreadState_SuspendRequested) ||
2918                     (current_thread->state & ThreadState_AbortRequested) ||
2919                     (current_thread->state & ThreadState_StopRequested)) {
2920                         UNLOCK_THREAD (current_thread);
2921                         mono_thread_execute_interruption (current_thread);
2922                 } else {
2923                         current_thread->state |= ThreadState_Stopped;
2924                         UNLOCK_THREAD (current_thread);
2925                 }
2926
2927                 /*since we're killing the thread, unset the current domain.*/
2928                 mono_domain_unset ();
2929
2930                 /* Wake up other threads potentially waiting for us */
2931                 mono_thread_info_exit ();
2932         } else {
2933                 shutting_down = TRUE;
2934
2935                 /* Not really a background state change, but this will
2936                  * interrupt the main thread if it is waiting for all
2937                  * the other threads.
2938                  */
2939                 SetEvent (background_change_event);
2940                 
2941                 mono_threads_unlock ();
2942         }
2943 }
2944
2945 void mono_thread_manage (void)
2946 {
2947         struct wait_data wait_data;
2948         struct wait_data *wait = &wait_data;
2949
2950         memset (wait, 0, sizeof (struct wait_data));
2951         /* join each thread that's still running */
2952         THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2953         
2954         mono_threads_lock ();
2955         if(threads==NULL) {
2956                 THREAD_DEBUG (g_message("%s: No threads", __func__));
2957                 mono_threads_unlock ();
2958                 return;
2959         }
2960         mono_threads_unlock ();
2961         
2962         do {
2963                 mono_threads_lock ();
2964                 if (shutting_down) {
2965                         /* somebody else is shutting down */
2966                         mono_threads_unlock ();
2967                         break;
2968                 }
2969                 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2970                         mono_g_hash_table_foreach (threads, print_tids, NULL));
2971         
2972                 ResetEvent (background_change_event);
2973                 wait->num=0;
2974                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2975                 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2976                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2977                 mono_threads_unlock ();
2978                 if(wait->num>0) {
2979                         /* Something to wait for */
2980                         wait_for_tids_or_state_change (wait, INFINITE);
2981                 }
2982                 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2983         } while(wait->num>0);
2984
2985         /* Mono is shutting down, so just wait for the end */
2986         if (!mono_runtime_try_shutdown ()) {
2987                 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2988                 mono_thread_suspend (mono_thread_internal_current ());
2989                 mono_thread_execute_interruption (mono_thread_internal_current ());
2990         }
2991
2992         /* 
2993          * Remove everything but the finalizer thread and self.
2994          * Also abort all the background threads
2995          * */
2996         do {
2997                 mono_threads_lock ();
2998
2999                 wait->num = 0;
3000                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3001                 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3002                 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3003
3004                 mono_threads_unlock ();
3005
3006                 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3007                 if(wait->num>0) {
3008                         /* Something to wait for */
3009                         wait_for_tids (wait, INFINITE);
3010                 }
3011         } while (wait->num > 0);
3012         
3013         /* 
3014          * give the subthreads a chance to really quit (this is mainly needed
3015          * to get correct user and system times from getrusage/wait/time(1)).
3016          * This could be removed if we avoid pthread_detach() and use pthread_join().
3017          */
3018         mono_thread_info_yield ();
3019 }
3020
3021 static void terminate_thread (gpointer key, gpointer value, gpointer user)
3022 {
3023         MonoInternalThread *thread=(MonoInternalThread *)value;
3024         
3025         if(thread->tid != (gsize)user) {
3026                 /*TerminateThread (thread->handle, -1);*/
3027         }
3028 }
3029
3030 void mono_thread_abort_all_other_threads (void)
3031 {
3032         gsize self = GetCurrentThreadId ();
3033
3034         mono_threads_lock ();
3035         THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
3036                                  mono_g_hash_table_size (threads));
3037                       mono_g_hash_table_foreach (threads, print_tids, NULL));
3038
3039         mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
3040         
3041         mono_threads_unlock ();
3042 }
3043
3044 static void
3045 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3046 {
3047         MonoInternalThread *thread = (MonoInternalThread*)value;
3048         struct wait_data *wait = (struct wait_data*)user_data;
3049         HANDLE handle;
3050
3051         /* 
3052          * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
3053          * limitation.
3054          * This needs no locking.
3055          */
3056         if ((thread->state & ThreadState_Suspended) != 0 || 
3057                 (thread->state & ThreadState_Stopped) != 0)
3058                 return;
3059
3060         if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3061                 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3062                 if (handle == NULL)
3063                         return;
3064
3065                 wait->handles [wait->num] = handle;
3066                 wait->threads [wait->num] = thread;
3067                 wait->num++;
3068         }
3069 }
3070
3071 /*
3072  * mono_thread_suspend_all_other_threads:
3073  *
3074  *  Suspend all managed threads except the finalizer thread and this thread. It is
3075  * not possible to resume them later.
3076  */
3077 void mono_thread_suspend_all_other_threads (void)
3078 {
3079         struct wait_data wait_data;
3080         struct wait_data *wait = &wait_data;
3081         int i;
3082         gsize self = GetCurrentThreadId ();
3083         guint32 eventidx = 0;
3084         gboolean starting, finished;
3085
3086         memset (wait, 0, sizeof (struct wait_data));
3087         /*
3088          * The other threads could be in an arbitrary state at this point, i.e.
3089          * they could be starting up, shutting down etc. This means that there could be
3090          * threads which are not even in the threads hash table yet.
3091          */
3092
3093         /* 
3094          * First we set a barrier which will be checked by all threads before they
3095          * are added to the threads hash table, and they will exit if the flag is set.
3096          * This ensures that no threads could be added to the hash later.
3097          * We will use shutting_down as the barrier for now.
3098          */
3099         g_assert (shutting_down);
3100
3101         /*
3102          * We make multiple calls to WaitForMultipleObjects since:
3103          * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3104          * - some threads could exit without becoming suspended
3105          */
3106         finished = FALSE;
3107         while (!finished) {
3108                 /*
3109                  * Make a copy of the hashtable since we can't do anything with
3110                  * threads while threads_mutex is held.
3111                  */
3112                 wait->num = 0;
3113                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3114                 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3115                 mono_threads_lock ();
3116                 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3117                 mono_threads_unlock ();
3118
3119                 eventidx = 0;
3120                 /* Get the suspended events that we'll be waiting for */
3121                 for (i = 0; i < wait->num; ++i) {
3122                         MonoInternalThread *thread = wait->threads [i];
3123
3124                         if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3125                                 //CloseHandle (wait->handles [i]);
3126                                 wait->threads [i] = NULL; /* ignore this thread in next loop */
3127                                 continue;
3128                         }
3129
3130                         LOCK_THREAD (thread);
3131
3132                         if ((thread->state & ThreadState_Suspended) != 0 || 
3133                                 (thread->state & ThreadState_StopRequested) != 0 ||
3134                                 (thread->state & ThreadState_Stopped) != 0) {
3135                                 UNLOCK_THREAD (thread);
3136                                 CloseHandle (wait->handles [i]);
3137                                 wait->threads [i] = NULL; /* ignore this thread in next loop */
3138                                 continue;
3139                         }
3140
3141                         ++eventidx;
3142
3143                         /* Convert abort requests into suspend requests */
3144                         if ((thread->state & ThreadState_AbortRequested) != 0)
3145                                 thread->state &= ~ThreadState_AbortRequested;
3146                         
3147                         thread->state |= ThreadState_SuspendRequested;
3148
3149                         UNLOCK_THREAD (thread);
3150
3151                         /* Signal the thread to suspend */
3152                         suspend_thread_internal (thread, TRUE);
3153                 }
3154                 if (eventidx <= 0) {
3155                         /* 
3156                          * If there are threads which are starting up, we wait until they
3157                          * are suspended when they try to register in the threads hash.
3158                          * This is guaranteed to finish, since the threads which can create new
3159                          * threads get suspended after a while.
3160                          * FIXME: The finalizer thread can still create new threads.
3161                          */
3162                         mono_threads_lock ();
3163                         if (threads_starting_up)
3164                                 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3165                         else
3166                                 starting = FALSE;
3167                         mono_threads_unlock ();
3168                         if (starting)
3169                                 Sleep (100);
3170                         else
3171                                 finished = TRUE;
3172                 }
3173         }
3174 }
3175
3176 static gboolean thread_dump_requested;
3177
3178 static G_GNUC_UNUSED gboolean
3179 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3180 {
3181         GString *p = (GString*)data;
3182         MonoMethod *method = NULL;
3183         if (frame->type == FRAME_TYPE_MANAGED)
3184                 method = mono_jit_info_get_method (frame->ji);
3185
3186         if (method) {
3187                 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3188                 g_string_append_printf (p, "  %s\n", location);
3189                 g_free (location);
3190         } else
3191                 g_string_append_printf (p, "  at <unknown> <0x%05x>\n", frame->native_offset);
3192
3193         return FALSE;
3194 }
3195
3196 static SuspendThreadResult
3197 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3198 {
3199         MonoInternalThread *thread = ud;
3200         GString* text = g_string_new (0);
3201         char *name;
3202         GError *error = NULL;
3203
3204         if (thread->name) {
3205                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3206                 g_assert (!error);
3207                 g_string_append_printf (text, "\n\"%s\"", name);
3208                 g_free (name);
3209         }
3210         else if (thread->threadpool_thread)
3211                 g_string_append (text, "\n\"<threadpool thread>\"");
3212         else
3213                 g_string_append (text, "\n\"<unnamed thread>\"");
3214
3215 #if 0
3216 /* This no longer works with remote unwinding */
3217 #ifndef HOST_WIN32
3218         wapi_desc = wapi_current_thread_desc ();
3219         g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread,  wapi_desc);
3220         free (wapi_desc);
3221 #endif
3222 #endif
3223
3224         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);
3225
3226         fprintf (stdout, "%s", text->str);
3227
3228 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3229         OutputDebugStringA(text->str);
3230 #endif
3231
3232         g_string_free (text, TRUE);
3233         fflush (stdout);
3234         return MonoResumeThread;
3235 }
3236
3237 static void
3238 dump_thread (gpointer key, gpointer value, gpointer user)
3239 {
3240         MonoInternalThread *thread = (MonoInternalThread *)value;
3241
3242         if (thread == mono_thread_internal_current ())
3243                 return;
3244
3245         /*
3246         FIXME This still can hang if we stop a thread during malloc.
3247         FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3248         that takes a callback and runs it with the target suspended.
3249         We probably should loop a bit around trying to get it to either managed code
3250         or WSJ state.
3251         */
3252         mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
3253 }
3254
3255 void
3256 mono_threads_perform_thread_dump (void)
3257 {
3258         if (!thread_dump_requested)
3259                 return;
3260
3261         printf ("Full thread dump:\n");
3262
3263         /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3264         something needs then in the process.
3265         */
3266         mono_loader_lock ();
3267         mono_domain_lock (mono_get_root_domain ());
3268
3269         mono_threads_lock ();
3270         mono_g_hash_table_foreach (threads, dump_thread, NULL);
3271         mono_threads_unlock ();
3272
3273         mono_domain_unlock (mono_get_root_domain ());
3274         mono_loader_unlock ();
3275
3276         thread_dump_requested = FALSE;
3277 }
3278
3279 /**
3280  * mono_threads_request_thread_dump:
3281  *
3282  *   Ask all threads except the current to print their stacktrace to stdout.
3283  */
3284 void
3285 mono_threads_request_thread_dump (void)
3286 {
3287         /*The new thread dump code runs out of the finalizer thread. */
3288         thread_dump_requested = TRUE;
3289         mono_gc_finalize_notify ();
3290 }
3291
3292 struct ref_stack {
3293         gpointer *refs;
3294         gint allocated; /* +1 so that refs [allocated] == NULL */
3295         gint bottom;
3296 };
3297
3298 typedef struct ref_stack RefStack;
3299
3300 static RefStack *
3301 ref_stack_new (gint initial_size)
3302 {
3303         RefStack *rs;
3304
3305         initial_size = MAX (initial_size, 16) + 1;
3306         rs = g_new0 (RefStack, 1);
3307         rs->refs = g_new0 (gpointer, initial_size);
3308         rs->allocated = initial_size;
3309         return rs;
3310 }
3311
3312 static void
3313 ref_stack_destroy (gpointer ptr)
3314 {
3315         RefStack *rs = ptr;
3316
3317         if (rs != NULL) {
3318                 g_free (rs->refs);
3319                 g_free (rs);
3320         }
3321 }
3322
3323 static void
3324 ref_stack_push (RefStack *rs, gpointer ptr)
3325 {
3326         g_assert (rs != NULL);
3327
3328         if (rs->bottom >= rs->allocated) {
3329                 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3330                 rs->allocated <<= 1;
3331                 rs->refs [rs->allocated] = NULL;
3332         }
3333         rs->refs [rs->bottom++] = ptr;
3334 }
3335
3336 static void
3337 ref_stack_pop (RefStack *rs)
3338 {
3339         if (rs == NULL || rs->bottom == 0)
3340                 return;
3341
3342         rs->bottom--;
3343         rs->refs [rs->bottom] = NULL;
3344 }
3345
3346 static gboolean
3347 ref_stack_find (RefStack *rs, gpointer ptr)
3348 {
3349         gpointer *refs;
3350
3351         if (rs == NULL)
3352                 return FALSE;
3353
3354         for (refs = rs->refs; refs && *refs; refs++) {
3355                 if (*refs == ptr)
3356                         return TRUE;
3357         }
3358         return FALSE;
3359 }
3360
3361 /*
3362  * mono_thread_push_appdomain_ref:
3363  *
3364  *   Register that the current thread may have references to objects in domain 
3365  * @domain on its stack. Each call to this function should be paired with a 
3366  * call to pop_appdomain_ref.
3367  */
3368 void 
3369 mono_thread_push_appdomain_ref (MonoDomain *domain)
3370 {
3371         MonoInternalThread *thread = mono_thread_internal_current ();
3372
3373         if (thread) {
3374                 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3375                 SPIN_LOCK (thread->lock_thread_id);
3376                 if (thread->appdomain_refs == NULL)
3377                         thread->appdomain_refs = ref_stack_new (16);
3378                 ref_stack_push (thread->appdomain_refs, domain);
3379                 SPIN_UNLOCK (thread->lock_thread_id);
3380         }
3381 }
3382
3383 void
3384 mono_thread_pop_appdomain_ref (void)
3385 {
3386         MonoInternalThread *thread = mono_thread_internal_current ();
3387
3388         if (thread) {
3389                 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3390                 SPIN_LOCK (thread->lock_thread_id);
3391                 ref_stack_pop (thread->appdomain_refs);
3392                 SPIN_UNLOCK (thread->lock_thread_id);
3393         }
3394 }
3395
3396 gboolean
3397 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3398 {
3399         gboolean res;
3400         SPIN_LOCK (thread->lock_thread_id);
3401         res = ref_stack_find (thread->appdomain_refs, domain);
3402         SPIN_UNLOCK (thread->lock_thread_id);
3403         return res;
3404 }
3405
3406 gboolean
3407 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3408 {
3409         return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3410 }
3411
3412 typedef struct abort_appdomain_data {
3413         struct wait_data wait;
3414         MonoDomain *domain;
3415 } abort_appdomain_data;
3416
3417 static void
3418 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3419 {
3420         MonoInternalThread *thread = (MonoInternalThread*)value;
3421         abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3422         MonoDomain *domain = data->domain;
3423
3424         if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3425                 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3426
3427                 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3428                         HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3429                         if (handle == NULL)
3430                                 return;
3431                         data->wait.handles [data->wait.num] = handle;
3432                         data->wait.threads [data->wait.num] = thread;
3433                         data->wait.num++;
3434                 } else {
3435                         /* Just ignore the rest, we can't do anything with
3436                          * them yet
3437                          */
3438                 }
3439         }
3440 }
3441
3442 /*
3443  * mono_threads_abort_appdomain_threads:
3444  *
3445  *   Abort threads which has references to the given appdomain.
3446  */
3447 gboolean
3448 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3449 {
3450 #ifdef __native_client__
3451         return FALSE;
3452 #endif
3453
3454         abort_appdomain_data user_data;
3455         guint32 start_time;
3456         int orig_timeout = timeout;
3457         int i;
3458
3459         THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3460
3461         start_time = mono_msec_ticks ();
3462         do {
3463                 mono_threads_lock ();
3464
3465                 user_data.domain = domain;
3466                 user_data.wait.num = 0;
3467                 /* This shouldn't take any locks */
3468                 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3469                 mono_threads_unlock ();
3470
3471                 if (user_data.wait.num > 0) {
3472                         /* Abort the threads outside the threads lock */
3473                         for (i = 0; i < user_data.wait.num; ++i)
3474                                 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3475
3476                         /*
3477                          * We should wait for the threads either to abort, or to leave the
3478                          * domain. We can't do the latter, so we wait with a timeout.
3479                          */
3480                         wait_for_tids (&user_data.wait, 100);
3481                 }
3482
3483                 /* Update remaining time */
3484                 timeout -= mono_msec_ticks () - start_time;
3485                 start_time = mono_msec_ticks ();
3486
3487                 if (orig_timeout != -1 && timeout < 0)
3488                         return FALSE;
3489         }
3490         while (user_data.wait.num > 0);
3491
3492         THREAD_DEBUG (g_message ("%s: abort done", __func__));
3493
3494         return TRUE;
3495 }
3496
3497 static void
3498 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3499 {
3500         MonoInternalThread *thread = (MonoInternalThread*)value;
3501         MonoDomain *domain = (MonoDomain*)user_data;
3502         int i;
3503
3504         /* No locking needed here */
3505         /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3506
3507         if (thread->cached_culture_info) {
3508                 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3509                         MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3510                         if (obj && obj->vtable->domain == domain)
3511                                 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3512                 }
3513         }
3514 }
3515         
3516 /*
3517  * mono_threads_clear_cached_culture:
3518  *
3519  *   Clear the cached_current_culture from all threads if it is in the
3520  * given appdomain.
3521  */
3522 void
3523 mono_threads_clear_cached_culture (MonoDomain *domain)
3524 {
3525         mono_threads_lock ();
3526         mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3527         mono_threads_unlock ();
3528 }
3529
3530 /*
3531  * mono_thread_get_undeniable_exception:
3532  *
3533  *   Return an exception which needs to be raised when leaving a catch clause.
3534  * This is used for undeniable exception propagation.
3535  */
3536 MonoException*
3537 mono_thread_get_undeniable_exception (void)
3538 {
3539         MonoInternalThread *thread = mono_thread_internal_current ();
3540
3541         if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3542                 /*
3543                  * FIXME: Clear the abort exception and return an AppDomainUnloaded 
3544                  * exception if the thread no longer references a dying appdomain.
3545                  */
3546                 thread->abort_exc->trace_ips = NULL;
3547                 thread->abort_exc->stack_trace = NULL;
3548                 return thread->abort_exc;
3549         }
3550
3551         return NULL;
3552 }
3553
3554 #if MONO_SMALL_CONFIG
3555 #define NUM_STATIC_DATA_IDX 4
3556 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3557         64, 256, 1024, 4096
3558 };
3559 #else
3560 #define NUM_STATIC_DATA_IDX 8
3561 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3562         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3563 };
3564 #endif
3565
3566 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3567 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3568
3569 static void
3570 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3571 {
3572         gpointer *static_data = addr;
3573
3574         for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3575                 void **ptr = static_data [i];
3576
3577                 if (!ptr)
3578                         continue;
3579
3580                 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3581                         void **p = ptr + idx;
3582
3583                         if (*p)
3584                                 mark_func ((MonoObject**)p, gc_data);
3585                 });
3586         }
3587 }
3588
3589 static void
3590 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3591 {
3592         mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3593 }
3594
3595 static void
3596 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3597 {
3598         mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3599 }
3600
3601 /*
3602  *  mono_alloc_static_data
3603  *
3604  *   Allocate memory blocks for storing threads or context static data
3605  */
3606 static void 
3607 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3608 {
3609         guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3610         int i;
3611
3612         gpointer* static_data = *static_data_ptr;
3613         if (!static_data) {
3614                 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3615                 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3616
3617                 if (mono_gc_user_markers_supported ()) {
3618                         if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3619                                 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3620
3621                         if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3622                                 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3623                 }
3624
3625                 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc);
3626                 *static_data_ptr = static_data;
3627                 static_data [0] = static_data;
3628         }
3629
3630         for (i = 1; i <= idx; ++i) {
3631                 if (static_data [i])
3632                         continue;
3633
3634                 if (mono_gc_user_markers_supported ())
3635                         static_data [i] = g_malloc0 (static_data_size [i]);
3636                 else
3637                         static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL);
3638         }
3639 }
3640
3641 static void 
3642 mono_free_static_data (gpointer* static_data)
3643 {
3644         int i;
3645         for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3646                 gpointer p = static_data [i];
3647                 if (!p)
3648                         continue;
3649                 /*
3650                  * At this point, the static data pointer array is still registered with the
3651                  * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3652                  * data.  Freeing the individual arrays without first nulling their slots
3653                  * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
3654                  * such an already freed array.  See bug #13813.
3655                  */
3656                 static_data [i] = NULL;
3657                 mono_memory_write_barrier ();
3658                 if (mono_gc_user_markers_supported ())
3659                         g_free (p);
3660                 else
3661                         mono_gc_free_fixed (p);
3662         }
3663         mono_gc_free_fixed (static_data);
3664 }
3665
3666 /*
3667  *  mono_init_static_data_info
3668  *
3669  *   Initializes static data counters
3670  */
3671 static void mono_init_static_data_info (StaticDataInfo *static_data)
3672 {
3673         static_data->idx = 0;
3674         static_data->offset = 0;
3675         static_data->freelist = NULL;
3676 }
3677
3678 /*
3679  *  mono_alloc_static_data_slot
3680  *
3681  *   Generates an offset for static data. static_data contains the counters
3682  *  used to generate it.
3683  */
3684 static guint32
3685 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3686 {
3687         if (!static_data->idx && !static_data->offset) {
3688                 /* 
3689                  * we use the first chunk of the first allocation also as
3690                  * an array for the rest of the data 
3691                  */
3692                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3693         }
3694         static_data->offset += align - 1;
3695         static_data->offset &= ~(align - 1);
3696         if (static_data->offset + size >= static_data_size [static_data->idx]) {
3697                 static_data->idx ++;
3698                 g_assert (size <= static_data_size [static_data->idx]);
3699                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3700                 static_data->offset = 0;
3701         }
3702         guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
3703         static_data->offset += size;
3704         return offset;
3705 }
3706
3707 /* 
3708  * ensure thread static fields already allocated are valid for thread
3709  * This function is called when a thread is created or on thread attach.
3710  */
3711 static void
3712 thread_adjust_static_data (MonoInternalThread *thread)
3713 {
3714         mono_threads_lock ();
3715         if (thread_static_info.offset || thread_static_info.idx > 0) {
3716                 /* get the current allocated size */
3717                 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
3718                 mono_alloc_static_data (&thread->static_data, offset, TRUE);
3719         }
3720         mono_threads_unlock ();
3721 }
3722
3723 /*
3724  * LOCKING: requires that threads_mutex is held
3725  */
3726 static void
3727 context_adjust_static_data (MonoAppContext *ctx)
3728 {
3729         if (context_static_info.offset || context_static_info.idx > 0) {
3730                 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
3731                 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3732         }
3733 }
3734
3735 /*
3736  * LOCKING: requires that threads_mutex is held
3737  */
3738 static void 
3739 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3740 {
3741         MonoInternalThread *thread = value;
3742         guint32 offset = GPOINTER_TO_UINT (user);
3743
3744         mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3745 }
3746
3747 /*
3748  * LOCKING: requires that threads_mutex is held
3749  */
3750 static gboolean
3751 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3752 {
3753         uint32_t gch = GPOINTER_TO_INT (key);
3754         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3755
3756         if (!ctx) {
3757                 mono_gchandle_free (gch);
3758                 return TRUE; // Remove this key/value pair
3759         }
3760
3761         guint32 offset = GPOINTER_TO_UINT (user);
3762         mono_alloc_static_data (&ctx->static_data, offset, FALSE);
3763
3764         return FALSE; // Don't remove it
3765 }
3766
3767 static StaticDataFreeList*
3768 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3769 {
3770         StaticDataFreeList* prev = NULL;
3771         StaticDataFreeList* tmp = static_data->freelist;
3772         while (tmp) {
3773                 if (tmp->size == size) {
3774                         if (prev)
3775                                 prev->next = tmp->next;
3776                         else
3777                                 static_data->freelist = tmp->next;
3778                         return tmp;
3779                 }
3780                 prev = tmp;
3781                 tmp = tmp->next;
3782         }
3783         return NULL;
3784 }
3785
3786 #if SIZEOF_VOID_P == 4
3787 #define ONE_P 1
3788 #else
3789 #define ONE_P 1ll
3790 #endif
3791
3792 static void
3793 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
3794 {
3795         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3796         if (!sets [idx])
3797                 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
3798         MonoBitSet *rb = sets [idx];
3799         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3800         offset /= sizeof (uintptr_t);
3801         /* offset is now the bitmap offset */
3802         for (int i = 0; i < numbits; ++i) {
3803                 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3804                         mono_bitset_set_fast (rb, offset + i);
3805         }
3806 }
3807
3808 static void
3809 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
3810 {
3811         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3812         MonoBitSet *rb = sets [idx];
3813         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
3814         offset /= sizeof (uintptr_t);
3815         /* offset is now the bitmap offset */
3816         for (int i = 0; i < size / sizeof (uintptr_t); i++)
3817                 mono_bitset_clear_fast (rb, offset + i);
3818 }
3819
3820 guint32
3821 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3822 {
3823         g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
3824
3825         StaticDataInfo *info;
3826         MonoBitSet **sets;
3827
3828         if (static_type == SPECIAL_STATIC_THREAD) {
3829                 info = &thread_static_info;
3830                 sets = thread_reference_bitmaps;
3831         } else {
3832                 info = &context_static_info;
3833                 sets = context_reference_bitmaps;
3834         }
3835
3836         mono_threads_lock ();
3837
3838         StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
3839         guint32 offset;
3840
3841         if (item) {
3842                 offset = item->offset;
3843                 g_free (item);
3844         } else {
3845                 offset = mono_alloc_static_data_slot (info, size, align);
3846         }
3847
3848         update_reference_bitmap (sets, offset, bitmap, numbits);
3849
3850         if (static_type == SPECIAL_STATIC_THREAD) {
3851                 /* This can be called during startup */
3852                 if (threads != NULL)
3853                         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3854         } else {
3855                 if (contexts != NULL)
3856                         g_hash_table_foreach_remove (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
3857
3858                 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
3859         }
3860
3861         mono_threads_unlock ();
3862
3863         return offset;
3864 }
3865
3866 gpointer
3867 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3868 {
3869         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3870
3871         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3872                 return get_thread_static_data (thread, offset);
3873         } else {
3874                 return get_context_static_data (thread->current_appcontext, offset);
3875         }
3876 }
3877
3878 gpointer
3879 mono_get_special_static_data (guint32 offset)
3880 {
3881         return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3882 }
3883
3884 typedef struct {
3885         guint32 offset;
3886         guint32 size;
3887 } OffsetSize;
3888
3889 /*
3890  * LOCKING: requires that threads_mutex is held
3891  */
3892 static void 
3893 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3894 {
3895         MonoInternalThread *thread = value;
3896         OffsetSize *data = user;
3897         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3898         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3899         char *ptr;
3900
3901         if (!thread->static_data || !thread->static_data [idx])
3902                 return;
3903         ptr = ((char*) thread->static_data [idx]) + off;
3904         mono_gc_bzero_atomic (ptr, data->size);
3905 }
3906
3907 /*
3908  * LOCKING: requires that threads_mutex is held
3909  */
3910 static gboolean
3911 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
3912 {
3913         uint32_t gch = GPOINTER_TO_INT (key);
3914         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (gch);
3915
3916         if (!ctx) {
3917                 mono_gchandle_free (gch);
3918                 return TRUE; // Remove this key/value pair
3919         }
3920
3921         OffsetSize *data = user;
3922         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
3923         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
3924         char *ptr;
3925
3926         if (!ctx->static_data || !ctx->static_data [idx])
3927                 return FALSE; // Don't remove this key/value pair
3928
3929         ptr = ((char*) ctx->static_data [idx]) + off;
3930         mono_gc_bzero_atomic (ptr, data->size);
3931
3932         return FALSE; // Don't remove this key/value pair
3933 }
3934
3935 static void
3936 do_free_special_slot (guint32 offset, guint32 size)
3937 {
3938         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
3939         MonoBitSet **sets;
3940         StaticDataInfo *info;
3941
3942         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3943                 info = &thread_static_info;
3944                 sets = thread_reference_bitmaps;
3945         } else {
3946                 info = &context_static_info;
3947                 sets = context_reference_bitmaps;
3948         }
3949
3950         guint32 data_offset = offset;
3951         ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
3952         OffsetSize data = { data_offset, size };
3953
3954         clear_reference_bitmap (sets, data.offset, data.size);
3955
3956         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
3957                 if (threads != NULL)
3958                         mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3959         } else {
3960                 if (contexts != NULL)
3961                         g_hash_table_foreach_remove (contexts, free_context_static_data_helper, &data);
3962         }
3963
3964         if (!mono_runtime_is_shutting_down ()) {
3965                 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
3966
3967                 item->offset = offset;
3968                 item->size = size;
3969
3970                 item->next = info->freelist;
3971                 info->freelist = item;
3972         }
3973 }
3974
3975 static void
3976 do_free_special (gpointer key, gpointer value, gpointer data)
3977 {
3978         MonoClassField *field = key;
3979         guint32 offset = GPOINTER_TO_UINT (value);
3980         gint32 align;
3981         guint32 size;
3982         size = mono_type_size (field->type, &align);
3983         do_free_special_slot (offset, size);
3984 }
3985
3986 void
3987 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3988 {
3989         mono_threads_lock ();
3990
3991         g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3992
3993         mono_threads_unlock ();
3994 }
3995
3996 static void
3997 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3998 {
3999         /* Only ever called for ThreadLocal instances */
4000         g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
4001
4002         mono_threads_lock ();
4003         do_free_special_slot (offset, size);
4004         mono_threads_unlock ();
4005 }
4006
4007 #ifdef HOST_WIN32
4008 static void CALLBACK dummy_apc (ULONG_PTR param)
4009 {
4010 }
4011 #endif
4012
4013 /*
4014  * mono_thread_execute_interruption
4015  * 
4016  * Performs the operation that the requested thread state requires (abort,
4017  * suspend or stop)
4018  */
4019 static MonoException*
4020 mono_thread_execute_interruption (MonoInternalThread *thread)
4021 {
4022         LOCK_THREAD (thread);
4023
4024         /* MonoThread::interruption_requested can only be changed with atomics */
4025         if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4026                 /* this will consume pending APC calls */
4027 #ifdef HOST_WIN32
4028                 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4029 #endif
4030                 InterlockedDecrement (&thread_interruption_requested);
4031
4032                 /* Clear the interrupted flag of the thread so it can wait again */
4033                 mono_thread_info_clear_self_interrupt ();
4034         }
4035
4036         if ((thread->state & ThreadState_AbortRequested) != 0) {
4037                 UNLOCK_THREAD (thread);
4038                 if (thread->abort_exc == NULL) {
4039                         /* 
4040                          * This might be racy, but it has to be called outside the lock
4041                          * since it calls managed code.
4042                          */
4043                         MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4044                 }
4045                 return thread->abort_exc;
4046         }
4047         else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4048                 self_suspend_internal (thread);         
4049                 return NULL;
4050         }
4051         else if ((thread->state & ThreadState_StopRequested) != 0) {
4052                 /* FIXME: do this through the JIT? */
4053
4054                 UNLOCK_THREAD (thread);
4055                 
4056                 mono_thread_exit ();
4057                 return NULL;
4058         } else if (thread->pending_exception) {
4059                 MonoException *exc;
4060
4061                 exc = thread->pending_exception;
4062                 thread->pending_exception = NULL;
4063
4064         UNLOCK_THREAD (thread);
4065         return exc;
4066         } else if (thread->thread_interrupt_requested) {
4067
4068                 thread->thread_interrupt_requested = FALSE;
4069                 UNLOCK_THREAD (thread);
4070                 
4071                 return(mono_get_exception_thread_interrupted ());
4072         }
4073         
4074         UNLOCK_THREAD (thread);
4075         
4076         return NULL;
4077 }
4078
4079 /*
4080  * mono_thread_request_interruption
4081  *
4082  * A signal handler can call this method to request the interruption of a
4083  * thread. The result of the interruption will depend on the current state of
4084  * the thread. If the result is an exception that needs to be throw, it is 
4085  * provided as return value.
4086  */
4087 MonoException*
4088 mono_thread_request_interruption (gboolean running_managed)
4089 {
4090         MonoInternalThread *thread = mono_thread_internal_current ();
4091
4092         /* The thread may already be stopping */
4093         if (thread == NULL) 
4094                 return NULL;
4095
4096 #ifdef HOST_WIN32
4097         if (thread->interrupt_on_stop && 
4098                 thread->state & ThreadState_StopRequested && 
4099                 thread->state & ThreadState_Background)
4100                 ExitThread (1);
4101 #endif
4102         
4103         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4104                 return NULL;
4105         InterlockedIncrement (&thread_interruption_requested);
4106
4107         if (!running_managed || is_running_protected_wrapper ()) {
4108                 /* Can't stop while in unmanaged code. Increase the global interruption
4109                    request count. When exiting the unmanaged method the count will be
4110                    checked and the thread will be interrupted. */
4111
4112                 if (mono_thread_notify_pending_exc_fn && !running_managed)
4113                         /* The JIT will notify the thread about the interruption */
4114                         /* This shouldn't take any locks */
4115                         mono_thread_notify_pending_exc_fn (NULL);
4116
4117                 /* this will awake the thread if it is in WaitForSingleObject 
4118                    or similar */
4119                 /* Our implementation of this function ignores the func argument */
4120 #ifdef HOST_WIN32
4121                 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4122 #else
4123                 mono_thread_info_self_interrupt ();
4124 #endif
4125                 return NULL;
4126         }
4127         else {
4128                 return mono_thread_execute_interruption (thread);
4129         }
4130 }
4131
4132 /*This function should be called by a thread after it has exited all of
4133  * its handle blocks at interruption time.*/
4134 MonoException*
4135 mono_thread_resume_interruption (void)
4136 {
4137         MonoInternalThread *thread = mono_thread_internal_current ();
4138         gboolean still_aborting;
4139
4140         /* The thread may already be stopping */
4141         if (thread == NULL)
4142                 return NULL;
4143
4144         LOCK_THREAD (thread);
4145         still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4146         UNLOCK_THREAD (thread);
4147
4148         /*This can happen if the protected block called Thread::ResetAbort*/
4149         if (!still_aborting)
4150                 return FALSE;
4151
4152         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4153                 return NULL;
4154         InterlockedIncrement (&thread_interruption_requested);
4155
4156         mono_thread_info_self_interrupt ();
4157
4158         return mono_thread_execute_interruption (thread);
4159 }
4160
4161 gboolean mono_thread_interruption_requested ()
4162 {
4163         if (thread_interruption_requested) {
4164                 MonoInternalThread *thread = mono_thread_internal_current ();
4165                 /* The thread may already be stopping */
4166                 if (thread != NULL) 
4167                         return (thread->interruption_requested);
4168         }
4169         return FALSE;
4170 }
4171
4172 static MonoException*
4173 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4174 {
4175         MonoInternalThread *thread = mono_thread_internal_current ();
4176
4177         /* The thread may already be stopping */
4178         if (thread == NULL)
4179                 return NULL;
4180
4181         if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4182                 MonoException* exc = mono_thread_execute_interruption (thread);
4183                 if (exc)
4184                         return exc;
4185         }
4186         return NULL;
4187 }
4188
4189 /*
4190  * Performs the interruption of the current thread, if one has been requested,
4191  * and the thread is not running a protected wrapper.
4192  * Return the exception which needs to be thrown, if any.
4193  */
4194 MonoException*
4195 mono_thread_interruption_checkpoint (void)
4196 {
4197         return mono_thread_interruption_checkpoint_request (FALSE);
4198 }
4199
4200 /*
4201  * Performs the interruption of the current thread, if one has been requested.
4202  * Return the exception which needs to be thrown, if any.
4203  */
4204 MonoException*
4205 mono_thread_force_interruption_checkpoint_noraise (void)
4206 {
4207         return mono_thread_interruption_checkpoint_request (TRUE);
4208 }
4209
4210 /*
4211  * Performs the interruption of the current thread, if one has been requested.
4212  * Throw the exception which needs to be thrown, if any.
4213  */
4214 void
4215 mono_thread_force_interruption_checkpoint (void)
4216 {
4217         MonoException *ex;
4218
4219         ex = mono_thread_interruption_checkpoint_request (TRUE);
4220         if (ex)
4221                 mono_raise_exception (ex);
4222 }
4223
4224 /*
4225  * mono_thread_get_and_clear_pending_exception:
4226  *
4227  *   Return any pending exceptions for the current thread and clear it as a side effect.
4228  */
4229 MonoException*
4230 mono_thread_get_and_clear_pending_exception (void)
4231 {
4232         MonoInternalThread *thread = mono_thread_internal_current ();
4233
4234         /* The thread may already be stopping */
4235         if (thread == NULL)
4236                 return NULL;
4237
4238         if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4239                 return mono_thread_execute_interruption (thread);
4240         }
4241         
4242         if (thread->pending_exception) {
4243                 MonoException *exc = thread->pending_exception;
4244
4245                 thread->pending_exception = NULL;
4246                 return exc;
4247         }
4248
4249         return NULL;
4250 }
4251
4252 /*
4253  * mono_set_pending_exception:
4254  *
4255  *   Set the pending exception of the current thread to EXC.
4256  * The exception will be thrown when execution returns to managed code.
4257  */
4258 void
4259 mono_set_pending_exception (MonoException *exc)
4260 {
4261         MonoInternalThread *thread = mono_thread_internal_current ();
4262
4263         /* The thread may already be stopping */
4264         if (thread == NULL)
4265                 return;
4266
4267         MONO_OBJECT_SETREF (thread, pending_exception, exc);
4268
4269     mono_thread_request_interruption (FALSE);
4270 }
4271
4272 /**
4273  * mono_thread_interruption_request_flag:
4274  *
4275  * Returns the address of a flag that will be non-zero if an interruption has
4276  * been requested for a thread. The thread to interrupt may not be the current
4277  * thread, so an additional call to mono_thread_interruption_requested() or
4278  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4279  * zero.
4280  */
4281 gint32* mono_thread_interruption_request_flag ()
4282 {
4283         return &thread_interruption_requested;
4284 }
4285
4286 void 
4287 mono_thread_init_apartment_state (void)
4288 {
4289 #ifdef HOST_WIN32
4290         MonoInternalThread* thread = mono_thread_internal_current ();
4291
4292         /* Positive return value indicates success, either
4293          * S_OK if this is first CoInitialize call, or
4294          * S_FALSE if CoInitialize already called, but with same
4295          * threading model. A negative value indicates failure,
4296          * probably due to trying to change the threading model.
4297          */
4298         if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA) 
4299                         ? COINIT_APARTMENTTHREADED 
4300                         : COINIT_MULTITHREADED) < 0) {
4301                 thread->apartment_state = ThreadApartmentState_Unknown;
4302         }
4303 #endif
4304 }
4305
4306 void 
4307 mono_thread_cleanup_apartment_state (void)
4308 {
4309 #ifdef HOST_WIN32
4310         MonoInternalThread* thread = mono_thread_internal_current ();
4311
4312         if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4313                 CoUninitialize ();
4314         }
4315 #endif
4316 }
4317
4318 void
4319 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4320 {
4321         LOCK_THREAD (thread);
4322         thread->state |= state;
4323         UNLOCK_THREAD (thread);
4324 }
4325
4326 void
4327 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4328 {
4329         LOCK_THREAD (thread);
4330         thread->state &= ~state;
4331         UNLOCK_THREAD (thread);
4332 }
4333
4334 gboolean
4335 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4336 {
4337         gboolean ret = FALSE;
4338
4339         LOCK_THREAD (thread);
4340
4341         if ((thread->state & test) != 0) {
4342                 ret = TRUE;
4343         }
4344         
4345         UNLOCK_THREAD (thread);
4346         
4347         return ret;
4348 }
4349
4350 static gboolean has_tls_get = FALSE;
4351
4352 void
4353 mono_runtime_set_has_tls_get (gboolean val)
4354 {
4355         has_tls_get = val;
4356 }
4357
4358 gboolean
4359 mono_runtime_has_tls_get (void)
4360 {
4361         return has_tls_get;
4362 }
4363
4364 static void
4365 self_interrupt_thread (void *_unused)
4366 {
4367         MonoThreadInfo *info = mono_thread_info_current ();
4368         MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ()); 
4369         if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4370                 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. */
4371         g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4372 }
4373
4374 static gboolean
4375 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4376 {
4377         if (!ji)
4378                 return FALSE;
4379         return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4380 }
4381
4382 static gboolean
4383 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4384 {
4385         MonoJitInfo **dest = data;
4386         *dest = frame->ji;
4387         return TRUE;
4388 }
4389
4390 static MonoJitInfo*
4391 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4392 {
4393         MonoJitInfo *ji = NULL;
4394         if (!info)
4395                 return NULL;
4396         mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4397         return ji;
4398 }
4399
4400 typedef struct {
4401         MonoInternalThread *thread;
4402         gboolean install_async_abort;
4403         MonoThreadInfoInterruptToken *interrupt_token;
4404 } AbortThreadData;
4405
4406 static SuspendThreadResult
4407 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4408 {
4409         AbortThreadData *data = ud;
4410         MonoInternalThread *thread = data->thread;
4411         MonoJitInfo *ji = NULL;
4412         gboolean protected_wrapper;
4413         gboolean running_managed;
4414
4415         if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4416                 return MonoResumeThread;
4417
4418         /*someone is already interrupting it*/
4419         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4420                 return MonoResumeThread;
4421
4422         InterlockedIncrement (&thread_interruption_requested);
4423
4424         ji = mono_thread_info_get_last_managed (info);
4425         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4426         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4427
4428         if (!protected_wrapper && running_managed) {
4429                 /*We are in managed code*/
4430                 /*Set the thread to call */
4431                 if (data->install_async_abort)
4432                         mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4433                 return MonoResumeThread;
4434         } else {
4435                 if (mono_thread_notify_pending_exc_fn)
4436                         /* The JIT will notify the thread about the interruption */
4437                         mono_thread_notify_pending_exc_fn (info);
4438
4439                 /* 
4440                  * This will cause waits to be broken.
4441                  * It will also prevent the thread from entering a wait, so if the thread returns
4442                  * from the wait before it receives the abort signal, it will just spin in the wait
4443                  * functions in the io-layer until the signal handler calls QueueUserAPC which will
4444                  * make it return.
4445                  */
4446                 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4447
4448                 return MonoResumeThread;
4449         }
4450 }
4451
4452 static void
4453 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4454 {
4455         AbortThreadData data = { 0 };
4456         data.thread = thread;
4457         data.install_async_abort = install_async_abort;
4458
4459         /*
4460         FIXME this is insanely broken, it doesn't cause interruption to happen
4461         synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4462         */
4463         if (thread == mono_thread_internal_current ()) {
4464                 /* Do it synchronously */
4465                 MonoException *exc = mono_thread_request_interruption (can_raise_exception); 
4466                 if (exc)
4467                         mono_raise_exception (exc);
4468
4469                 mono_thread_info_self_interrupt ();
4470
4471                 return;
4472         }
4473
4474         mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
4475         if (data.interrupt_token)
4476                 mono_thread_info_finish_interrupt (data.interrupt_token);
4477         /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4478 }
4479
4480 typedef struct{
4481         MonoInternalThread *thread;
4482         gboolean interrupt;
4483         MonoThreadInfoInterruptToken *interrupt_token;
4484 } SuspendThreadData;
4485
4486 static SuspendThreadResult
4487 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4488 {
4489         SuspendThreadData *data = ud;
4490         MonoInternalThread *thread = data->thread;
4491         MonoJitInfo *ji = NULL;
4492         gboolean protected_wrapper;
4493         gboolean running_managed;
4494
4495         ji = mono_thread_info_get_last_managed (info);
4496         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4497         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4498
4499         if (running_managed && !protected_wrapper) {
4500                 thread->state &= ~ThreadState_SuspendRequested;
4501                 thread->state |= ThreadState_Suspended;
4502                 return KeepSuspended;
4503         } else {
4504                 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4505                         InterlockedIncrement (&thread_interruption_requested);
4506                 if (data->interrupt)
4507                         data->interrupt_token = mono_thread_info_prepare_interrupt (thread->thread_info);
4508                 
4509                 if (mono_thread_notify_pending_exc_fn && !running_managed)
4510                         /* The JIT will notify the thread about the interruption */
4511                         mono_thread_notify_pending_exc_fn (info);
4512                 return MonoResumeThread;
4513         }
4514 }
4515         
4516 static void
4517 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4518 {
4519         LOCK_THREAD (thread);
4520         if (thread == mono_thread_internal_current ()) {
4521                 mono_thread_info_begin_self_suspend ();
4522                 //XXX replace this with better named functions
4523                 thread->state &= ~ThreadState_SuspendRequested;
4524                 thread->state |= ThreadState_Suspended;
4525                 UNLOCK_THREAD (thread);
4526                 mono_thread_info_end_self_suspend ();
4527         } else {
4528                 SuspendThreadData data = { 0 };
4529                 data.thread = thread;
4530                 data.interrupt = interrupt;
4531
4532                 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
4533                 if (data.interrupt_token)
4534                         mono_thread_info_finish_interrupt (data.interrupt_token);
4535                 UNLOCK_THREAD (thread);
4536         }
4537 }
4538
4539 /*This is called with @thread synch_cs held and it must release it*/
4540 static void
4541 self_suspend_internal (MonoInternalThread *thread)
4542 {
4543         mono_thread_info_begin_self_suspend ();
4544         thread->state &= ~ThreadState_SuspendRequested;
4545         thread->state |= ThreadState_Suspended;
4546         UNLOCK_THREAD (thread);
4547         mono_thread_info_end_self_suspend ();
4548 }
4549
4550 /*This is called with @thread synch_cs held and it must release it*/
4551 static gboolean
4552 resume_thread_internal (MonoInternalThread *thread)
4553 {
4554         UNLOCK_THREAD (thread);
4555         /* Awake the thread */
4556         if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4557                 return FALSE;
4558         LOCK_THREAD (thread);
4559         thread->state &= ~ThreadState_Suspended;
4560         UNLOCK_THREAD (thread);
4561         return TRUE;
4562 }
4563
4564
4565 /*
4566  * mono_thread_is_foreign:
4567  * @thread: the thread to query
4568  *
4569  * This function allows one to determine if a thread was created by the mono runtime and has
4570  * a well defined lifecycle or it's a foreigh one, created by the native environment.
4571  *
4572  * Returns: true if @thread was not created by the runtime.
4573  */
4574 mono_bool
4575 mono_thread_is_foreign (MonoThread *thread)
4576 {
4577         MonoThreadInfo *info = thread->internal_thread->thread_info;
4578         return info->runtime_thread == FALSE;
4579 }
4580
4581 /*
4582  * mono_add_joinable_thread:
4583  *
4584  *   Add TID to the list of joinable threads.
4585  * LOCKING: Acquires the threads lock.
4586  */
4587 void
4588 mono_threads_add_joinable_thread (gpointer tid)
4589 {
4590 #ifndef HOST_WIN32
4591         /*
4592          * We cannot detach from threads because it causes problems like
4593          * 2fd16f60/r114307. So we collect them and join them when
4594          * we have time (in he finalizer thread).
4595          */
4596         joinable_threads_lock ();
4597         if (!joinable_threads)
4598                 joinable_threads = g_hash_table_new (NULL, NULL);
4599         g_hash_table_insert (joinable_threads, tid, tid);
4600         joinable_thread_count ++;
4601         joinable_threads_unlock ();
4602
4603         mono_gc_finalize_notify ();
4604 #endif
4605 }
4606
4607 /*
4608  * mono_threads_join_threads:
4609  *
4610  *   Join all joinable threads. This is called from the finalizer thread.
4611  * LOCKING: Acquires the threads lock.
4612  */
4613 void
4614 mono_threads_join_threads (void)
4615 {
4616 #ifndef HOST_WIN32
4617         GHashTableIter iter;
4618         gpointer key;
4619         gpointer tid;
4620         pthread_t thread;
4621         gboolean found;
4622
4623         /* Fastpath */
4624         if (!joinable_thread_count)
4625                 return;
4626
4627         while (TRUE) {
4628                 joinable_threads_lock ();
4629                 found = FALSE;
4630                 if (g_hash_table_size (joinable_threads)) {
4631                         g_hash_table_iter_init (&iter, joinable_threads);
4632                         g_hash_table_iter_next (&iter, &key, (void**)&tid);
4633                         thread = (pthread_t)tid;
4634                         g_hash_table_remove (joinable_threads, key);
4635                         joinable_thread_count --;
4636                         found = TRUE;
4637                 }
4638                 joinable_threads_unlock ();
4639                 if (found) {
4640                         if (thread != pthread_self ())
4641                                 /* This shouldn't block */
4642                                 pthread_join (thread, NULL);
4643                 } else {
4644                         break;
4645                 }
4646         }
4647 #endif
4648 }
4649
4650 /*
4651  * mono_thread_join:
4652  *
4653  *   Wait for thread TID to exit.
4654  * LOCKING: Acquires the threads lock.
4655  */
4656 void
4657 mono_thread_join (gpointer tid)
4658 {
4659 #ifndef HOST_WIN32
4660         pthread_t thread;
4661         gboolean found = FALSE;
4662
4663         joinable_threads_lock ();
4664         if (!joinable_threads)
4665                 joinable_threads = g_hash_table_new (NULL, NULL);
4666         if (g_hash_table_lookup (joinable_threads, tid)) {
4667                 g_hash_table_remove (joinable_threads, tid);
4668                 joinable_thread_count --;
4669                 found = TRUE;
4670         }
4671         joinable_threads_unlock ();
4672         if (!found)
4673                 return;
4674         thread = (pthread_t)tid;
4675         pthread_join (thread, NULL);
4676 #endif
4677 }
4678
4679 void
4680 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4681 {
4682         if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4683                 mono_thread_interruption_checkpoint ();
4684 }
4685
4686 static inline gboolean
4687 is_appdomainunloaded_exception (MonoClass *klass)
4688 {
4689         static MonoClass *app_domain_unloaded_exception_klass = NULL;
4690
4691         if (!app_domain_unloaded_exception_klass)
4692                 app_domain_unloaded_exception_klass = mono_class_from_name (mono_defaults.corlib, "System", "AppDomainUnloadedException");
4693         g_assert (app_domain_unloaded_exception_klass);
4694
4695         return klass == app_domain_unloaded_exception_klass;
4696 }
4697
4698 static inline gboolean
4699 is_threadabort_exception (MonoClass *klass)
4700 {
4701         return klass == mono_defaults.threadabortexception_class;
4702 }
4703
4704 void
4705 mono_thread_internal_unhandled_exception (MonoObject* exc)
4706 {
4707         if (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
4708                 MonoClass *klass = exc->vtable->klass;
4709                 if (is_threadabort_exception (klass)) {
4710                         mono_thread_internal_reset_abort (mono_thread_internal_current ());
4711                 } else if (!is_appdomainunloaded_exception (klass)) {
4712                         mono_unhandled_exception (exc);
4713                         if (mono_environment_exitcode_get () == 1)
4714                                 exit (255);
4715                 }
4716         }
4717 }