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