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