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