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