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