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