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