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