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