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