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