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