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