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