[threads] Remove mono_threads_create_thread (#4411)
[mono.git] / mono / metadata / threads.c
1 /*
2  * threads.c: Thread support internal calls
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *      Paolo Molaro (lupus@ximian.com)
7  *      Patrik Torstensson (patrik.torstensson@labs2.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14
15 #include <config.h>
16
17 #include <glib.h>
18 #include <string.h>
19
20 #include <mono/metadata/object.h>
21 #include <mono/metadata/domain-internals.h>
22 #include <mono/metadata/profiler-private.h>
23 #include <mono/metadata/threads.h>
24 #include <mono/metadata/threads-types.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/environment.h>
27 #include <mono/metadata/monitor.h>
28 #include <mono/metadata/gc-internals.h>
29 #include <mono/metadata/marshal.h>
30 #include <mono/metadata/runtime.h>
31 #include <mono/metadata/object-internals.h>
32 #include <mono/metadata/debug-internals.h>
33 #include <mono/utils/monobitset.h>
34 #include <mono/utils/mono-compiler.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-membar.h>
37 #include <mono/utils/mono-time.h>
38 #include <mono/utils/mono-threads.h>
39 #include <mono/utils/mono-threads-coop.h>
40 #include <mono/utils/hazard-pointer.h>
41 #include <mono/utils/mono-tls.h>
42 #include <mono/utils/atomic.h>
43 #include <mono/utils/mono-memory-model.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/os-event.h>
46 #include <mono/utils/mono-threads-debug.h>
47 #include <mono/metadata/w32handle.h>
48 #include <mono/metadata/w32event.h>
49 #include <mono/metadata/w32mutex.h>
50
51 #include <mono/metadata/reflection-internals.h>
52 #include <mono/metadata/abi-details.h>
53 #include <mono/metadata/w32error.h>
54 #include <mono/utils/w32api.h>
55
56 #ifdef HAVE_SIGNAL_H
57 #include <signal.h>
58 #endif
59
60 #if defined(HOST_WIN32)
61 #include <objbase.h>
62 #endif
63
64 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
65 #define USE_TKILL_ON_ANDROID 1
66 #endif
67
68 #ifdef PLATFORM_ANDROID
69 #include <errno.h>
70
71 #ifdef USE_TKILL_ON_ANDROID
72 extern int tkill (pid_t tid, int signal);
73 #endif
74 #endif
75
76 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
77 #define THREAD_DEBUG(a)
78 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
79 #define THREAD_WAIT_DEBUG(a)
80 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
81 #define LIBGC_DEBUG(a)
82
83 #define SPIN_TRYLOCK(i) (InterlockedCompareExchange (&(i), 1, 0) == 0)
84 #define SPIN_LOCK(i) do { \
85                                 if (SPIN_TRYLOCK (i)) \
86                                         break; \
87                         } while (1)
88
89 #define SPIN_UNLOCK(i) i = 0
90
91 #define LOCK_THREAD(thread) lock_thread((thread))
92 #define UNLOCK_THREAD(thread) unlock_thread((thread))
93
94 typedef union {
95         gint32 ival;
96         gfloat fval;
97 } IntFloatUnion;
98
99 typedef union {
100         gint64 ival;
101         gdouble fval;
102 } LongDoubleUnion;
103  
104 typedef struct _StaticDataFreeList StaticDataFreeList;
105 struct _StaticDataFreeList {
106         StaticDataFreeList *next;
107         guint32 offset;
108         guint32 size;
109 };
110
111 typedef struct {
112         int idx;
113         int offset;
114         StaticDataFreeList *freelist;
115 } StaticDataInfo;
116
117 /* Controls access to the 'threads' hash table */
118 static void mono_threads_lock (void);
119 static void mono_threads_unlock (void);
120 static MonoCoopMutex threads_mutex;
121
122 /* Controls access to the 'joinable_threads' hash table */
123 #define joinable_threads_lock() mono_os_mutex_lock (&joinable_threads_mutex)
124 #define joinable_threads_unlock() mono_os_mutex_unlock (&joinable_threads_mutex)
125 static mono_mutex_t joinable_threads_mutex;
126
127 /* Holds current status of static data heap */
128 static StaticDataInfo thread_static_info;
129 static StaticDataInfo context_static_info;
130
131 /* The hash of existing threads (key is thread ID, value is
132  * MonoInternalThread*) that need joining before exit
133  */
134 static MonoGHashTable *threads=NULL;
135
136 /* List of app context GC handles.
137  * Added to from ves_icall_System_Runtime_Remoting_Contexts_Context_RegisterContext ().
138  */
139 static GHashTable *contexts = NULL;
140
141 /* Cleanup queue for contexts. */
142 static MonoReferenceQueue *context_queue;
143
144 /*
145  * Threads which are starting up and they are not in the 'threads' hash yet.
146  * When mono_thread_attach_internal is called for a thread, it will be removed from this hash table.
147  * Protected by mono_threads_lock ().
148  */
149 static MonoGHashTable *threads_starting_up = NULL;
150
151 /* Contains tids */
152 /* Protected by the threads lock */
153 static GHashTable *joinable_threads;
154 static int joinable_thread_count;
155
156 #define SET_CURRENT_OBJECT(x) mono_tls_set_thread (x)
157 #define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_tls_get_thread ()
158
159 /* function called at thread start */
160 static MonoThreadStartCB mono_thread_start_cb = NULL;
161
162 /* function called at thread attach */
163 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
164
165 /* function called at thread cleanup */
166 static MonoThreadCleanupFunc mono_thread_cleanup_fn = NULL;
167
168 /* The default stack size for each thread */
169 static guint32 default_stacksize = 0;
170 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
171
172 static void context_adjust_static_data (MonoAppContext *ctx);
173 static void mono_free_static_data (gpointer* static_data);
174 static void mono_init_static_data_info (StaticDataInfo *static_data);
175 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
176 static gboolean mono_thread_resume (MonoInternalThread* thread);
177 static void async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort);
178 static void self_abort_internal (MonoError *error);
179 static void async_suspend_internal (MonoInternalThread *thread, gboolean interrupt);
180 static void self_suspend_internal (void);
181
182 static MonoException* mono_thread_execute_interruption (void);
183 static void ref_stack_destroy (gpointer rs);
184
185 /* Spin lock for InterlockedXXX 64 bit functions */
186 #define mono_interlocked_lock() mono_os_mutex_lock (&interlocked_mutex)
187 #define mono_interlocked_unlock() mono_os_mutex_unlock (&interlocked_mutex)
188 static mono_mutex_t interlocked_mutex;
189
190 /* global count of thread interruptions requested */
191 static gint32 thread_interruption_requested = 0;
192
193 /* Event signaled when a thread changes its background mode */
194 static MonoOSEvent background_change_event;
195
196 static gboolean shutting_down = FALSE;
197
198 static gint32 managed_thread_id_counter = 0;
199
200 /* Class lazy loading functions */
201 static GENERATE_GET_CLASS_WITH_CACHE (appdomain_unloaded_exception, "System", "AppDomainUnloadedException")
202
203 static void
204 mono_threads_lock (void)
205 {
206         mono_locks_coop_acquire (&threads_mutex, ThreadsLock);
207 }
208
209 static void
210 mono_threads_unlock (void)
211 {
212         mono_locks_coop_release (&threads_mutex, ThreadsLock);
213 }
214
215
216 static guint32
217 get_next_managed_thread_id (void)
218 {
219         return InterlockedIncrement (&managed_thread_id_counter);
220 }
221
222 enum {
223         INTERRUPT_REQUESTED_BIT = 0x1,
224         INTERRUPT_REQUEST_DEFERRED_BIT = 0x2,
225         ABORT_PROT_BLOCK_SHIFT = 2,
226         ABORT_PROT_BLOCK_BITS = 8,
227         ABORT_PROT_BLOCK_MASK = (((1 << ABORT_PROT_BLOCK_BITS) - 1) << ABORT_PROT_BLOCK_SHIFT)
228 };
229
230 static int
231 mono_thread_get_abort_prot_block_count (MonoInternalThread *thread)
232 {
233         gsize state = thread->thread_state;
234         return (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
235 }
236
237 static void
238 verify_thread_state (gsize state)
239 {
240         //can't have both INTERRUPT_REQUESTED_BIT and INTERRUPT_REQUEST_DEFERRED_BIT set at the same time
241         g_assert ((state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)) != (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT));
242
243         //XXX This would be nice to be true, but can happen due to self-aborts (and possibly set-pending-exception)
244         //if prot_count > 0, INTERRUPT_REQUESTED_BIT must never be set
245         // int prot_count = (state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT;
246         // g_assert (!(prot_count > 0 && (state & INTERRUPT_REQUESTED_BIT)));
247 }
248
249 void
250 mono_threads_begin_abort_protected_block (void)
251 {
252         MonoInternalThread *thread = mono_thread_internal_current ();
253         gsize old_state, new_state;
254         do {
255                 old_state = thread->thread_state;
256                 verify_thread_state (old_state);
257
258                 int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) + 1;
259
260                 new_state = 0;
261                 if (old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)) {
262                         if (old_state & INTERRUPT_REQUESTED_BIT)
263                                 printf ("begin prot happy as it demoted interrupt to deferred interrupt\n");
264                         new_state |= INTERRUPT_REQUEST_DEFERRED_BIT;
265                 }
266
267                 //bounds check abort_prot_count
268                 g_assert (new_val > 0);
269                 g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
270                 new_state |= new_val << ABORT_PROT_BLOCK_SHIFT;
271
272         } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
273 }
274
275 gboolean
276 mono_threads_end_abort_protected_block (void)
277 {
278         MonoInternalThread *thread = mono_thread_internal_current ();
279         gsize old_state, new_state;
280         do {
281                 old_state = thread->thread_state;
282                 verify_thread_state (old_state);
283
284                 int new_val = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT) - 1;
285                 new_state = 0;
286
287                 if ((old_state & INTERRUPT_REQUEST_DEFERRED_BIT) && new_val == 0) {
288                         printf ("end abort on alert, promoted deferred to pront interrupt\n");
289                         new_state |= INTERRUPT_REQUESTED_BIT;
290                 }
291
292                 //bounds check abort_prot_count
293                 g_assert (new_val >= 0);
294                 g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
295                 new_state |= new_val << ABORT_PROT_BLOCK_SHIFT;
296
297         } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
298         return (new_state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
299 }
300
301
302 //Don't use this function, use inc/dec below
303 static void
304 mono_thread_abort_prot_block_count_add (MonoInternalThread *thread, int val)
305 {
306         gsize old_state, new_state;
307         do {
308                 old_state = thread->thread_state;
309                 verify_thread_state (old_state);
310
311                 int new_val = val + ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT);
312                 //bounds check abort_prot_count
313                 g_assert (new_val >= 0);
314                 g_assert (new_val < (1 << ABORT_PROT_BLOCK_BITS));
315                 new_state = (old_state & ~ABORT_PROT_BLOCK_MASK) | (new_val << ABORT_PROT_BLOCK_SHIFT);
316
317         } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
318 }
319
320 static void
321 mono_thread_inc_abort_prot_block_count (MonoInternalThread *thread)
322 {
323         mono_thread_abort_prot_block_count_add (thread, 1);
324 }
325
326 static void
327 mono_thread_dec_abort_prot_block_count (MonoInternalThread *thread)
328 {
329         mono_thread_abort_prot_block_count_add (thread, -1);
330 }
331
332 static gboolean
333 mono_thread_get_interruption_requested (MonoInternalThread *thread)
334 {
335         gsize state = thread->thread_state;
336         return (state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
337 }
338
339 /* Returns TRUE is there was a state change */
340 static gboolean
341 mono_thread_clear_interruption_requested (MonoInternalThread *thread)
342 {
343         gsize old_state, new_state;
344         do {
345                 old_state = thread->thread_state;
346                 verify_thread_state (old_state);
347
348                 //Already cleared
349                 if (!(old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT)))
350                         return FALSE;
351                 new_state = old_state & ~(INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT);
352         } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
353         return TRUE;
354 }
355
356 /* Returns TRUE is there was a state change */
357 static gboolean
358 mono_thread_set_interruption_requested (MonoInternalThread *thread)
359 {
360         //always force when the current thread is doing it to itself.
361         gboolean force_interrupt = thread == mono_thread_internal_current ();
362         gsize old_state, new_state;
363         do {
364                 old_state = thread->thread_state;
365                 verify_thread_state (old_state);
366
367                 int prot_count = ((old_state & ABORT_PROT_BLOCK_MASK) >> ABORT_PROT_BLOCK_SHIFT);
368                 //Already set
369                 if (old_state & (INTERRUPT_REQUESTED_BIT | INTERRUPT_REQUEST_DEFERRED_BIT))
370                         return FALSE;
371
372                 //If there's an outstanding prot block, we queue it
373                 if (prot_count && !force_interrupt) {
374                         printf ("set interrupt unhappy, as it's only putting a deferred req %d\n", force_interrupt);
375                         new_state = old_state | INTERRUPT_REQUEST_DEFERRED_BIT;
376                 } else
377                         new_state = old_state | INTERRUPT_REQUESTED_BIT;
378         } while (InterlockedCompareExchangePointer ((volatile gpointer)&thread->thread_state, (gpointer)new_state, (gpointer)old_state) != (gpointer)old_state);
379
380         return (new_state & INTERRUPT_REQUESTED_BIT) == INTERRUPT_REQUESTED_BIT;
381 }
382
383 static inline MonoNativeThreadId
384 thread_get_tid (MonoInternalThread *thread)
385 {
386         /* We store the tid as a guint64 to keep the object layout constant between platforms */
387         return MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid);
388 }
389
390 static void ensure_synch_cs_set (MonoInternalThread *thread)
391 {
392         MonoCoopMutex *synch_cs;
393
394         if (thread->synch_cs != NULL) {
395                 return;
396         }
397
398         synch_cs = g_new0 (MonoCoopMutex, 1);
399         mono_coop_mutex_init_recursive (synch_cs);
400
401         if (InterlockedCompareExchangePointer ((gpointer *)&thread->synch_cs,
402                                                synch_cs, NULL) != NULL) {
403                 /* Another thread must have installed this CS */
404                 mono_coop_mutex_destroy (synch_cs);
405                 g_free (synch_cs);
406         }
407 }
408
409 static inline void
410 lock_thread (MonoInternalThread *thread)
411 {
412         if (!thread->synch_cs)
413                 ensure_synch_cs_set (thread);
414
415         g_assert (thread->synch_cs);
416
417         mono_coop_mutex_lock (thread->synch_cs);
418 }
419
420 static inline void
421 unlock_thread (MonoInternalThread *thread)
422 {
423         mono_coop_mutex_unlock (thread->synch_cs);
424 }
425
426 static inline gboolean
427 is_appdomainunloaded_exception (MonoClass *klass)
428 {
429         return klass == mono_class_get_appdomain_unloaded_exception_class ();
430 }
431
432 static inline gboolean
433 is_threadabort_exception (MonoClass *klass)
434 {
435         return klass == mono_defaults.threadabortexception_class;
436 }
437
438 /*
439  * A special static data offset (guint32) consists of 3 parts:
440  *
441  * [0]   6-bit index into the array of chunks.
442  * [6]   25-bit offset into the array.
443  * [31]  Bit indicating thread or context static.
444  */
445
446 typedef union {
447         struct {
448 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
449                 guint32 type : 1;
450                 guint32 offset : 25;
451                 guint32 index : 6;
452 #else
453                 guint32 index : 6;
454                 guint32 offset : 25;
455                 guint32 type : 1;
456 #endif
457         } fields;
458         guint32 raw;
459 } SpecialStaticOffset;
460
461 #define SPECIAL_STATIC_OFFSET_TYPE_THREAD 0
462 #define SPECIAL_STATIC_OFFSET_TYPE_CONTEXT 1
463
464 #define MAKE_SPECIAL_STATIC_OFFSET(index, offset, type) \
465         ((SpecialStaticOffset) { .fields = { (index), (offset), (type) } }.raw)
466 #define ACCESS_SPECIAL_STATIC_OFFSET(x,f) \
467         (((SpecialStaticOffset *) &(x))->fields.f)
468
469 static gpointer
470 get_thread_static_data (MonoInternalThread *thread, guint32 offset)
471 {
472         g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_THREAD);
473
474         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
475         int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
476
477         return ((char *) thread->static_data [idx]) + off;
478 }
479
480 static gpointer
481 get_context_static_data (MonoAppContext *ctx, guint32 offset)
482 {
483         g_assert (ACCESS_SPECIAL_STATIC_OFFSET (offset, type) == SPECIAL_STATIC_OFFSET_TYPE_CONTEXT);
484
485         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
486         int off = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
487
488         return ((char *) ctx->static_data [idx]) + off;
489 }
490
491 static MonoThread**
492 get_current_thread_ptr_for_domain (MonoDomain *domain, MonoInternalThread *thread)
493 {
494         static MonoClassField *current_thread_field = NULL;
495
496         guint32 offset;
497
498         if (!current_thread_field) {
499                 current_thread_field = mono_class_get_field_from_name (mono_defaults.thread_class, "current_thread");
500                 g_assert (current_thread_field);
501         }
502
503         mono_class_vtable (domain, mono_defaults.thread_class);
504         mono_domain_lock (domain);
505         offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, current_thread_field));
506         mono_domain_unlock (domain);
507         g_assert (offset);
508
509         return (MonoThread **)get_thread_static_data (thread, offset);
510 }
511
512 static void
513 set_current_thread_for_domain (MonoDomain *domain, MonoInternalThread *thread, MonoThread *current)
514 {
515         MonoThread **current_thread_ptr = get_current_thread_ptr_for_domain (domain, thread);
516
517         g_assert (current->obj.vtable->domain == domain);
518
519         g_assert (!*current_thread_ptr);
520         *current_thread_ptr = current;
521 }
522
523 static MonoThread*
524 create_thread_object (MonoDomain *domain, MonoInternalThread *internal)
525 {
526         MonoThread *thread;
527         MonoVTable *vtable;
528         MonoError error;
529
530         vtable = mono_class_vtable (domain, mono_defaults.thread_class);
531         g_assert (vtable);
532
533         thread = (MonoThread*)mono_object_new_mature (vtable, &error);
534         /* only possible failure mode is OOM, from which we don't expect to recover. */
535         mono_error_assert_ok (&error);
536
537         MONO_OBJECT_SETREF (thread, internal_thread, internal);
538
539         return thread;
540 }
541
542 static MonoInternalThread*
543 create_internal_thread_object (void)
544 {
545         MonoError error;
546         MonoInternalThread *thread;
547         MonoVTable *vt;
548
549         vt = mono_class_vtable (mono_get_root_domain (), mono_defaults.internal_thread_class);
550         thread = (MonoInternalThread*) mono_object_new_mature (vt, &error);
551         /* only possible failure mode is OOM, from which we don't exect to recover */
552         mono_error_assert_ok (&error);
553
554         thread->synch_cs = g_new0 (MonoCoopMutex, 1);
555         mono_coop_mutex_init_recursive (thread->synch_cs);
556
557         thread->apartment_state = ThreadApartmentState_Unknown;
558         thread->managed_id = get_next_managed_thread_id ();
559         if (mono_gc_is_moving ()) {
560                 thread->thread_pinning_ref = thread;
561                 MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference");
562         }
563
564         thread->priority = MONO_THREAD_PRIORITY_NORMAL;
565
566         thread->suspended = g_new0 (MonoOSEvent, 1);
567         mono_os_event_init (thread->suspended, TRUE);
568
569         return thread;
570 }
571
572 static void
573 mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPriority priority)
574 {
575         g_assert (internal);
576
577         g_assert (priority >= MONO_THREAD_PRIORITY_LOWEST);
578         g_assert (priority <= MONO_THREAD_PRIORITY_HIGHEST);
579         g_assert (MONO_THREAD_PRIORITY_LOWEST < MONO_THREAD_PRIORITY_HIGHEST);
580
581 #ifdef HOST_WIN32
582         BOOL res;
583
584         g_assert (internal->native_handle);
585
586         res = SetThreadPriority (internal->native_handle, priority - 2);
587         if (!res)
588                 g_error ("%s: SetThreadPriority failed, error %d", __func__, GetLastError ());
589 #else /* HOST_WIN32 */
590         pthread_t tid;
591         int policy;
592         struct sched_param param;
593         gint res;
594
595         tid = thread_get_tid (internal);
596
597         res = pthread_getschedparam (tid, &policy, &param);
598         if (res != 0)
599                 g_error ("%s: pthread_getschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
600
601 #ifdef _POSIX_PRIORITY_SCHEDULING
602         int max, min;
603
604         /* Necessary to get valid priority range */
605
606         min = sched_get_priority_min (policy);
607         max = sched_get_priority_max (policy);
608
609         if (max > 0 && min >= 0 && max > min) {
610                 double srange, drange, sposition, dposition;
611                 srange = MONO_THREAD_PRIORITY_HIGHEST - MONO_THREAD_PRIORITY_LOWEST;
612                 drange = max - min;
613                 sposition = priority - MONO_THREAD_PRIORITY_LOWEST;
614                 dposition = (sposition / srange) * drange;
615                 param.sched_priority = (int)(dposition + min);
616         } else
617 #endif
618         {
619                 switch (policy) {
620                 case SCHED_FIFO:
621                 case SCHED_RR:
622                         param.sched_priority = 50;
623                         break;
624 #ifdef SCHED_BATCH
625                 case SCHED_BATCH:
626 #endif
627                 case SCHED_OTHER:
628                         param.sched_priority = 0;
629                         break;
630                 default:
631                         g_warning ("%s: unknown policy %d", __func__, policy);
632                         return;
633                 }
634         }
635
636         res = pthread_setschedparam (tid, policy, &param);
637         if (res != 0) {
638                 if (res == EPERM) {
639                         g_warning ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
640                         return;
641                 }
642                 g_error ("%s: pthread_setschedparam failed, error: \"%s\" (%d)", __func__, g_strerror (res), res);
643         }
644 #endif /* HOST_WIN32 */
645 }
646
647 static void 
648 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal);
649
650 static gboolean
651 mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain)
652 {
653         MonoThreadInfo *info;
654         MonoInternalThread *internal;
655         MonoDomain *domain, *root_domain;
656
657         g_assert (thread);
658
659         info = mono_thread_info_current ();
660
661         internal = thread->internal_thread;
662         internal->handle = mono_threads_open_thread_handle (info->handle);
663 #ifdef HOST_WIN32
664         internal->native_handle = OpenThread (THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId ());
665 #endif
666         internal->tid = MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ());
667         internal->thread_info = info;
668         internal->small_id = info->small_id;
669
670         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Setting current_object_key to %p", __func__, mono_native_thread_id_get (), internal));
671
672         SET_CURRENT_OBJECT (internal);
673
674         domain = mono_object_domain (thread);
675
676         mono_thread_push_appdomain_ref (domain);
677         if (!mono_domain_set (domain, force_domain)) {
678                 mono_thread_pop_appdomain_ref ();
679                 return FALSE;
680         }
681
682         mono_threads_lock ();
683
684         if (threads_starting_up)
685                 mono_g_hash_table_remove (threads_starting_up, thread);
686
687         if (shutting_down && !force_attach) {
688                 mono_threads_unlock ();
689                 mono_thread_pop_appdomain_ref ();
690                 return FALSE;
691         }
692
693         if (!threads) {
694                 threads = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "threads table");
695         }
696
697         /* We don't need to duplicate thread->handle, because it is
698          * only closed when the thread object is finalized by the GC. */
699         mono_g_hash_table_insert (threads, (gpointer)(gsize)(internal->tid), internal);
700
701         /* We have to do this here because mono_thread_start_cb
702          * requires that root_domain_thread is set up. */
703         if (thread_static_info.offset || thread_static_info.idx > 0) {
704                 /* get the current allocated size */
705                 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0);
706                 mono_alloc_static_data (&internal->static_data, offset, TRUE);
707         }
708
709         mono_threads_unlock ();
710
711         root_domain = mono_get_root_domain ();
712
713         g_assert (!internal->root_domain_thread);
714         if (domain != root_domain)
715                 MONO_OBJECT_SETREF (internal, root_domain_thread, create_thread_object (root_domain, internal));
716         else
717                 MONO_OBJECT_SETREF (internal, root_domain_thread, thread);
718
719         if (domain != root_domain)
720                 set_current_thread_for_domain (root_domain, internal, internal->root_domain_thread);
721
722         set_current_thread_for_domain (domain, internal, thread);
723
724         THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, internal->tid, internal->handle));
725
726         return TRUE;
727 }
728
729 typedef struct {
730         gint32 ref;
731         MonoThread *thread;
732         MonoObject *start_delegate;
733         MonoObject *start_delegate_arg;
734         MonoThreadStart start_func;
735         gpointer start_func_arg;
736         gboolean force_attach;
737         gboolean failed;
738         MonoCoopSem registered;
739 } StartInfo;
740
741 static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr)
742 {
743         MonoError error;
744         MonoThreadStart start_func;
745         void *start_func_arg;
746         gsize tid;
747         /* 
748          * We don't create a local to hold start_info->thread, so hopefully it won't get pinned during a
749          * GC stack walk.
750          */
751         MonoThread *thread;
752         MonoInternalThread *internal;
753         MonoObject *start_delegate;
754         MonoObject *start_delegate_arg;
755         MonoDomain *domain;
756
757         thread = start_info->thread;
758         internal = thread->internal_thread;
759         domain = mono_object_domain (start_info->thread);
760
761         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper", __func__, mono_native_thread_id_get ()));
762
763         if (!mono_thread_attach_internal (thread, start_info->force_attach, FALSE)) {
764                 start_info->failed = TRUE;
765
766                 mono_coop_sem_post (&start_info->registered);
767
768                 if (InterlockedDecrement (&start_info->ref) == 0) {
769                         mono_coop_sem_destroy (&start_info->registered);
770                         g_free (start_info);
771                 }
772
773                 return 0;
774         }
775
776         mono_thread_internal_set_priority (internal, internal->priority);
777
778         tid = internal->tid;
779
780         start_delegate = start_info->start_delegate;
781         start_delegate_arg = start_info->start_delegate_arg;
782         start_func = start_info->start_func;
783         start_func_arg = start_info->start_func_arg;
784
785         /* This MUST be called before any managed code can be
786          * executed, as it calls the callback function that (for the
787          * jit) sets the lmf marker.
788          */
789
790         if (mono_thread_start_cb)
791                 mono_thread_start_cb (tid, stack_ptr, start_func);
792
793         /* On 2.0 profile (and higher), set explicitly since state might have been
794            Unknown */
795         if (internal->apartment_state == ThreadApartmentState_Unknown)
796                 internal->apartment_state = ThreadApartmentState_MTA;
797
798         mono_thread_init_apartment_state ();
799
800         /* Let the thread that called Start() know we're ready */
801         mono_coop_sem_post (&start_info->registered);
802
803         if (InterlockedDecrement (&start_info->ref) == 0) {
804                 mono_coop_sem_destroy (&start_info->registered);
805                 g_free (start_info);
806         }
807
808         /* start_info is not valid anymore */
809         start_info = NULL;
810
811         /* 
812          * Call this after calling start_notify, since the profiler callback might want
813          * to lock the thread, and the lock is held by thread_start () which waits for
814          * start_notify.
815          */
816         mono_profiler_thread_start (tid);
817
818         /* if the name was set before starting, we didn't invoke the profiler callback */
819         if (internal->name) {
820                 char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
821                 mono_profiler_thread_name (internal->tid, tname);
822                 mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname);
823                 g_free (tname);
824         }
825
826         /* start_func is set only for unmanaged start functions */
827         if (start_func) {
828                 start_func (start_func_arg);
829         } else {
830                 void *args [1];
831
832                 g_assert (start_delegate != NULL);
833
834                 /* we may want to handle the exception here. See comment below on unhandled exceptions */
835                 args [0] = (gpointer) start_delegate_arg;
836                 mono_runtime_delegate_invoke_checked (start_delegate, args, &error);
837
838                 if (!mono_error_ok (&error)) {
839                         MonoException *ex = mono_error_convert_to_exception (&error);
840
841                         g_assert (ex != NULL);
842                         MonoClass *klass = mono_object_get_class (&ex->object);
843                         if ((mono_runtime_unhandled_exception_policy_get () != MONO_UNHANDLED_POLICY_LEGACY) &&
844                             !is_threadabort_exception (klass)) {
845                                 mono_unhandled_exception (&ex->object);
846                                 mono_invoke_unhandled_exception_hook (&ex->object);
847                                 g_assert_not_reached ();
848                         }
849                 } else {
850                         mono_error_cleanup (&error);
851                 }
852         }
853
854         /* If the thread calls ExitThread at all, this remaining code
855          * will not be executed, but the main thread will eventually
856          * call mono_thread_detach_internal() on this thread's behalf.
857          */
858
859         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Start wrapper terminating", __func__, mono_native_thread_id_get ()));
860
861         /* Do any cleanup needed for apartment state. This
862          * cannot be done in mono_thread_detach_internal since
863          * mono_thread_detach_internal could be  called for a
864          * thread other than the current thread.
865          * mono_thread_cleanup_apartment_state cleans up apartment
866          * for the current thead */
867         mono_thread_cleanup_apartment_state ();
868
869         mono_thread_detach_internal (internal);
870
871         internal->tid = 0;
872
873         return(0);
874 }
875
876 static gsize WINAPI
877 start_wrapper (gpointer data)
878 {
879         StartInfo *start_info;
880         MonoThreadInfo *info;
881         gsize res;
882
883         start_info = (StartInfo*) data;
884         g_assert (start_info);
885
886         info = mono_thread_info_attach (&res);
887         info->runtime_thread = TRUE;
888
889         /* Run the actual main function of the thread */
890         res = start_wrapper_internal (start_info, &res);
891
892         mono_thread_info_exit (res);
893
894         g_assert_not_reached ();
895 }
896
897 /*
898  * create_thread:
899  *
900  *   Common thread creation code.
901  * LOCKING: Acquires the threads lock.
902  */
903 static gboolean
904 create_thread (MonoThread *thread, MonoInternalThread *internal, MonoObject *start_delegate, MonoThreadStart start_func, gpointer start_func_arg,
905         MonoThreadCreateFlags flags, MonoError *error)
906 {
907         StartInfo *start_info = NULL;
908         MonoNativeThreadId tid;
909         gboolean ret;
910         gsize stack_set_size;
911
912         if (start_delegate)
913                 g_assert (!start_func && !start_func_arg);
914         if (start_func)
915                 g_assert (!start_delegate);
916
917         if (flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL) {
918                 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER));
919                 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
920         }
921         if (flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER) {
922                 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL));
923                 g_assert (!(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE));
924         }
925
926         /*
927          * Join joinable threads to prevent running out of threads since the finalizer
928          * thread might be blocked/backlogged.
929          */
930         mono_threads_join_threads ();
931
932         error_init (error);
933
934         mono_threads_lock ();
935         if (shutting_down && !(flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE)) {
936                 mono_threads_unlock ();
937                 return FALSE;
938         }
939         if (threads_starting_up == NULL) {
940                 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
941         }
942         mono_g_hash_table_insert (threads_starting_up, thread, thread);
943         mono_threads_unlock ();
944
945         internal->threadpool_thread = flags & MONO_THREAD_CREATE_FLAGS_THREADPOOL;
946         if (internal->threadpool_thread)
947                 mono_thread_set_state (internal, ThreadState_Background);
948
949         internal->debugger_thread = flags & MONO_THREAD_CREATE_FLAGS_DEBUGGER;
950
951         start_info = g_new0 (StartInfo, 1);
952         start_info->ref = 2;
953         start_info->thread = thread;
954         start_info->start_delegate = start_delegate;
955         start_info->start_delegate_arg = thread->start_obj;
956         start_info->start_func = start_func;
957         start_info->start_func_arg = start_func_arg;
958         start_info->force_attach = flags & MONO_THREAD_CREATE_FLAGS_FORCE_CREATE;
959         start_info->failed = FALSE;
960         mono_coop_sem_init (&start_info->registered, 0);
961
962         if (flags != MONO_THREAD_CREATE_FLAGS_SMALL_STACK)
963                 stack_set_size = default_stacksize_for_thread (internal);
964         else
965                 stack_set_size = 0;
966
967         if (!mono_thread_platform_create_thread (start_wrapper, start_info, &stack_set_size, &tid)) {
968                 /* The thread couldn't be created, so set an exception */
969                 mono_threads_lock ();
970                 mono_g_hash_table_remove (threads_starting_up, thread);
971                 mono_threads_unlock ();
972                 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
973                 /* ref is not going to be decremented in start_wrapper_internal */
974                 InterlockedDecrement (&start_info->ref);
975                 ret = FALSE;
976                 goto done;
977         }
978
979         internal->stack_size = (int) stack_set_size;
980
981         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
982
983         /*
984          * Wait for the thread to set up its TLS data etc, so
985          * theres no potential race condition if someone tries
986          * to look up the data believing the thread has
987          * started
988          */
989
990         mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
991
992         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Done launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
993
994         ret = !start_info->failed;
995
996 done:
997         if (InterlockedDecrement (&start_info->ref) == 0) {
998                 mono_coop_sem_destroy (&start_info->registered);
999                 g_free (start_info);
1000         }
1001
1002         return ret;
1003 }
1004
1005 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
1006 {
1007         if (mono_thread_start_cb) {
1008                 mono_thread_start_cb (tid, stack_start, func);
1009         }
1010 }
1011
1012 void mono_threads_set_default_stacksize (guint32 stacksize)
1013 {
1014         default_stacksize = stacksize;
1015 }
1016
1017 guint32 mono_threads_get_default_stacksize (void)
1018 {
1019         return default_stacksize;
1020 }
1021
1022 /*
1023  * mono_thread_create_internal:
1024  *
1025  *   ARG should not be a GC reference.
1026  */
1027 MonoInternalThread*
1028 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, MonoThreadCreateFlags flags, MonoError *error)
1029 {
1030         MonoThread *thread;
1031         MonoInternalThread *internal;
1032         gboolean res;
1033
1034         error_init (error);
1035
1036         internal = create_internal_thread_object ();
1037
1038         thread = create_thread_object (domain, internal);
1039
1040         LOCK_THREAD (internal);
1041
1042         res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, flags, error);
1043
1044         UNLOCK_THREAD (internal);
1045
1046         return_val_if_nok (error, NULL);
1047         return internal;
1048 }
1049
1050 void
1051 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1052 {
1053         MonoError error;
1054         if (!mono_thread_create_checked (domain, func, arg, &error))
1055                 mono_error_cleanup (&error);
1056 }
1057
1058 gboolean
1059 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1060 {
1061         return (NULL != mono_thread_create_internal (domain, func, arg, MONO_THREAD_CREATE_FLAGS_NONE, error));
1062 }
1063
1064 MonoThread *
1065 mono_thread_attach (MonoDomain *domain)
1066 {
1067         MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1068
1069         return thread;
1070 }
1071
1072 MonoThread *
1073 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1074 {
1075         MonoInternalThread *internal;
1076         MonoThread *thread;
1077         MonoThreadInfo *info;
1078         MonoNativeThreadId tid;
1079         gsize stack_ptr;
1080
1081         if (mono_thread_internal_current_is_attached ()) {
1082                 if (domain != mono_domain_get ())
1083                         mono_domain_set (domain, TRUE);
1084                 /* Already attached */
1085                 return mono_thread_current ();
1086         }
1087
1088         info = mono_thread_info_attach (&stack_ptr);
1089         g_assert (info);
1090
1091         tid=mono_native_thread_id_get ();
1092
1093         internal = create_internal_thread_object ();
1094
1095         thread = create_thread_object (domain, internal);
1096
1097         if (!mono_thread_attach_internal (thread, force_attach, TRUE)) {
1098                 /* Mono is shutting down, so just wait for the end */
1099                 for (;;)
1100                         mono_thread_info_sleep (10000, NULL);
1101         }
1102
1103         THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1104
1105         if (mono_thread_attach_cb) {
1106                 guint8 *staddr;
1107                 size_t stsize;
1108
1109                 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1110
1111                 if (staddr == NULL)
1112                         mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1113                 else
1114                         mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1115         }
1116
1117         /* Can happen when we attach the profiler helper thread in order to heapshot. */
1118         if (!mono_thread_info_current ()->tools_thread)
1119                 // FIXME: Need a separate callback
1120                 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1121
1122         return thread;
1123 }
1124
1125 void
1126 mono_thread_detach_internal (MonoInternalThread *thread)
1127 {
1128         gboolean removed;
1129
1130         g_assert (thread != NULL);
1131
1132         THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1133
1134 #ifndef HOST_WIN32
1135         mono_w32mutex_abandon ();
1136 #endif
1137
1138         if (thread->abort_state_handle) {
1139                 mono_gchandle_free (thread->abort_state_handle);
1140                 thread->abort_state_handle = 0;
1141         }
1142
1143         thread->abort_exc = NULL;
1144         thread->current_appcontext = NULL;
1145
1146         /*
1147          * thread->synch_cs can be NULL if this was called after
1148          * ves_icall_System_Threading_InternalThread_Thread_free_internal.
1149          * This can happen only during shutdown.
1150          * The shutting_down flag is not always set, so we can't assert on it.
1151          */
1152         if (thread->synch_cs)
1153                 LOCK_THREAD (thread);
1154
1155         thread->state |= ThreadState_Stopped;
1156         thread->state &= ~ThreadState_Background;
1157
1158         if (thread->synch_cs)
1159                 UNLOCK_THREAD (thread);
1160
1161         /*
1162         An interruption request has leaked to cleanup. Adjust the global counter.
1163
1164         This can happen is the abort source thread finds the abortee (this) thread
1165         in unmanaged code. If this thread never trips back to managed code or check
1166         the local flag it will be left set and positively unbalance the global counter.
1167         
1168         Leaving the counter unbalanced will cause a performance degradation since all threads
1169         will now keep checking their local flags all the time.
1170         */
1171         if (mono_thread_clear_interruption_requested (thread))
1172                 InterlockedDecrement (&thread_interruption_requested);
1173
1174         mono_threads_lock ();
1175
1176         if (!threads) {
1177                 removed = FALSE;
1178         } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
1179                 /* We have to check whether the thread object for the
1180                  * tid is still the same in the table because the
1181                  * thread might have been destroyed and the tid reused
1182                  * in the meantime, in which case the tid would be in
1183                  * the table, but with another thread object.
1184                  */
1185                 removed = FALSE;
1186         } else {
1187                 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
1188                 removed = TRUE;
1189         }
1190
1191         mono_threads_unlock ();
1192
1193         /* Don't close the handle here, wait for the object finalizer
1194          * to do it. Otherwise, the following race condition applies:
1195          *
1196          * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
1197          *
1198          * 2) Some other handle is reassigned the same slot
1199          *
1200          * 3) Another thread tries to join the first thread, and
1201          * blocks waiting for the reassigned handle to be signalled
1202          * (which might never happen).  This is possible, because the
1203          * thread calling Join() still has a reference to the first
1204          * thread's object.
1205          */
1206
1207         /* if the thread is not in the hash it has been removed already */
1208         if (!removed) {
1209                 mono_domain_unset ();
1210                 mono_memory_barrier ();
1211
1212                 if (mono_thread_cleanup_fn)
1213                         mono_thread_cleanup_fn (thread_get_tid (thread));
1214
1215                 goto done;
1216         }
1217
1218         mono_release_type_locks (thread);
1219
1220         /* Can happen when we attach the profiler helper thread in order to heapshot. */
1221         if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
1222                 mono_profiler_thread_end (thread->tid);
1223
1224         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1225
1226         /*
1227          * This will signal async signal handlers that the thread has exited.
1228          * The profiler callback needs this to be set, so it cannot be done earlier.
1229          */
1230         mono_domain_unset ();
1231         mono_memory_barrier ();
1232
1233         if (thread == mono_thread_internal_current ())
1234                 mono_thread_pop_appdomain_ref ();
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, MONO_THREAD_CREATE_FLAGS_NONE, &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 /*
3938  * mono_thread_get_undeniable_exception:
3939  *
3940  *   Return an exception which needs to be raised when leaving a catch clause.
3941  * This is used for undeniable exception propagation.
3942  */
3943 MonoException*
3944 mono_thread_get_undeniable_exception (void)
3945 {
3946         MonoInternalThread *thread = mono_thread_internal_current ();
3947
3948         if (!(thread && thread->abort_exc && !is_running_protected_wrapper ()))
3949                 return NULL;
3950
3951         // We don't want to have our exception effect calls made by
3952         // the catching block
3953
3954         if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
3955                 return NULL;
3956
3957         /*
3958          * FIXME: Clear the abort exception and return an AppDomainUnloaded 
3959          * exception if the thread no longer references a dying appdomain.
3960          */ 
3961         thread->abort_exc->trace_ips = NULL;
3962         thread->abort_exc->stack_trace = NULL;
3963         return thread->abort_exc;
3964 }
3965
3966 #if MONO_SMALL_CONFIG
3967 #define NUM_STATIC_DATA_IDX 4
3968 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3969         64, 256, 1024, 4096
3970 };
3971 #else
3972 #define NUM_STATIC_DATA_IDX 8
3973 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
3974         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
3975 };
3976 #endif
3977
3978 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
3979 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
3980
3981 static void
3982 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
3983 {
3984         gpointer *static_data = (gpointer *)addr;
3985
3986         for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
3987                 void **ptr = (void **)static_data [i];
3988
3989                 if (!ptr)
3990                         continue;
3991
3992                 MONO_BITSET_FOREACH (bitmaps [i], idx, {
3993                         void **p = ptr + idx;
3994
3995                         if (*p)
3996                                 mark_func ((MonoObject**)p, gc_data);
3997                 });
3998         }
3999 }
4000
4001 static void
4002 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4003 {
4004         mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
4005 }
4006
4007 static void
4008 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4009 {
4010         mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
4011 }
4012
4013 /*
4014  *  mono_alloc_static_data
4015  *
4016  *   Allocate memory blocks for storing threads or context static data
4017  */
4018 static void 
4019 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4020 {
4021         guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4022         int i;
4023
4024         gpointer* static_data = *static_data_ptr;
4025         if (!static_data) {
4026                 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4027                 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4028
4029                 if (mono_gc_user_markers_supported ()) {
4030                         if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4031                                 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4032
4033                         if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4034                                 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4035                 }
4036
4037                 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4038                         threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4039                         threadlocal ? "managed thread-static variables" : "managed context-static variables");
4040                 *static_data_ptr = static_data;
4041                 static_data [0] = static_data;
4042         }
4043
4044         for (i = 1; i <= idx; ++i) {
4045                 if (static_data [i])
4046                         continue;
4047
4048                 if (mono_gc_user_markers_supported ())
4049                         static_data [i] = g_malloc0 (static_data_size [i]);
4050                 else
4051                         static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4052                                 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4053                                 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4054         }
4055 }
4056
4057 static void 
4058 mono_free_static_data (gpointer* static_data)
4059 {
4060         int i;
4061         for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4062                 gpointer p = static_data [i];
4063                 if (!p)
4064                         continue;
4065                 /*
4066                  * At this point, the static data pointer array is still registered with the
4067                  * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4068                  * data.  Freeing the individual arrays without first nulling their slots
4069                  * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4070                  * such an already freed array.  See bug #13813.
4071                  */
4072                 static_data [i] = NULL;
4073                 mono_memory_write_barrier ();
4074                 if (mono_gc_user_markers_supported ())
4075                         g_free (p);
4076                 else
4077                         mono_gc_free_fixed (p);
4078         }
4079         mono_gc_free_fixed (static_data);
4080 }
4081
4082 /*
4083  *  mono_init_static_data_info
4084  *
4085  *   Initializes static data counters
4086  */
4087 static void mono_init_static_data_info (StaticDataInfo *static_data)
4088 {
4089         static_data->idx = 0;
4090         static_data->offset = 0;
4091         static_data->freelist = NULL;
4092 }
4093
4094 /*
4095  *  mono_alloc_static_data_slot
4096  *
4097  *   Generates an offset for static data. static_data contains the counters
4098  *  used to generate it.
4099  */
4100 static guint32
4101 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4102 {
4103         if (!static_data->idx && !static_data->offset) {
4104                 /* 
4105                  * we use the first chunk of the first allocation also as
4106                  * an array for the rest of the data 
4107                  */
4108                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4109         }
4110         static_data->offset += align - 1;
4111         static_data->offset &= ~(align - 1);
4112         if (static_data->offset + size >= static_data_size [static_data->idx]) {
4113                 static_data->idx ++;
4114                 g_assert (size <= static_data_size [static_data->idx]);
4115                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4116                 static_data->offset = 0;
4117         }
4118         guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4119         static_data->offset += size;
4120         return offset;
4121 }
4122
4123 /*
4124  * LOCKING: requires that threads_mutex is held
4125  */
4126 static void
4127 context_adjust_static_data (MonoAppContext *ctx)
4128 {
4129         if (context_static_info.offset || context_static_info.idx > 0) {
4130                 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4131                 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4132                 ctx->data->static_data = ctx->static_data;
4133         }
4134 }
4135
4136 /*
4137  * LOCKING: requires that threads_mutex is held
4138  */
4139 static void 
4140 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4141 {
4142         MonoInternalThread *thread = (MonoInternalThread *)value;
4143         guint32 offset = GPOINTER_TO_UINT (user);
4144
4145         mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4146 }
4147
4148 /*
4149  * LOCKING: requires that threads_mutex is held
4150  */
4151 static void
4152 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4153 {
4154         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4155
4156         if (!ctx)
4157                 return;
4158
4159         guint32 offset = GPOINTER_TO_UINT (user);
4160         mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4161         ctx->data->static_data = ctx->static_data;
4162 }
4163
4164 static StaticDataFreeList*
4165 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4166 {
4167         StaticDataFreeList* prev = NULL;
4168         StaticDataFreeList* tmp = static_data->freelist;
4169         while (tmp) {
4170                 if (tmp->size == size) {
4171                         if (prev)
4172                                 prev->next = tmp->next;
4173                         else
4174                                 static_data->freelist = tmp->next;
4175                         return tmp;
4176                 }
4177                 prev = tmp;
4178                 tmp = tmp->next;
4179         }
4180         return NULL;
4181 }
4182
4183 #if SIZEOF_VOID_P == 4
4184 #define ONE_P 1
4185 #else
4186 #define ONE_P 1ll
4187 #endif
4188
4189 static void
4190 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4191 {
4192         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4193         if (!sets [idx])
4194                 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4195         MonoBitSet *rb = sets [idx];
4196         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4197         offset /= sizeof (uintptr_t);
4198         /* offset is now the bitmap offset */
4199         for (int i = 0; i < numbits; ++i) {
4200                 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4201                         mono_bitset_set_fast (rb, offset + i);
4202         }
4203 }
4204
4205 static void
4206 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4207 {
4208         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4209         MonoBitSet *rb = sets [idx];
4210         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4211         offset /= sizeof (uintptr_t);
4212         /* offset is now the bitmap offset */
4213         for (int i = 0; i < size / sizeof (uintptr_t); i++)
4214                 mono_bitset_clear_fast (rb, offset + i);
4215 }
4216
4217 guint32
4218 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4219 {
4220         g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4221
4222         StaticDataInfo *info;
4223         MonoBitSet **sets;
4224
4225         if (static_type == SPECIAL_STATIC_THREAD) {
4226                 info = &thread_static_info;
4227                 sets = thread_reference_bitmaps;
4228         } else {
4229                 info = &context_static_info;
4230                 sets = context_reference_bitmaps;
4231         }
4232
4233         mono_threads_lock ();
4234
4235         StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4236         guint32 offset;
4237
4238         if (item) {
4239                 offset = item->offset;
4240                 g_free (item);
4241         } else {
4242                 offset = mono_alloc_static_data_slot (info, size, align);
4243         }
4244
4245         update_reference_bitmap (sets, offset, bitmap, numbits);
4246
4247         if (static_type == SPECIAL_STATIC_THREAD) {
4248                 /* This can be called during startup */
4249                 if (threads != NULL)
4250                         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4251         } else {
4252                 if (contexts != NULL)
4253                         g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4254
4255                 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4256         }
4257
4258         mono_threads_unlock ();
4259
4260         return offset;
4261 }
4262
4263 gpointer
4264 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4265 {
4266         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4267
4268         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4269                 return get_thread_static_data (thread, offset);
4270         } else {
4271                 return get_context_static_data (thread->current_appcontext, offset);
4272         }
4273 }
4274
4275 gpointer
4276 mono_get_special_static_data (guint32 offset)
4277 {
4278         return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4279 }
4280
4281 typedef struct {
4282         guint32 offset;
4283         guint32 size;
4284 } OffsetSize;
4285
4286 /*
4287  * LOCKING: requires that threads_mutex is held
4288  */
4289 static void 
4290 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4291 {
4292         MonoInternalThread *thread = (MonoInternalThread *)value;
4293         OffsetSize *data = (OffsetSize *)user;
4294         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4295         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4296         char *ptr;
4297
4298         if (!thread->static_data || !thread->static_data [idx])
4299                 return;
4300         ptr = ((char*) thread->static_data [idx]) + off;
4301         mono_gc_bzero_atomic (ptr, data->size);
4302 }
4303
4304 /*
4305  * LOCKING: requires that threads_mutex is held
4306  */
4307 static void
4308 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4309 {
4310         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4311
4312         if (!ctx)
4313                 return;
4314
4315         OffsetSize *data = (OffsetSize *)user;
4316         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4317         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4318         char *ptr;
4319
4320         if (!ctx->static_data || !ctx->static_data [idx])
4321                 return;
4322
4323         ptr = ((char*) ctx->static_data [idx]) + off;
4324         mono_gc_bzero_atomic (ptr, data->size);
4325 }
4326
4327 static void
4328 do_free_special_slot (guint32 offset, guint32 size)
4329 {
4330         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4331         MonoBitSet **sets;
4332         StaticDataInfo *info;
4333
4334         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4335                 info = &thread_static_info;
4336                 sets = thread_reference_bitmaps;
4337         } else {
4338                 info = &context_static_info;
4339                 sets = context_reference_bitmaps;
4340         }
4341
4342         guint32 data_offset = offset;
4343         ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4344         OffsetSize data = { data_offset, size };
4345
4346         clear_reference_bitmap (sets, data.offset, data.size);
4347
4348         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4349                 if (threads != NULL)
4350                         mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4351         } else {
4352                 if (contexts != NULL)
4353                         g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4354         }
4355
4356         if (!mono_runtime_is_shutting_down ()) {
4357                 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4358
4359                 item->offset = offset;
4360                 item->size = size;
4361
4362                 item->next = info->freelist;
4363                 info->freelist = item;
4364         }
4365 }
4366
4367 static void
4368 do_free_special (gpointer key, gpointer value, gpointer data)
4369 {
4370         MonoClassField *field = (MonoClassField *)key;
4371         guint32 offset = GPOINTER_TO_UINT (value);
4372         gint32 align;
4373         guint32 size;
4374         size = mono_type_size (field->type, &align);
4375         do_free_special_slot (offset, size);
4376 }
4377
4378 void
4379 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4380 {
4381         mono_threads_lock ();
4382
4383         g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4384
4385         mono_threads_unlock ();
4386 }
4387
4388 #ifdef HOST_WIN32
4389 static void CALLBACK dummy_apc (ULONG_PTR param)
4390 {
4391 }
4392 #endif
4393
4394 /*
4395  * mono_thread_execute_interruption
4396  * 
4397  * Performs the operation that the requested thread state requires (abort,
4398  * suspend or stop)
4399  */
4400 static MonoException*
4401 mono_thread_execute_interruption (void)
4402 {
4403         MonoInternalThread *thread = mono_thread_internal_current ();
4404         MonoThread *sys_thread = mono_thread_current ();
4405
4406         LOCK_THREAD (thread);
4407
4408         /* MonoThread::interruption_requested can only be changed with atomics */
4409         if (mono_thread_clear_interruption_requested (thread)) {
4410                 /* this will consume pending APC calls */
4411 #ifdef HOST_WIN32
4412                 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4413 #endif
4414                 InterlockedDecrement (&thread_interruption_requested);
4415
4416                 /* Clear the interrupted flag of the thread so it can wait again */
4417                 mono_thread_info_clear_self_interrupt ();
4418         }
4419
4420         /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4421         if (sys_thread->pending_exception) {
4422                 MonoException *exc;
4423
4424                 exc = sys_thread->pending_exception;
4425                 sys_thread->pending_exception = NULL;
4426
4427                 UNLOCK_THREAD (thread);
4428                 return exc;
4429         } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4430                 UNLOCK_THREAD (thread);
4431                 g_assert (sys_thread->pending_exception == NULL);
4432                 if (thread->abort_exc == NULL) {
4433                         /* 
4434                          * This might be racy, but it has to be called outside the lock
4435                          * since it calls managed code.
4436                          */
4437                         MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4438                 }
4439                 return thread->abort_exc;
4440         }
4441         else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4442                 /* calls UNLOCK_THREAD (thread) */
4443                 self_suspend_internal ();
4444                 return NULL;
4445         }
4446         else if ((thread->state & ThreadState_StopRequested) != 0) {
4447                 /* FIXME: do this through the JIT? */
4448
4449                 UNLOCK_THREAD (thread);
4450                 
4451                 mono_thread_exit ();
4452                 return NULL;
4453         } else if (thread->thread_interrupt_requested) {
4454
4455                 thread->thread_interrupt_requested = FALSE;
4456                 UNLOCK_THREAD (thread);
4457                 
4458                 return(mono_get_exception_thread_interrupted ());
4459         }
4460         
4461         UNLOCK_THREAD (thread);
4462         
4463         return NULL;
4464 }
4465
4466 /*
4467  * mono_thread_request_interruption
4468  *
4469  * A signal handler can call this method to request the interruption of a
4470  * thread. The result of the interruption will depend on the current state of
4471  * the thread. If the result is an exception that needs to be throw, it is 
4472  * provided as return value.
4473  */
4474 MonoException*
4475 mono_thread_request_interruption (gboolean running_managed)
4476 {
4477         MonoInternalThread *thread = mono_thread_internal_current ();
4478
4479         /* The thread may already be stopping */
4480         if (thread == NULL) 
4481                 return NULL;
4482
4483 #ifdef HOST_WIN32
4484         if (thread->interrupt_on_stop && 
4485                 thread->state & ThreadState_StopRequested && 
4486                 thread->state & ThreadState_Background)
4487                 ExitThread (1);
4488 #endif
4489         if (!mono_thread_set_interruption_requested (thread))
4490                 return NULL;
4491         InterlockedIncrement (&thread_interruption_requested);
4492
4493         if (!running_managed || is_running_protected_wrapper ()) {
4494                 /* Can't stop while in unmanaged code. Increase the global interruption
4495                    request count. When exiting the unmanaged method the count will be
4496                    checked and the thread will be interrupted. */
4497
4498                 /* this will awake the thread if it is in WaitForSingleObject 
4499                    or similar */
4500                 /* Our implementation of this function ignores the func argument */
4501 #ifdef HOST_WIN32
4502                 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
4503 #else
4504                 mono_thread_info_self_interrupt ();
4505 #endif
4506                 return NULL;
4507         }
4508         else {
4509                 return mono_thread_execute_interruption ();
4510         }
4511 }
4512
4513 /*This function should be called by a thread after it has exited all of
4514  * its handle blocks at interruption time.*/
4515 MonoException*
4516 mono_thread_resume_interruption (void)
4517 {
4518         MonoInternalThread *thread = mono_thread_internal_current ();
4519         gboolean still_aborting;
4520
4521         /* The thread may already be stopping */
4522         if (thread == NULL)
4523                 return NULL;
4524
4525         LOCK_THREAD (thread);
4526         still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4527         UNLOCK_THREAD (thread);
4528
4529         /*This can happen if the protected block called Thread::ResetAbort*/
4530         if (!still_aborting)
4531                 return FALSE;
4532
4533         if (!mono_thread_set_interruption_requested (thread))
4534                 return NULL;
4535         InterlockedIncrement (&thread_interruption_requested);
4536
4537         mono_thread_info_self_interrupt ();
4538
4539         return mono_thread_execute_interruption ();
4540 }
4541
4542 gboolean mono_thread_interruption_requested ()
4543 {
4544         if (thread_interruption_requested) {
4545                 MonoInternalThread *thread = mono_thread_internal_current ();
4546                 /* The thread may already be stopping */
4547                 if (thread != NULL) 
4548                         return mono_thread_get_interruption_requested (thread);
4549         }
4550         return FALSE;
4551 }
4552
4553 static MonoException*
4554 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4555 {
4556         MonoInternalThread *thread = mono_thread_internal_current ();
4557
4558         /* The thread may already be stopping */
4559         if (!thread)
4560                 return NULL;
4561         if (!mono_thread_get_interruption_requested (thread))
4562                 return NULL;
4563         if (!bypass_abort_protection && is_running_protected_wrapper ())
4564                 return NULL;
4565
4566         return mono_thread_execute_interruption ();
4567 }
4568
4569 /*
4570  * Performs the interruption of the current thread, if one has been requested,
4571  * and the thread is not running a protected wrapper.
4572  * Return the exception which needs to be thrown, if any.
4573  */
4574 MonoException*
4575 mono_thread_interruption_checkpoint (void)
4576 {
4577         return mono_thread_interruption_checkpoint_request (FALSE);
4578 }
4579
4580 /*
4581  * Performs the interruption of the current thread, if one has been requested.
4582  * Return the exception which needs to be thrown, if any.
4583  */
4584 MonoException*
4585 mono_thread_force_interruption_checkpoint_noraise (void)
4586 {
4587         return mono_thread_interruption_checkpoint_request (TRUE);
4588 }
4589
4590 /*
4591  * mono_set_pending_exception:
4592  *
4593  *   Set the pending exception of the current thread to EXC.
4594  * The exception will be thrown when execution returns to managed code.
4595  */
4596 void
4597 mono_set_pending_exception (MonoException *exc)
4598 {
4599         MonoThread *thread = mono_thread_current ();
4600
4601         /* The thread may already be stopping */
4602         if (thread == NULL)
4603                 return;
4604
4605         MONO_OBJECT_SETREF (thread, pending_exception, exc);
4606
4607     mono_thread_request_interruption (FALSE);
4608 }
4609
4610 /**
4611  * mono_thread_interruption_request_flag:
4612  *
4613  * Returns the address of a flag that will be non-zero if an interruption has
4614  * been requested for a thread. The thread to interrupt may not be the current
4615  * thread, so an additional call to mono_thread_interruption_requested() or
4616  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4617  * zero.
4618  */
4619 gint32* mono_thread_interruption_request_flag ()
4620 {
4621         return &thread_interruption_requested;
4622 }
4623
4624 void 
4625 mono_thread_init_apartment_state (void)
4626 {
4627 #ifdef HOST_WIN32
4628         MonoInternalThread* thread = mono_thread_internal_current ();
4629
4630         /* Positive return value indicates success, either
4631          * S_OK if this is first CoInitialize call, or
4632          * S_FALSE if CoInitialize already called, but with same
4633          * threading model. A negative value indicates failure,
4634          * probably due to trying to change the threading model.
4635          */
4636         if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA) 
4637                         ? COINIT_APARTMENTTHREADED 
4638                         : COINIT_MULTITHREADED) < 0) {
4639                 thread->apartment_state = ThreadApartmentState_Unknown;
4640         }
4641 #endif
4642 }
4643
4644 void 
4645 mono_thread_cleanup_apartment_state (void)
4646 {
4647 #ifdef HOST_WIN32
4648         MonoInternalThread* thread = mono_thread_internal_current ();
4649
4650         if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4651                 CoUninitialize ();
4652         }
4653 #endif
4654 }
4655
4656 void
4657 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4658 {
4659         LOCK_THREAD (thread);
4660         thread->state |= state;
4661         UNLOCK_THREAD (thread);
4662 }
4663
4664 /**
4665  * mono_thread_test_and_set_state:
4666  *
4667  * Test if current state of @thread include @test. If it does not, OR @set into the state.
4668  *
4669  * Returns TRUE is @set was OR'd in.
4670  */
4671 gboolean
4672 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4673 {
4674         LOCK_THREAD (thread);
4675
4676         if ((thread->state & test) != 0) {
4677                 UNLOCK_THREAD (thread);
4678                 return FALSE;
4679         }
4680
4681         thread->state |= set;
4682         UNLOCK_THREAD (thread);
4683
4684         return TRUE;
4685 }
4686
4687 void
4688 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4689 {
4690         LOCK_THREAD (thread);
4691         thread->state &= ~state;
4692         UNLOCK_THREAD (thread);
4693 }
4694
4695 gboolean
4696 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4697 {
4698         gboolean ret = FALSE;
4699
4700         LOCK_THREAD (thread);
4701
4702         if ((thread->state & test) != 0) {
4703                 ret = TRUE;
4704         }
4705         
4706         UNLOCK_THREAD (thread);
4707         
4708         return ret;
4709 }
4710
4711 static void
4712 self_interrupt_thread (void *_unused)
4713 {
4714         MonoException *exc;
4715         MonoThreadInfo *info;
4716
4717         exc = mono_thread_execute_interruption ();
4718         if (!exc) {
4719                 if (mono_threads_is_coop_enabled ()) {
4720                         /* We can return from an async call in coop, as
4721                          * it's simply called when exiting the safepoint */
4722                         return;
4723                 }
4724
4725                 g_error ("%s: we can't resume from an async call", __func__);
4726         }
4727
4728         info = mono_thread_info_current ();
4729
4730         /* We must use _with_context since we didn't trampoline into the runtime */
4731         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. */
4732 }
4733
4734 static gboolean
4735 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4736 {
4737         if (!ji)
4738                 return FALSE;
4739         return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4740 }
4741
4742 static gboolean
4743 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4744 {
4745         MonoJitInfo **dest = (MonoJitInfo **)data;
4746         *dest = frame->ji;
4747         return TRUE;
4748 }
4749
4750 static MonoJitInfo*
4751 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4752 {
4753         MonoJitInfo *ji = NULL;
4754         if (!info)
4755                 return NULL;
4756
4757         /*
4758          * The suspended thread might be holding runtime locks. Make sure we don't try taking
4759          * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4760          * where we hold runtime locks.
4761          */
4762         if (!mono_threads_is_coop_enabled ())
4763                 mono_thread_info_set_is_async_context (TRUE);
4764         mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4765         if (!mono_threads_is_coop_enabled ())
4766                 mono_thread_info_set_is_async_context (FALSE);
4767         return ji;
4768 }
4769
4770 typedef struct {
4771         MonoInternalThread *thread;
4772         gboolean install_async_abort;
4773         MonoThreadInfoInterruptToken *interrupt_token;
4774 } AbortThreadData;
4775
4776 static SuspendThreadResult
4777 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4778 {
4779         AbortThreadData *data = (AbortThreadData *)ud;
4780         MonoInternalThread *thread = data->thread;
4781         MonoJitInfo *ji = NULL;
4782         gboolean protected_wrapper;
4783         gboolean running_managed;
4784
4785         if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4786                 return MonoResumeThread;
4787
4788         /*someone is already interrupting it*/
4789         if (!mono_thread_set_interruption_requested (thread))
4790                 return MonoResumeThread;
4791
4792         InterlockedIncrement (&thread_interruption_requested);
4793
4794         ji = mono_thread_info_get_last_managed (info);
4795         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4796         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4797
4798         if (!protected_wrapper && running_managed) {
4799                 /*We are in managed code*/
4800                 /*Set the thread to call */
4801                 if (data->install_async_abort)
4802                         mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4803                 return MonoResumeThread;
4804         } else {
4805                 /* 
4806                  * This will cause waits to be broken.
4807                  * It will also prevent the thread from entering a wait, so if the thread returns
4808                  * from the wait before it receives the abort signal, it will just spin in the wait
4809                  * functions in the io-layer until the signal handler calls QueueUserAPC which will
4810                  * make it return.
4811                  */
4812                 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4813
4814                 return MonoResumeThread;
4815         }
4816 }
4817
4818 static void
4819 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4820 {
4821         AbortThreadData data;
4822
4823         g_assert (thread != mono_thread_internal_current ());
4824
4825         data.thread = thread;
4826         data.install_async_abort = install_async_abort;
4827         data.interrupt_token = NULL;
4828
4829         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4830         if (data.interrupt_token)
4831                 mono_thread_info_finish_interrupt (data.interrupt_token);
4832         /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4833 }
4834
4835 static void
4836 self_abort_internal (MonoError *error)
4837 {
4838         MonoException *exc;
4839
4840         error_init (error);
4841
4842         /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4843          * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4844
4845         /*
4846         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.
4847         */
4848         exc = mono_thread_request_interruption (TRUE);
4849         if (exc)
4850                 mono_error_set_exception_instance (error, exc);
4851         else
4852                 mono_thread_info_self_interrupt ();
4853 }
4854
4855 typedef struct {
4856         MonoInternalThread *thread;
4857         gboolean interrupt;
4858         MonoThreadInfoInterruptToken *interrupt_token;
4859 } SuspendThreadData;
4860
4861 static SuspendThreadResult
4862 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4863 {
4864         SuspendThreadData *data = (SuspendThreadData *)ud;
4865         MonoInternalThread *thread = data->thread;
4866         MonoJitInfo *ji = NULL;
4867         gboolean protected_wrapper;
4868         gboolean running_managed;
4869
4870         ji = mono_thread_info_get_last_managed (info);
4871         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4872         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4873
4874         if (running_managed && !protected_wrapper) {
4875                 if (mono_threads_is_coop_enabled ()) {
4876                         mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4877                         return MonoResumeThread;
4878                 } else {
4879                         thread->state &= ~ThreadState_SuspendRequested;
4880                         thread->state |= ThreadState_Suspended;
4881                         return KeepSuspended;
4882                 }
4883         } else {
4884                 if (mono_thread_set_interruption_requested (thread))
4885                         InterlockedIncrement (&thread_interruption_requested);
4886                 if (data->interrupt)
4887                         data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4888
4889                 return MonoResumeThread;
4890         }
4891 }
4892
4893 /* LOCKING: called with @thread synch_cs held, and releases it */
4894 static void
4895 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4896 {
4897         SuspendThreadData data;
4898
4899         g_assert (thread != mono_thread_internal_current ());
4900
4901         // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4902
4903         thread->self_suspended = FALSE;
4904
4905         data.thread = thread;
4906         data.interrupt = interrupt;
4907         data.interrupt_token = NULL;
4908
4909         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4910         if (data.interrupt_token)
4911                 mono_thread_info_finish_interrupt (data.interrupt_token);
4912
4913         UNLOCK_THREAD (thread);
4914 }
4915
4916 /* LOCKING: called with @thread synch_cs held, and releases it */
4917 static void
4918 self_suspend_internal (void)
4919 {
4920         MonoInternalThread *thread;
4921         MonoOSEvent *event;
4922         MonoOSEventWaitRet res;
4923
4924         thread = mono_thread_internal_current ();
4925
4926         // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4927
4928         thread->self_suspended = TRUE;
4929
4930         thread->state &= ~ThreadState_SuspendRequested;
4931         thread->state |= ThreadState_Suspended;
4932
4933         UNLOCK_THREAD (thread);
4934
4935         event = thread->suspended;
4936
4937         MONO_ENTER_GC_SAFE;
4938         res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT, TRUE);
4939         g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
4940         MONO_EXIT_GC_SAFE;
4941 }
4942
4943 static void
4944 suspend_for_shutdown_async_call (gpointer unused)
4945 {
4946         for (;;)
4947                 mono_thread_info_yield ();
4948 }
4949
4950 static SuspendThreadResult
4951 suspend_for_shutdown_critical (MonoThreadInfo *info, gpointer unused)
4952 {
4953         mono_thread_info_setup_async_call (info, suspend_for_shutdown_async_call, NULL);
4954         return MonoResumeThread;
4955 }
4956
4957 void
4958 mono_thread_internal_suspend_for_shutdown (MonoInternalThread *thread)
4959 {
4960         g_assert (thread != mono_thread_internal_current ());
4961
4962         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, suspend_for_shutdown_critical, NULL);
4963 }
4964
4965 /*
4966  * mono_thread_is_foreign:
4967  * @thread: the thread to query
4968  *
4969  * This function allows one to determine if a thread was created by the mono runtime and has
4970  * a well defined lifecycle or it's a foreigh one, created by the native environment.
4971  *
4972  * Returns: TRUE if @thread was not created by the runtime.
4973  */
4974 mono_bool
4975 mono_thread_is_foreign (MonoThread *thread)
4976 {
4977         MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
4978         return info->runtime_thread == FALSE;
4979 }
4980
4981 /*
4982  * mono_add_joinable_thread:
4983  *
4984  *   Add TID to the list of joinable threads.
4985  * LOCKING: Acquires the threads lock.
4986  */
4987 void
4988 mono_threads_add_joinable_thread (gpointer tid)
4989 {
4990 #ifndef HOST_WIN32
4991         /*
4992          * We cannot detach from threads because it causes problems like
4993          * 2fd16f60/r114307. So we collect them and join them when
4994          * we have time (in he finalizer thread).
4995          */
4996         joinable_threads_lock ();
4997         if (!joinable_threads)
4998                 joinable_threads = g_hash_table_new (NULL, NULL);
4999         g_hash_table_insert (joinable_threads, tid, tid);
5000         joinable_thread_count ++;
5001         joinable_threads_unlock ();
5002
5003         mono_gc_finalize_notify ();
5004 #endif
5005 }
5006
5007 /*
5008  * mono_threads_join_threads:
5009  *
5010  *   Join all joinable threads. This is called from the finalizer thread.
5011  * LOCKING: Acquires the threads lock.
5012  */
5013 void
5014 mono_threads_join_threads (void)
5015 {
5016 #ifndef HOST_WIN32
5017         GHashTableIter iter;
5018         gpointer key;
5019         gpointer tid;
5020         pthread_t thread;
5021         gboolean found;
5022
5023         /* Fastpath */
5024         if (!joinable_thread_count)
5025                 return;
5026
5027         while (TRUE) {
5028                 joinable_threads_lock ();
5029                 found = FALSE;
5030                 if (g_hash_table_size (joinable_threads)) {
5031                         g_hash_table_iter_init (&iter, joinable_threads);
5032                         g_hash_table_iter_next (&iter, &key, (void**)&tid);
5033                         thread = (pthread_t)tid;
5034                         g_hash_table_remove (joinable_threads, key);
5035                         joinable_thread_count --;
5036                         found = TRUE;
5037                 }
5038                 joinable_threads_unlock ();
5039                 if (found) {
5040                         if (thread != pthread_self ()) {
5041                                 MONO_ENTER_GC_SAFE;
5042                                 /* This shouldn't block */
5043                                 mono_threads_join_lock ();
5044                                 mono_native_thread_join (thread);
5045                                 mono_threads_join_unlock ();
5046                                 MONO_EXIT_GC_SAFE;
5047                         }
5048                 } else {
5049                         break;
5050                 }
5051         }
5052 #endif
5053 }
5054
5055 /*
5056  * mono_thread_join:
5057  *
5058  *   Wait for thread TID to exit.
5059  * LOCKING: Acquires the threads lock.
5060  */
5061 void
5062 mono_thread_join (gpointer tid)
5063 {
5064 #ifndef HOST_WIN32
5065         pthread_t thread;
5066         gboolean found = FALSE;
5067
5068         joinable_threads_lock ();
5069         if (!joinable_threads)
5070                 joinable_threads = g_hash_table_new (NULL, NULL);
5071         if (g_hash_table_lookup (joinable_threads, tid)) {
5072                 g_hash_table_remove (joinable_threads, tid);
5073                 joinable_thread_count --;
5074                 found = TRUE;
5075         }
5076         joinable_threads_unlock ();
5077         if (!found)
5078                 return;
5079         thread = (pthread_t)tid;
5080         MONO_ENTER_GC_SAFE;
5081         mono_native_thread_join (thread);
5082         MONO_EXIT_GC_SAFE;
5083 #endif
5084 }
5085
5086 void
5087 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
5088 {
5089         if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
5090                 mono_thread_interruption_checkpoint ();
5091 }
5092
5093 void
5094 mono_thread_internal_unhandled_exception (MonoObject* exc)
5095 {
5096         MonoClass *klass = exc->vtable->klass;
5097         if (is_threadabort_exception (klass)) {
5098                 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5099         } else if (!is_appdomainunloaded_exception (klass)
5100                 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5101                 mono_unhandled_exception (exc);
5102                 if (mono_environment_exitcode_get () == 1) {
5103                         mono_environment_exitcode_set (255);
5104                         mono_invoke_unhandled_exception_hook (exc);
5105                         g_assert_not_reached ();
5106                 }
5107         }
5108 }
5109
5110 void
5111 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5112 {
5113         MonoError error;
5114         mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5115         mono_error_set_pending_exception (&error);
5116 }
5117
5118 /*
5119  * mono_threads_attach_coop: called by native->managed wrappers
5120  *
5121  * In non-coop mode:
5122  *  - @dummy: is NULL
5123  *  - @return: the original domain which needs to be restored, or NULL.
5124  *
5125  * In coop mode:
5126  *  - @dummy: contains the original domain
5127  *  - @return: a cookie containing current MonoThreadInfo*.
5128  */
5129 gpointer
5130 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5131 {
5132         MonoDomain *orig;
5133         gboolean fresh_thread = FALSE;
5134
5135         if (!domain) {
5136                 /* Happens when called from AOTed code which is only used in the root domain. */
5137                 domain = mono_get_root_domain ();
5138         }
5139
5140         g_assert (domain);
5141
5142         /* On coop, when we detached, we moved the thread from  RUNNING->BLOCKING.
5143          * If we try to reattach we do a BLOCKING->RUNNING transition.  If the thread
5144          * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5145          * we're only responsible for making the cookie. */
5146         if (mono_threads_is_coop_enabled ()) {
5147                 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5148                 fresh_thread = !info || !mono_thread_info_is_live (info);
5149         }
5150
5151         if (!mono_thread_internal_current ()) {
5152                 mono_thread_attach_full (domain, FALSE);
5153
5154                 // #678164
5155                 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5156         }
5157
5158         orig = mono_domain_get ();
5159         if (orig != domain)
5160                 mono_domain_set (domain, TRUE);
5161
5162         if (!mono_threads_is_coop_enabled ())
5163                 return orig != domain ? orig : NULL;
5164
5165         if (fresh_thread) {
5166                 *dummy = NULL;
5167                 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5168                  * return the right cookie. */
5169                 return mono_threads_enter_gc_unsafe_region_cookie ();
5170         } else {
5171                 *dummy = orig;
5172                 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5173                 return mono_threads_enter_gc_unsafe_region (dummy);
5174         }
5175 }
5176
5177 /*
5178  * mono_threads_detach_coop: called by native->managed wrappers
5179  *
5180  * In non-coop mode:
5181  *  - @cookie: the original domain which needs to be restored, or NULL.
5182  *  - @dummy: is NULL
5183  *
5184  * In coop mode:
5185  *  - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5186  *  - @dummy: contains the original domain
5187  */
5188 void
5189 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5190 {
5191         MonoDomain *domain, *orig;
5192
5193         if (!mono_threads_is_coop_enabled ()) {
5194                 orig = (MonoDomain*) cookie;
5195                 if (orig)
5196                         mono_domain_set (orig, TRUE);
5197         } else {
5198                 orig = (MonoDomain*) *dummy;
5199
5200                 domain = mono_domain_get ();
5201                 g_assert (domain);
5202
5203                 /* it won't do anything if cookie is NULL
5204                  * thread state RUNNING -> (RUNNING|BLOCKING) */
5205                 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5206
5207                 if (orig != domain) {
5208                         if (!orig)
5209                                 mono_domain_unset ();
5210                         else
5211                                 mono_domain_set (orig, TRUE);
5212                 }
5213         }
5214 }
5215
5216 MonoException*
5217 mono_thread_try_resume_interruption (void)
5218 {
5219         MonoInternalThread *thread;
5220
5221         thread = mono_thread_internal_current ();
5222         if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
5223                 return NULL;
5224         if (mono_thread_get_abort_prot_block_count (thread) > 0 || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5225                 return NULL;
5226
5227         return mono_thread_resume_interruption ();
5228 }
5229
5230 #if 0
5231 /* Returns TRUE if the current thread is ready to be interrupted. */
5232 gboolean
5233 mono_threads_is_ready_to_be_interrupted (void)
5234 {
5235         MonoInternalThread *thread;
5236
5237         thread = mono_thread_internal_current ();
5238         LOCK_THREAD (thread);
5239         if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5240                 UNLOCK_THREAD (thread);
5241                 return FALSE;
5242         }
5243
5244         if (mono_thread_get_abort_prot_block_count (thread) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5245                 UNLOCK_THREAD (thread);
5246                 return FALSE;
5247         }
5248
5249         UNLOCK_THREAD (thread);
5250         return TRUE;
5251 }
5252 #endif
5253
5254 void
5255 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5256 {
5257         g_string_append_printf (text, ", thread handle : %p", internal->handle);
5258
5259         if (internal->thread_info) {
5260                 g_string_append (text, ", state : ");
5261                 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5262         }
5263
5264         if (internal->owned_mutexes) {
5265                 int i;
5266
5267                 g_string_append (text, ", owns : [");
5268                 for (i = 0; i < internal->owned_mutexes->len; i++)
5269                         g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5270                 g_string_append (text, "]");
5271         }
5272 }
5273
5274 gboolean
5275 mono_thread_internal_is_current (MonoInternalThread *internal)
5276 {
5277         g_assert (internal);
5278         return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
5279 }