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