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