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