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