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