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