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