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