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