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