Merge pull request #1743 from alexrp/profiler-versioning
[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 void
2022 ves_icall_System_Threading_Thread_Abort (MonoInternalThread *thread, MonoObject *state)
2023 {
2024         LOCK_THREAD (thread);
2025         
2026         if ((thread->state & ThreadState_AbortRequested) != 0 || 
2027                 (thread->state & ThreadState_StopRequested) != 0 ||
2028                 (thread->state & ThreadState_Stopped) != 0)
2029         {
2030                 UNLOCK_THREAD (thread);
2031                 return;
2032         }
2033
2034         if ((thread->state & ThreadState_Unstarted) != 0) {
2035                 thread->state |= ThreadState_Aborted;
2036                 UNLOCK_THREAD (thread);
2037                 return;
2038         }
2039
2040         thread->state |= ThreadState_AbortRequested;
2041         if (thread->abort_state_handle)
2042                 mono_gchandle_free (thread->abort_state_handle);
2043         if (state) {
2044                 thread->abort_state_handle = mono_gchandle_new (state, FALSE);
2045                 g_assert (thread->abort_state_handle);
2046         } else {
2047                 thread->abort_state_handle = 0;
2048         }
2049         thread->abort_exc = NULL;
2050
2051         UNLOCK_THREAD (thread);
2052
2053         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Abort requested for %p (%"G_GSIZE_FORMAT")", __func__, GetCurrentThreadId (), thread, (gsize)thread->tid));
2054
2055         /* During shutdown, we can't wait for other threads */
2056         if (!shutting_down)
2057                 /* Make sure the thread is awake */
2058                 mono_thread_resume (thread);
2059         
2060         abort_thread_internal (thread, TRUE, TRUE);
2061 }
2062
2063 void
2064 ves_icall_System_Threading_Thread_ResetAbort (void)
2065 {
2066         MonoInternalThread *thread = mono_thread_internal_current ();
2067         gboolean was_aborting;
2068
2069         LOCK_THREAD (thread);
2070         was_aborting = thread->state & ThreadState_AbortRequested;
2071         thread->state &= ~ThreadState_AbortRequested;
2072         UNLOCK_THREAD (thread);
2073
2074         if (!was_aborting) {
2075                 const char *msg = "Unable to reset abort because no abort was requested";
2076                 mono_set_pending_exception (mono_get_exception_thread_state (msg));
2077                 return;
2078         }
2079         thread->abort_exc = NULL;
2080         if (thread->abort_state_handle) {
2081                 mono_gchandle_free (thread->abort_state_handle);
2082                 /* This is actually not necessary - the handle
2083                    only counts if the exception is set */
2084                 thread->abort_state_handle = 0;
2085         }
2086 }
2087
2088 void
2089 mono_thread_internal_reset_abort (MonoInternalThread *thread)
2090 {
2091         LOCK_THREAD (thread);
2092
2093         thread->state &= ~ThreadState_AbortRequested;
2094
2095         if (thread->abort_exc) {
2096                 thread->abort_exc = NULL;
2097                 if (thread->abort_state_handle) {
2098                         mono_gchandle_free (thread->abort_state_handle);
2099                         /* This is actually not necessary - the handle
2100                            only counts if the exception is set */
2101                         thread->abort_state_handle = 0;
2102                 }
2103         }
2104
2105         UNLOCK_THREAD (thread);
2106 }
2107
2108 MonoObject*
2109 ves_icall_System_Threading_Thread_GetAbortExceptionState (MonoThread *this)
2110 {
2111         MonoInternalThread *thread = this->internal_thread;
2112         MonoObject *state, *deserialized = NULL, *exc;
2113         MonoDomain *domain;
2114
2115         if (!thread->abort_state_handle)
2116                 return NULL;
2117
2118         state = mono_gchandle_get_target (thread->abort_state_handle);
2119         g_assert (state);
2120
2121         domain = mono_domain_get ();
2122         if (mono_object_domain (state) == domain)
2123                 return state;
2124
2125         deserialized = mono_object_xdomain_representation (state, domain, &exc);
2126
2127         if (!deserialized) {
2128                 MonoException *invalid_op_exc = mono_get_exception_invalid_operation ("Thread.ExceptionState cannot access an ExceptionState from a different AppDomain");
2129                 if (exc)
2130                         MONO_OBJECT_SETREF (invalid_op_exc, inner_ex, exc);
2131                 mono_set_pending_exception (invalid_op_exc);
2132                 return NULL;
2133         }
2134
2135         return deserialized;
2136 }
2137
2138 static gboolean
2139 mono_thread_suspend (MonoInternalThread *thread)
2140 {
2141         LOCK_THREAD (thread);
2142
2143         if ((thread->state & ThreadState_Unstarted) != 0 || 
2144                 (thread->state & ThreadState_Aborted) != 0 || 
2145                 (thread->state & ThreadState_Stopped) != 0)
2146         {
2147                 UNLOCK_THREAD (thread);
2148                 return FALSE;
2149         }
2150
2151         if ((thread->state & ThreadState_Suspended) != 0 || 
2152                 (thread->state & ThreadState_SuspendRequested) != 0 ||
2153                 (thread->state & ThreadState_StopRequested) != 0) 
2154         {
2155                 UNLOCK_THREAD (thread);
2156                 return TRUE;
2157         }
2158         
2159         thread->state |= ThreadState_SuspendRequested;
2160
2161         UNLOCK_THREAD (thread);
2162
2163         suspend_thread_internal (thread, FALSE);
2164         return TRUE;
2165 }
2166
2167 void
2168 ves_icall_System_Threading_Thread_Suspend (MonoInternalThread *thread)
2169 {
2170         if (!mono_thread_suspend (thread)) {
2171                 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2172                 return;
2173         }
2174 }
2175
2176 static gboolean
2177 mono_thread_resume (MonoInternalThread *thread)
2178 {
2179         LOCK_THREAD (thread);
2180
2181         if ((thread->state & ThreadState_SuspendRequested) != 0) {
2182                 thread->state &= ~ThreadState_SuspendRequested;
2183                 UNLOCK_THREAD (thread);
2184                 return TRUE;
2185         }
2186
2187         if ((thread->state & ThreadState_Suspended) == 0 ||
2188                 (thread->state & ThreadState_Unstarted) != 0 || 
2189                 (thread->state & ThreadState_Aborted) != 0 || 
2190                 (thread->state & ThreadState_Stopped) != 0)
2191         {
2192                 UNLOCK_THREAD (thread);
2193                 return FALSE;
2194         }
2195
2196         return resume_thread_internal (thread);
2197 }
2198
2199 void
2200 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
2201 {
2202         if (!thread->internal_thread || !mono_thread_resume (thread->internal_thread)) {
2203                 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
2204                 return;
2205         }
2206 }
2207
2208 static gboolean
2209 mono_threads_is_critical_method (MonoMethod *method)
2210 {
2211         switch (method->wrapper_type) {
2212         case MONO_WRAPPER_RUNTIME_INVOKE:
2213         case MONO_WRAPPER_XDOMAIN_INVOKE:
2214         case MONO_WRAPPER_XDOMAIN_DISPATCH:     
2215                 return TRUE;
2216         }
2217         return FALSE;
2218 }
2219
2220 static gboolean
2221 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
2222 {
2223         if (managed)
2224                 return TRUE;
2225
2226         if (mono_threads_is_critical_method (m)) {
2227                 *((gboolean*)data) = TRUE;
2228                 return TRUE;
2229         }
2230         return FALSE;
2231 }
2232
2233 static gboolean 
2234 is_running_protected_wrapper (void)
2235 {
2236         gboolean found = FALSE;
2237         mono_stack_walk (find_wrapper, &found);
2238         return found;
2239 }
2240
2241 void mono_thread_internal_stop (MonoInternalThread *thread)
2242 {
2243         LOCK_THREAD (thread);
2244
2245         if ((thread->state & ThreadState_StopRequested) != 0 ||
2246                 (thread->state & ThreadState_Stopped) != 0)
2247         {
2248                 UNLOCK_THREAD (thread);
2249                 return;
2250         }
2251         
2252         /* Make sure the thread is awake */
2253         mono_thread_resume (thread);
2254
2255         thread->state |= ThreadState_StopRequested;
2256         thread->state &= ~ThreadState_AbortRequested;
2257         
2258         UNLOCK_THREAD (thread);
2259         
2260         abort_thread_internal (thread, TRUE, TRUE);
2261 }
2262
2263 void mono_thread_stop (MonoThread *thread)
2264 {
2265         mono_thread_internal_stop (thread->internal_thread);
2266 }
2267
2268 gint8
2269 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
2270 {
2271         gint8 tmp;
2272         mono_atomic_load_acquire (tmp, gint8, (volatile gint8 *) ptr);
2273         return tmp;
2274 }
2275
2276 gint16
2277 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
2278 {
2279         gint16 tmp;
2280         mono_atomic_load_acquire (tmp, gint16, (volatile gint16 *) ptr);
2281         return tmp;
2282 }
2283
2284 gint32
2285 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
2286 {
2287         gint32 tmp;
2288         mono_atomic_load_acquire (tmp, gint32, (volatile gint32 *) ptr);
2289         return tmp;
2290 }
2291
2292 gint64
2293 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
2294 {
2295         gint64 tmp;
2296         mono_atomic_load_acquire (tmp, gint64, (volatile gint64 *) ptr);
2297         return tmp;
2298 }
2299
2300 void *
2301 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
2302 {
2303         volatile void *tmp;
2304         mono_atomic_load_acquire (tmp, volatile void *, (volatile void **) ptr);
2305         return (void *) tmp;
2306 }
2307
2308 void *
2309 ves_icall_System_Threading_Thread_VolatileReadObject (void *ptr)
2310 {
2311         volatile MonoObject *tmp;
2312         mono_atomic_load_acquire (tmp, volatile MonoObject *, (volatile MonoObject **) ptr);
2313         return (MonoObject *) tmp;
2314 }
2315
2316 double
2317 ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
2318 {
2319         double tmp;
2320         mono_atomic_load_acquire (tmp, double, (volatile double *) ptr);
2321         return tmp;
2322 }
2323
2324 float
2325 ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
2326 {
2327         float tmp;
2328         mono_atomic_load_acquire (tmp, float, (volatile float *) ptr);
2329         return tmp;
2330 }
2331
2332 gint8
2333 ves_icall_System_Threading_Volatile_Read1 (void *ptr)
2334 {
2335         return InterlockedRead8 (ptr);
2336 }
2337
2338 gint16
2339 ves_icall_System_Threading_Volatile_Read2 (void *ptr)
2340 {
2341         return InterlockedRead16 (ptr);
2342 }
2343
2344 gint32
2345 ves_icall_System_Threading_Volatile_Read4 (void *ptr)
2346 {
2347         return InterlockedRead (ptr);
2348 }
2349
2350 gint64
2351 ves_icall_System_Threading_Volatile_Read8 (void *ptr)
2352 {
2353 #if SIZEOF_VOID_P == 4
2354         if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2355                 gint64 val;
2356                 mono_interlocked_lock ();
2357                 val = *(gint64*)ptr;
2358                 mono_interlocked_unlock ();
2359                 return val;
2360         }
2361 #endif
2362         return InterlockedRead64 (ptr);
2363 }
2364
2365 void *
2366 ves_icall_System_Threading_Volatile_ReadIntPtr (void *ptr)
2367 {
2368         return InterlockedReadPointer (ptr);
2369 }
2370
2371 double
2372 ves_icall_System_Threading_Volatile_ReadDouble (void *ptr)
2373 {
2374         LongDoubleUnion u;
2375
2376 #if SIZEOF_VOID_P == 4
2377         if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2378                 double val;
2379                 mono_interlocked_lock ();
2380                 val = *(double*)ptr;
2381                 mono_interlocked_unlock ();
2382                 return val;
2383         }
2384 #endif
2385
2386         u.ival = InterlockedRead64 (ptr);
2387
2388         return u.fval;
2389 }
2390
2391 float
2392 ves_icall_System_Threading_Volatile_ReadFloat (void *ptr)
2393 {
2394         IntFloatUnion u;
2395
2396         u.ival = InterlockedRead (ptr);
2397
2398         return u.fval;
2399 }
2400
2401 MonoObject*
2402 ves_icall_System_Threading_Volatile_Read_T (void *ptr)
2403 {
2404         return InterlockedReadPointer (ptr);
2405 }
2406
2407 void
2408 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
2409 {
2410         mono_atomic_store_release ((volatile gint8 *) ptr, value);
2411 }
2412
2413 void
2414 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
2415 {
2416         mono_atomic_store_release ((volatile gint16 *) ptr, value);
2417 }
2418
2419 void
2420 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
2421 {
2422         mono_atomic_store_release ((volatile gint32 *) ptr, value);
2423 }
2424
2425 void
2426 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
2427 {
2428         mono_atomic_store_release ((volatile gint64 *) ptr, value);
2429 }
2430
2431 void
2432 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
2433 {
2434         mono_atomic_store_release ((volatile void **) ptr, value);
2435 }
2436
2437 void
2438 ves_icall_System_Threading_Thread_VolatileWriteObject (void *ptr, MonoObject *value)
2439 {
2440         mono_gc_wbarrier_generic_store_atomic (ptr, value);
2441 }
2442
2443 void
2444 ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
2445 {
2446         mono_atomic_store_release ((volatile double *) ptr, value);
2447 }
2448
2449 void
2450 ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
2451 {
2452         mono_atomic_store_release ((volatile float *) ptr, value);
2453 }
2454
2455 void
2456 ves_icall_System_Threading_Volatile_Write1 (void *ptr, gint8 value)
2457 {
2458         InterlockedWrite8 (ptr, value);
2459 }
2460
2461 void
2462 ves_icall_System_Threading_Volatile_Write2 (void *ptr, gint16 value)
2463 {
2464         InterlockedWrite16 (ptr, value);
2465 }
2466
2467 void
2468 ves_icall_System_Threading_Volatile_Write4 (void *ptr, gint32 value)
2469 {
2470         InterlockedWrite (ptr, value);
2471 }
2472
2473 void
2474 ves_icall_System_Threading_Volatile_Write8 (void *ptr, gint64 value)
2475 {
2476 #if SIZEOF_VOID_P == 4
2477         if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2478                 mono_interlocked_lock ();
2479                 *(gint64*)ptr = value;
2480                 mono_interlocked_unlock ();
2481                 return;
2482         }
2483 #endif
2484
2485         InterlockedWrite64 (ptr, value);
2486 }
2487
2488 void
2489 ves_icall_System_Threading_Volatile_WriteIntPtr (void *ptr, void *value)
2490 {
2491         InterlockedWritePointer (ptr, value);
2492 }
2493
2494 void
2495 ves_icall_System_Threading_Volatile_WriteDouble (void *ptr, double value)
2496 {
2497         LongDoubleUnion u;
2498
2499 #if SIZEOF_VOID_P == 4
2500         if (G_UNLIKELY ((size_t)ptr & 0x7)) {
2501                 mono_interlocked_lock ();
2502                 *(double*)ptr = value;
2503                 mono_interlocked_unlock ();
2504                 return;
2505         }
2506 #endif
2507
2508         u.fval = value;
2509
2510         InterlockedWrite64 (ptr, u.ival);
2511 }
2512
2513 void
2514 ves_icall_System_Threading_Volatile_WriteFloat (void *ptr, float value)
2515 {
2516         IntFloatUnion u;
2517
2518         u.fval = value;
2519
2520         InterlockedWrite (ptr, u.ival);
2521 }
2522
2523 void
2524 ves_icall_System_Threading_Volatile_Write_T (void *ptr, MonoObject *value)
2525 {
2526         mono_gc_wbarrier_generic_store_atomic (ptr, value);
2527 }
2528
2529 void
2530 mono_thread_init_tls (void)
2531 {
2532         MONO_FAST_TLS_INIT (tls_current_object);
2533         mono_native_tls_alloc (&current_object_key, NULL);
2534 }
2535
2536 void mono_thread_init (MonoThreadStartCB start_cb,
2537                        MonoThreadAttachCB attach_cb)
2538 {
2539         mono_mutex_init_recursive(&threads_mutex);
2540         mono_mutex_init_recursive(&interlocked_mutex);
2541         mono_mutex_init_recursive(&contexts_mutex);
2542         mono_mutex_init_recursive(&joinable_threads_mutex);
2543         
2544         background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2545         g_assert(background_change_event != NULL);
2546         
2547         mono_init_static_data_info (&thread_static_info);
2548         mono_init_static_data_info (&context_static_info);
2549
2550         THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
2551
2552         mono_thread_start_cb = start_cb;
2553         mono_thread_attach_cb = attach_cb;
2554
2555         /* Get a pseudo handle to the current process.  This is just a
2556          * kludge so that wapi can build a process handle if needed.
2557          * As a pseudo handle is returned, we don't need to clean
2558          * anything up.
2559          */
2560         GetCurrentProcess ();
2561 }
2562
2563 void mono_thread_cleanup (void)
2564 {
2565 #if !defined(HOST_WIN32) && !defined(RUN_IN_SUBTHREAD)
2566         MonoThreadInfo *info;
2567
2568         /* The main thread must abandon any held mutexes (particularly
2569          * important for named mutexes as they are shared across
2570          * processes, see bug 74680.)  This will happen when the
2571          * thread exits, but if it's not running in a subthread it
2572          * won't exit in time.
2573          */
2574         info = mono_thread_info_current ();
2575         wapi_thread_handle_set_exited (info->handle, mono_environment_exitcode_get ());
2576 #endif
2577
2578 #if 0
2579         /* This stuff needs more testing, it seems one of these
2580          * critical sections can be locked when mono_thread_cleanup is
2581          * called.
2582          */
2583         mono_mutex_destroy (&threads_mutex);
2584         mono_mutex_destroy (&interlocked_mutex);
2585         mono_mutex_destroy (&contexts_mutex);
2586         mono_mutex_destroy (&delayed_free_table_mutex);
2587         mono_mutex_destroy (&small_id_mutex);
2588         CloseHandle (background_change_event);
2589 #endif
2590
2591         mono_native_tls_free (current_object_key);
2592 }
2593
2594 void
2595 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2596 {
2597         mono_thread_cleanup_fn = func;
2598 }
2599
2600 void
2601 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2602 {
2603         thread->internal_thread->manage_callback = func;
2604 }
2605
2606 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
2607 {
2608         mono_thread_notify_pending_exc_fn = func;
2609 }
2610
2611 G_GNUC_UNUSED
2612 static void print_tids (gpointer key, gpointer value, gpointer user)
2613 {
2614         /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2615          * sizeof(uint) and a cast to uint would overflow
2616          */
2617         /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2618          * print this as a pointer.
2619          */
2620         g_message ("Waiting for: %p", key);
2621 }
2622
2623 struct wait_data 
2624 {
2625         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2626         MonoInternalThread *threads[MAXIMUM_WAIT_OBJECTS];
2627         guint32 num;
2628 };
2629
2630 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
2631 {
2632         guint32 i, ret;
2633         
2634         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2635
2636         MONO_PREPARE_BLOCKING
2637         ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2638         MONO_FINISH_BLOCKING
2639
2640         if(ret==WAIT_FAILED) {
2641                 /* See the comment in build_wait_tids() */
2642                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2643                 return;
2644         }
2645         
2646         for(i=0; i<wait->num; i++)
2647                 CloseHandle (wait->handles[i]);
2648
2649         if (ret == WAIT_TIMEOUT)
2650                 return;
2651
2652         for(i=0; i<wait->num; i++) {
2653                 gsize tid = wait->threads[i]->tid;
2654
2655                 /*
2656                  * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2657                  * it can still run io-layer etc. code. So wait for it to really exit.
2658                  * FIXME: This won't join threads which are not in the joinable_hash yet.
2659                  */
2660                 mono_thread_join ((gpointer)tid);
2661
2662                 mono_threads_lock ();
2663                 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2664                         /* This thread must have been killed, because
2665                          * it hasn't cleaned itself up. (It's just
2666                          * possible that the thread exited before the
2667                          * parent thread had a chance to store the
2668                          * handle, and now there is another pointer to
2669                          * the already-exited thread stored.  In this
2670                          * case, we'll just get two
2671                          * mono_profiler_thread_end() calls for the
2672                          * same thread.)
2673                          */
2674         
2675                         mono_threads_unlock ();
2676                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2677                         thread_cleanup (wait->threads[i]);
2678                 } else {
2679                         mono_threads_unlock ();
2680                 }
2681         }
2682 }
2683
2684 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2685 {
2686         guint32 i, ret, count;
2687         
2688         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2689
2690         /* Add the thread state change event, so it wakes up if a thread changes
2691          * to background mode.
2692          */
2693         count = wait->num;
2694         if (count < MAXIMUM_WAIT_OBJECTS) {
2695                 wait->handles [count] = background_change_event;
2696                 count++;
2697         }
2698
2699         MONO_PREPARE_BLOCKING
2700         ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2701         MONO_FINISH_BLOCKING
2702
2703         if(ret==WAIT_FAILED) {
2704                 /* See the comment in build_wait_tids() */
2705                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2706                 return;
2707         }
2708         
2709         for(i=0; i<wait->num; i++)
2710                 CloseHandle (wait->handles[i]);
2711
2712         if (ret == WAIT_TIMEOUT)
2713                 return;
2714         
2715         if (ret < wait->num) {
2716                 gsize tid = wait->threads[ret]->tid;
2717                 mono_threads_lock ();
2718                 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2719                         /* See comment in wait_for_tids about thread cleanup */
2720                         mono_threads_unlock ();
2721                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
2722                         thread_cleanup (wait->threads [ret]);
2723                 } else
2724                         mono_threads_unlock ();
2725         }
2726 }
2727
2728 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
2729 {
2730         struct wait_data *wait=(struct wait_data *)user;
2731
2732         if(wait->num<MAXIMUM_WAIT_OBJECTS) {
2733                 HANDLE handle;
2734                 MonoInternalThread *thread=(MonoInternalThread *)value;
2735
2736                 /* Ignore background threads, we abort them later */
2737                 /* Do not lock here since it is not needed and the caller holds threads_lock */
2738                 if (thread->state & ThreadState_Background) {
2739                         THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2740                         return; /* just leave, ignore */
2741                 }
2742                 
2743                 if (mono_gc_is_finalizer_internal_thread (thread)) {
2744                         THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2745                         return;
2746                 }
2747
2748                 if (thread == mono_thread_internal_current ()) {
2749                         THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2750                         return;
2751                 }
2752
2753                 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
2754                         THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2755                         return;
2756                 }
2757
2758                 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
2759                         THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
2760                         return;
2761                 }
2762
2763                 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2764                 if (handle == NULL) {
2765                         THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2766                         return;
2767                 }
2768                 
2769                 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
2770                 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
2771                         wait->handles[wait->num]=handle;
2772                         wait->threads[wait->num]=thread;
2773                         wait->num++;
2774
2775                         THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2776                 } else {
2777                         THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
2778                 }
2779                 
2780                 
2781         } else {
2782                 /* Just ignore the rest, we can't do anything with
2783                  * them yet
2784                  */
2785         }
2786 }
2787
2788 static gboolean
2789 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
2790 {
2791         struct wait_data *wait=(struct wait_data *)user;
2792         gsize self = GetCurrentThreadId ();
2793         MonoInternalThread *thread = value;
2794         HANDLE handle;
2795
2796         if (wait->num >= MAXIMUM_WAIT_OBJECTS)
2797                 return FALSE;
2798
2799         /* The finalizer thread is not a background thread */
2800         if (thread->tid != self && (thread->state & ThreadState_Background) != 0 &&
2801                 !(thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
2802         
2803                 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2804                 if (handle == NULL)
2805                         return FALSE;
2806
2807                 /* printf ("A: %d\n", wait->num); */
2808                 wait->handles[wait->num]=thread->handle;
2809                 wait->threads[wait->num]=thread;
2810                 wait->num++;
2811
2812                 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
2813                 mono_thread_internal_stop (thread);
2814                 return TRUE;
2815         }
2816
2817         return (thread->tid != self && !mono_gc_is_finalizer_internal_thread (thread)); 
2818 }
2819
2820 /** 
2821  * mono_threads_set_shutting_down:
2822  *
2823  * Is called by a thread that wants to shut down Mono. If the runtime is already
2824  * shutting down, the calling thread is suspended/stopped, and this function never
2825  * returns.
2826  */
2827 void
2828 mono_threads_set_shutting_down (void)
2829 {
2830         MonoInternalThread *current_thread = mono_thread_internal_current ();
2831
2832         mono_threads_lock ();
2833
2834         if (shutting_down) {
2835                 mono_threads_unlock ();
2836
2837                 /* Make sure we're properly suspended/stopped */
2838
2839                 LOCK_THREAD (current_thread);
2840
2841                 if ((current_thread->state & ThreadState_SuspendRequested) ||
2842                     (current_thread->state & ThreadState_AbortRequested) ||
2843                     (current_thread->state & ThreadState_StopRequested)) {
2844                         UNLOCK_THREAD (current_thread);
2845                         mono_thread_execute_interruption (current_thread);
2846                 } else {
2847                         current_thread->state |= ThreadState_Stopped;
2848                         UNLOCK_THREAD (current_thread);
2849                 }
2850
2851                 /*since we're killing the thread, unset the current domain.*/
2852                 mono_domain_unset ();
2853
2854                 /* Wake up other threads potentially waiting for us */
2855                 mono_thread_info_exit ();
2856         } else {
2857                 shutting_down = TRUE;
2858
2859                 /* Not really a background state change, but this will
2860                  * interrupt the main thread if it is waiting for all
2861                  * the other threads.
2862                  */
2863                 SetEvent (background_change_event);
2864                 
2865                 mono_threads_unlock ();
2866         }
2867 }
2868
2869 void mono_thread_manage (void)
2870 {
2871         struct wait_data wait_data;
2872         struct wait_data *wait = &wait_data;
2873
2874         memset (wait, 0, sizeof (struct wait_data));
2875         /* join each thread that's still running */
2876         THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
2877         
2878         mono_threads_lock ();
2879         if(threads==NULL) {
2880                 THREAD_DEBUG (g_message("%s: No threads", __func__));
2881                 mono_threads_unlock ();
2882                 return;
2883         }
2884         mono_threads_unlock ();
2885         
2886         do {
2887                 mono_threads_lock ();
2888                 if (shutting_down) {
2889                         /* somebody else is shutting down */
2890                         mono_threads_unlock ();
2891                         break;
2892                 }
2893                 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
2894                         mono_g_hash_table_foreach (threads, print_tids, NULL));
2895         
2896                 ResetEvent (background_change_event);
2897                 wait->num=0;
2898                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2899                 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2900                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
2901                 mono_threads_unlock ();
2902                 if(wait->num>0) {
2903                         /* Something to wait for */
2904                         wait_for_tids_or_state_change (wait, INFINITE);
2905                 }
2906                 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
2907         } while(wait->num>0);
2908
2909         /* Mono is shutting down, so just wait for the end */
2910         if (!mono_runtime_try_shutdown ()) {
2911                 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
2912                 mono_thread_suspend (mono_thread_internal_current ());
2913                 mono_thread_execute_interruption (mono_thread_internal_current ());
2914         }
2915
2916         /* 
2917          * Remove everything but the finalizer thread and self.
2918          * Also abort all the background threads
2919          * */
2920         do {
2921                 mono_threads_lock ();
2922
2923                 wait->num = 0;
2924                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
2925                 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
2926                 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
2927
2928                 mono_threads_unlock ();
2929
2930                 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
2931                 if(wait->num>0) {
2932                         /* Something to wait for */
2933                         wait_for_tids (wait, INFINITE);
2934                 }
2935         } while (wait->num > 0);
2936         
2937         /* 
2938          * give the subthreads a chance to really quit (this is mainly needed
2939          * to get correct user and system times from getrusage/wait/time(1)).
2940          * This could be removed if we avoid pthread_detach() and use pthread_join().
2941          */
2942         mono_thread_info_yield ();
2943 }
2944
2945 static void terminate_thread (gpointer key, gpointer value, gpointer user)
2946 {
2947         MonoInternalThread *thread=(MonoInternalThread *)value;
2948         
2949         if(thread->tid != (gsize)user) {
2950                 /*TerminateThread (thread->handle, -1);*/
2951         }
2952 }
2953
2954 void mono_thread_abort_all_other_threads (void)
2955 {
2956         gsize self = GetCurrentThreadId ();
2957
2958         mono_threads_lock ();
2959         THREAD_DEBUG (g_message ("%s: There are %d threads to abort", __func__,
2960                                  mono_g_hash_table_size (threads));
2961                       mono_g_hash_table_foreach (threads, print_tids, NULL));
2962
2963         mono_g_hash_table_foreach (threads, terminate_thread, (gpointer)self);
2964         
2965         mono_threads_unlock ();
2966 }
2967
2968 static void
2969 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
2970 {
2971         MonoInternalThread *thread = (MonoInternalThread*)value;
2972         struct wait_data *wait = (struct wait_data*)user_data;
2973         HANDLE handle;
2974
2975         /* 
2976          * We try to exclude threads early, to avoid running into the MAXIMUM_WAIT_OBJECTS
2977          * limitation.
2978          * This needs no locking.
2979          */
2980         if ((thread->state & ThreadState_Suspended) != 0 || 
2981                 (thread->state & ThreadState_Stopped) != 0)
2982                 return;
2983
2984         if (wait->num<MAXIMUM_WAIT_OBJECTS) {
2985                 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
2986                 if (handle == NULL)
2987                         return;
2988
2989                 wait->handles [wait->num] = handle;
2990                 wait->threads [wait->num] = thread;
2991                 wait->num++;
2992         }
2993 }
2994
2995 /*
2996  * mono_thread_suspend_all_other_threads:
2997  *
2998  *  Suspend all managed threads except the finalizer thread and this thread. It is
2999  * not possible to resume them later.
3000  */
3001 void mono_thread_suspend_all_other_threads (void)
3002 {
3003         struct wait_data wait_data;
3004         struct wait_data *wait = &wait_data;
3005         int i;
3006         gsize self = GetCurrentThreadId ();
3007         guint32 eventidx = 0;
3008         gboolean starting, finished;
3009
3010         memset (wait, 0, sizeof (struct wait_data));
3011         /*
3012          * The other threads could be in an arbitrary state at this point, i.e.
3013          * they could be starting up, shutting down etc. This means that there could be
3014          * threads which are not even in the threads hash table yet.
3015          */
3016
3017         /* 
3018          * First we set a barrier which will be checked by all threads before they
3019          * are added to the threads hash table, and they will exit if the flag is set.
3020          * This ensures that no threads could be added to the hash later.
3021          * We will use shutting_down as the barrier for now.
3022          */
3023         g_assert (shutting_down);
3024
3025         /*
3026          * We make multiple calls to WaitForMultipleObjects since:
3027          * - we can only wait for MAXIMUM_WAIT_OBJECTS threads
3028          * - some threads could exit without becoming suspended
3029          */
3030         finished = FALSE;
3031         while (!finished) {
3032                 /*
3033                  * Make a copy of the hashtable since we can't do anything with
3034                  * threads while threads_mutex is held.
3035                  */
3036                 wait->num = 0;
3037                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3038                 memset (wait->threads, 0, MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3039                 mono_threads_lock ();
3040                 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3041                 mono_threads_unlock ();
3042
3043                 eventidx = 0;
3044                 /* Get the suspended events that we'll be waiting for */
3045                 for (i = 0; i < wait->num; ++i) {
3046                         MonoInternalThread *thread = wait->threads [i];
3047
3048                         if ((thread->tid == self) || mono_gc_is_finalizer_internal_thread (thread) || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)) {
3049                                 //CloseHandle (wait->handles [i]);
3050                                 wait->threads [i] = NULL; /* ignore this thread in next loop */
3051                                 continue;
3052                         }
3053
3054                         LOCK_THREAD (thread);
3055
3056                         if ((thread->state & ThreadState_Suspended) != 0 || 
3057                                 (thread->state & ThreadState_StopRequested) != 0 ||
3058                                 (thread->state & ThreadState_Stopped) != 0) {
3059                                 UNLOCK_THREAD (thread);
3060                                 CloseHandle (wait->handles [i]);
3061                                 wait->threads [i] = NULL; /* ignore this thread in next loop */
3062                                 continue;
3063                         }
3064
3065                         ++eventidx;
3066
3067                         /* Convert abort requests into suspend requests */
3068                         if ((thread->state & ThreadState_AbortRequested) != 0)
3069                                 thread->state &= ~ThreadState_AbortRequested;
3070                         
3071                         thread->state |= ThreadState_SuspendRequested;
3072
3073                         UNLOCK_THREAD (thread);
3074
3075                         /* Signal the thread to suspend */
3076                         suspend_thread_internal (thread, TRUE);
3077                 }
3078                 if (eventidx <= 0) {
3079                         /* 
3080                          * If there are threads which are starting up, we wait until they
3081                          * are suspended when they try to register in the threads hash.
3082                          * This is guaranteed to finish, since the threads which can create new
3083                          * threads get suspended after a while.
3084                          * FIXME: The finalizer thread can still create new threads.
3085                          */
3086                         mono_threads_lock ();
3087                         if (threads_starting_up)
3088                                 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3089                         else
3090                                 starting = FALSE;
3091                         mono_threads_unlock ();
3092                         if (starting)
3093                                 Sleep (100);
3094                         else
3095                                 finished = TRUE;
3096                 }
3097         }
3098 }
3099
3100 static void
3101 collect_threads (gpointer key, gpointer value, gpointer user_data)
3102 {
3103         MonoInternalThread *thread = (MonoInternalThread*)value;
3104         struct wait_data *wait = (struct wait_data*)user_data;
3105         HANDLE handle;
3106
3107         if (wait->num<MAXIMUM_WAIT_OBJECTS) {
3108                 handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3109                 if (handle == NULL)
3110                         return;
3111
3112                 wait->handles [wait->num] = handle;
3113                 wait->threads [wait->num] = thread;
3114                 wait->num++;
3115         }
3116 }
3117
3118 static gboolean thread_dump_requested;
3119
3120 static G_GNUC_UNUSED gboolean
3121 print_stack_frame_to_string (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3122 {
3123         GString *p = (GString*)data;
3124         MonoMethod *method = NULL;
3125         if (frame->ji)
3126                 method = mono_jit_info_get_method (frame->ji);
3127
3128         if (method) {
3129                 gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3130                 g_string_append_printf (p, "  %s\n", location);
3131                 g_free (location);
3132         } else
3133                 g_string_append_printf (p, "  at <unknown> <0x%05x>\n", frame->native_offset);
3134
3135         return FALSE;
3136 }
3137
3138 static SuspendThreadResult
3139 print_thread_dump (MonoThreadInfo *info, gpointer ud)
3140 {
3141         MonoInternalThread *thread = ud;
3142         GString* text = g_string_new (0);
3143         char *name;
3144         GError *error = NULL;
3145
3146         if (thread->name) {
3147                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3148                 g_assert (!error);
3149                 g_string_append_printf (text, "\n\"%s\"", name);
3150                 g_free (name);
3151         }
3152         else if (thread->threadpool_thread)
3153                 g_string_append (text, "\n\"<threadpool thread>\"");
3154         else
3155                 g_string_append (text, "\n\"<unnamed thread>\"");
3156
3157 #if 0
3158 /* This no longer works with remote unwinding */
3159 #ifndef HOST_WIN32
3160         wapi_desc = wapi_current_thread_desc ();
3161         g_string_append_printf (text, " tid=0x%p this=0x%p %s\n", (gpointer)(gsize)thread->tid, thread,  wapi_desc);
3162         free (wapi_desc);
3163 #endif
3164 #endif
3165
3166         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);
3167
3168         fprintf (stdout, "%s", text->str);
3169
3170 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3171         OutputDebugStringA(text->str);
3172 #endif
3173
3174         g_string_free (text, TRUE);
3175         fflush (stdout);
3176         return MonoResumeThread;
3177 }
3178
3179 static void
3180 dump_thread (gpointer key, gpointer value, gpointer user)
3181 {
3182         MonoInternalThread *thread = (MonoInternalThread *)value;
3183
3184         if (thread == mono_thread_internal_current ())
3185                 return;
3186
3187         /*
3188         FIXME This still can hang if we stop a thread during malloc.
3189         FIXME This can hang if we suspend on a critical method and the GC kicks in. A fix might be to have function
3190         that takes a callback and runs it with the target suspended.
3191         We probably should loop a bit around trying to get it to either managed code
3192         or WSJ state.
3193         */
3194         mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, FALSE, print_thread_dump, thread);
3195 }
3196
3197 void
3198 mono_threads_perform_thread_dump (void)
3199 {
3200         if (!thread_dump_requested)
3201                 return;
3202
3203         printf ("Full thread dump:\n");
3204
3205         /* We take the loader lock and the root domain lock as to increase our odds of not deadlocking if
3206         something needs then in the process.
3207         */
3208         mono_loader_lock ();
3209         mono_domain_lock (mono_get_root_domain ());
3210
3211         mono_threads_lock ();
3212         mono_g_hash_table_foreach (threads, dump_thread, NULL);
3213         mono_threads_unlock ();
3214
3215         mono_domain_unlock (mono_get_root_domain ());
3216         mono_loader_unlock ();
3217
3218         thread_dump_requested = FALSE;
3219 }
3220
3221 /**
3222  * mono_threads_request_thread_dump:
3223  *
3224  *   Ask all threads except the current to print their stacktrace to stdout.
3225  */
3226 void
3227 mono_threads_request_thread_dump (void)
3228 {
3229         /*The new thread dump code runs out of the finalizer thread. */
3230         thread_dump_requested = TRUE;
3231         mono_gc_finalize_notify ();
3232 }
3233
3234 struct ref_stack {
3235         gpointer *refs;
3236         gint allocated; /* +1 so that refs [allocated] == NULL */
3237         gint bottom;
3238 };
3239
3240 typedef struct ref_stack RefStack;
3241
3242 static RefStack *
3243 ref_stack_new (gint initial_size)
3244 {
3245         RefStack *rs;
3246
3247         initial_size = MAX (initial_size, 16) + 1;
3248         rs = g_new0 (RefStack, 1);
3249         rs->refs = g_new0 (gpointer, initial_size);
3250         rs->allocated = initial_size;
3251         return rs;
3252 }
3253
3254 static void
3255 ref_stack_destroy (gpointer ptr)
3256 {
3257         RefStack *rs = ptr;
3258
3259         if (rs != NULL) {
3260                 g_free (rs->refs);
3261                 g_free (rs);
3262         }
3263 }
3264
3265 static void
3266 ref_stack_push (RefStack *rs, gpointer ptr)
3267 {
3268         g_assert (rs != NULL);
3269
3270         if (rs->bottom >= rs->allocated) {
3271                 rs->refs = g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3272                 rs->allocated <<= 1;
3273                 rs->refs [rs->allocated] = NULL;
3274         }
3275         rs->refs [rs->bottom++] = ptr;
3276 }
3277
3278 static void
3279 ref_stack_pop (RefStack *rs)
3280 {
3281         if (rs == NULL || rs->bottom == 0)
3282                 return;
3283
3284         rs->bottom--;
3285         rs->refs [rs->bottom] = NULL;
3286 }
3287
3288 static gboolean
3289 ref_stack_find (RefStack *rs, gpointer ptr)
3290 {
3291         gpointer *refs;
3292
3293         if (rs == NULL)
3294                 return FALSE;
3295
3296         for (refs = rs->refs; refs && *refs; refs++) {
3297                 if (*refs == ptr)
3298                         return TRUE;
3299         }
3300         return FALSE;
3301 }
3302
3303 /*
3304  * mono_thread_push_appdomain_ref:
3305  *
3306  *   Register that the current thread may have references to objects in domain 
3307  * @domain on its stack. Each call to this function should be paired with a 
3308  * call to pop_appdomain_ref.
3309  */
3310 void 
3311 mono_thread_push_appdomain_ref (MonoDomain *domain)
3312 {
3313         MonoInternalThread *thread = mono_thread_internal_current ();
3314
3315         if (thread) {
3316                 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3317                 SPIN_LOCK (thread->lock_thread_id);
3318                 if (thread->appdomain_refs == NULL)
3319                         thread->appdomain_refs = ref_stack_new (16);
3320                 ref_stack_push (thread->appdomain_refs, domain);
3321                 SPIN_UNLOCK (thread->lock_thread_id);
3322         }
3323 }
3324
3325 void
3326 mono_thread_pop_appdomain_ref (void)
3327 {
3328         MonoInternalThread *thread = mono_thread_internal_current ();
3329
3330         if (thread) {
3331                 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3332                 SPIN_LOCK (thread->lock_thread_id);
3333                 ref_stack_pop (thread->appdomain_refs);
3334                 SPIN_UNLOCK (thread->lock_thread_id);
3335         }
3336 }
3337
3338 gboolean
3339 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3340 {
3341         gboolean res;
3342         SPIN_LOCK (thread->lock_thread_id);
3343         res = ref_stack_find (thread->appdomain_refs, domain);
3344         SPIN_UNLOCK (thread->lock_thread_id);
3345         return res;
3346 }
3347
3348 gboolean
3349 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3350 {
3351         return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3352 }
3353
3354 typedef struct abort_appdomain_data {
3355         struct wait_data wait;
3356         MonoDomain *domain;
3357 } abort_appdomain_data;
3358
3359 static void
3360 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3361 {
3362         MonoInternalThread *thread = (MonoInternalThread*)value;
3363         abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3364         MonoDomain *domain = data->domain;
3365
3366         if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3367                 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3368
3369                 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
3370                         HANDLE handle = mono_threads_open_thread_handle (thread->handle, (MonoNativeThreadId)thread->tid);
3371                         if (handle == NULL)
3372                                 return;
3373                         data->wait.handles [data->wait.num] = handle;
3374                         data->wait.threads [data->wait.num] = thread;
3375                         data->wait.num++;
3376                 } else {
3377                         /* Just ignore the rest, we can't do anything with
3378                          * them yet
3379                          */
3380                 }
3381         }
3382 }
3383
3384 /*
3385  * mono_threads_abort_appdomain_threads:
3386  *
3387  *   Abort threads which has references to the given appdomain.
3388  */
3389 gboolean
3390 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3391 {
3392 #ifdef __native_client__
3393         return FALSE;
3394 #endif
3395
3396         abort_appdomain_data user_data;
3397         guint32 start_time;
3398         int orig_timeout = timeout;
3399         int i;
3400
3401         THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3402
3403         start_time = mono_msec_ticks ();
3404         do {
3405                 mono_threads_lock ();
3406
3407                 user_data.domain = domain;
3408                 user_data.wait.num = 0;
3409                 /* This shouldn't take any locks */
3410                 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3411                 mono_threads_unlock ();
3412
3413                 if (user_data.wait.num > 0) {
3414                         /* Abort the threads outside the threads lock */
3415                         for (i = 0; i < user_data.wait.num; ++i)
3416                                 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3417
3418                         /*
3419                          * We should wait for the threads either to abort, or to leave the
3420                          * domain. We can't do the latter, so we wait with a timeout.
3421                          */
3422                         wait_for_tids (&user_data.wait, 100);
3423                 }
3424
3425                 /* Update remaining time */
3426                 timeout -= mono_msec_ticks () - start_time;
3427                 start_time = mono_msec_ticks ();
3428
3429                 if (orig_timeout != -1 && timeout < 0)
3430                         return FALSE;
3431         }
3432         while (user_data.wait.num > 0);
3433
3434         THREAD_DEBUG (g_message ("%s: abort done", __func__));
3435
3436         return TRUE;
3437 }
3438
3439 static void
3440 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3441 {
3442         MonoInternalThread *thread = (MonoInternalThread*)value;
3443         MonoDomain *domain = (MonoDomain*)user_data;
3444         int i;
3445
3446         /* No locking needed here */
3447         /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3448
3449         if (thread->cached_culture_info) {
3450                 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3451                         MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3452                         if (obj && obj->vtable->domain == domain)
3453                                 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3454                 }
3455         }
3456 }
3457         
3458 /*
3459  * mono_threads_clear_cached_culture:
3460  *
3461  *   Clear the cached_current_culture from all threads if it is in the
3462  * given appdomain.
3463  */
3464 void
3465 mono_threads_clear_cached_culture (MonoDomain *domain)
3466 {
3467         mono_threads_lock ();
3468         mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3469         mono_threads_unlock ();
3470 }
3471
3472 /*
3473  * mono_thread_get_undeniable_exception:
3474  *
3475  *   Return an exception which needs to be raised when leaving a catch clause.
3476  * This is used for undeniable exception propagation.
3477  */
3478 MonoException*
3479 mono_thread_get_undeniable_exception (void)
3480 {
3481         MonoInternalThread *thread = mono_thread_internal_current ();
3482
3483         if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3484                 /*
3485                  * FIXME: Clear the abort exception and return an AppDomainUnloaded 
3486                  * exception if the thread no longer references a dying appdomain.
3487                  */
3488                 thread->abort_exc->trace_ips = NULL;
3489                 thread->abort_exc->stack_trace = NULL;
3490                 return thread->abort_exc;
3491         }
3492
3493         return NULL;
3494 }
3495
3496 #if MONO_SMALL_CONFIG
3497 #define NUM_STATIC_DATA_IDX 4
3498 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3499         64, 256, 1024, 4096
3500 };
3501 #else
3502 #define NUM_STATIC_DATA_IDX 8
3503 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3504         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3505 };
3506 #endif
3507
3508 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3509
3510 static void
3511 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3512 {
3513         int i;
3514         gpointer *static_data = addr;
3515         for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3516                 int j, numwords;
3517                 void **ptr;
3518                 if (!static_data [i])
3519                         continue;
3520                 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3521                 ptr = static_data [i];
3522                 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3523                         uintptr_t bmap = static_reference_bitmaps [i][j];
3524                         void ** p = ptr;
3525                         while (bmap) {
3526                                 if ((bmap & 1) && *p) {
3527                                         mark_func (p, gc_data);
3528                                 }
3529                                 p++;
3530                                 bmap >>= 1;
3531                         }
3532                 }
3533         }
3534 }
3535
3536 /*
3537  *  mono_alloc_static_data
3538  *
3539  *   Allocate memory blocks for storing threads or context static data
3540  */
3541 static void 
3542 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3543 {
3544         guint idx = (offset >> 24) - 1;
3545         int i;
3546
3547         gpointer* static_data = *static_data_ptr;
3548         if (!static_data) {
3549                 static void* tls_desc = NULL;
3550                 if (mono_gc_user_markers_supported () && !tls_desc)
3551                         tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3552                 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3553                 *static_data_ptr = static_data;
3554                 static_data [0] = static_data;
3555         }
3556
3557         for (i = 1; i <= idx; ++i) {
3558                 if (static_data [i])
3559                         continue;
3560                 if (mono_gc_user_markers_supported () && threadlocal)
3561                         static_data [i] = g_malloc0 (static_data_size [i]);
3562                 else
3563                         static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3564         }
3565 }
3566
3567 static void 
3568 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3569 {
3570         int i;
3571         for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3572                 gpointer p = static_data [i];
3573                 if (!p)
3574                         continue;
3575                 /*
3576                  * At this point, the static data pointer array is still registered with the
3577                  * GC, so must ensure that mark_tls_slots() will not encounter any invalid
3578                  * data.  Freeing the individual arrays without first nulling their slots
3579                  * would make it possible for mark_tls_slots() to encounter a pointer to
3580                  * such an already freed array.  See bug #13813.
3581                  */
3582                 static_data [i] = NULL;
3583                 mono_memory_write_barrier ();
3584                 if (mono_gc_user_markers_supported () && threadlocal)
3585                         g_free (p);
3586                 else
3587                         mono_gc_free_fixed (p);
3588         }
3589         mono_gc_free_fixed (static_data);
3590 }
3591
3592 /*
3593  *  mono_init_static_data_info
3594  *
3595  *   Initializes static data counters
3596  */
3597 static void mono_init_static_data_info (StaticDataInfo *static_data)
3598 {
3599         static_data->idx = 0;
3600         static_data->offset = 0;
3601         static_data->freelist = NULL;
3602 }
3603
3604 /*
3605  *  mono_alloc_static_data_slot
3606  *
3607  *   Generates an offset for static data. static_data contains the counters
3608  *  used to generate it.
3609  */
3610 static guint32
3611 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3612 {
3613         guint32 offset;
3614
3615         if (!static_data->idx && !static_data->offset) {
3616                 /* 
3617                  * we use the first chunk of the first allocation also as
3618                  * an array for the rest of the data 
3619                  */
3620                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3621         }
3622         static_data->offset += align - 1;
3623         static_data->offset &= ~(align - 1);
3624         if (static_data->offset + size >= static_data_size [static_data->idx]) {
3625                 static_data->idx ++;
3626                 g_assert (size <= static_data_size [static_data->idx]);
3627                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3628                 static_data->offset = 0;
3629         }
3630         offset = static_data->offset | ((static_data->idx + 1) << 24);
3631         static_data->offset += size;
3632         return offset;
3633 }
3634
3635 /* 
3636  * ensure thread static fields already allocated are valid for thread
3637  * This function is called when a thread is created or on thread attach.
3638  */
3639 static void
3640 thread_adjust_static_data (MonoInternalThread *thread)
3641 {
3642         guint32 offset;
3643
3644         mono_threads_lock ();
3645         if (thread_static_info.offset || thread_static_info.idx > 0) {
3646                 /* get the current allocated size */
3647                 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3648                 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3649         }
3650         mono_threads_unlock ();
3651 }
3652
3653 static void 
3654 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3655 {
3656         MonoInternalThread *thread = value;
3657         guint32 offset = GPOINTER_TO_UINT (user);
3658
3659         mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3660 }
3661
3662 static MonoThreadDomainTls*
3663 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3664 {
3665         MonoThreadDomainTls* prev = NULL;
3666         MonoThreadDomainTls* tmp = static_data->freelist;
3667         while (tmp) {
3668                 if (tmp->size == size) {
3669                         if (prev)
3670                                 prev->next = tmp->next;
3671                         else
3672                                 static_data->freelist = tmp->next;
3673                         return tmp;
3674                 }
3675                 prev = tmp;
3676                 tmp = tmp->next;
3677         }
3678         return NULL;
3679 }
3680
3681 #if SIZEOF_VOID_P == 4
3682 #define ONE_P 1
3683 #else
3684 #define ONE_P 1ll
3685 #endif
3686
3687 static void
3688 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3689 {
3690         int i;
3691         int idx = (offset >> 24) - 1;
3692         uintptr_t *rb;
3693         if (!static_reference_bitmaps [idx])
3694                 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3695         rb = static_reference_bitmaps [idx];
3696         offset &= 0xffffff;
3697         offset /= sizeof (gpointer);
3698         /* offset is now the bitmap offset */
3699         for (i = 0; i < numbits; ++i) {
3700                 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
3701                         rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (ONE_P << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3702         }
3703 }
3704
3705 static void
3706 clear_reference_bitmap (guint32 offset, guint32 size)
3707 {
3708         int idx = (offset >> 24) - 1;
3709         uintptr_t *rb;
3710         rb = static_reference_bitmaps [idx];
3711         offset &= 0xffffff;
3712         offset /= sizeof (gpointer);
3713         size /= sizeof (gpointer);
3714         size += offset;
3715         /* offset is now the bitmap offset */
3716         for (; offset < size; ++offset)
3717                 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3718 }
3719
3720 /*
3721  * The offset for a special static variable is composed of three parts:
3722  * a bit that indicates the type of static data (0:thread, 1:context),
3723  * an index in the array of chunks of memory for the thread (thread->static_data)
3724  * and an offset in that chunk of mem. This allows allocating less memory in the 
3725  * common case.
3726  */
3727
3728 guint32
3729 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3730 {
3731         guint32 offset;
3732         if (static_type == SPECIAL_STATIC_THREAD) {
3733                 MonoThreadDomainTls *item;
3734                 mono_threads_lock ();
3735                 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3736                 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3737                 if (item) {
3738                         offset = item->offset;
3739                         g_free (item);
3740                 } else {
3741                         offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3742                 }
3743                 update_tls_reference_bitmap (offset, bitmap, numbits);
3744                 /* This can be called during startup */
3745                 if (threads != NULL)
3746                         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3747                 mono_threads_unlock ();
3748         } else {
3749                 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3750                 mono_contexts_lock ();
3751                 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3752                 mono_contexts_unlock ();
3753                 offset |= 0x80000000;   /* Set the high bit to indicate context static data */
3754         }
3755         return offset;
3756 }
3757
3758 gpointer
3759 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3760 {
3761         /* The high bit means either thread (0) or static (1) data. */
3762
3763         guint32 static_type = (offset & 0x80000000);
3764         int idx;
3765
3766         offset &= 0x7fffffff;
3767         idx = (offset >> 24) - 1;
3768
3769         if (static_type == 0) {
3770                 return get_thread_static_data (thread, offset);
3771         } else {
3772                 /* Allocate static data block under demand, since we don't have a list
3773                 // of contexts
3774                 */
3775                 MonoAppContext *context = mono_context_get ();
3776                 if (!context->static_data || !context->static_data [idx]) {
3777                         mono_contexts_lock ();
3778                         mono_alloc_static_data (&(context->static_data), offset, FALSE);
3779                         mono_contexts_unlock ();
3780                 }
3781                 return ((char*) context->static_data [idx]) + (offset & 0xffffff);      
3782         }
3783 }
3784
3785 gpointer
3786 mono_get_special_static_data (guint32 offset)
3787 {
3788         return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3789 }
3790
3791 typedef struct {
3792         guint32 offset;
3793         guint32 size;
3794 } TlsOffsetSize;
3795
3796 static void 
3797 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3798 {
3799         MonoInternalThread *thread = value;
3800         TlsOffsetSize *data = user;
3801         int idx = (data->offset >> 24) - 1;
3802         char *ptr;
3803
3804         if (!thread->static_data || !thread->static_data [idx])
3805                 return;
3806         ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3807         mono_gc_bzero_atomic (ptr, data->size);
3808 }
3809
3810 static void
3811 do_free_special_slot (guint32 offset, guint32 size)
3812 {
3813         guint32 static_type = (offset & 0x80000000);
3814         /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3815         if (static_type == 0) {
3816                 TlsOffsetSize data;
3817                 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3818                 data.offset = offset & 0x7fffffff;
3819                 data.size = size;
3820                 clear_reference_bitmap (data.offset, data.size);
3821                 if (threads != NULL)
3822                         mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3823                 item->offset = offset;
3824                 item->size = size;
3825
3826                 if (!mono_runtime_is_shutting_down ()) {
3827                         item->next = thread_static_info.freelist;
3828                         thread_static_info.freelist = item;
3829                 } else {
3830                         /* We could be called during shutdown after mono_thread_cleanup () is called */
3831                         g_free (item);
3832                 }
3833         } else {
3834                 /* FIXME: free context static data as well */
3835         }
3836 }
3837
3838 static void
3839 do_free_special (gpointer key, gpointer value, gpointer data)
3840 {
3841         MonoClassField *field = key;
3842         guint32 offset = GPOINTER_TO_UINT (value);
3843         gint32 align;
3844         guint32 size;
3845         size = mono_type_size (field->type, &align);
3846         do_free_special_slot (offset, size);
3847 }
3848
3849 void
3850 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3851 {
3852         mono_threads_lock ();
3853         g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3854         mono_threads_unlock ();
3855 }
3856
3857 void
3858 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3859 {
3860         mono_threads_lock ();
3861         do_free_special_slot (offset, size);
3862         mono_threads_unlock ();
3863 }
3864
3865 /*
3866  * allocates room in the thread local area for storing an instance of the struct type
3867  * the allocation is kept track of in domain->tlsrec_list.
3868  */
3869 uint32_t
3870 mono_thread_alloc_tls (MonoReflectionType *type)
3871 {
3872         MonoDomain *domain = mono_domain_get ();
3873         MonoClass *klass;
3874         MonoTlsDataRecord *tlsrec;
3875         int max_set = 0;
3876         gsize *bitmap;
3877         gsize default_bitmap [4] = {0};
3878         uint32_t tls_offset;
3879         guint32 size;
3880         gint32 align;
3881
3882         klass = mono_class_from_mono_type (type->type);
3883         /* TlsDatum is a struct, so we subtract the object header size offset */
3884         bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3885         size = mono_type_size (type->type, &align);
3886         tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3887         if (bitmap != default_bitmap)
3888                 g_free (bitmap);
3889         tlsrec = g_new0 (MonoTlsDataRecord, 1);
3890         tlsrec->tls_offset = tls_offset;
3891         tlsrec->size = size;
3892         mono_domain_lock (domain);
3893         tlsrec->next = domain->tlsrec_list;
3894         domain->tlsrec_list = tlsrec;
3895         mono_domain_unlock (domain);
3896         return tls_offset;
3897 }
3898
3899 static void
3900 destroy_tls (MonoDomain *domain, uint32_t tls_offset)
3901 {
3902         MonoTlsDataRecord *prev = NULL;
3903         MonoTlsDataRecord *cur;
3904         guint32 size = 0;
3905
3906         mono_domain_lock (domain);
3907         cur = domain->tlsrec_list;
3908         while (cur) {
3909                 if (cur->tls_offset == tls_offset) {
3910                         if (prev)
3911                                 prev->next = cur->next;
3912                         else
3913                                 domain->tlsrec_list = cur->next;
3914                         size = cur->size;
3915                         g_free (cur);
3916                         break;
3917                 }
3918                 prev = cur;
3919                 cur = cur->next;
3920         }
3921         mono_domain_unlock (domain);
3922         if (size)
3923                 mono_special_static_data_free_slot (tls_offset, size);
3924 }
3925
3926 void
3927 mono_thread_destroy_tls (uint32_t tls_offset)
3928 {
3929         destroy_tls (mono_domain_get (), tls_offset);
3930 }
3931
3932 /*
3933  * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
3934  */
3935 void
3936 mono_thread_destroy_domain_tls (MonoDomain *domain)
3937 {
3938         while (domain->tlsrec_list)
3939                 destroy_tls (domain, domain->tlsrec_list->tls_offset);
3940 }
3941
3942 static MonoClassField *local_slots = NULL;
3943
3944 typedef struct {
3945         /* local tls data to get locals_slot from a thread */
3946         guint32 offset;
3947         int idx;
3948         /* index in the locals_slot array */
3949         int slot;
3950 } LocalSlotID;
3951
3952 static void
3953 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
3954 {
3955         LocalSlotID *sid = user_data;
3956         MonoInternalThread *thread = (MonoInternalThread*)value;
3957         MonoArray *slots_array;
3958         /*
3959          * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
3960          * it is for the right domain, so we need to check if it is allocated an initialized
3961          * for the current thread.
3962          */
3963         /*g_print ("handling thread %p\n", thread);*/
3964         if (!thread->static_data || !thread->static_data [sid->idx])
3965                 return;
3966         slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
3967         if (!slots_array || sid->slot >= mono_array_length (slots_array))
3968                 return;
3969         mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
3970 }
3971
3972 void
3973 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
3974 {
3975         MonoDomain *domain;
3976         LocalSlotID sid;
3977         sid.slot = slot;
3978         if (thread_local) {
3979                 void *addr = NULL;
3980                 if (!local_slots) {
3981                         local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
3982                         if (!local_slots) {
3983                                 g_warning ("local_slots field not found in Thread class");
3984                                 return;
3985                         }
3986                 }
3987                 domain = mono_domain_get ();
3988                 mono_domain_lock (domain);
3989                 if (domain->special_static_fields)
3990                         addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
3991                 mono_domain_unlock (domain);
3992                 if (!addr)
3993                         return;
3994                 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
3995                 sid.offset = GPOINTER_TO_UINT (addr);
3996                 sid.offset &= 0x7fffffff;
3997                 sid.idx = (sid.offset >> 24) - 1;
3998                 mono_threads_lock ();
3999                 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4000                 mono_threads_unlock ();
4001         } else {
4002                 /* FIXME: clear the slot for MonoAppContexts, too */
4003         }
4004 }
4005
4006 #ifdef HOST_WIN32
4007 static void CALLBACK dummy_apc (ULONG_PTR param)
4008 {
4009 }
4010 #endif
4011
4012 /*
4013  * mono_thread_execute_interruption
4014  * 
4015  * Performs the operation that the requested thread state requires (abort,
4016  * suspend or stop)
4017  */
4018 static MonoException*
4019 mono_thread_execute_interruption (MonoInternalThread *thread)
4020 {
4021         LOCK_THREAD (thread);
4022
4023         /* MonoThread::interruption_requested can only be changed with atomics */
4024         if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4025                 /* this will consume pending APC calls */
4026 #ifdef HOST_WIN32
4027                 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4028 #endif
4029                 InterlockedDecrement (&thread_interruption_requested);
4030                 /* Clear the interrupted flag of the thread so it can wait again */
4031                 mono_thread_info_clear_interruption ();
4032         }
4033
4034         if ((thread->state & ThreadState_AbortRequested) != 0) {
4035                 UNLOCK_THREAD (thread);
4036                 if (thread->abort_exc == NULL) {
4037                         /* 
4038                          * This might be racy, but it has to be called outside the lock
4039                          * since it calls managed code.
4040                          */
4041                         MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4042                 }
4043                 return thread->abort_exc;
4044         }
4045         else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4046                 self_suspend_internal (thread);         
4047                 return NULL;
4048         }
4049         else if ((thread->state & ThreadState_StopRequested) != 0) {
4050                 /* FIXME: do this through the JIT? */
4051
4052                 UNLOCK_THREAD (thread);
4053                 
4054                 mono_thread_exit ();
4055                 return NULL;
4056         } else if (thread->pending_exception) {
4057                 MonoException *exc;
4058
4059                 exc = thread->pending_exception;
4060                 thread->pending_exception = NULL;
4061
4062         UNLOCK_THREAD (thread);
4063         return exc;
4064         } else if (thread->thread_interrupt_requested) {
4065
4066                 thread->thread_interrupt_requested = FALSE;
4067                 UNLOCK_THREAD (thread);
4068                 
4069                 return(mono_get_exception_thread_interrupted ());
4070         }
4071         
4072         UNLOCK_THREAD (thread);
4073         
4074         return NULL;
4075 }
4076
4077 /*
4078  * mono_thread_request_interruption
4079  *
4080  * A signal handler can call this method to request the interruption of a
4081  * thread. The result of the interruption will depend on the current state of
4082  * the thread. If the result is an exception that needs to be throw, it is 
4083  * provided as return value.
4084  */
4085 MonoException*
4086 mono_thread_request_interruption (gboolean running_managed)
4087 {
4088         MonoInternalThread *thread = mono_thread_internal_current ();
4089
4090         /* The thread may already be stopping */
4091         if (thread == NULL) 
4092                 return NULL;
4093
4094 #ifdef HOST_WIN32
4095         if (thread->interrupt_on_stop && 
4096                 thread->state & ThreadState_StopRequested && 
4097                 thread->state & ThreadState_Background)
4098                 ExitThread (1);
4099 #endif
4100         
4101         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4102                 return NULL;
4103         InterlockedIncrement (&thread_interruption_requested);
4104
4105         if (!running_managed || is_running_protected_wrapper ()) {
4106                 /* Can't stop while in unmanaged code. Increase the global interruption
4107                    request count. When exiting the unmanaged method the count will be
4108                    checked and the thread will be interrupted. */
4109
4110                 if (mono_thread_notify_pending_exc_fn && !running_managed)
4111                         /* The JIT will notify the thread about the interruption */
4112                         /* This shouldn't take any locks */
4113                         mono_thread_notify_pending_exc_fn (NULL);
4114
4115                 /* this will awake the thread if it is in WaitForSingleObject 
4116                    or similar */
4117                 /* Our implementation of this function ignores the func argument */
4118 #ifdef HOST_WIN32
4119                 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4120 #else
4121                 mono_thread_info_self_interrupt ();
4122 #endif
4123                 return NULL;
4124         }
4125         else {
4126                 return mono_thread_execute_interruption (thread);
4127         }
4128 }
4129
4130 /*This function should be called by a thread after it has exited all of
4131  * its handle blocks at interruption time.*/
4132 MonoException*
4133 mono_thread_resume_interruption (void)
4134 {
4135         MonoInternalThread *thread = mono_thread_internal_current ();
4136         gboolean still_aborting;
4137
4138         /* The thread may already be stopping */
4139         if (thread == NULL)
4140                 return NULL;
4141
4142         LOCK_THREAD (thread);
4143         still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4144         UNLOCK_THREAD (thread);
4145
4146         /*This can happen if the protected block called Thread::ResetAbort*/
4147         if (!still_aborting)
4148                 return FALSE;
4149
4150         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4151                 return NULL;
4152         InterlockedIncrement (&thread_interruption_requested);
4153
4154         mono_thread_info_self_interrupt ();
4155
4156         return mono_thread_execute_interruption (thread);
4157 }
4158
4159 gboolean mono_thread_interruption_requested ()
4160 {
4161         if (thread_interruption_requested) {
4162                 MonoInternalThread *thread = mono_thread_internal_current ();
4163                 /* The thread may already be stopping */
4164                 if (thread != NULL) 
4165                         return (thread->interruption_requested);
4166         }
4167         return FALSE;
4168 }
4169
4170 static MonoException*
4171 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4172 {
4173         MonoInternalThread *thread = mono_thread_internal_current ();
4174
4175         /* The thread may already be stopping */
4176         if (thread == NULL)
4177                 return NULL;
4178
4179         if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4180                 MonoException* exc = mono_thread_execute_interruption (thread);
4181                 if (exc)
4182                         return exc;
4183         }
4184         return NULL;
4185 }
4186
4187 /*
4188  * Performs the interruption of the current thread, if one has been requested,
4189  * and the thread is not running a protected wrapper.
4190  * Return the exception which needs to be thrown, if any.
4191  */
4192 MonoException*
4193 mono_thread_interruption_checkpoint (void)
4194 {
4195         return mono_thread_interruption_checkpoint_request (FALSE);
4196 }
4197
4198 /*
4199  * Performs the interruption of the current thread, if one has been requested.
4200  * Return the exception which needs to be thrown, if any.
4201  */
4202 MonoException*
4203 mono_thread_force_interruption_checkpoint_noraise (void)
4204 {
4205         return mono_thread_interruption_checkpoint_request (TRUE);
4206 }
4207
4208 /*
4209  * Performs the interruption of the current thread, if one has been requested.
4210  * Throw the exception which needs to be thrown, if any.
4211  */
4212 void
4213 mono_thread_force_interruption_checkpoint (void)
4214 {
4215         MonoException *ex;
4216
4217         ex = mono_thread_interruption_checkpoint_request (TRUE);
4218         if (ex)
4219                 mono_raise_exception (ex);
4220 }
4221
4222 /*
4223  * mono_thread_get_and_clear_pending_exception:
4224  *
4225  *   Return any pending exceptions for the current thread and clear it as a side effect.
4226  */
4227 MonoException*
4228 mono_thread_get_and_clear_pending_exception (void)
4229 {
4230         MonoInternalThread *thread = mono_thread_internal_current ();
4231
4232         /* The thread may already be stopping */
4233         if (thread == NULL)
4234                 return NULL;
4235
4236         if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4237                 return mono_thread_execute_interruption (thread);
4238         }
4239         
4240         if (thread->pending_exception) {
4241                 MonoException *exc = thread->pending_exception;
4242
4243                 thread->pending_exception = NULL;
4244                 return exc;
4245         }
4246
4247         return NULL;
4248 }
4249
4250 /*
4251  * mono_set_pending_exception:
4252  *
4253  *   Set the pending exception of the current thread to EXC.
4254  * The exception will be thrown when execution returns to managed code.
4255  */
4256 void
4257 mono_set_pending_exception (MonoException *exc)
4258 {
4259         MonoInternalThread *thread = mono_thread_internal_current ();
4260
4261         /* The thread may already be stopping */
4262         if (thread == NULL)
4263                 return;
4264
4265         MONO_OBJECT_SETREF (thread, pending_exception, exc);
4266
4267     mono_thread_request_interruption (FALSE);
4268 }
4269
4270 /**
4271  * mono_thread_interruption_request_flag:
4272  *
4273  * Returns the address of a flag that will be non-zero if an interruption has
4274  * been requested for a thread. The thread to interrupt may not be the current
4275  * thread, so an additional call to mono_thread_interruption_requested() or
4276  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4277  * zero.
4278  */
4279 gint32* mono_thread_interruption_request_flag ()
4280 {
4281         return &thread_interruption_requested;
4282 }
4283
4284 void 
4285 mono_thread_init_apartment_state (void)
4286 {
4287 #ifdef HOST_WIN32
4288         MonoInternalThread* thread = mono_thread_internal_current ();
4289
4290         /* Positive return value indicates success, either
4291          * S_OK if this is first CoInitialize call, or
4292          * S_FALSE if CoInitialize already called, but with same
4293          * threading model. A negative value indicates failure,
4294          * probably due to trying to change the threading model.
4295          */
4296         if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA) 
4297                         ? COINIT_APARTMENTTHREADED 
4298                         : COINIT_MULTITHREADED) < 0) {
4299                 thread->apartment_state = ThreadApartmentState_Unknown;
4300         }
4301 #endif
4302 }
4303
4304 void 
4305 mono_thread_cleanup_apartment_state (void)
4306 {
4307 #ifdef HOST_WIN32
4308         MonoInternalThread* thread = mono_thread_internal_current ();
4309
4310         if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4311                 CoUninitialize ();
4312         }
4313 #endif
4314 }
4315
4316 void
4317 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4318 {
4319         LOCK_THREAD (thread);
4320         thread->state |= state;
4321         UNLOCK_THREAD (thread);
4322 }
4323
4324 void
4325 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4326 {
4327         LOCK_THREAD (thread);
4328         thread->state &= ~state;
4329         UNLOCK_THREAD (thread);
4330 }
4331
4332 gboolean
4333 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4334 {
4335         gboolean ret = FALSE;
4336
4337         LOCK_THREAD (thread);
4338
4339         if ((thread->state & test) != 0) {
4340                 ret = TRUE;
4341         }
4342         
4343         UNLOCK_THREAD (thread);
4344         
4345         return ret;
4346 }
4347
4348 //static MonoClassField *execution_context_field;
4349
4350 static MonoObject**
4351 get_execution_context_addr (void)
4352 {
4353         MonoDomain *domain = mono_domain_get ();
4354         guint32 offset = domain->execution_context_field_offset;
4355
4356         if (!offset) {
4357                 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4358                 g_assert (field);
4359
4360                 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4361
4362                 mono_domain_lock (domain);
4363                 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4364                 mono_domain_unlock (domain);
4365                 g_assert (offset);
4366
4367                 domain->execution_context_field_offset = offset;
4368         }
4369
4370         return (MonoObject**) mono_get_special_static_data (offset);
4371 }
4372
4373 MonoObject*
4374 mono_thread_get_execution_context (void)
4375 {
4376         return *get_execution_context_addr ();
4377 }
4378
4379 void
4380 mono_thread_set_execution_context (MonoObject *ec)
4381 {
4382         *get_execution_context_addr () = ec;
4383 }
4384
4385 static gboolean has_tls_get = FALSE;
4386
4387 void
4388 mono_runtime_set_has_tls_get (gboolean val)
4389 {
4390         has_tls_get = val;
4391 }
4392
4393 gboolean
4394 mono_runtime_has_tls_get (void)
4395 {
4396         return has_tls_get;
4397 }
4398
4399 static void
4400 self_interrupt_thread (void *_unused)
4401 {
4402         MonoThreadInfo *info = mono_thread_info_current ();
4403         MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ()); 
4404         if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4405                 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. */
4406         g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4407 }
4408
4409 static gboolean
4410 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4411 {
4412         if (!ji)
4413                 return FALSE;
4414         return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4415 }
4416
4417 static gboolean
4418 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4419 {
4420         MonoJitInfo **dest = data;
4421         *dest = frame->ji;
4422         return TRUE;
4423 }
4424
4425 static MonoJitInfo*
4426 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4427 {
4428         MonoJitInfo *ji = NULL;
4429         if (!info)
4430                 return NULL;
4431         mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4432         return ji;
4433 }
4434
4435 typedef struct {
4436         MonoInternalThread *thread;
4437         gboolean install_async_abort;
4438         gpointer interrupt_handle;
4439 } AbortThreadData;
4440
4441 static SuspendThreadResult
4442 abort_thread_critical (MonoThreadInfo *info, gpointer ud)
4443 {
4444         AbortThreadData *data = ud;
4445         MonoInternalThread *thread = data->thread;
4446         MonoJitInfo *ji = NULL;
4447         gboolean protected_wrapper;
4448         gboolean running_managed;
4449
4450         if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4451                 return MonoResumeThread;
4452
4453         /*someone is already interrupting it*/
4454         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4455                 return MonoResumeThread;
4456
4457         InterlockedIncrement (&thread_interruption_requested);
4458
4459         ji = mono_thread_info_get_last_managed (info);
4460         protected_wrapper = ji && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4461         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4462
4463         if (!protected_wrapper && running_managed) {
4464                 /*We are in managed code*/
4465                 /*Set the thread to call */
4466                 if (data->install_async_abort)
4467                         mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4468                 return MonoResumeThread;
4469         } else {
4470                 if (mono_thread_notify_pending_exc_fn)
4471                         /* The JIT will notify the thread about the interruption */
4472                         mono_thread_notify_pending_exc_fn (info);
4473
4474                 /* 
4475                  * This will cause waits to be broken.
4476                  * It will also prevent the thread from entering a wait, so if the thread returns
4477                  * from the wait before it receives the abort signal, it will just spin in the wait
4478                  * functions in the io-layer until the signal handler calls QueueUserAPC which will
4479                  * make it return.
4480                  */
4481                 data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4482                 return MonoResumeThread;
4483         }
4484 }
4485
4486 static void
4487 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4488 {
4489         AbortThreadData data = { 0 };
4490         data.thread = thread;
4491         data.install_async_abort = install_async_abort;
4492
4493         /*
4494         FIXME this is insanely broken, it doesn't cause interruption to happen
4495         synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4496         */
4497         if (thread == mono_thread_internal_current ()) {
4498                 /* Do it synchronously */
4499                 MonoException *exc = mono_thread_request_interruption (can_raise_exception); 
4500                 if (exc)
4501                         mono_raise_exception (exc);
4502                 mono_thread_info_interrupt (thread->handle);
4503                 return;
4504         }
4505
4506         mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, TRUE, abort_thread_critical, &data);
4507         if (data.interrupt_handle)
4508                 mono_thread_info_finish_interrupt (data.interrupt_handle);
4509         /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4510 }
4511
4512 typedef struct{
4513         MonoInternalThread *thread;
4514         gboolean interrupt;
4515         gpointer interrupt_handle;
4516 } SuspendThreadData;
4517
4518 static SuspendThreadResult
4519 suspend_thread_critical (MonoThreadInfo *info, gpointer ud)
4520 {
4521         SuspendThreadData *data = ud;
4522         MonoInternalThread *thread = data->thread;
4523         MonoJitInfo *ji = NULL;
4524         gboolean protected_wrapper;
4525         gboolean running_managed;
4526
4527         ji = mono_thread_info_get_last_managed (info);
4528         protected_wrapper = ji && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4529         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4530
4531         if (running_managed && !protected_wrapper) {
4532                 thread->state &= ~ThreadState_SuspendRequested;
4533                 thread->state |= ThreadState_Suspended;
4534                 return KeepSuspended;
4535         } else {
4536                 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4537                         InterlockedIncrement (&thread_interruption_requested);
4538                 if (data->interrupt)
4539                         data->interrupt_handle = mono_thread_info_prepare_interrupt (thread->handle);
4540                 
4541                 if (mono_thread_notify_pending_exc_fn && !running_managed)
4542                         /* The JIT will notify the thread about the interruption */
4543                         mono_thread_notify_pending_exc_fn (info);
4544                 return MonoResumeThread;
4545         }
4546 }
4547         
4548 static void
4549 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4550 {
4551         LOCK_THREAD (thread);
4552         if (thread == mono_thread_internal_current ()) {
4553                 mono_thread_info_begin_self_suspend ();
4554                 //XXX replace this with better named functions
4555                 thread->state &= ~ThreadState_SuspendRequested;
4556                 thread->state |= ThreadState_Suspended;
4557                 UNLOCK_THREAD (thread);
4558                 mono_thread_info_end_self_suspend ();
4559         } else {
4560                 SuspendThreadData data = { 0 };
4561                 data.thread = thread;
4562                 data.interrupt = interrupt;
4563
4564                 mono_thread_info_safe_suspend_and_run ((MonoNativeThreadId)(gsize)thread->tid, interrupt, suspend_thread_critical, &data);
4565                 if (data.interrupt_handle)
4566                         mono_thread_info_finish_interrupt (data.interrupt_handle);
4567                 UNLOCK_THREAD (thread);
4568         }
4569 }
4570
4571 /*This is called with @thread synch_cs held and it must release it*/
4572 static void
4573 self_suspend_internal (MonoInternalThread *thread)
4574 {
4575         mono_thread_info_begin_self_suspend ();
4576         thread->state &= ~ThreadState_SuspendRequested;
4577         thread->state |= ThreadState_Suspended;
4578         UNLOCK_THREAD (thread);
4579         mono_thread_info_end_self_suspend ();
4580 }
4581
4582 /*This is called with @thread synch_cs held and it must release it*/
4583 static gboolean
4584 resume_thread_internal (MonoInternalThread *thread)
4585 {
4586         UNLOCK_THREAD (thread);
4587         /* Awake the thread */
4588         if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4589                 return FALSE;
4590         LOCK_THREAD (thread);
4591         thread->state &= ~ThreadState_Suspended;
4592         UNLOCK_THREAD (thread);
4593         return TRUE;
4594 }
4595
4596
4597 /*
4598  * mono_thread_is_foreign:
4599  * @thread: the thread to query
4600  *
4601  * This function allows one to determine if a thread was created by the mono runtime and has
4602  * a well defined lifecycle or it's a foreigh one, created by the native environment.
4603  *
4604  * Returns: true if @thread was not created by the runtime.
4605  */
4606 mono_bool
4607 mono_thread_is_foreign (MonoThread *thread)
4608 {
4609         MonoThreadInfo *info = thread->internal_thread->thread_info;
4610         return info->runtime_thread == FALSE;
4611 }
4612
4613 /*
4614  * mono_add_joinable_thread:
4615  *
4616  *   Add TID to the list of joinable threads.
4617  * LOCKING: Acquires the threads lock.
4618  */
4619 void
4620 mono_threads_add_joinable_thread (gpointer tid)
4621 {
4622 #ifndef HOST_WIN32
4623         /*
4624          * We cannot detach from threads because it causes problems like
4625          * 2fd16f60/r114307. So we collect them and join them when
4626          * we have time (in he finalizer thread).
4627          */
4628         joinable_threads_lock ();
4629         if (!joinable_threads)
4630                 joinable_threads = g_hash_table_new (NULL, NULL);
4631         g_hash_table_insert (joinable_threads, tid, tid);
4632         joinable_thread_count ++;
4633         joinable_threads_unlock ();
4634
4635         mono_gc_finalize_notify ();
4636 #endif
4637 }
4638
4639 /*
4640  * mono_threads_join_threads:
4641  *
4642  *   Join all joinable threads. This is called from the finalizer thread.
4643  * LOCKING: Acquires the threads lock.
4644  */
4645 void
4646 mono_threads_join_threads (void)
4647 {
4648 #ifndef HOST_WIN32
4649         GHashTableIter iter;
4650         gpointer key;
4651         gpointer tid;
4652         pthread_t thread;
4653         gboolean found;
4654
4655         /* Fastpath */
4656         if (!joinable_thread_count)
4657                 return;
4658
4659         while (TRUE) {
4660                 joinable_threads_lock ();
4661                 found = FALSE;
4662                 if (g_hash_table_size (joinable_threads)) {
4663                         g_hash_table_iter_init (&iter, joinable_threads);
4664                         g_hash_table_iter_next (&iter, &key, (void**)&tid);
4665                         thread = (pthread_t)tid;
4666                         g_hash_table_remove (joinable_threads, key);
4667                         joinable_thread_count --;
4668                         found = TRUE;
4669                 }
4670                 joinable_threads_unlock ();
4671                 if (found) {
4672                         if (thread != pthread_self ())
4673                                 /* This shouldn't block */
4674                                 pthread_join (thread, NULL);
4675                 } else {
4676                         break;
4677                 }
4678         }
4679 #endif
4680 }
4681
4682 /*
4683  * mono_thread_join:
4684  *
4685  *   Wait for thread TID to exit.
4686  * LOCKING: Acquires the threads lock.
4687  */
4688 void
4689 mono_thread_join (gpointer tid)
4690 {
4691 #ifndef HOST_WIN32
4692         pthread_t thread;
4693         gboolean found = FALSE;
4694
4695         joinable_threads_lock ();
4696         if (!joinable_threads)
4697                 joinable_threads = g_hash_table_new (NULL, NULL);
4698         if (g_hash_table_lookup (joinable_threads, tid)) {
4699                 g_hash_table_remove (joinable_threads, tid);
4700                 joinable_thread_count --;
4701                 found = TRUE;
4702         }
4703         joinable_threads_unlock ();
4704         if (!found)
4705                 return;
4706         thread = (pthread_t)tid;
4707         pthread_join (thread, NULL);
4708 #endif
4709 }