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