6d582f15e859dfc08c92ce17d498647ed17eb823
[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         abort_appdomain_data user_data;
3479         guint32 start_time;
3480         int orig_timeout = timeout;
3481         int i;
3482
3483         THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3484
3485         start_time = mono_msec_ticks ();
3486         do {
3487                 mono_threads_lock ();
3488
3489                 user_data.domain = domain;
3490                 user_data.wait.num = 0;
3491                 /* This shouldn't take any locks */
3492                 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3493                 mono_threads_unlock ();
3494
3495                 if (user_data.wait.num > 0) {
3496                         /* Abort the threads outside the threads lock */
3497                         for (i = 0; i < user_data.wait.num; ++i)
3498                                 ves_icall_System_Threading_Thread_Abort (user_data.wait.threads [i], NULL);
3499
3500                         /*
3501                          * We should wait for the threads either to abort, or to leave the
3502                          * domain. We can't do the latter, so we wait with a timeout.
3503                          */
3504                         wait_for_tids (&user_data.wait, 100);
3505                 }
3506
3507                 /* Update remaining time */
3508                 timeout -= mono_msec_ticks () - start_time;
3509                 start_time = mono_msec_ticks ();
3510
3511                 if (orig_timeout != -1 && timeout < 0)
3512                         return FALSE;
3513         }
3514         while (user_data.wait.num > 0);
3515
3516         THREAD_DEBUG (g_message ("%s: abort done", __func__));
3517
3518         return TRUE;
3519 }
3520
3521 static void
3522 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3523 {
3524         MonoInternalThread *thread = (MonoInternalThread*)value;
3525         MonoDomain *domain = (MonoDomain*)user_data;
3526         int i;
3527
3528         /* No locking needed here */
3529         /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3530
3531         if (thread->cached_culture_info) {
3532                 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3533                         MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3534                         if (obj && obj->vtable->domain == domain)
3535                                 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3536                 }
3537         }
3538 }
3539         
3540 /*
3541  * mono_threads_clear_cached_culture:
3542  *
3543  *   Clear the cached_current_culture from all threads if it is in the
3544  * given appdomain.
3545  */
3546 void
3547 mono_threads_clear_cached_culture (MonoDomain *domain)
3548 {
3549         mono_threads_lock ();
3550         mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3551         mono_threads_unlock ();
3552 }
3553
3554 /*
3555  * mono_thread_get_undeniable_exception:
3556  *
3557  *   Return an exception which needs to be raised when leaving a catch clause.
3558  * This is used for undeniable exception propagation.
3559  */
3560 MonoException*
3561 mono_thread_get_undeniable_exception (void)
3562 {
3563         MonoInternalThread *thread = mono_thread_internal_current ();
3564
3565         if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3566                 /*
3567                  * FIXME: Clear the abort exception and return an AppDomainUnloaded 
3568                  * exception if the thread no longer references a dying appdomain.
3569                  */
3570                 thread->abort_exc->trace_ips = NULL;
3571                 thread->abort_exc->stack_trace = NULL;
3572                 return thread->abort_exc;
3573         }
3574
3575         return NULL;
3576 }
3577
3578 #if MONO_SMALL_CONFIG
3579 #define NUM_STATIC_DATA_IDX 4
3580 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3581         64, 256, 1024, 4096
3582 };
3583 #else
3584 #define NUM_STATIC_DATA_IDX 8
3585 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3586         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3587 };
3588 #endif
3589
3590 static uintptr_t* static_reference_bitmaps [NUM_STATIC_DATA_IDX];
3591
3592 static void
3593 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func)
3594 {
3595         int i;
3596         gpointer *static_data = addr;
3597         for (i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3598                 int j, numwords;
3599                 void **ptr;
3600                 if (!static_data [i])
3601                         continue;
3602                 numwords = 1 + static_data_size [i] / sizeof (gpointer) / (sizeof(uintptr_t) * 8);
3603                 ptr = static_data [i];
3604                 for (j = 0; j < numwords; ++j, ptr += sizeof (uintptr_t) * 8) {
3605                         uintptr_t bmap = static_reference_bitmaps [i][j];
3606                         void ** p = ptr;
3607                         while (bmap) {
3608                                 if ((bmap & 1) && *p) {
3609                                         mark_func (p);
3610                                 }
3611                                 p++;
3612                                 bmap >>= 1;
3613                         }
3614                 }
3615         }
3616 }
3617
3618 /*
3619  *  mono_alloc_static_data
3620  *
3621  *   Allocate memory blocks for storing threads or context static data
3622  */
3623 static void 
3624 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3625 {
3626         guint idx = (offset >> 24) - 1;
3627         int i;
3628
3629         gpointer* static_data = *static_data_ptr;
3630         if (!static_data) {
3631                 static void* tls_desc = NULL;
3632                 if (mono_gc_user_markers_supported () && !tls_desc)
3633                         tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3634                 static_data = mono_gc_alloc_fixed (static_data_size [0], threadlocal?tls_desc:NULL);
3635                 *static_data_ptr = static_data;
3636                 static_data [0] = static_data;
3637         }
3638
3639         for (i = 1; i <= idx; ++i) {
3640                 if (static_data [i])
3641                         continue;
3642                 if (mono_gc_user_markers_supported () && threadlocal)
3643                         static_data [i] = g_malloc0 (static_data_size [i]);
3644                 else
3645                         static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
3646         }
3647 }
3648
3649 static void 
3650 mono_free_static_data (gpointer* static_data, gboolean threadlocal)
3651 {
3652         int i;
3653         for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3654                 if (!static_data [i])
3655                         continue;
3656                 if (mono_gc_user_markers_supported () && threadlocal)
3657                         g_free (static_data [i]);
3658                 else
3659                         mono_gc_free_fixed (static_data [i]);
3660         }
3661         mono_gc_free_fixed (static_data);
3662 }
3663
3664 /*
3665  *  mono_init_static_data_info
3666  *
3667  *   Initializes static data counters
3668  */
3669 static void mono_init_static_data_info (StaticDataInfo *static_data)
3670 {
3671         static_data->idx = 0;
3672         static_data->offset = 0;
3673         static_data->freelist = NULL;
3674 }
3675
3676 /*
3677  *  mono_alloc_static_data_slot
3678  *
3679  *   Generates an offset for static data. static_data contains the counters
3680  *  used to generate it.
3681  */
3682 static guint32
3683 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
3684 {
3685         guint32 offset;
3686
3687         if (!static_data->idx && !static_data->offset) {
3688                 /* 
3689                  * we use the first chunk of the first allocation also as
3690                  * an array for the rest of the data 
3691                  */
3692                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
3693         }
3694         static_data->offset += align - 1;
3695         static_data->offset &= ~(align - 1);
3696         if (static_data->offset + size >= static_data_size [static_data->idx]) {
3697                 static_data->idx ++;
3698                 g_assert (size <= static_data_size [static_data->idx]);
3699                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
3700                 static_data->offset = 0;
3701         }
3702         offset = static_data->offset | ((static_data->idx + 1) << 24);
3703         static_data->offset += size;
3704         return offset;
3705 }
3706
3707 /* 
3708  * ensure thread static fields already allocated are valid for thread
3709  * This function is called when a thread is created or on thread attach.
3710  */
3711 static void
3712 thread_adjust_static_data (MonoInternalThread *thread)
3713 {
3714         guint32 offset;
3715
3716         mono_threads_lock ();
3717         if (thread_static_info.offset || thread_static_info.idx > 0) {
3718                 /* get the current allocated size */
3719                 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
3720                 mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3721         }
3722         mono_threads_unlock ();
3723 }
3724
3725 static void 
3726 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3727 {
3728         MonoInternalThread *thread = value;
3729         guint32 offset = GPOINTER_TO_UINT (user);
3730
3731         mono_alloc_static_data (&(thread->static_data), offset, TRUE);
3732 }
3733
3734 static MonoThreadDomainTls*
3735 search_tls_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
3736 {
3737         MonoThreadDomainTls* prev = NULL;
3738         MonoThreadDomainTls* tmp = static_data->freelist;
3739         while (tmp) {
3740                 if (tmp->size == size) {
3741                         if (prev)
3742                                 prev->next = tmp->next;
3743                         else
3744                                 static_data->freelist = tmp->next;
3745                         return tmp;
3746                 }
3747                 tmp = tmp->next;
3748         }
3749         return NULL;
3750 }
3751
3752 static void
3753 update_tls_reference_bitmap (guint32 offset, uintptr_t *bitmap, int numbits)
3754 {
3755         int i;
3756         int idx = (offset >> 24) - 1;
3757         uintptr_t *rb;
3758         if (!static_reference_bitmaps [idx])
3759                 static_reference_bitmaps [idx] = g_new0 (uintptr_t, 1 + static_data_size [idx] / sizeof(gpointer) / (sizeof(uintptr_t) * 8));
3760         rb = static_reference_bitmaps [idx];
3761         offset &= 0xffffff;
3762         offset /= sizeof (gpointer);
3763         /* offset is now the bitmap offset */
3764         for (i = 0; i < numbits; ++i) {
3765                 if (bitmap [i / sizeof (uintptr_t)] & (1L << (i & (sizeof (uintptr_t) * 8 -1))))
3766                         rb [(offset + i) / (sizeof (uintptr_t) * 8)] |= (1L << ((offset + i) & (sizeof (uintptr_t) * 8 -1)));
3767         }
3768 }
3769
3770 static void
3771 clear_reference_bitmap (guint32 offset, guint32 size)
3772 {
3773         int idx = (offset >> 24) - 1;
3774         uintptr_t *rb;
3775         rb = static_reference_bitmaps [idx];
3776         offset &= 0xffffff;
3777         offset /= sizeof (gpointer);
3778         size /= sizeof (gpointer);
3779         size += offset;
3780         /* offset is now the bitmap offset */
3781         for (; offset < size; ++offset)
3782                 rb [offset / (sizeof (uintptr_t) * 8)] &= ~(1L << (offset & (sizeof (uintptr_t) * 8 -1)));
3783 }
3784
3785 /*
3786  * The offset for a special static variable is composed of three parts:
3787  * a bit that indicates the type of static data (0:thread, 1:context),
3788  * an index in the array of chunks of memory for the thread (thread->static_data)
3789  * and an offset in that chunk of mem. This allows allocating less memory in the 
3790  * common case.
3791  */
3792
3793 guint32
3794 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
3795 {
3796         guint32 offset;
3797         if (static_type == SPECIAL_STATIC_THREAD) {
3798                 MonoThreadDomainTls *item;
3799                 mono_threads_lock ();
3800                 item = search_tls_slot_in_freelist (&thread_static_info, size, align);
3801                 /*g_print ("TLS alloc: %d in domain %p (total: %d), cached: %p\n", size, mono_domain_get (), thread_static_info.offset, item);*/
3802                 if (item) {
3803                         offset = item->offset;
3804                         g_free (item);
3805                 } else {
3806                         offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
3807                 }
3808                 update_tls_reference_bitmap (offset, bitmap, numbits);
3809                 /* This can be called during startup */
3810                 if (threads != NULL)
3811                         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
3812                 mono_threads_unlock ();
3813         } else {
3814                 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
3815                 mono_contexts_lock ();
3816                 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
3817                 mono_contexts_unlock ();
3818                 offset |= 0x80000000;   /* Set the high bit to indicate context static data */
3819         }
3820         return offset;
3821 }
3822
3823 gpointer
3824 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
3825 {
3826         /* The high bit means either thread (0) or static (1) data. */
3827
3828         guint32 static_type = (offset & 0x80000000);
3829         int idx;
3830
3831         offset &= 0x7fffffff;
3832         idx = (offset >> 24) - 1;
3833
3834         if (static_type == 0) {
3835                 return get_thread_static_data (thread, offset);
3836         } else {
3837                 /* Allocate static data block under demand, since we don't have a list
3838                 // of contexts
3839                 */
3840                 MonoAppContext *context = mono_context_get ();
3841                 if (!context->static_data || !context->static_data [idx]) {
3842                         mono_contexts_lock ();
3843                         mono_alloc_static_data (&(context->static_data), offset, FALSE);
3844                         mono_contexts_unlock ();
3845                 }
3846                 return ((char*) context->static_data [idx]) + (offset & 0xffffff);      
3847         }
3848 }
3849
3850 gpointer
3851 mono_get_special_static_data (guint32 offset)
3852 {
3853         return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
3854 }
3855
3856 typedef struct {
3857         guint32 offset;
3858         guint32 size;
3859 } TlsOffsetSize;
3860
3861 static void 
3862 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
3863 {
3864         MonoInternalThread *thread = value;
3865         TlsOffsetSize *data = user;
3866         int idx = (data->offset >> 24) - 1;
3867         char *ptr;
3868
3869         if (!thread->static_data || !thread->static_data [idx])
3870                 return;
3871         ptr = ((char*) thread->static_data [idx]) + (data->offset & 0xffffff);
3872         mono_gc_bzero (ptr, data->size);
3873 }
3874
3875 static void
3876 do_free_special_slot (guint32 offset, guint32 size)
3877 {
3878         guint32 static_type = (offset & 0x80000000);
3879         /*g_print ("free %s , size: %d, offset: %x\n", field->name, size, offset);*/
3880         if (static_type == 0) {
3881                 TlsOffsetSize data;
3882                 MonoThreadDomainTls *item = g_new0 (MonoThreadDomainTls, 1);
3883                 data.offset = offset & 0x7fffffff;
3884                 data.size = size;
3885                 clear_reference_bitmap (data.offset, data.size);
3886                 if (threads != NULL)
3887                         mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
3888                 item->offset = offset;
3889                 item->size = size;
3890
3891                 if (!mono_runtime_is_shutting_down ()) {
3892                         item->next = thread_static_info.freelist;
3893                         thread_static_info.freelist = item;
3894                 } else {
3895                         /* We could be called during shutdown after mono_thread_cleanup () is called */
3896                         g_free (item);
3897                 }
3898         } else {
3899                 /* FIXME: free context static data as well */
3900         }
3901 }
3902
3903 static void
3904 do_free_special (gpointer key, gpointer value, gpointer data)
3905 {
3906         MonoClassField *field = key;
3907         guint32 offset = GPOINTER_TO_UINT (value);
3908         gint32 align;
3909         guint32 size;
3910         size = mono_type_size (field->type, &align);
3911         do_free_special_slot (offset, size);
3912 }
3913
3914 void
3915 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
3916 {
3917         mono_threads_lock ();
3918         g_hash_table_foreach (special_static_fields, do_free_special, NULL);
3919         mono_threads_unlock ();
3920 }
3921
3922 void
3923 mono_special_static_data_free_slot (guint32 offset, guint32 size)
3924 {
3925         mono_threads_lock ();
3926         do_free_special_slot (offset, size);
3927         mono_threads_unlock ();
3928 }
3929
3930 /*
3931  * allocates room in the thread local area for storing an instance of the struct type
3932  * the allocation is kept track of in domain->tlsrec_list.
3933  */
3934 uint32_t
3935 mono_thread_alloc_tls (MonoReflectionType *type)
3936 {
3937         MonoDomain *domain = mono_domain_get ();
3938         MonoClass *klass;
3939         MonoTlsDataRecord *tlsrec;
3940         int max_set = 0;
3941         gsize *bitmap;
3942         gsize default_bitmap [4] = {0};
3943         uint32_t tls_offset;
3944         guint32 size;
3945         gint32 align;
3946
3947         klass = mono_class_from_mono_type (type->type);
3948         /* TlsDatum is a struct, so we subtract the object header size offset */
3949         bitmap = mono_class_compute_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
3950         size = mono_type_size (type->type, &align);
3951         tls_offset = mono_alloc_special_static_data (SPECIAL_STATIC_THREAD, size, align, (uintptr_t*)bitmap, max_set + 1);
3952         if (bitmap != default_bitmap)
3953                 g_free (bitmap);
3954         tlsrec = g_new0 (MonoTlsDataRecord, 1);
3955         tlsrec->tls_offset = tls_offset;
3956         tlsrec->size = size;
3957         mono_domain_lock (domain);
3958         tlsrec->next = domain->tlsrec_list;
3959         domain->tlsrec_list = tlsrec;
3960         mono_domain_unlock (domain);
3961         return tls_offset;
3962 }
3963
3964 void
3965 mono_thread_destroy_tls (uint32_t tls_offset)
3966 {
3967         MonoTlsDataRecord *prev = NULL;
3968         MonoTlsDataRecord *cur;
3969         guint32 size = 0;
3970         MonoDomain *domain = mono_domain_get ();
3971         mono_domain_lock (domain);
3972         cur = domain->tlsrec_list;
3973         while (cur) {
3974                 if (cur->tls_offset == tls_offset) {
3975                         if (prev)
3976                                 prev->next = cur->next;
3977                         else
3978                                 domain->tlsrec_list = cur->next;
3979                         size = cur->size;
3980                         g_free (cur);
3981                         break;
3982                 }
3983                 prev = cur;
3984                 cur = cur->next;
3985         }
3986         mono_domain_unlock (domain);
3987         if (size)
3988                 mono_special_static_data_free_slot (tls_offset, size);
3989 }
3990
3991 /*
3992  * This is just to ensure cleanup: the finalizers should have taken care, so this is not perf-critical.
3993  */
3994 void
3995 mono_thread_destroy_domain_tls (MonoDomain *domain)
3996 {
3997         while (domain->tlsrec_list)
3998                 mono_thread_destroy_tls (domain->tlsrec_list->tls_offset);
3999 }
4000
4001 static MonoClassField *local_slots = NULL;
4002
4003 typedef struct {
4004         /* local tls data to get locals_slot from a thread */
4005         guint32 offset;
4006         int idx;
4007         /* index in the locals_slot array */
4008         int slot;
4009 } LocalSlotID;
4010
4011 static void
4012 clear_local_slot (gpointer key, gpointer value, gpointer user_data)
4013 {
4014         LocalSlotID *sid = user_data;
4015         MonoInternalThread *thread = (MonoInternalThread*)value;
4016         MonoArray *slots_array;
4017         /*
4018          * the static field is stored at: ((char*) thread->static_data [idx]) + (offset & 0xffffff);
4019          * it is for the right domain, so we need to check if it is allocated an initialized
4020          * for the current thread.
4021          */
4022         /*g_print ("handling thread %p\n", thread);*/
4023         if (!thread->static_data || !thread->static_data [sid->idx])
4024                 return;
4025         slots_array = *(MonoArray **)(((char*) thread->static_data [sid->idx]) + (sid->offset & 0xffffff));
4026         if (!slots_array || sid->slot >= mono_array_length (slots_array))
4027                 return;
4028         mono_array_set (slots_array, MonoObject*, sid->slot, NULL);
4029 }
4030
4031 void
4032 mono_thread_free_local_slot_values (int slot, MonoBoolean thread_local)
4033 {
4034         MonoDomain *domain;
4035         LocalSlotID sid;
4036         sid.slot = slot;
4037         if (thread_local) {
4038                 void *addr = NULL;
4039                 if (!local_slots) {
4040                         local_slots = mono_class_get_field_from_name (mono_defaults.thread_class, "local_slots");
4041                         if (!local_slots) {
4042                                 g_warning ("local_slots field not found in Thread class");
4043                                 return;
4044                         }
4045                 }
4046                 domain = mono_domain_get ();
4047                 mono_domain_lock (domain);
4048                 if (domain->special_static_fields)
4049                         addr = g_hash_table_lookup (domain->special_static_fields, local_slots);
4050                 mono_domain_unlock (domain);
4051                 if (!addr)
4052                         return;
4053                 /*g_print ("freeing slot %d at %p\n", slot, addr);*/
4054                 sid.offset = GPOINTER_TO_UINT (addr);
4055                 sid.offset &= 0x7fffffff;
4056                 sid.idx = (sid.offset >> 24) - 1;
4057                 mono_threads_lock ();
4058                 mono_g_hash_table_foreach (threads, clear_local_slot, &sid);
4059                 mono_threads_unlock ();
4060         } else {
4061                 /* FIXME: clear the slot for MonoAppContexts, too */
4062         }
4063 }
4064
4065 #ifdef HOST_WIN32
4066 static void CALLBACK dummy_apc (ULONG_PTR param)
4067 {
4068 }
4069 #else
4070 static guint32 dummy_apc (gpointer param)
4071 {
4072         return 0;
4073 }
4074 #endif
4075
4076 /*
4077  * mono_thread_execute_interruption
4078  * 
4079  * Performs the operation that the requested thread state requires (abort,
4080  * suspend or stop)
4081  */
4082 static MonoException* mono_thread_execute_interruption (MonoInternalThread *thread)
4083 {
4084         ensure_synch_cs_set (thread);
4085         
4086         EnterCriticalSection (thread->synch_cs);
4087
4088         /* MonoThread::interruption_requested can only be changed with atomics */
4089         if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4090                 /* this will consume pending APC calls */
4091                 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4092                 InterlockedDecrement (&thread_interruption_requested);
4093 #ifndef HOST_WIN32
4094                 /* Clear the interrupted flag of the thread so it can wait again */
4095                 wapi_clear_interruption ();
4096 #endif
4097         }
4098
4099         if ((thread->state & ThreadState_AbortRequested) != 0) {
4100                 LeaveCriticalSection (thread->synch_cs);
4101                 if (thread->abort_exc == NULL) {
4102                         /* 
4103                          * This might be racy, but it has to be called outside the lock
4104                          * since it calls managed code.
4105                          */
4106                         MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4107                 }
4108                 return thread->abort_exc;
4109         }
4110         else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4111                 self_suspend_internal (thread);         
4112                 return NULL;
4113         }
4114         else if ((thread->state & ThreadState_StopRequested) != 0) {
4115                 /* FIXME: do this through the JIT? */
4116
4117                 LeaveCriticalSection (thread->synch_cs);
4118                 
4119                 mono_thread_exit ();
4120                 return NULL;
4121         } else if (thread->pending_exception) {
4122                 MonoException *exc;
4123
4124                 exc = thread->pending_exception;
4125                 thread->pending_exception = NULL;
4126
4127         LeaveCriticalSection (thread->synch_cs);
4128         return exc;
4129         } else if (thread->thread_interrupt_requested) {
4130
4131                 thread->thread_interrupt_requested = FALSE;
4132                 LeaveCriticalSection (thread->synch_cs);
4133                 
4134                 return(mono_get_exception_thread_interrupted ());
4135         }
4136         
4137         LeaveCriticalSection (thread->synch_cs);
4138         
4139         return NULL;
4140 }
4141
4142 /*
4143  * mono_thread_request_interruption
4144  *
4145  * A signal handler can call this method to request the interruption of a
4146  * thread. The result of the interruption will depend on the current state of
4147  * the thread. If the result is an exception that needs to be throw, it is 
4148  * provided as return value.
4149  */
4150 MonoException*
4151 mono_thread_request_interruption (gboolean running_managed)
4152 {
4153         MonoInternalThread *thread = mono_thread_internal_current ();
4154
4155         /* The thread may already be stopping */
4156         if (thread == NULL) 
4157                 return NULL;
4158
4159 #ifdef HOST_WIN32
4160         if (thread->interrupt_on_stop && 
4161                 thread->state & ThreadState_StopRequested && 
4162                 thread->state & ThreadState_Background)
4163                 ExitThread (1);
4164 #endif
4165         
4166         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4167                 return NULL;
4168         InterlockedIncrement (&thread_interruption_requested);
4169
4170         if (!running_managed || is_running_protected_wrapper ()) {
4171                 /* Can't stop while in unmanaged code. Increase the global interruption
4172                    request count. When exiting the unmanaged method the count will be
4173                    checked and the thread will be interrupted. */
4174                 
4175
4176                 if (mono_thread_notify_pending_exc_fn && !running_managed)
4177                         /* The JIT will notify the thread about the interruption */
4178                         /* This shouldn't take any locks */
4179                         mono_thread_notify_pending_exc_fn ();
4180
4181                 /* this will awake the thread if it is in WaitForSingleObject 
4182                    or similar */
4183                 /* Our implementation of this function ignores the func argument */
4184                 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
4185                 return NULL;
4186         }
4187         else {
4188                 return mono_thread_execute_interruption (thread);
4189         }
4190 }
4191
4192 /*This function should be called by a thread after it has exited all of
4193  * its handle blocks at interruption time.*/
4194 MonoException*
4195 mono_thread_resume_interruption (void)
4196 {
4197         MonoInternalThread *thread = mono_thread_internal_current ();
4198         gboolean still_aborting;
4199
4200         /* The thread may already be stopping */
4201         if (thread == NULL)
4202                 return NULL;
4203
4204         ensure_synch_cs_set (thread);
4205         EnterCriticalSection (thread->synch_cs);
4206         still_aborting = (thread->state & ThreadState_AbortRequested) != 0;
4207         LeaveCriticalSection (thread->synch_cs);
4208
4209         /*This can happen if the protected block called Thread::ResetAbort*/
4210         if (!still_aborting)
4211                 return FALSE;
4212
4213         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4214                 return NULL;
4215         InterlockedIncrement (&thread_interruption_requested);
4216
4217 #ifndef HOST_WIN32
4218         wapi_self_interrupt ();
4219 #endif
4220         return mono_thread_execute_interruption (thread);
4221 }
4222
4223 gboolean mono_thread_interruption_requested ()
4224 {
4225         if (thread_interruption_requested) {
4226                 MonoInternalThread *thread = mono_thread_internal_current ();
4227                 /* The thread may already be stopping */
4228                 if (thread != NULL) 
4229                         return (thread->interruption_requested);
4230         }
4231         return FALSE;
4232 }
4233
4234 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4235 {
4236         MonoInternalThread *thread = mono_thread_internal_current ();
4237
4238         /* The thread may already be stopping */
4239         if (thread == NULL)
4240                 return;
4241
4242         mono_debugger_check_interruption ();
4243
4244         if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4245                 MonoException* exc = mono_thread_execute_interruption (thread);
4246                 if (exc) mono_raise_exception (exc);
4247         }
4248 }
4249
4250 /*
4251  * Performs the interruption of the current thread, if one has been requested,
4252  * and the thread is not running a protected wrapper.
4253  */
4254 void mono_thread_interruption_checkpoint ()
4255 {
4256         mono_thread_interruption_checkpoint_request (FALSE);
4257 }
4258
4259 /*
4260  * Performs the interruption of the current thread, if one has been requested.
4261  */
4262 void mono_thread_force_interruption_checkpoint ()
4263 {
4264         mono_thread_interruption_checkpoint_request (TRUE);
4265 }
4266
4267 /*
4268  * mono_thread_get_and_clear_pending_exception:
4269  *
4270  *   Return any pending exceptions for the current thread and clear it as a side effect.
4271  */
4272 MonoException*
4273 mono_thread_get_and_clear_pending_exception (void)
4274 {
4275         MonoInternalThread *thread = mono_thread_internal_current ();
4276
4277         /* The thread may already be stopping */
4278         if (thread == NULL)
4279                 return NULL;
4280
4281         if (thread->interruption_requested && !is_running_protected_wrapper ()) {
4282                 return mono_thread_execute_interruption (thread);
4283         }
4284         
4285         if (thread->pending_exception) {
4286                 MonoException *exc = thread->pending_exception;
4287
4288                 thread->pending_exception = NULL;
4289                 return exc;
4290         }
4291
4292         return NULL;
4293 }
4294
4295 /*
4296  * mono_set_pending_exception:
4297  *
4298  *   Set the pending exception of the current thread to EXC.
4299  * The exception will be thrown when execution returns to managed code.
4300  */
4301 void
4302 mono_set_pending_exception (MonoException *exc)
4303 {
4304         MonoInternalThread *thread = mono_thread_internal_current ();
4305
4306         /* The thread may already be stopping */
4307         if (thread == NULL)
4308                 return;
4309
4310         MONO_OBJECT_SETREF (thread, pending_exception, exc);
4311
4312     mono_thread_request_interruption (FALSE);
4313 }
4314
4315 /**
4316  * mono_thread_interruption_request_flag:
4317  *
4318  * Returns the address of a flag that will be non-zero if an interruption has
4319  * been requested for a thread. The thread to interrupt may not be the current
4320  * thread, so an additional call to mono_thread_interruption_requested() or
4321  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4322  * zero.
4323  */
4324 gint32* mono_thread_interruption_request_flag ()
4325 {
4326         return &thread_interruption_requested;
4327 }
4328
4329 void 
4330 mono_thread_init_apartment_state (void)
4331 {
4332 #ifdef HOST_WIN32
4333         MonoInternalThread* thread = mono_thread_internal_current ();
4334
4335         /* Positive return value indicates success, either
4336          * S_OK if this is first CoInitialize call, or
4337          * S_FALSE if CoInitialize already called, but with same
4338          * threading model. A negative value indicates failure,
4339          * probably due to trying to change the threading model.
4340          */
4341         if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA) 
4342                         ? COINIT_APARTMENTTHREADED 
4343                         : COINIT_MULTITHREADED) < 0) {
4344                 thread->apartment_state = ThreadApartmentState_Unknown;
4345         }
4346 #endif
4347 }
4348
4349 void 
4350 mono_thread_cleanup_apartment_state (void)
4351 {
4352 #ifdef HOST_WIN32
4353         MonoInternalThread* thread = mono_thread_internal_current ();
4354
4355         if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4356                 CoUninitialize ();
4357         }
4358 #endif
4359 }
4360
4361 void
4362 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4363 {
4364         ensure_synch_cs_set (thread);
4365         
4366         EnterCriticalSection (thread->synch_cs);
4367         thread->state |= state;
4368         LeaveCriticalSection (thread->synch_cs);
4369 }
4370
4371 void
4372 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4373 {
4374         ensure_synch_cs_set (thread);
4375         
4376         EnterCriticalSection (thread->synch_cs);
4377         thread->state &= ~state;
4378         LeaveCriticalSection (thread->synch_cs);
4379 }
4380
4381 gboolean
4382 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4383 {
4384         gboolean ret = FALSE;
4385
4386         ensure_synch_cs_set (thread);
4387         
4388         EnterCriticalSection (thread->synch_cs);
4389
4390         if ((thread->state & test) != 0) {
4391                 ret = TRUE;
4392         }
4393         
4394         LeaveCriticalSection (thread->synch_cs);
4395         
4396         return ret;
4397 }
4398
4399 //static MonoClassField *execution_context_field;
4400
4401 static MonoObject**
4402 get_execution_context_addr (void)
4403 {
4404         MonoDomain *domain = mono_domain_get ();
4405         guint32 offset = domain->execution_context_field_offset;
4406
4407         if (!offset) {
4408                 MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
4409                 g_assert (field);
4410
4411                 g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
4412
4413                 mono_domain_lock (domain);
4414                 offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
4415                 mono_domain_unlock (domain);
4416                 g_assert (offset);
4417
4418                 domain->execution_context_field_offset = offset;
4419         }
4420
4421         return (MonoObject**) mono_get_special_static_data (offset);
4422 }
4423
4424 MonoObject*
4425 mono_thread_get_execution_context (void)
4426 {
4427         return *get_execution_context_addr ();
4428 }
4429
4430 void
4431 mono_thread_set_execution_context (MonoObject *ec)
4432 {
4433         *get_execution_context_addr () = ec;
4434 }
4435
4436 static gboolean has_tls_get = FALSE;
4437
4438 void
4439 mono_runtime_set_has_tls_get (gboolean val)
4440 {
4441         has_tls_get = val;
4442 }
4443
4444 gboolean
4445 mono_runtime_has_tls_get (void)
4446 {
4447         return has_tls_get;
4448 }
4449
4450 int
4451 mono_thread_kill (MonoInternalThread *thread, int signal)
4452 {
4453 #ifdef HOST_WIN32
4454         /* Win32 uses QueueUserAPC and callers of this are guarded */
4455         g_assert_not_reached ();
4456 #else
4457 #  ifdef PTHREAD_POINTER_ID
4458         return pthread_kill ((gpointer)(gsize)(thread->tid), mono_thread_get_abort_signal ());
4459 #  else
4460 #    ifdef PLATFORM_ANDROID
4461         if (thread->android_tid != 0) {
4462                 int  ret;
4463                 int  old_errno = errno;
4464
4465                 ret = tkill ((pid_t) thread->android_tid, signal);
4466                 if (ret < 0) {
4467                         ret = errno;
4468                         errno = old_errno;
4469                 }
4470
4471                 return ret;
4472         }
4473         else
4474                 return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4475 #    else
4476         return pthread_kill (thread->tid, mono_thread_get_abort_signal ());
4477 #    endif
4478 #  endif
4479 #endif
4480 }
4481
4482 static void
4483 self_interrupt_thread (void *_unused)
4484 {
4485         MonoThreadInfo *info = mono_thread_info_current ();
4486         MonoException *exc = mono_thread_execute_interruption (mono_thread_internal_current ()); 
4487         if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4488                 mono_raise_exception_with_context (exc, &info->suspend_state.ctx);
4489         g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4490 }
4491
4492 static gboolean
4493 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4494 {
4495         if (!ji)
4496                 return FALSE;
4497         return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4498 }
4499
4500 static gboolean
4501 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4502 {
4503         MonoJitInfo **dest = data;
4504         *dest = frame->ji;
4505         return TRUE;
4506 }
4507
4508 static MonoJitInfo*
4509 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4510 {
4511         MonoJitInfo *ji = NULL;
4512         if (!info)
4513                 return NULL;
4514         mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, &info->suspend_state, MONO_UNWIND_SIGNAL_SAFE, &ji);
4515         return ji;
4516 }
4517
4518 static void
4519 abort_thread_internal (MonoInternalThread *thread, gboolean can_raise_exception, gboolean install_async_abort)
4520 {
4521         MonoJitInfo *ji;
4522         MonoThreadInfo *info = NULL;
4523         gboolean protected_wrapper;
4524         gboolean running_managed;
4525
4526         if (!mono_thread_info_new_interrupt_enabled ()) {
4527                 signal_thread_state_change (thread);
4528                 return;
4529         }
4530
4531         /*
4532         FIXME this is insanely broken, it doesn't cause interruption to happen
4533         synchronously since passing FALSE to mono_thread_request_interruption makes sure it returns NULL
4534         */
4535         if (thread == mono_thread_internal_current ()) {
4536                 /* Do it synchronously */
4537                 MonoException *exc = mono_thread_request_interruption (can_raise_exception); 
4538                 if (exc)
4539                         mono_raise_exception (exc);
4540 #ifndef HOST_WIN32
4541                 wapi_interrupt_thread (thread->handle);
4542 #endif
4543                 return;
4544         }
4545
4546         /*FIXME we need to check 2 conditions here, request to interrupt this thread or if the target died*/
4547         if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, TRUE))) {
4548                 return;
4549         }
4550
4551         if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (&info->suspend_state)) {
4552                 mono_thread_info_resume (mono_thread_info_get_tid (info));
4553                 return;
4554         }
4555
4556         /*someone is already interrupting it*/
4557         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1) {
4558                 mono_thread_info_resume (mono_thread_info_get_tid (info));
4559                 return;
4560         }
4561         InterlockedIncrement (&thread_interruption_requested);
4562
4563         ji = mono_thread_info_get_last_managed (info);
4564         protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4565         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4566
4567         if (!protected_wrapper && running_managed) {
4568                 /*We are in managed code*/
4569                 /*Set the thread to call */
4570                 if (install_async_abort)
4571                         mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4572                 mono_thread_info_resume (mono_thread_info_get_tid (info));
4573         } else {
4574                 gpointer interrupt_handle;
4575                 /* 
4576                  * This will cause waits to be broken.
4577                  * It will also prevent the thread from entering a wait, so if the thread returns
4578                  * from the wait before it receives the abort signal, it will just spin in the wait
4579                  * functions in the io-layer until the signal handler calls QueueUserAPC which will
4580                  * make it return.
4581                  */
4582 #ifndef HOST_WIN32
4583                 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4584 #endif
4585                 mono_thread_info_resume (mono_thread_info_get_tid (info));
4586 #ifndef HOST_WIN32
4587                 wapi_finish_interrupt_thread (interrupt_handle);
4588 #endif
4589         }
4590         /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4591 }
4592
4593 static void
4594 transition_to_suspended (MonoInternalThread *thread)
4595 {
4596         if ((thread->state & ThreadState_SuspendRequested) == 0) {
4597                 g_assert (0); /*FIXME we should not reach this */
4598                 /*Make sure we balance the suspend count.*/
4599                 mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid);
4600         } else {
4601                 thread->state &= ~ThreadState_SuspendRequested;
4602                 thread->state |= ThreadState_Suspended;
4603         }
4604         LeaveCriticalSection (thread->synch_cs);
4605 }
4606
4607 static void
4608 suspend_thread_internal (MonoInternalThread *thread, gboolean interrupt)
4609 {
4610         if (!mono_thread_info_new_interrupt_enabled ()) {
4611                 signal_thread_state_change (thread);
4612                 return;
4613         }
4614
4615         EnterCriticalSection (thread->synch_cs);
4616         if (thread == mono_thread_internal_current ()) {
4617                 transition_to_suspended (thread);
4618                 mono_thread_info_self_suspend ();
4619         } else {
4620                 MonoThreadInfo *info;
4621                 MonoJitInfo *ji;
4622                 gboolean protected_wrapper;
4623                 gboolean running_managed;
4624
4625                 /*A null info usually means the thread is already dead. */
4626                 if (!(info = mono_thread_info_safe_suspend_sync ((MonoNativeThreadId)(gsize)thread->tid, interrupt))) {
4627                         LeaveCriticalSection (thread->synch_cs);
4628                         return;
4629                 }
4630
4631                 ji = mono_thread_info_get_last_managed (info);
4632                 protected_wrapper = ji && mono_threads_is_critical_method (ji->method);
4633                 running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&info->suspend_state.ctx));
4634
4635                 if (running_managed && !protected_wrapper) {
4636                         transition_to_suspended (thread);
4637                 } else {
4638                         gpointer interrupt_handle;
4639
4640                         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4641                                 InterlockedIncrement (&thread_interruption_requested);
4642 #ifndef HOST_WIN32
4643                         if (interrupt)
4644                                 interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
4645 #endif
4646                         mono_thread_info_resume (mono_thread_info_get_tid (info));
4647 #ifndef HOST_WIN32
4648                         if (interrupt)
4649                                 wapi_finish_interrupt_thread (interrupt_handle);
4650 #endif
4651                         LeaveCriticalSection (thread->synch_cs);
4652                 }
4653         }
4654 }
4655
4656 /*This is called with @thread synch_cs held and it must release it*/
4657 static void
4658 self_suspend_internal (MonoInternalThread *thread)
4659 {
4660         if (!mono_thread_info_new_interrupt_enabled ()) {
4661                 thread->state &= ~ThreadState_SuspendRequested;
4662                 thread->state |= ThreadState_Suspended;
4663                 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4664                 if (thread->suspend_event == NULL) {
4665                         LeaveCriticalSection (thread->synch_cs);
4666                         return;
4667                 }
4668                 if (thread->suspended_event)
4669                         SetEvent (thread->suspended_event);
4670
4671                 LeaveCriticalSection (thread->synch_cs);
4672
4673                 if (shutting_down) {
4674                         /* After we left the lock, the runtime might shut down so everything becomes invalid */
4675                         for (;;)
4676                                 Sleep (1000);
4677                 }
4678                 
4679                 WaitForSingleObject (thread->suspend_event, INFINITE);
4680                 
4681                 EnterCriticalSection (thread->synch_cs);
4682
4683                 CloseHandle (thread->suspend_event);
4684                 thread->suspend_event = NULL;
4685                 thread->state &= ~ThreadState_Suspended;
4686         
4687                 /* The thread that requested the resume will have replaced this event
4688                  * and will be waiting for it
4689                  */
4690                 SetEvent (thread->resume_event);
4691
4692                 LeaveCriticalSection (thread->synch_cs);
4693                 return;
4694         }
4695
4696         transition_to_suspended (thread);
4697         mono_thread_info_self_suspend ();
4698 }
4699
4700 /*This is called with @thread synch_cs held and it must release it*/
4701 static gboolean
4702 resume_thread_internal (MonoInternalThread *thread)
4703 {
4704         if (!mono_thread_info_new_interrupt_enabled ()) {
4705                 thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
4706                 if (thread->resume_event == NULL) {
4707                         LeaveCriticalSection (thread->synch_cs);
4708                         return FALSE;
4709                 }
4710
4711                 /* Awake the thread */
4712                 SetEvent (thread->suspend_event);
4713
4714                 LeaveCriticalSection (thread->synch_cs);
4715
4716                 /* Wait for the thread to awake */
4717                 WaitForSingleObject (thread->resume_event, INFINITE);
4718                 CloseHandle (thread->resume_event);
4719                 thread->resume_event = NULL;
4720                 return TRUE;
4721         }
4722
4723         LeaveCriticalSection (thread->synch_cs);        
4724         /* Awake the thread */
4725         if (!mono_thread_info_resume ((MonoNativeThreadId)(gpointer)(gsize)thread->tid))
4726                 return FALSE;
4727         EnterCriticalSection (thread->synch_cs);
4728         thread->state &= ~ThreadState_Suspended;
4729         LeaveCriticalSection (thread->synch_cs);
4730         return TRUE;
4731 }