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