[runtime] Fix build
[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
2854 void mono_thread_cleanup (void)
2855 {
2856 #if !defined(RUN_IN_SUBTHREAD)
2857         /* The main thread must abandon any held mutexes (particularly
2858          * important for named mutexes as they are shared across
2859          * processes, see bug 74680.)  This will happen when the
2860          * thread exits, but if it's not running in a subthread it
2861          * won't exit in time.
2862          */
2863         mono_thread_info_set_exited (mono_thread_info_current ());
2864 #endif
2865
2866 #if 0
2867         /* This stuff needs more testing, it seems one of these
2868          * critical sections can be locked when mono_thread_cleanup is
2869          * called.
2870          */
2871         mono_coop_mutex_destroy (&threads_mutex);
2872         mono_os_mutex_destroy (&interlocked_mutex);
2873         mono_os_mutex_destroy (&delayed_free_table_mutex);
2874         mono_os_mutex_destroy (&small_id_mutex);
2875         CloseHandle (background_change_event);
2876 #endif
2877
2878         mono_native_tls_free (current_object_key);
2879 }
2880
2881 void
2882 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
2883 {
2884         mono_thread_cleanup_fn = func;
2885 }
2886
2887 void
2888 mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
2889 {
2890         thread->internal_thread->manage_callback = func;
2891 }
2892
2893 G_GNUC_UNUSED
2894 static void print_tids (gpointer key, gpointer value, gpointer user)
2895 {
2896         /* GPOINTER_TO_UINT breaks horribly if sizeof(void *) >
2897          * sizeof(uint) and a cast to uint would overflow
2898          */
2899         /* Older versions of glib don't have G_GSIZE_FORMAT, so just
2900          * print this as a pointer.
2901          */
2902         g_message ("Waiting for: %p", key);
2903 }
2904
2905 struct wait_data 
2906 {
2907         HANDLE handles[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2908         MonoInternalThread *threads[MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS];
2909         guint32 num;
2910 };
2911
2912 static void
2913 wait_for_tids (struct wait_data *wait, guint32 timeout)
2914 {
2915         guint32 i, ret;
2916         
2917         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2918
2919         MONO_ENTER_GC_SAFE;
2920         ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, TRUE);
2921         MONO_EXIT_GC_SAFE;
2922
2923         if(ret==WAIT_FAILED) {
2924                 /* See the comment in build_wait_tids() */
2925                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2926                 return;
2927         }
2928         
2929         for(i=0; i<wait->num; i++)
2930                 mono_threads_close_thread_handle (wait->handles [i]);
2931
2932         if (ret == WAIT_TIMEOUT)
2933                 return;
2934
2935         for(i=0; i<wait->num; i++) {
2936                 gsize tid = wait->threads[i]->tid;
2937
2938                 /*
2939                  * On !win32, when the thread handle becomes signalled, it just means the thread has exited user code,
2940                  * it can still run io-layer etc. code. So wait for it to really exit.
2941                  * FIXME: This won't join threads which are not in the joinable_hash yet.
2942                  */
2943                 mono_thread_join ((gpointer)tid);
2944
2945                 mono_threads_lock ();
2946                 if(mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
2947                         /* This thread must have been killed, because
2948                          * it hasn't cleaned itself up. (It's just
2949                          * possible that the thread exited before the
2950                          * parent thread had a chance to store the
2951                          * handle, and now there is another pointer to
2952                          * the already-exited thread stored.  In this
2953                          * case, we'll just get two
2954                          * mono_profiler_thread_end() calls for the
2955                          * same thread.)
2956                          */
2957         
2958                         mono_threads_unlock ();
2959                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %p (%"G_GSIZE_FORMAT")", __func__, wait->threads[i], tid));
2960                         thread_cleanup (wait->threads[i]);
2961                 } else {
2962                         mono_threads_unlock ();
2963                 }
2964         }
2965 }
2966
2967 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
2968 {
2969         guint32 i, ret, count;
2970         
2971         THREAD_DEBUG (g_message("%s: %d threads to wait for in this batch", __func__, wait->num));
2972
2973         /* Add the thread state change event, so it wakes up if a thread changes
2974          * to background mode.
2975          */
2976         count = wait->num;
2977         if (count < MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
2978                 wait->handles [count] = background_change_event;
2979                 count++;
2980         }
2981
2982         MONO_ENTER_GC_SAFE;
2983         ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, TRUE);
2984         MONO_EXIT_GC_SAFE;
2985
2986         if(ret==WAIT_FAILED) {
2987                 /* See the comment in build_wait_tids() */
2988                 THREAD_DEBUG (g_message ("%s: Wait failed", __func__));
2989                 return;
2990         }
2991         
2992         for(i=0; i<wait->num; i++)
2993                 mono_threads_close_thread_handle (wait->handles [i]);
2994
2995         if (ret == WAIT_TIMEOUT)
2996                 return;
2997         
2998         if (ret < wait->num) {
2999                 gsize tid = wait->threads[ret]->tid;
3000                 mono_threads_lock ();
3001                 if (mono_g_hash_table_lookup (threads, (gpointer)tid)!=NULL) {
3002                         /* See comment in wait_for_tids about thread cleanup */
3003                         mono_threads_unlock ();
3004                         THREAD_DEBUG (g_message ("%s: cleaning up after thread %"G_GSIZE_FORMAT, __func__, tid));
3005                         thread_cleanup (wait->threads [ret]);
3006                 } else
3007                         mono_threads_unlock ();
3008         }
3009 }
3010
3011 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
3012 {
3013         struct wait_data *wait=(struct wait_data *)user;
3014
3015         if(wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3016                 HANDLE handle;
3017                 MonoInternalThread *thread=(MonoInternalThread *)value;
3018
3019                 /* Ignore background threads, we abort them later */
3020                 /* Do not lock here since it is not needed and the caller holds threads_lock */
3021                 if (thread->state & ThreadState_Background) {
3022                         THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3023                         return; /* just leave, ignore */
3024                 }
3025                 
3026                 if (mono_gc_is_finalizer_internal_thread (thread)) {
3027                         THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3028                         return;
3029                 }
3030
3031                 if (thread == mono_thread_internal_current ()) {
3032                         THREAD_DEBUG (g_message ("%s: ignoring current thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3033                         return;
3034                 }
3035
3036                 if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread)) {
3037                         THREAD_DEBUG (g_message ("%s: ignoring main thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3038                         return;
3039                 }
3040
3041                 if (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) {
3042                         THREAD_DEBUG (g_message ("%s: ignoring thread %" G_GSIZE_FORMAT "with DONT_MANAGE flag set.", __func__, (gsize)thread->tid));
3043                         return;
3044                 }
3045
3046                 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3047                 if (handle == NULL) {
3048                         THREAD_DEBUG (g_message ("%s: ignoring unopenable thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3049                         return;
3050                 }
3051                 
3052                 THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
3053                 if ((thread->manage_callback == NULL) || (thread->manage_callback (thread->root_domain_thread) == TRUE)) {
3054                         wait->handles[wait->num]=handle;
3055                         wait->threads[wait->num]=thread;
3056                         wait->num++;
3057
3058                         THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3059                 } else {
3060                         THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
3061                 }
3062                 
3063                 
3064         } else {
3065                 /* Just ignore the rest, we can't do anything with
3066                  * them yet
3067                  */
3068         }
3069 }
3070
3071 static gboolean
3072 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
3073 {
3074         struct wait_data *wait=(struct wait_data *)user;
3075         MonoNativeThreadId self = mono_native_thread_id_get ();
3076         MonoInternalThread *thread = (MonoInternalThread *)value;
3077         HANDLE handle;
3078
3079         if (wait->num >= MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS)
3080                 return FALSE;
3081
3082         /* The finalizer thread is not a background thread */
3083         if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3084              && (thread->state & ThreadState_Background) != 0
3085              && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3086         ) {
3087                 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3088                 if (handle == NULL)
3089                         return FALSE;
3090
3091                 wait->handles[wait->num] = handle;
3092                 wait->threads[wait->num] = thread;
3093                 wait->num++;
3094
3095                 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3096                 mono_thread_internal_abort (thread);
3097                 return TRUE;
3098         }
3099
3100         return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3101                 && !mono_gc_is_finalizer_internal_thread (thread);
3102 }
3103
3104 /** 
3105  * mono_threads_set_shutting_down:
3106  *
3107  * Is called by a thread that wants to shut down Mono. If the runtime is already
3108  * shutting down, the calling thread is suspended/stopped, and this function never
3109  * returns.
3110  */
3111 void
3112 mono_threads_set_shutting_down (void)
3113 {
3114         MonoInternalThread *current_thread = mono_thread_internal_current ();
3115
3116         mono_threads_lock ();
3117
3118         if (shutting_down) {
3119                 mono_threads_unlock ();
3120
3121                 /* Make sure we're properly suspended/stopped */
3122
3123                 LOCK_THREAD (current_thread);
3124
3125                 if ((current_thread->state & ThreadState_SuspendRequested) ||
3126                     (current_thread->state & ThreadState_AbortRequested) ||
3127                     (current_thread->state & ThreadState_StopRequested)) {
3128                         UNLOCK_THREAD (current_thread);
3129                         mono_thread_execute_interruption ();
3130                 } else {
3131                         current_thread->state |= ThreadState_Stopped;
3132                         UNLOCK_THREAD (current_thread);
3133                 }
3134
3135                 /*since we're killing the thread, unset the current domain.*/
3136                 mono_domain_unset ();
3137
3138                 /* Wake up other threads potentially waiting for us */
3139                 mono_thread_info_exit ();
3140         } else {
3141                 shutting_down = TRUE;
3142
3143                 /* Not really a background state change, but this will
3144                  * interrupt the main thread if it is waiting for all
3145                  * the other threads.
3146                  */
3147                 mono_w32event_set (background_change_event);
3148                 
3149                 mono_threads_unlock ();
3150         }
3151 }
3152
3153 void mono_thread_manage (void)
3154 {
3155         struct wait_data wait_data;
3156         struct wait_data *wait = &wait_data;
3157
3158         memset (wait, 0, sizeof (struct wait_data));
3159         /* join each thread that's still running */
3160         THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3161         
3162         mono_threads_lock ();
3163         if(threads==NULL) {
3164                 THREAD_DEBUG (g_message("%s: No threads", __func__));
3165                 mono_threads_unlock ();
3166                 return;
3167         }
3168         mono_threads_unlock ();
3169         
3170         do {
3171                 mono_threads_lock ();
3172                 if (shutting_down) {
3173                         /* somebody else is shutting down */
3174                         mono_threads_unlock ();
3175                         break;
3176                 }
3177                 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3178                         mono_g_hash_table_foreach (threads, print_tids, NULL));
3179         
3180                 mono_w32event_reset (background_change_event);
3181                 wait->num=0;
3182                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3183                 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3184                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3185                 mono_threads_unlock ();
3186                 if(wait->num>0) {
3187                         /* Something to wait for */
3188                         wait_for_tids_or_state_change (wait, INFINITE);
3189                 }
3190                 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3191         } while(wait->num>0);
3192
3193         /* Mono is shutting down, so just wait for the end */
3194         if (!mono_runtime_try_shutdown ()) {
3195                 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3196                 mono_thread_suspend (mono_thread_internal_current ());
3197                 mono_thread_execute_interruption ();
3198         }
3199
3200         /* 
3201          * Remove everything but the finalizer thread and self.
3202          * Also abort all the background threads
3203          * */
3204         do {
3205                 mono_threads_lock ();
3206
3207                 wait->num = 0;
3208                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3209                 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3210                 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3211
3212                 mono_threads_unlock ();
3213
3214                 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3215                 if(wait->num>0) {
3216                         /* Something to wait for */
3217                         wait_for_tids (wait, INFINITE);
3218                 }
3219         } while (wait->num > 0);
3220         
3221         /* 
3222          * give the subthreads a chance to really quit (this is mainly needed
3223          * to get correct user and system times from getrusage/wait/time(1)).
3224          * This could be removed if we avoid pthread_detach() and use pthread_join().
3225          */
3226         mono_thread_info_yield ();
3227 }
3228
3229 static void
3230 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3231 {
3232         MonoInternalThread *thread = (MonoInternalThread*)value;
3233         struct wait_data *wait = (struct wait_data*)user_data;
3234         HANDLE handle;
3235
3236         /* 
3237          * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3238          * limitation.
3239          * This needs no locking.
3240          */
3241         if ((thread->state & ThreadState_Suspended) != 0 || 
3242                 (thread->state & ThreadState_Stopped) != 0)
3243                 return;
3244
3245         if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3246                 handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3247                 if (handle == NULL)
3248                         return;
3249
3250                 wait->handles [wait->num] = handle;
3251                 wait->threads [wait->num] = thread;
3252                 wait->num++;
3253         }
3254 }
3255
3256 /*
3257  * mono_thread_suspend_all_other_threads:
3258  *
3259  *  Suspend all managed threads except the finalizer thread and this thread. It is
3260  * not possible to resume them later.
3261  */
3262 void mono_thread_suspend_all_other_threads (void)
3263 {
3264         struct wait_data wait_data;
3265         struct wait_data *wait = &wait_data;
3266         int i;
3267         MonoNativeThreadId self = mono_native_thread_id_get ();
3268         guint32 eventidx = 0;
3269         gboolean starting, finished;
3270
3271         memset (wait, 0, sizeof (struct wait_data));
3272         /*
3273          * The other threads could be in an arbitrary state at this point, i.e.
3274          * they could be starting up, shutting down etc. This means that there could be
3275          * threads which are not even in the threads hash table yet.
3276          */
3277
3278         /* 
3279          * First we set a barrier which will be checked by all threads before they
3280          * are added to the threads hash table, and they will exit if the flag is set.
3281          * This ensures that no threads could be added to the hash later.
3282          * We will use shutting_down as the barrier for now.
3283          */
3284         g_assert (shutting_down);
3285
3286         /*
3287          * We make multiple calls to WaitForMultipleObjects since:
3288          * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3289          * - some threads could exit without becoming suspended
3290          */
3291         finished = FALSE;
3292         while (!finished) {
3293                 /*
3294                  * Make a copy of the hashtable since we can't do anything with
3295                  * threads while threads_mutex is held.
3296                  */
3297                 wait->num = 0;
3298                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3299                 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3300                 mono_threads_lock ();
3301                 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3302                 mono_threads_unlock ();
3303
3304                 eventidx = 0;
3305                 /* Get the suspended events that we'll be waiting for */
3306                 for (i = 0; i < wait->num; ++i) {
3307                         MonoInternalThread *thread = wait->threads [i];
3308
3309                         if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3310                              || mono_gc_is_finalizer_internal_thread (thread)
3311                              || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3312                         ) {
3313                                 //mono_threads_close_thread_handle (wait->handles [i]);
3314                                 wait->threads [i] = NULL; /* ignore this thread in next loop */
3315                                 continue;
3316                         }
3317
3318                         LOCK_THREAD (thread);
3319
3320                         if ((thread->state & ThreadState_Suspended) != 0 || 
3321                                 (thread->state & ThreadState_StopRequested) != 0 ||
3322                                 (thread->state & ThreadState_Stopped) != 0) {
3323                                 UNLOCK_THREAD (thread);
3324                                 mono_threads_close_thread_handle (wait->handles [i]);
3325                                 wait->threads [i] = NULL; /* ignore this thread in next loop */
3326                                 continue;
3327                         }
3328
3329                         ++eventidx;
3330
3331                         /* Convert abort requests into suspend requests */
3332                         if ((thread->state & ThreadState_AbortRequested) != 0)
3333                                 thread->state &= ~ThreadState_AbortRequested;
3334                         
3335                         thread->state |= ThreadState_SuspendRequested;
3336
3337                         /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3338                         async_suspend_internal (thread, TRUE);
3339                 }
3340                 if (eventidx <= 0) {
3341                         /* 
3342                          * If there are threads which are starting up, we wait until they
3343                          * are suspended when they try to register in the threads hash.
3344                          * This is guaranteed to finish, since the threads which can create new
3345                          * threads get suspended after a while.
3346                          * FIXME: The finalizer thread can still create new threads.
3347                          */
3348                         mono_threads_lock ();
3349                         if (threads_starting_up)
3350                                 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3351                         else
3352                                 starting = FALSE;
3353                         mono_threads_unlock ();
3354                         if (starting)
3355                                 mono_thread_info_sleep (100, NULL);
3356                         else
3357                                 finished = TRUE;
3358                 }
3359         }
3360 }
3361
3362 typedef struct {
3363         MonoInternalThread *thread;
3364         MonoStackFrameInfo *frames;
3365         int nframes, max_frames;
3366         int nthreads, max_threads;
3367         MonoInternalThread **threads;
3368 } ThreadDumpUserData;
3369
3370 static gboolean thread_dump_requested;
3371
3372 /* This needs to be async safe */
3373 static gboolean
3374 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3375 {
3376         ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3377
3378         if (ud->nframes < ud->max_frames) {
3379                 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3380                 ud->nframes ++;
3381         }
3382
3383         return FALSE;
3384 }
3385
3386 /* This needs to be async safe */
3387 static SuspendThreadResult
3388 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3389 {
3390         ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3391         MonoInternalThread *thread = user_data->thread;
3392
3393 #if 0
3394 /* This no longer works with remote unwinding */
3395         g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3396         mono_thread_info_describe (info, text);
3397         g_string_append (text, "\n");
3398 #endif
3399
3400         if (thread == mono_thread_internal_current ())
3401                 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3402         else
3403                 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3404
3405         return MonoResumeThread;
3406 }
3407
3408 typedef struct {
3409         int nthreads, max_threads;
3410         MonoInternalThread **threads;
3411 } CollectThreadsUserData;
3412
3413 static void
3414 collect_thread (gpointer key, gpointer value, gpointer user)
3415 {
3416         CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3417         MonoInternalThread *thread = (MonoInternalThread *)value;
3418
3419         if (ud->nthreads < ud->max_threads)
3420                 ud->threads [ud->nthreads ++] = thread;
3421 }
3422
3423 /*
3424  * Collect running threads into the THREADS array.
3425  * THREADS should be an array allocated on the stack.
3426  */
3427 static int
3428 collect_threads (MonoInternalThread **thread_array, int max_threads)
3429 {
3430         CollectThreadsUserData ud;
3431
3432         memset (&ud, 0, sizeof (ud));
3433         /* This array contains refs, but its on the stack, so its ok */
3434         ud.threads = thread_array;
3435         ud.max_threads = max_threads;
3436
3437         mono_threads_lock ();
3438         mono_g_hash_table_foreach (threads, collect_thread, &ud);
3439         mono_threads_unlock ();
3440
3441         return ud.nthreads;
3442 }
3443
3444 static void
3445 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3446 {
3447         GString* text = g_string_new (0);
3448         char *name;
3449         GError *error = NULL;
3450         int i;
3451
3452         ud->thread = thread;
3453         ud->nframes = 0;
3454
3455         /* Collect frames for the thread */
3456         if (thread == mono_thread_internal_current ()) {
3457                 get_thread_dump (mono_thread_info_current (), ud);
3458         } else {
3459                 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3460         }
3461
3462         /*
3463          * Do all the non async-safe work outside of get_thread_dump.
3464          */
3465         if (thread->name) {
3466                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3467                 g_assert (!error);
3468                 g_string_append_printf (text, "\n\"%s\"", name);
3469                 g_free (name);
3470         }
3471         else if (thread->threadpool_thread) {
3472                 g_string_append (text, "\n\"<threadpool thread>\"");
3473         } else {
3474                 g_string_append (text, "\n\"<unnamed thread>\"");
3475         }
3476
3477         for (i = 0; i < ud->nframes; ++i) {
3478                 MonoStackFrameInfo *frame = &ud->frames [i];
3479                 MonoMethod *method = NULL;
3480
3481                 if (frame->type == FRAME_TYPE_MANAGED)
3482                         method = mono_jit_info_get_method (frame->ji);
3483
3484                 if (method) {
3485                         gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3486                         g_string_append_printf (text, "  %s\n", location);
3487                         g_free (location);
3488                 } else {
3489                         g_string_append_printf (text, "  at <unknown> <0x%05x>\n", frame->native_offset);
3490                 }
3491         }
3492
3493         fprintf (stdout, "%s", text->str);
3494
3495 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3496         OutputDebugStringA(text->str);
3497 #endif
3498
3499         g_string_free (text, TRUE);
3500         fflush (stdout);
3501 }
3502
3503 void
3504 mono_threads_perform_thread_dump (void)
3505 {
3506         ThreadDumpUserData ud;
3507         MonoInternalThread *thread_array [128];
3508         int tindex, nthreads;
3509
3510         if (!thread_dump_requested)
3511                 return;
3512
3513         printf ("Full thread dump:\n");
3514
3515         /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3516         nthreads = collect_threads (thread_array, 128);
3517
3518         memset (&ud, 0, sizeof (ud));
3519         ud.frames = g_new0 (MonoStackFrameInfo, 256);
3520         ud.max_frames = 256;
3521
3522         for (tindex = 0; tindex < nthreads; ++tindex)
3523                 dump_thread (thread_array [tindex], &ud);
3524
3525         g_free (ud.frames);
3526
3527         thread_dump_requested = FALSE;
3528 }
3529
3530 /* Obtain the thread dump of all threads */
3531 static gboolean
3532 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3533 {
3534
3535         ThreadDumpUserData ud;
3536         MonoInternalThread *thread_array [128];
3537         MonoDomain *domain = mono_domain_get ();
3538         MonoDebugSourceLocation *location;
3539         int tindex, nthreads;
3540
3541         mono_error_init (error);
3542         
3543         *out_threads = NULL;
3544         *out_stack_frames = NULL;
3545
3546         /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3547         nthreads = collect_threads (thread_array, 128);
3548
3549         memset (&ud, 0, sizeof (ud));
3550         ud.frames = g_new0 (MonoStackFrameInfo, 256);
3551         ud.max_frames = 256;
3552
3553         *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3554         if (!is_ok (error))
3555                 goto leave;
3556         *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3557         if (!is_ok (error))
3558                 goto leave;
3559
3560         for (tindex = 0; tindex < nthreads; ++tindex) {
3561                 MonoInternalThread *thread = thread_array [tindex];
3562                 MonoArray *thread_frames;
3563                 int i;
3564
3565                 ud.thread = thread;
3566                 ud.nframes = 0;
3567
3568                 /* Collect frames for the thread */
3569                 if (thread == mono_thread_internal_current ()) {
3570                         get_thread_dump (mono_thread_info_current (), &ud);
3571                 } else {
3572                         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3573                 }
3574
3575                 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3576
3577                 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3578                 if (!is_ok (error))
3579                         goto leave;
3580                 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3581
3582                 for (i = 0; i < ud.nframes; ++i) {
3583                         MonoStackFrameInfo *frame = &ud.frames [i];
3584                         MonoMethod *method = NULL;
3585                         MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3586                         if (!is_ok (error))
3587                                 goto leave;
3588
3589                         sf->native_offset = frame->native_offset;
3590
3591                         if (frame->type == FRAME_TYPE_MANAGED)
3592                                 method = mono_jit_info_get_method (frame->ji);
3593
3594                         if (method) {
3595                                 sf->method_address = (gsize) frame->ji->code_start;
3596
3597                                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3598                                 if (!is_ok (error))
3599                                         goto leave;
3600                                 MONO_OBJECT_SETREF (sf, method, rm);
3601
3602                                 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3603                                 if (location) {
3604                                         sf->il_offset = location->il_offset;
3605
3606                                         if (location && location->source_file) {
3607                                                 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3608                                                 sf->line = location->row;
3609                                                 sf->column = location->column;
3610                                         }
3611                                         mono_debug_free_source_location (location);
3612                                 } else {
3613                                         sf->il_offset = -1;
3614                                 }
3615                         }
3616                         mono_array_setref (thread_frames, i, sf);
3617                 }
3618         }
3619
3620 leave:
3621         g_free (ud.frames);
3622         return is_ok (error);
3623 }
3624
3625 /**
3626  * mono_threads_request_thread_dump:
3627  *
3628  *   Ask all threads except the current to print their stacktrace to stdout.
3629  */
3630 void
3631 mono_threads_request_thread_dump (void)
3632 {
3633         /*The new thread dump code runs out of the finalizer thread. */
3634         thread_dump_requested = TRUE;
3635         mono_gc_finalize_notify ();
3636 }
3637
3638 struct ref_stack {
3639         gpointer *refs;
3640         gint allocated; /* +1 so that refs [allocated] == NULL */
3641         gint bottom;
3642 };
3643
3644 typedef struct ref_stack RefStack;
3645
3646 static RefStack *
3647 ref_stack_new (gint initial_size)
3648 {
3649         RefStack *rs;
3650
3651         initial_size = MAX (initial_size, 16) + 1;
3652         rs = g_new0 (RefStack, 1);
3653         rs->refs = g_new0 (gpointer, initial_size);
3654         rs->allocated = initial_size;
3655         return rs;
3656 }
3657
3658 static void
3659 ref_stack_destroy (gpointer ptr)
3660 {
3661         RefStack *rs = (RefStack *)ptr;
3662
3663         if (rs != NULL) {
3664                 g_free (rs->refs);
3665                 g_free (rs);
3666         }
3667 }
3668
3669 static void
3670 ref_stack_push (RefStack *rs, gpointer ptr)
3671 {
3672         g_assert (rs != NULL);
3673
3674         if (rs->bottom >= rs->allocated) {
3675                 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3676                 rs->allocated <<= 1;
3677                 rs->refs [rs->allocated] = NULL;
3678         }
3679         rs->refs [rs->bottom++] = ptr;
3680 }
3681
3682 static void
3683 ref_stack_pop (RefStack *rs)
3684 {
3685         if (rs == NULL || rs->bottom == 0)
3686                 return;
3687
3688         rs->bottom--;
3689         rs->refs [rs->bottom] = NULL;
3690 }
3691
3692 static gboolean
3693 ref_stack_find (RefStack *rs, gpointer ptr)
3694 {
3695         gpointer *refs;
3696
3697         if (rs == NULL)
3698                 return FALSE;
3699
3700         for (refs = rs->refs; refs && *refs; refs++) {
3701                 if (*refs == ptr)
3702                         return TRUE;
3703         }
3704         return FALSE;
3705 }
3706
3707 /*
3708  * mono_thread_push_appdomain_ref:
3709  *
3710  *   Register that the current thread may have references to objects in domain 
3711  * @domain on its stack. Each call to this function should be paired with a 
3712  * call to pop_appdomain_ref.
3713  */
3714 void 
3715 mono_thread_push_appdomain_ref (MonoDomain *domain)
3716 {
3717         MonoInternalThread *thread = mono_thread_internal_current ();
3718
3719         if (thread) {
3720                 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3721                 SPIN_LOCK (thread->lock_thread_id);
3722                 if (thread->appdomain_refs == NULL)
3723                         thread->appdomain_refs = ref_stack_new (16);
3724                 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3725                 SPIN_UNLOCK (thread->lock_thread_id);
3726         }
3727 }
3728
3729 void
3730 mono_thread_pop_appdomain_ref (void)
3731 {
3732         MonoInternalThread *thread = mono_thread_internal_current ();
3733
3734         if (thread) {
3735                 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3736                 SPIN_LOCK (thread->lock_thread_id);
3737                 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3738                 SPIN_UNLOCK (thread->lock_thread_id);
3739         }
3740 }
3741
3742 gboolean
3743 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3744 {
3745         gboolean res;
3746         SPIN_LOCK (thread->lock_thread_id);
3747         res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3748         SPIN_UNLOCK (thread->lock_thread_id);
3749         return res;
3750 }
3751
3752 gboolean
3753 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3754 {
3755         return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3756 }
3757
3758 typedef struct abort_appdomain_data {
3759         struct wait_data wait;
3760         MonoDomain *domain;
3761 } abort_appdomain_data;
3762
3763 static void
3764 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3765 {
3766         MonoInternalThread *thread = (MonoInternalThread*)value;
3767         abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3768         MonoDomain *domain = data->domain;
3769
3770         if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3771                 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3772
3773                 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3774                         HANDLE handle = mono_threads_open_thread_handle (thread->handle, thread_get_tid (thread));
3775                         if (handle == NULL)
3776                                 return;
3777                         data->wait.handles [data->wait.num] = handle;
3778                         data->wait.threads [data->wait.num] = thread;
3779                         data->wait.num++;
3780                 } else {
3781                         /* Just ignore the rest, we can't do anything with
3782                          * them yet
3783                          */
3784                 }
3785         }
3786 }
3787
3788 /*
3789  * mono_threads_abort_appdomain_threads:
3790  *
3791  *   Abort threads which has references to the given appdomain.
3792  */
3793 gboolean
3794 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3795 {
3796 #ifdef __native_client__
3797         return FALSE;
3798 #endif
3799
3800         abort_appdomain_data user_data;
3801         gint64 start_time;
3802         int orig_timeout = timeout;
3803         int i;
3804
3805         THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3806
3807         start_time = mono_msec_ticks ();
3808         do {
3809                 mono_threads_lock ();
3810
3811                 user_data.domain = domain;
3812                 user_data.wait.num = 0;
3813                 /* This shouldn't take any locks */
3814                 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3815                 mono_threads_unlock ();
3816
3817                 if (user_data.wait.num > 0) {
3818                         /* Abort the threads outside the threads lock */
3819                         for (i = 0; i < user_data.wait.num; ++i)
3820                                 mono_thread_internal_abort (user_data.wait.threads [i]);
3821
3822                         /*
3823                          * We should wait for the threads either to abort, or to leave the
3824                          * domain. We can't do the latter, so we wait with a timeout.
3825                          */
3826                         wait_for_tids (&user_data.wait, 100);
3827                 }
3828
3829                 /* Update remaining time */
3830                 timeout -= mono_msec_ticks () - start_time;
3831                 start_time = mono_msec_ticks ();
3832
3833                 if (orig_timeout != -1 && timeout < 0)
3834                         return FALSE;
3835         }
3836         while (user_data.wait.num > 0);
3837
3838         THREAD_DEBUG (g_message ("%s: abort done", __func__));
3839
3840         return TRUE;
3841 }
3842
3843 static void
3844 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3845 {
3846         MonoInternalThread *thread = (MonoInternalThread*)value;
3847         MonoDomain *domain = (MonoDomain*)user_data;
3848         int i;
3849
3850         /* No locking needed here */
3851         /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3852
3853         if (thread->cached_culture_info) {
3854                 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3855                         MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3856                         if (obj && obj->vtable->domain == domain)
3857                                 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3858                 }
3859         }
3860 }
3861         
3862 /*
3863  * mono_threads_clear_cached_culture:
3864  *
3865  *   Clear the cached_current_culture from all threads if it is in the
3866  * given appdomain.
3867  */
3868 void
3869 mono_threads_clear_cached_culture (MonoDomain *domain)
3870 {
3871         mono_threads_lock ();
3872         mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3873         mono_threads_unlock ();
3874 }
3875
3876 /*
3877  * mono_thread_get_undeniable_exception:
3878  *
3879  *   Return an exception which needs to be raised when leaving a catch clause.
3880  * This is used for undeniable exception propagation.
3881  */
3882 MonoException*
3883 mono_thread_get_undeniable_exception (void)
3884 {
3885         MonoInternalThread *thread = mono_thread_internal_current ();
3886
3887         if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
3888                 /*
3889                  * FIXME: Clear the abort exception and return an AppDomainUnloaded 
3890                  * exception if the thread no longer references a dying appdomain.
3891                  */
3892                 thread->abort_exc->trace_ips = NULL;
3893                 thread->abort_exc->stack_trace = NULL;
3894                 return thread->abort_exc;
3895         }
3896
3897         return NULL;
3898 }
3899
3900 #if MONO_SMALL_CONFIG
3901 #define NUM_STATIC_DATA_IDX 4
3902 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3903         64, 256, 1024, 4096
3904 };
3905 #else
3906 #define NUM_STATIC_DATA_IDX 8
3907 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3908         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3909 };
3910 #endif
3911
3912 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3913 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3914
3915 static void
3916 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3917 {
3918         gpointer *static_data = (gpointer *)addr;
3919
3920         for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3921                 void **ptr = (void **)static_data [i];
3922
3923                 if (!ptr)
3924                         continue;
3925
3926                 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3927                         void **p = ptr + idx;
3928
3929                         if (*p)
3930                                 mark_func ((MonoObject**)p, gc_data);
3931                 });
3932         }
3933 }
3934
3935 static void
3936 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3937 {
3938         mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
3939 }
3940
3941 static void
3942 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
3943 {
3944         mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
3945 }
3946
3947 /*
3948  *  mono_alloc_static_data
3949  *
3950  *   Allocate memory blocks for storing threads or context static data
3951  */
3952 static void 
3953 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
3954 {
3955         guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
3956         int i;
3957
3958         gpointer* static_data = *static_data_ptr;
3959         if (!static_data) {
3960                 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
3961                 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
3962
3963                 if (mono_gc_user_markers_supported ()) {
3964                         if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
3965                                 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
3966
3967                         if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
3968                                 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
3969                 }
3970
3971                 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
3972                         threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3973                         threadlocal ? "managed thread-static variables" : "managed context-static variables");
3974                 *static_data_ptr = static_data;
3975                 static_data [0] = static_data;
3976         }
3977
3978         for (i = 1; i <= idx; ++i) {
3979                 if (static_data [i])
3980                         continue;
3981
3982                 if (mono_gc_user_markers_supported ())
3983                         static_data [i] = g_malloc0 (static_data_size [i]);
3984                 else
3985                         static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
3986                                 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
3987                                 threadlocal ? "managed thread-static variables" : "managed context-static variables");
3988         }
3989 }
3990
3991 static void 
3992 mono_free_static_data (gpointer* static_data)
3993 {
3994         int i;
3995         for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
3996                 gpointer p = static_data [i];
3997                 if (!p)
3998                         continue;
3999                 /*
4000                  * At this point, the static data pointer array is still registered with the
4001                  * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4002                  * data.  Freeing the individual arrays without first nulling their slots
4003                  * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4004                  * such an already freed array.  See bug #13813.
4005                  */
4006                 static_data [i] = NULL;
4007                 mono_memory_write_barrier ();
4008                 if (mono_gc_user_markers_supported ())
4009                         g_free (p);
4010                 else
4011                         mono_gc_free_fixed (p);
4012         }
4013         mono_gc_free_fixed (static_data);
4014 }
4015
4016 /*
4017  *  mono_init_static_data_info
4018  *
4019  *   Initializes static data counters
4020  */
4021 static void mono_init_static_data_info (StaticDataInfo *static_data)
4022 {
4023         static_data->idx = 0;
4024         static_data->offset = 0;
4025         static_data->freelist = NULL;
4026 }
4027
4028 /*
4029  *  mono_alloc_static_data_slot
4030  *
4031  *   Generates an offset for static data. static_data contains the counters
4032  *  used to generate it.
4033  */
4034 static guint32
4035 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4036 {
4037         if (!static_data->idx && !static_data->offset) {
4038                 /* 
4039                  * we use the first chunk of the first allocation also as
4040                  * an array for the rest of the data 
4041                  */
4042                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4043         }
4044         static_data->offset += align - 1;
4045         static_data->offset &= ~(align - 1);
4046         if (static_data->offset + size >= static_data_size [static_data->idx]) {
4047                 static_data->idx ++;
4048                 g_assert (size <= static_data_size [static_data->idx]);
4049                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4050                 static_data->offset = 0;
4051         }
4052         guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4053         static_data->offset += size;
4054         return offset;
4055 }
4056
4057 /*
4058  * LOCKING: requires that threads_mutex is held
4059  */
4060 static void
4061 context_adjust_static_data (MonoAppContext *ctx)
4062 {
4063         if (context_static_info.offset || context_static_info.idx > 0) {
4064                 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4065                 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4066                 ctx->data->static_data = ctx->static_data;
4067         }
4068 }
4069
4070 /*
4071  * LOCKING: requires that threads_mutex is held
4072  */
4073 static void 
4074 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4075 {
4076         MonoInternalThread *thread = (MonoInternalThread *)value;
4077         guint32 offset = GPOINTER_TO_UINT (user);
4078
4079         mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4080 }
4081
4082 /*
4083  * LOCKING: requires that threads_mutex is held
4084  */
4085 static void
4086 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4087 {
4088         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4089
4090         if (!ctx)
4091                 return;
4092
4093         guint32 offset = GPOINTER_TO_UINT (user);
4094         mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4095         ctx->data->static_data = ctx->static_data;
4096 }
4097
4098 static StaticDataFreeList*
4099 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4100 {
4101         StaticDataFreeList* prev = NULL;
4102         StaticDataFreeList* tmp = static_data->freelist;
4103         while (tmp) {
4104                 if (tmp->size == size) {
4105                         if (prev)
4106                                 prev->next = tmp->next;
4107                         else
4108                                 static_data->freelist = tmp->next;
4109                         return tmp;
4110                 }
4111                 prev = tmp;
4112                 tmp = tmp->next;
4113         }
4114         return NULL;
4115 }
4116
4117 #if SIZEOF_VOID_P == 4
4118 #define ONE_P 1
4119 #else
4120 #define ONE_P 1ll
4121 #endif
4122
4123 static void
4124 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4125 {
4126         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4127         if (!sets [idx])
4128                 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4129         MonoBitSet *rb = sets [idx];
4130         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4131         offset /= sizeof (uintptr_t);
4132         /* offset is now the bitmap offset */
4133         for (int i = 0; i < numbits; ++i) {
4134                 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4135                         mono_bitset_set_fast (rb, offset + i);
4136         }
4137 }
4138
4139 static void
4140 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4141 {
4142         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4143         MonoBitSet *rb = sets [idx];
4144         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4145         offset /= sizeof (uintptr_t);
4146         /* offset is now the bitmap offset */
4147         for (int i = 0; i < size / sizeof (uintptr_t); i++)
4148                 mono_bitset_clear_fast (rb, offset + i);
4149 }
4150
4151 guint32
4152 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4153 {
4154         g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4155
4156         StaticDataInfo *info;
4157         MonoBitSet **sets;
4158
4159         if (static_type == SPECIAL_STATIC_THREAD) {
4160                 info = &thread_static_info;
4161                 sets = thread_reference_bitmaps;
4162         } else {
4163                 info = &context_static_info;
4164                 sets = context_reference_bitmaps;
4165         }
4166
4167         mono_threads_lock ();
4168
4169         StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4170         guint32 offset;
4171
4172         if (item) {
4173                 offset = item->offset;
4174                 g_free (item);
4175         } else {
4176                 offset = mono_alloc_static_data_slot (info, size, align);
4177         }
4178
4179         update_reference_bitmap (sets, offset, bitmap, numbits);
4180
4181         if (static_type == SPECIAL_STATIC_THREAD) {
4182                 /* This can be called during startup */
4183                 if (threads != NULL)
4184                         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4185         } else {
4186                 if (contexts != NULL)
4187                         g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4188
4189                 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4190         }
4191
4192         mono_threads_unlock ();
4193
4194         return offset;
4195 }
4196
4197 gpointer
4198 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4199 {
4200         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4201
4202         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4203                 return get_thread_static_data (thread, offset);
4204         } else {
4205                 return get_context_static_data (thread->current_appcontext, offset);
4206         }
4207 }
4208
4209 gpointer
4210 mono_get_special_static_data (guint32 offset)
4211 {
4212         return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4213 }
4214
4215 typedef struct {
4216         guint32 offset;
4217         guint32 size;
4218 } OffsetSize;
4219
4220 /*
4221  * LOCKING: requires that threads_mutex is held
4222  */
4223 static void 
4224 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4225 {
4226         MonoInternalThread *thread = (MonoInternalThread *)value;
4227         OffsetSize *data = (OffsetSize *)user;
4228         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4229         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4230         char *ptr;
4231
4232         if (!thread->static_data || !thread->static_data [idx])
4233                 return;
4234         ptr = ((char*) thread->static_data [idx]) + off;
4235         mono_gc_bzero_atomic (ptr, data->size);
4236 }
4237
4238 /*
4239  * LOCKING: requires that threads_mutex is held
4240  */
4241 static void
4242 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4243 {
4244         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4245
4246         if (!ctx)
4247                 return;
4248
4249         OffsetSize *data = (OffsetSize *)user;
4250         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4251         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4252         char *ptr;
4253
4254         if (!ctx->static_data || !ctx->static_data [idx])
4255                 return;
4256
4257         ptr = ((char*) ctx->static_data [idx]) + off;
4258         mono_gc_bzero_atomic (ptr, data->size);
4259 }
4260
4261 static void
4262 do_free_special_slot (guint32 offset, guint32 size)
4263 {
4264         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4265         MonoBitSet **sets;
4266         StaticDataInfo *info;
4267
4268         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4269                 info = &thread_static_info;
4270                 sets = thread_reference_bitmaps;
4271         } else {
4272                 info = &context_static_info;
4273                 sets = context_reference_bitmaps;
4274         }
4275
4276         guint32 data_offset = offset;
4277         ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4278         OffsetSize data = { data_offset, size };
4279
4280         clear_reference_bitmap (sets, data.offset, data.size);
4281
4282         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4283                 if (threads != NULL)
4284                         mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4285         } else {
4286                 if (contexts != NULL)
4287                         g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4288         }
4289
4290         if (!mono_runtime_is_shutting_down ()) {
4291                 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4292
4293                 item->offset = offset;
4294                 item->size = size;
4295
4296                 item->next = info->freelist;
4297                 info->freelist = item;
4298         }
4299 }
4300
4301 static void
4302 do_free_special (gpointer key, gpointer value, gpointer data)
4303 {
4304         MonoClassField *field = (MonoClassField *)key;
4305         guint32 offset = GPOINTER_TO_UINT (value);
4306         gint32 align;
4307         guint32 size;
4308         size = mono_type_size (field->type, &align);
4309         do_free_special_slot (offset, size);
4310 }
4311
4312 void
4313 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4314 {
4315         mono_threads_lock ();
4316
4317         g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4318
4319         mono_threads_unlock ();
4320 }
4321
4322 #ifdef HOST_WIN32
4323 static void CALLBACK dummy_apc (ULONG_PTR param)
4324 {
4325 }
4326 #endif
4327
4328 /*
4329  * mono_thread_execute_interruption
4330  * 
4331  * Performs the operation that the requested thread state requires (abort,
4332  * suspend or stop)
4333  */
4334 static MonoException*
4335 mono_thread_execute_interruption (void)
4336 {
4337         MonoInternalThread *thread = mono_thread_internal_current ();
4338         MonoThread *sys_thread = mono_thread_current ();
4339
4340         LOCK_THREAD (thread);
4341
4342         /* MonoThread::interruption_requested can only be changed with atomics */
4343         if (InterlockedCompareExchange (&thread->interruption_requested, FALSE, TRUE)) {
4344                 /* this will consume pending APC calls */
4345 #ifdef HOST_WIN32
4346                 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4347 #endif
4348                 InterlockedDecrement (&thread_interruption_requested);
4349
4350                 /* Clear the interrupted flag of the thread so it can wait again */
4351                 mono_thread_info_clear_self_interrupt ();
4352         }
4353
4354         /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4355         if (sys_thread->pending_exception) {
4356                 MonoException *exc;
4357
4358                 exc = sys_thread->pending_exception;
4359                 sys_thread->pending_exception = NULL;
4360
4361                 UNLOCK_THREAD (thread);
4362                 return exc;
4363         } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4364                 UNLOCK_THREAD (thread);
4365                 g_assert (sys_thread->pending_exception == NULL);
4366                 if (thread->abort_exc == NULL) {
4367                         /* 
4368                          * This might be racy, but it has to be called outside the lock
4369                          * since it calls managed code.
4370                          */
4371                         MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4372                 }
4373                 return thread->abort_exc;
4374         }
4375         else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4376                 /* calls UNLOCK_THREAD (thread) */
4377                 self_suspend_internal ();
4378                 return NULL;
4379         }
4380         else if ((thread->state & ThreadState_StopRequested) != 0) {
4381                 /* FIXME: do this through the JIT? */
4382
4383                 UNLOCK_THREAD (thread);
4384                 
4385                 mono_thread_exit ();
4386                 return NULL;
4387         } else if (thread->thread_interrupt_requested) {
4388
4389                 thread->thread_interrupt_requested = FALSE;
4390                 UNLOCK_THREAD (thread);
4391                 
4392                 return(mono_get_exception_thread_interrupted ());
4393         }
4394         
4395         UNLOCK_THREAD (thread);
4396         
4397         return NULL;
4398 }
4399
4400 /*
4401  * mono_thread_request_interruption
4402  *
4403  * A signal handler can call this method to request the interruption of a
4404  * thread. The result of the interruption will depend on the current state of
4405  * the thread. If the result is an exception that needs to be throw, it is 
4406  * provided as return value.
4407  */
4408 MonoException*
4409 mono_thread_request_interruption (gboolean running_managed)
4410 {
4411         MonoInternalThread *thread = mono_thread_internal_current ();
4412
4413         /* The thread may already be stopping */
4414         if (thread == NULL) 
4415                 return NULL;
4416
4417 #ifdef HOST_WIN32
4418         if (thread->interrupt_on_stop && 
4419                 thread->state & ThreadState_StopRequested && 
4420                 thread->state & ThreadState_Background)
4421                 ExitThread (1);
4422 #endif
4423         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4424                 return NULL;
4425         InterlockedIncrement (&thread_interruption_requested);
4426
4427         if (!running_managed || is_running_protected_wrapper ()) {
4428                 /* Can't stop while in unmanaged code. Increase the global interruption
4429                    request count. When exiting the unmanaged method the count will be
4430                    checked and the thread will be interrupted. */
4431
4432                 /* this will awake the thread if it is in WaitForSingleObject 
4433                    or similar */
4434                 /* Our implementation of this function ignores the func argument */
4435 #ifdef HOST_WIN32
4436                 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, (ULONG_PTR)NULL);
4437 #else
4438                 mono_thread_info_self_interrupt ();
4439 #endif
4440                 return NULL;
4441         }
4442         else {
4443                 return mono_thread_execute_interruption ();
4444         }
4445 }
4446
4447 /*This function should be called by a thread after it has exited all of
4448  * its handle blocks at interruption time.*/
4449 MonoException*
4450 mono_thread_resume_interruption (void)
4451 {
4452         MonoInternalThread *thread = mono_thread_internal_current ();
4453         gboolean still_aborting;
4454
4455         /* The thread may already be stopping */
4456         if (thread == NULL)
4457                 return NULL;
4458
4459         LOCK_THREAD (thread);
4460         still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4461         UNLOCK_THREAD (thread);
4462
4463         /*This can happen if the protected block called Thread::ResetAbort*/
4464         if (!still_aborting)
4465                 return FALSE;
4466
4467         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4468                 return NULL;
4469         InterlockedIncrement (&thread_interruption_requested);
4470
4471         mono_thread_info_self_interrupt ();
4472
4473         return mono_thread_execute_interruption ();
4474 }
4475
4476 gboolean mono_thread_interruption_requested ()
4477 {
4478         if (thread_interruption_requested) {
4479                 MonoInternalThread *thread = mono_thread_internal_current ();
4480                 /* The thread may already be stopping */
4481                 if (thread != NULL) 
4482                         return (thread->interruption_requested);
4483         }
4484         return FALSE;
4485 }
4486
4487 static MonoException*
4488 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4489 {
4490         MonoInternalThread *thread = mono_thread_internal_current ();
4491
4492         /* The thread may already be stopping */
4493         if (thread == NULL)
4494                 return NULL;
4495
4496         if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
4497                 MonoException* exc = mono_thread_execute_interruption ();
4498                 if (exc)
4499                         return exc;
4500         }
4501         return NULL;
4502 }
4503
4504 /*
4505  * Performs the interruption of the current thread, if one has been requested,
4506  * and the thread is not running a protected wrapper.
4507  * Return the exception which needs to be thrown, if any.
4508  */
4509 MonoException*
4510 mono_thread_interruption_checkpoint (void)
4511 {
4512         return mono_thread_interruption_checkpoint_request (FALSE);
4513 }
4514
4515 /*
4516  * Performs the interruption of the current thread, if one has been requested.
4517  * Return the exception which needs to be thrown, if any.
4518  */
4519 MonoException*
4520 mono_thread_force_interruption_checkpoint_noraise (void)
4521 {
4522         return mono_thread_interruption_checkpoint_request (TRUE);
4523 }
4524
4525 /*
4526  * mono_set_pending_exception:
4527  *
4528  *   Set the pending exception of the current thread to EXC.
4529  * The exception will be thrown when execution returns to managed code.
4530  */
4531 void
4532 mono_set_pending_exception (MonoException *exc)
4533 {
4534         MonoThread *thread = mono_thread_current ();
4535
4536         /* The thread may already be stopping */
4537         if (thread == NULL)
4538                 return;
4539
4540         MONO_OBJECT_SETREF (thread, pending_exception, exc);
4541
4542     mono_thread_request_interruption (FALSE);
4543 }
4544
4545 /**
4546  * mono_thread_interruption_request_flag:
4547  *
4548  * Returns the address of a flag that will be non-zero if an interruption has
4549  * been requested for a thread. The thread to interrupt may not be the current
4550  * thread, so an additional call to mono_thread_interruption_requested() or
4551  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4552  * zero.
4553  */
4554 gint32* mono_thread_interruption_request_flag ()
4555 {
4556         return &thread_interruption_requested;
4557 }
4558
4559 void 
4560 mono_thread_init_apartment_state (void)
4561 {
4562 #ifdef HOST_WIN32
4563         MonoInternalThread* thread = mono_thread_internal_current ();
4564
4565         /* Positive return value indicates success, either
4566          * S_OK if this is first CoInitialize call, or
4567          * S_FALSE if CoInitialize already called, but with same
4568          * threading model. A negative value indicates failure,
4569          * probably due to trying to change the threading model.
4570          */
4571         if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA) 
4572                         ? COINIT_APARTMENTTHREADED 
4573                         : COINIT_MULTITHREADED) < 0) {
4574                 thread->apartment_state = ThreadApartmentState_Unknown;
4575         }
4576 #endif
4577 }
4578
4579 void 
4580 mono_thread_cleanup_apartment_state (void)
4581 {
4582 #ifdef HOST_WIN32
4583         MonoInternalThread* thread = mono_thread_internal_current ();
4584
4585         if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4586                 CoUninitialize ();
4587         }
4588 #endif
4589 }
4590
4591 void
4592 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4593 {
4594         LOCK_THREAD (thread);
4595         thread->state |= state;
4596         UNLOCK_THREAD (thread);
4597 }
4598
4599 /**
4600  * mono_thread_test_and_set_state:
4601  *
4602  * Test if current state of @thread include @test. If it does not, OR @set into the state.
4603  *
4604  * Returns TRUE is @set was OR'd in.
4605  */
4606 gboolean
4607 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4608 {
4609         LOCK_THREAD (thread);
4610
4611         if ((thread->state & test) != 0) {
4612                 UNLOCK_THREAD (thread);
4613                 return FALSE;
4614         }
4615
4616         thread->state |= set;
4617         UNLOCK_THREAD (thread);
4618
4619         return TRUE;
4620 }
4621
4622 void
4623 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4624 {
4625         LOCK_THREAD (thread);
4626         thread->state &= ~state;
4627         UNLOCK_THREAD (thread);
4628 }
4629
4630 gboolean
4631 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4632 {
4633         gboolean ret = FALSE;
4634
4635         LOCK_THREAD (thread);
4636
4637         if ((thread->state & test) != 0) {
4638                 ret = TRUE;
4639         }
4640         
4641         UNLOCK_THREAD (thread);
4642         
4643         return ret;
4644 }
4645
4646 static gboolean has_tls_get = FALSE;
4647
4648 void
4649 mono_runtime_set_has_tls_get (gboolean val)
4650 {
4651         has_tls_get = val;
4652 }
4653
4654 gboolean
4655 mono_runtime_has_tls_get (void)
4656 {
4657         return has_tls_get;
4658 }
4659
4660 static void
4661 self_interrupt_thread (void *_unused)
4662 {
4663         MonoThreadInfo *info = mono_thread_info_current ();
4664         MonoException *exc = mono_thread_execute_interruption ();
4665         if (exc) /*We must use _with_context since we didn't trampoline into the runtime*/
4666                 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. */
4667         g_assert_not_reached (); /*this MUST not happen since we can't resume from an async call*/
4668 }
4669
4670 static gboolean
4671 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4672 {
4673         if (!ji)
4674                 return FALSE;
4675         return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4676 }
4677
4678 static gboolean
4679 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4680 {
4681         MonoJitInfo **dest = (MonoJitInfo **)data;
4682         *dest = frame->ji;
4683         return TRUE;
4684 }
4685
4686 static MonoJitInfo*
4687 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4688 {
4689         MonoJitInfo *ji = NULL;
4690         if (!info)
4691                 return NULL;
4692
4693         /*
4694          * The suspended thread might be holding runtime locks. Make sure we don't try taking
4695          * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4696          * where we hold runtime locks.
4697          */
4698         if (!mono_threads_is_coop_enabled ())
4699                 mono_thread_info_set_is_async_context (TRUE);
4700         mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4701         if (!mono_threads_is_coop_enabled ())
4702                 mono_thread_info_set_is_async_context (FALSE);
4703         return ji;
4704 }
4705
4706 typedef struct {
4707         MonoInternalThread *thread;
4708         gboolean install_async_abort;
4709         MonoThreadInfoInterruptToken *interrupt_token;
4710 } AbortThreadData;
4711
4712 static SuspendThreadResult
4713 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4714 {
4715         AbortThreadData *data = (AbortThreadData *)ud;
4716         MonoInternalThread *thread = data->thread;
4717         MonoJitInfo *ji = NULL;
4718         gboolean protected_wrapper;
4719         gboolean running_managed;
4720
4721         if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4722                 return MonoResumeThread;
4723
4724         /*
4725         The target thread is running at least one protected block, which must not be interrupted, so we give up.
4726         The protected block code will give them a chance when appropriate.
4727         */
4728         if (thread->abort_protected_block_count)
4729                 return MonoResumeThread;
4730
4731         /*someone is already interrupting it*/
4732         if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 1)
4733                 return MonoResumeThread;
4734
4735         InterlockedIncrement (&thread_interruption_requested);
4736
4737         ji = mono_thread_info_get_last_managed (info);
4738         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4739         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4740
4741         if (!protected_wrapper && running_managed) {
4742                 /*We are in managed code*/
4743                 /*Set the thread to call */
4744                 if (data->install_async_abort)
4745                         mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4746                 return MonoResumeThread;
4747         } else {
4748                 /* 
4749                  * This will cause waits to be broken.
4750                  * It will also prevent the thread from entering a wait, so if the thread returns
4751                  * from the wait before it receives the abort signal, it will just spin in the wait
4752                  * functions in the io-layer until the signal handler calls QueueUserAPC which will
4753                  * make it return.
4754                  */
4755                 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4756
4757                 return MonoResumeThread;
4758         }
4759 }
4760
4761 static void
4762 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4763 {
4764         AbortThreadData data;
4765
4766         g_assert (thread != mono_thread_internal_current ());
4767
4768         data.thread = thread;
4769         data.install_async_abort = install_async_abort;
4770         data.interrupt_token = NULL;
4771
4772         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4773         if (data.interrupt_token)
4774                 mono_thread_info_finish_interrupt (data.interrupt_token);
4775         /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4776 }
4777
4778 static void
4779 self_abort_internal (MonoError *error)
4780 {
4781         MonoException *exc;
4782
4783         mono_error_init (error);
4784
4785         /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4786          * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4787
4788         /*
4789         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.
4790         */
4791         exc = mono_thread_request_interruption (TRUE);
4792         if (exc)
4793                 mono_error_set_exception_instance (error, exc);
4794         else
4795                 mono_thread_info_self_interrupt ();
4796 }
4797
4798 typedef struct {
4799         MonoInternalThread *thread;
4800         gboolean interrupt;
4801         MonoThreadInfoInterruptToken *interrupt_token;
4802 } SuspendThreadData;
4803
4804 static SuspendThreadResult
4805 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4806 {
4807         SuspendThreadData *data = (SuspendThreadData *)ud;
4808         MonoInternalThread *thread = data->thread;
4809         MonoJitInfo *ji = NULL;
4810         gboolean protected_wrapper;
4811         gboolean running_managed;
4812
4813         ji = mono_thread_info_get_last_managed (info);
4814         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4815         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4816
4817         if (running_managed && !protected_wrapper) {
4818                 thread->state &= ~ThreadState_SuspendRequested;
4819                 thread->state |= ThreadState_Suspended;
4820                 return KeepSuspended;
4821         } else {
4822                 if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
4823                         InterlockedIncrement (&thread_interruption_requested);
4824                 if (data->interrupt)
4825                         data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4826
4827                 return MonoResumeThread;
4828         }
4829 }
4830
4831 /* LOCKING: called with @thread synch_cs held, and releases it */
4832 static void
4833 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4834 {
4835         SuspendThreadData data;
4836
4837         g_assert (thread != mono_thread_internal_current ());
4838
4839         data.thread = thread;
4840         data.interrupt = interrupt;
4841         data.interrupt_token = NULL;
4842
4843         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4844         if (data.interrupt_token)
4845                 mono_thread_info_finish_interrupt (data.interrupt_token);
4846
4847         UNLOCK_THREAD (thread);
4848 }
4849
4850 /* LOCKING: called with @thread synch_cs held, and releases it */
4851 static void
4852 self_suspend_internal (void)
4853 {
4854         MonoInternalThread *thread;
4855
4856         thread = mono_thread_internal_current ();
4857
4858         mono_thread_info_begin_self_suspend ();
4859         thread->state &= ~ThreadState_SuspendRequested;
4860         thread->state |= ThreadState_Suspended;
4861
4862         UNLOCK_THREAD (thread);
4863
4864         mono_thread_info_end_self_suspend ();
4865 }
4866
4867 /*
4868  * mono_thread_is_foreign:
4869  * @thread: the thread to query
4870  *
4871  * This function allows one to determine if a thread was created by the mono runtime and has
4872  * a well defined lifecycle or it's a foreigh one, created by the native environment.
4873  *
4874  * Returns: TRUE if @thread was not created by the runtime.
4875  */
4876 mono_bool
4877 mono_thread_is_foreign (MonoThread *thread)
4878 {
4879         MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4880         return info->runtime_thread == FALSE;
4881 }
4882
4883 /*
4884  * mono_add_joinable_thread:
4885  *
4886  *   Add TID to the list of joinable threads.
4887  * LOCKING: Acquires the threads lock.
4888  */
4889 void
4890 mono_threads_add_joinable_thread (gpointer tid)
4891 {
4892 #ifndef HOST_WIN32
4893         /*
4894          * We cannot detach from threads because it causes problems like
4895          * 2fd16f60/r114307. So we collect them and join them when
4896          * we have time (in he finalizer thread).
4897          */
4898         joinable_threads_lock ();
4899         if (!joinable_threads)
4900                 joinable_threads = g_hash_table_new (NULL, NULL);
4901         g_hash_table_insert (joinable_threads, tid, tid);
4902         joinable_thread_count ++;
4903         joinable_threads_unlock ();
4904
4905         mono_gc_finalize_notify ();
4906 #endif
4907 }
4908
4909 /*
4910  * mono_threads_join_threads:
4911  *
4912  *   Join all joinable threads. This is called from the finalizer thread.
4913  * LOCKING: Acquires the threads lock.
4914  */
4915 void
4916 mono_threads_join_threads (void)
4917 {
4918 #ifndef HOST_WIN32
4919         GHashTableIter iter;
4920         gpointer key;
4921         gpointer tid;
4922         pthread_t thread;
4923         gboolean found;
4924
4925         /* Fastpath */
4926         if (!joinable_thread_count)
4927                 return;
4928
4929         while (TRUE) {
4930                 joinable_threads_lock ();
4931                 found = FALSE;
4932                 if (g_hash_table_size (joinable_threads)) {
4933                         g_hash_table_iter_init (&iter, joinable_threads);
4934                         g_hash_table_iter_next (&iter, &key, (void**)&tid);
4935                         thread = (pthread_t)tid;
4936                         g_hash_table_remove (joinable_threads, key);
4937                         joinable_thread_count --;
4938                         found = TRUE;
4939                 }
4940                 joinable_threads_unlock ();
4941                 if (found) {
4942                         if (thread != pthread_self ()) {
4943                                 MONO_ENTER_GC_SAFE;
4944                                 /* This shouldn't block */
4945                                 pthread_join (thread, NULL);
4946                                 MONO_EXIT_GC_SAFE;
4947                         }
4948                 } else {
4949                         break;
4950                 }
4951         }
4952 #endif
4953 }
4954
4955 /*
4956  * mono_thread_join:
4957  *
4958  *   Wait for thread TID to exit.
4959  * LOCKING: Acquires the threads lock.
4960  */
4961 void
4962 mono_thread_join (gpointer tid)
4963 {
4964 #ifndef HOST_WIN32
4965         pthread_t thread;
4966         gboolean found = FALSE;
4967
4968         joinable_threads_lock ();
4969         if (!joinable_threads)
4970                 joinable_threads = g_hash_table_new (NULL, NULL);
4971         if (g_hash_table_lookup (joinable_threads, tid)) {
4972                 g_hash_table_remove (joinable_threads, tid);
4973                 joinable_thread_count --;
4974                 found = TRUE;
4975         }
4976         joinable_threads_unlock ();
4977         if (!found)
4978                 return;
4979         thread = (pthread_t)tid;
4980         MONO_ENTER_GC_SAFE;
4981         pthread_join (thread, NULL);
4982         MONO_EXIT_GC_SAFE;
4983 #endif
4984 }
4985
4986 void
4987 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
4988 {
4989         if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
4990                 mono_thread_interruption_checkpoint ();
4991 }
4992
4993 void
4994 mono_thread_internal_unhandled_exception (MonoObject* exc)
4995 {
4996         MonoClass *klass = exc->vtable->klass;
4997         if (is_threadabort_exception (klass)) {
4998                 mono_thread_internal_reset_abort (mono_thread_internal_current ());
4999         } else if (!is_appdomainunloaded_exception (klass)
5000                 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5001                 mono_unhandled_exception (exc);
5002                 if (mono_environment_exitcode_get () == 1) {
5003                         mono_environment_exitcode_set (255);
5004                         mono_invoke_unhandled_exception_hook (exc);
5005                         g_assert_not_reached ();
5006                 }
5007         }
5008 }
5009
5010 void
5011 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5012 {
5013         MonoError error;
5014         mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5015         mono_error_set_pending_exception (&error);
5016 }
5017
5018 /*
5019  * mono_threads_attach_coop: called by native->managed wrappers
5020  *
5021  * In non-coop mode:
5022  *  - @dummy: is NULL
5023  *  - @return: the original domain which needs to be restored, or NULL.
5024  *
5025  * In coop mode:
5026  *  - @dummy: contains the original domain
5027  *  - @return: a cookie containing current MonoThreadInfo*.
5028  */
5029 gpointer
5030 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5031 {
5032         MonoDomain *orig;
5033         gboolean fresh_thread = FALSE;
5034
5035         if (!domain) {
5036                 /* Happens when called from AOTed code which is only used in the root domain. */
5037                 domain = mono_get_root_domain ();
5038         }
5039
5040         g_assert (domain);
5041
5042         /* On coop, when we detached, we moved the thread from  RUNNING->BLOCKING.
5043          * If we try to reattach we do a BLOCKING->RUNNING transition.  If the thread
5044          * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5045          * we're only responsible for making the cookie. */
5046         if (mono_threads_is_coop_enabled ()) {
5047                 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5048                 fresh_thread = !info || !mono_thread_info_is_live (info);
5049         }
5050
5051         if (!mono_thread_internal_current ()) {
5052                 mono_thread_attach_full (domain, FALSE);
5053
5054                 // #678164
5055                 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5056         }
5057
5058         orig = mono_domain_get ();
5059         if (orig != domain)
5060                 mono_domain_set (domain, TRUE);
5061
5062         if (!mono_threads_is_coop_enabled ())
5063                 return orig != domain ? orig : NULL;
5064
5065         if (fresh_thread) {
5066                 *dummy = NULL;
5067                 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5068                  * return the right cookie. */
5069                 return mono_threads_enter_gc_unsafe_region_cookie ();
5070         } else {
5071                 *dummy = orig;
5072                 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5073                 return mono_threads_enter_gc_unsafe_region (dummy);
5074         }
5075 }
5076
5077 /*
5078  * mono_threads_detach_coop: called by native->managed wrappers
5079  *
5080  * In non-coop mode:
5081  *  - @cookie: the original domain which needs to be restored, or NULL.
5082  *  - @dummy: is NULL
5083  *
5084  * In coop mode:
5085  *  - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5086  *  - @dummy: contains the original domain
5087  */
5088 void
5089 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5090 {
5091         MonoDomain *domain, *orig;
5092
5093         if (!mono_threads_is_coop_enabled ()) {
5094                 orig = (MonoDomain*) cookie;
5095                 if (orig)
5096                         mono_domain_set (orig, TRUE);
5097         } else {
5098                 orig = (MonoDomain*) *dummy;
5099
5100                 domain = mono_domain_get ();
5101                 g_assert (domain);
5102
5103                 /* it won't do anything if cookie is NULL
5104                  * thread state RUNNING -> (RUNNING|BLOCKING) */
5105                 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5106
5107                 if (orig != domain) {
5108                         if (!orig)
5109                                 mono_domain_unset ();
5110                         else
5111                                 mono_domain_set (orig, TRUE);
5112                 }
5113         }
5114 }
5115
5116 void
5117 mono_threads_begin_abort_protected_block (void)
5118 {
5119         MonoInternalThread *thread;
5120
5121         thread = mono_thread_internal_current ();
5122         ++thread->abort_protected_block_count;
5123         mono_memory_barrier ();
5124 }
5125
5126 void
5127 mono_threads_end_abort_protected_block (void)
5128 {
5129         MonoInternalThread *thread;
5130
5131         thread = mono_thread_internal_current ();
5132
5133         mono_memory_barrier ();
5134         --thread->abort_protected_block_count;
5135 }
5136
5137 MonoException*
5138 mono_thread_try_resume_interruption (void)
5139 {
5140         MonoInternalThread *thread;
5141
5142         thread = mono_thread_internal_current ();
5143         if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5144                 return NULL;
5145
5146         return mono_thread_resume_interruption ();
5147 }
5148
5149 /* Returns TRUE if the current thread is ready to be interrupted. */
5150 gboolean
5151 mono_threads_is_ready_to_be_interrupted (void)
5152 {
5153         MonoInternalThread *thread;
5154
5155         thread = mono_thread_internal_current ();
5156         LOCK_THREAD (thread);
5157         if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5158                 UNLOCK_THREAD (thread);
5159                 return FALSE;
5160         }
5161
5162         if (thread->abort_protected_block_count || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5163                 UNLOCK_THREAD (thread);
5164                 return FALSE;
5165         }
5166
5167         UNLOCK_THREAD (thread);
5168         return TRUE;
5169 }