b94a4ff7ff3a96bc0425f137514931e03b118acc
[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                 return FALSE;
699         }
700
701         if (!threads) {
702                 MONO_GC_REGISTER_ROOT_FIXED (threads, MONO_ROOT_SOURCE_THREADING, "threads table");
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         mono_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                 MONO_GC_REGISTER_ROOT_FIXED (threads_starting_up, MONO_ROOT_SOURCE_THREADING, "starting threads table");
927                 threads_starting_up = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_KEY_VALUE_GC, MONO_ROOT_SOURCE_THREADING, "starting threads table");
928         }
929         mono_g_hash_table_insert (threads_starting_up, thread, thread);
930         mono_threads_unlock ();
931
932         internal->threadpool_thread = threadpool_thread;
933         if (threadpool_thread)
934                 mono_thread_set_state (internal, ThreadState_Background);
935
936         start_info = g_new0 (StartInfo, 1);
937         start_info->ref = 2;
938         start_info->thread = thread;
939         start_info->start_delegate = start_delegate;
940         start_info->start_delegate_arg = thread->start_obj;
941         start_info->start_func = start_func;
942         start_info->start_func_arg = start_func_arg;
943         start_info->failed = FALSE;
944         mono_coop_sem_init (&start_info->registered, 0);
945
946         if (stack_size == 0)
947                 stack_set_size = default_stacksize_for_thread (internal);
948         else
949                 stack_set_size = 0;
950
951         thread_handle = mono_threads_create_thread (start_wrapper, start_info, &stack_set_size, &tid);
952
953         if (thread_handle == NULL) {
954                 /* The thread couldn't be created, so set an exception */
955                 mono_threads_lock ();
956                 mono_g_hash_table_remove (threads_starting_up, thread);
957                 mono_threads_unlock ();
958                 mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", mono_w32error_get_last());
959                 /* ref is not going to be decremented in start_wrapper_internal */
960                 InterlockedDecrement (&start_info->ref);
961                 ret = FALSE;
962                 goto done;
963         }
964
965         internal->stack_size = (int) stack_set_size;
966
967         THREAD_DEBUG (g_message ("%s: (%"G_GSIZE_FORMAT") Launching thread %p (%"G_GSIZE_FORMAT")", __func__, mono_native_thread_id_get (), internal, (gsize)internal->tid));
968
969         /*
970          * Wait for the thread to set up its TLS data etc, so
971          * theres no potential race condition if someone tries
972          * to look up the data believing the thread has
973          * started
974          */
975
976         mono_coop_sem_wait (&start_info->registered, MONO_SEM_FLAGS_NONE);
977
978         mono_threads_close_thread_handle (thread_handle);
979
980         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));
981
982         ret = !start_info->failed;
983
984 done:
985         if (InterlockedDecrement (&start_info->ref) == 0) {
986                 mono_coop_sem_destroy (&start_info->registered);
987                 g_free (start_info);
988         }
989
990         return ret;
991 }
992
993 void mono_thread_new_init (intptr_t tid, gpointer stack_start, gpointer func)
994 {
995         if (mono_thread_start_cb) {
996                 mono_thread_start_cb (tid, stack_start, func);
997         }
998 }
999
1000 void mono_threads_set_default_stacksize (guint32 stacksize)
1001 {
1002         default_stacksize = stacksize;
1003 }
1004
1005 guint32 mono_threads_get_default_stacksize (void)
1006 {
1007         return default_stacksize;
1008 }
1009
1010 /*
1011  * mono_thread_create_internal:
1012  *
1013  *   ARG should not be a GC reference.
1014  */
1015 MonoInternalThread*
1016 mono_thread_create_internal (MonoDomain *domain, gpointer func, gpointer arg, gboolean threadpool_thread, guint32 stack_size, MonoError *error)
1017 {
1018         MonoThread *thread;
1019         MonoInternalThread *internal;
1020         gboolean res;
1021
1022         mono_error_init (error);
1023
1024         internal = create_internal_thread_object ();
1025
1026         thread = create_thread_object (domain, internal);
1027
1028         LOCK_THREAD (internal);
1029
1030         res = create_thread (thread, internal, NULL, (MonoThreadStart) func, arg, threadpool_thread, stack_size, error);
1031         return_val_if_nok (error, NULL);
1032
1033         UNLOCK_THREAD (internal);
1034
1035         return internal;
1036 }
1037
1038 void
1039 mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
1040 {
1041         MonoError error;
1042         if (!mono_thread_create_checked (domain, func, arg, &error))
1043                 mono_error_cleanup (&error);
1044 }
1045
1046 gboolean
1047 mono_thread_create_checked (MonoDomain *domain, gpointer func, gpointer arg, MonoError *error)
1048 {
1049         return (NULL != mono_thread_create_internal (domain, func, arg, FALSE, 0, error));
1050 }
1051
1052 MonoThread *
1053 mono_thread_attach (MonoDomain *domain)
1054 {
1055         MonoThread *thread = mono_thread_attach_full (domain, FALSE);
1056
1057         return thread;
1058 }
1059
1060 MonoThread *
1061 mono_thread_attach_full (MonoDomain *domain, gboolean force_attach)
1062 {
1063         MonoInternalThread *internal;
1064         MonoThread *thread;
1065         MonoNativeThreadId tid;
1066         gsize stack_ptr;
1067
1068         if (mono_thread_internal_current_is_attached ()) {
1069                 if (domain != mono_domain_get ())
1070                         mono_domain_set (domain, TRUE);
1071                 /* Already attached */
1072                 return mono_thread_current ();
1073         }
1074
1075         if (!mono_gc_register_thread (&domain)) {
1076                 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 ());
1077         }
1078
1079         tid=mono_native_thread_id_get ();
1080
1081         internal = create_internal_thread_object ();
1082
1083         thread = create_thread_object (domain, internal);
1084
1085         if (!mono_thread_attach_internal (thread, force_attach, TRUE, &stack_ptr)) {
1086                 /* Mono is shutting down, so just wait for the end */
1087                 for (;;)
1088                         mono_thread_info_sleep (10000, NULL);
1089         }
1090
1091         THREAD_DEBUG (g_message ("%s: Attached thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, internal->handle));
1092
1093         if (mono_thread_attach_cb) {
1094                 guint8 *staddr;
1095                 size_t stsize;
1096
1097                 mono_thread_info_get_stack_bounds (&staddr, &stsize);
1098
1099                 if (staddr == NULL)
1100                         mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), &stack_ptr);
1101                 else
1102                         mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), staddr + stsize);
1103         }
1104
1105         /* Can happen when we attach the profiler helper thread in order to heapshot. */
1106         if (!mono_thread_info_current ()->tools_thread)
1107                 // FIXME: Need a separate callback
1108                 mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid));
1109
1110         return thread;
1111 }
1112
1113 void
1114 mono_thread_detach_internal (MonoInternalThread *thread)
1115 {
1116         gboolean removed;
1117
1118         g_assert (thread != NULL);
1119
1120         THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1121
1122 #ifndef HOST_WIN32
1123         mono_w32mutex_abandon ();
1124 #endif
1125
1126         if (thread->abort_state_handle) {
1127                 mono_gchandle_free (thread->abort_state_handle);
1128                 thread->abort_state_handle = 0;
1129         }
1130
1131         thread->abort_exc = NULL;
1132         thread->current_appcontext = NULL;
1133
1134         /*
1135          * This is necessary because otherwise we might have
1136          * cross-domain references which will not get cleaned up when
1137          * the target domain is unloaded.
1138          */
1139         if (thread->cached_culture_info) {
1140                 int i;
1141                 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i)
1142                         mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
1143         }
1144
1145         /*
1146          * thread->synch_cs can be NULL if this was called after
1147          * ves_icall_System_Threading_InternalThread_Thread_free_internal.
1148          * This can happen only during shutdown.
1149          * The shutting_down flag is not always set, so we can't assert on it.
1150          */
1151         if (thread->synch_cs)
1152                 LOCK_THREAD (thread);
1153
1154         thread->state |= ThreadState_Stopped;
1155         thread->state &= ~ThreadState_Background;
1156
1157         if (thread->synch_cs)
1158                 UNLOCK_THREAD (thread);
1159
1160         /*
1161         An interruption request has leaked to cleanup. Adjust the global counter.
1162
1163         This can happen is the abort source thread finds the abortee (this) thread
1164         in unmanaged code. If this thread never trips back to managed code or check
1165         the local flag it will be left set and positively unbalance the global counter.
1166         
1167         Leaving the counter unbalanced will cause a performance degradation since all threads
1168         will now keep checking their local flags all the time.
1169         */
1170         if (mono_thread_clear_interruption_requested (thread))
1171                 InterlockedDecrement (&thread_interruption_requested);
1172
1173         mono_threads_lock ();
1174
1175         if (!threads) {
1176                 removed = FALSE;
1177         } else if (mono_g_hash_table_lookup (threads, (gpointer)thread->tid) != thread) {
1178                 /* We have to check whether the thread object for the
1179                  * tid is still the same in the table because the
1180                  * thread might have been destroyed and the tid reused
1181                  * in the meantime, in which case the tid would be in
1182                  * the table, but with another thread object.
1183                  */
1184                 removed = FALSE;
1185         } else {
1186                 mono_g_hash_table_remove (threads, (gpointer)thread->tid);
1187                 removed = TRUE;
1188         }
1189
1190         mono_threads_unlock ();
1191
1192         /* Don't close the handle here, wait for the object finalizer
1193          * to do it. Otherwise, the following race condition applies:
1194          *
1195          * 1) Thread exits (and mono_thread_detach_internal() closes the handle)
1196          *
1197          * 2) Some other handle is reassigned the same slot
1198          *
1199          * 3) Another thread tries to join the first thread, and
1200          * blocks waiting for the reassigned handle to be signalled
1201          * (which might never happen).  This is possible, because the
1202          * thread calling Join() still has a reference to the first
1203          * thread's object.
1204          */
1205
1206         /* if the thread is not in the hash it has been removed already */
1207         if (!removed) {
1208                 mono_domain_unset ();
1209                 mono_memory_barrier ();
1210
1211                 if (mono_thread_cleanup_fn)
1212                         mono_thread_cleanup_fn (thread_get_tid (thread));
1213
1214                 goto done;
1215         }
1216
1217         mono_release_type_locks (thread);
1218
1219         /* Can happen when we attach the profiler helper thread in order to heapshot. */
1220         if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread)
1221                 mono_profiler_thread_end (thread->tid);
1222
1223         mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
1224
1225         /*
1226          * This will signal async signal handlers that the thread has exited.
1227          * The profiler callback needs this to be set, so it cannot be done earlier.
1228          */
1229         mono_domain_unset ();
1230         mono_memory_barrier ();
1231
1232         if (thread == mono_thread_internal_current ())
1233                 mono_thread_pop_appdomain_ref ();
1234
1235         thread->cached_culture_info = NULL;
1236
1237         mono_free_static_data (thread->static_data);
1238         thread->static_data = NULL;
1239         ref_stack_destroy (thread->appdomain_refs);
1240         thread->appdomain_refs = NULL;
1241
1242         g_assert (thread->suspended);
1243         mono_os_event_destroy (thread->suspended);
1244         g_free (thread->suspended);
1245         thread->suspended = NULL;
1246
1247         if (mono_thread_cleanup_fn)
1248                 mono_thread_cleanup_fn (thread_get_tid (thread));
1249
1250         mono_memory_barrier ();
1251
1252         if (mono_gc_is_moving ()) {
1253                 MONO_GC_UNREGISTER_ROOT (thread->thread_pinning_ref);
1254                 thread->thread_pinning_ref = NULL;
1255         }
1256
1257 done:
1258         SET_CURRENT_OBJECT (NULL);
1259         mono_domain_unset ();
1260
1261         /* Don't need to close the handle to this thread, even though we took a
1262          * reference in mono_thread_attach (), because the GC will do it
1263          * when the Thread object is finalised.
1264          */
1265 }
1266
1267 void
1268 mono_thread_detach (MonoThread *thread)
1269 {
1270         if (thread)
1271                 mono_thread_detach_internal (thread->internal_thread);
1272 }
1273
1274 /*
1275  * mono_thread_detach_if_exiting:
1276  *
1277  *   Detach the current thread from the runtime if it is exiting, i.e. it is running pthread dtors.
1278  * This should be used at the end of embedding code which calls into managed code, and which
1279  * can be called from pthread dtors, like dealloc: implementations in objective-c.
1280  */
1281 mono_bool
1282 mono_thread_detach_if_exiting (void)
1283 {
1284         if (mono_thread_info_is_exiting ()) {
1285                 MonoInternalThread *thread;
1286
1287                 thread = mono_thread_internal_current ();
1288                 if (thread) {
1289                         mono_thread_detach_internal (thread);
1290                         mono_thread_info_detach ();
1291                         return TRUE;
1292                 }
1293         }
1294         return FALSE;
1295 }
1296
1297 gboolean
1298 mono_thread_internal_current_is_attached (void)
1299 {
1300         MonoInternalThread *internal;
1301
1302         internal = GET_CURRENT_OBJECT ();
1303         if (!internal)
1304                 return FALSE;
1305
1306         return TRUE;
1307 }
1308
1309 void
1310 mono_thread_exit (void)
1311 {
1312         MonoInternalThread *thread = mono_thread_internal_current ();
1313
1314         THREAD_DEBUG (g_message ("%s: mono_thread_exit for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid));
1315
1316         mono_thread_detach_internal (thread);
1317
1318         /* we could add a callback here for embedders to use. */
1319         if (mono_thread_get_main () && (thread == mono_thread_get_main ()->internal_thread))
1320                 exit (mono_environment_exitcode_get ());
1321
1322         mono_thread_info_exit (0);
1323 }
1324
1325 void
1326 ves_icall_System_Threading_Thread_ConstructInternalThread (MonoThread *this_obj)
1327 {
1328         MonoInternalThread *internal;
1329
1330         internal = create_internal_thread_object ();
1331
1332         internal->state = ThreadState_Unstarted;
1333
1334         InterlockedCompareExchangePointer ((volatile gpointer *)&this_obj->internal_thread, internal, NULL);
1335 }
1336
1337 MonoThread *
1338 ves_icall_System_Threading_Thread_GetCurrentThread (void)
1339 {
1340         return mono_thread_current ();
1341 }
1342
1343 HANDLE
1344 ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
1345                                                                                                    MonoObject *start)
1346 {
1347         MonoError error;
1348         MonoInternalThread *internal;
1349         gboolean res;
1350
1351         THREAD_DEBUG (g_message("%s: Trying to start a new thread: this (%p) start (%p)", __func__, this_obj, start));
1352
1353         if (!this_obj->internal_thread)
1354                 ves_icall_System_Threading_Thread_ConstructInternalThread (this_obj);
1355         internal = this_obj->internal_thread;
1356
1357         LOCK_THREAD (internal);
1358
1359         if ((internal->state & ThreadState_Unstarted) == 0) {
1360                 UNLOCK_THREAD (internal);
1361                 mono_set_pending_exception (mono_get_exception_thread_state ("Thread has already been started."));
1362                 return NULL;
1363         }
1364
1365         if ((internal->state & ThreadState_Aborted) != 0) {
1366                 UNLOCK_THREAD (internal);
1367                 return this_obj;
1368         }
1369
1370         res = create_thread (this_obj, internal, start, NULL, NULL, FALSE, 0, &error);
1371         if (!res) {
1372                 mono_error_cleanup (&error);
1373                 UNLOCK_THREAD (internal);
1374                 return NULL;
1375         }
1376
1377         internal->state &= ~ThreadState_Unstarted;
1378
1379         THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread));
1380
1381         UNLOCK_THREAD (internal);
1382         return internal->handle;
1383 }
1384
1385 /*
1386  * This is called from the finalizer of the internal thread object.
1387  */
1388 void
1389 ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThread *this_obj)
1390 {
1391         THREAD_DEBUG (g_message ("%s: Closing thread %p, handle %p", __func__, this, this_obj->handle));
1392
1393         /*
1394          * Since threads keep a reference to their thread object while running, by
1395          * the time this function is called, the thread has already exited/detached,
1396          * i.e. mono_thread_detach_internal () has ran. The exception is during
1397          * shutdown, when mono_thread_detach_internal () can be called after this.
1398          */
1399         if (this_obj->handle) {
1400                 mono_threads_close_thread_handle (this_obj->handle);
1401                 this_obj->handle = NULL;
1402         }
1403
1404 #if HOST_WIN32
1405         CloseHandle (this_obj->native_handle);
1406 #endif
1407
1408         if (this_obj->synch_cs) {
1409                 MonoCoopMutex *synch_cs = this_obj->synch_cs;
1410                 this_obj->synch_cs = NULL;
1411                 mono_coop_mutex_destroy (synch_cs);
1412                 g_free (synch_cs);
1413         }
1414
1415         if (this_obj->name) {
1416                 void *name = this_obj->name;
1417                 this_obj->name = NULL;
1418                 g_free (name);
1419         }
1420 }
1421
1422 void
1423 ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
1424 {
1425         guint32 res;
1426         MonoInternalThread *thread = mono_thread_internal_current ();
1427
1428         THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
1429
1430         if (mono_thread_current_check_pending_interrupt ())
1431                 return;
1432
1433         while (TRUE) {
1434                 gboolean alerted = FALSE;
1435
1436                 mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
1437
1438                 res = mono_thread_info_sleep (ms, &alerted);
1439
1440                 mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
1441
1442                 if (alerted) {
1443                         MonoException* exc = mono_thread_execute_interruption ();
1444                         if (exc) {
1445                                 mono_raise_exception (exc);
1446                         } else {
1447                                 // FIXME: !MONO_INFINITE_WAIT
1448                                 if (ms != MONO_INFINITE_WAIT)
1449                                         break;
1450                         }
1451                 } else {
1452                         break;
1453                 }
1454         }
1455 }
1456
1457 void ves_icall_System_Threading_Thread_SpinWait_nop (void)
1458 {
1459 }
1460
1461 gint32
1462 ves_icall_System_Threading_Thread_GetDomainID (void) 
1463 {
1464         return mono_domain_get()->domain_id;
1465 }
1466
1467 gboolean 
1468 ves_icall_System_Threading_Thread_Yield (void)
1469 {
1470         return mono_thread_info_yield ();
1471 }
1472
1473 /*
1474  * mono_thread_get_name:
1475  *
1476  *   Return the name of the thread. NAME_LEN is set to the length of the name.
1477  * Return NULL if the thread has no name. The returned memory is owned by the
1478  * caller.
1479  */
1480 gunichar2*
1481 mono_thread_get_name (MonoInternalThread *this_obj, guint32 *name_len)
1482 {
1483         gunichar2 *res;
1484
1485         LOCK_THREAD (this_obj);
1486         
1487         if (!this_obj->name) {
1488                 *name_len = 0;
1489                 res = NULL;
1490         } else {
1491                 *name_len = this_obj->name_len;
1492                 res = g_new (gunichar2, this_obj->name_len);
1493                 memcpy (res, this_obj->name, sizeof (gunichar2) * this_obj->name_len);
1494         }
1495         
1496         UNLOCK_THREAD (this_obj);
1497
1498         return res;
1499 }
1500
1501 /*
1502  * mono_thread_get_name_utf8:
1503  *
1504  * Return the name of the thread in UTF-8.
1505  * Return NULL if the thread has no name.
1506  * The returned memory is owned by the caller.
1507  */
1508 char *
1509 mono_thread_get_name_utf8 (MonoThread *thread)
1510 {
1511         if (thread == NULL)
1512                 return NULL;
1513
1514         MonoInternalThread *internal = thread->internal_thread;
1515         if (internal == NULL)
1516                 return NULL;
1517
1518         LOCK_THREAD (internal);
1519
1520         char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL);
1521
1522         UNLOCK_THREAD (internal);
1523
1524         return tname;
1525 }
1526
1527 /*
1528  * mono_thread_get_managed_id:
1529  *
1530  * Return the Thread.ManagedThreadId value of `thread`.
1531  * Returns -1 if `thread` is NULL.
1532  */
1533 int32_t
1534 mono_thread_get_managed_id (MonoThread *thread)
1535 {
1536         if (thread == NULL)
1537                 return -1;
1538
1539         MonoInternalThread *internal = thread->internal_thread;
1540         if (internal == NULL)
1541                 return -1;
1542
1543         int32_t id = internal->managed_id;
1544
1545         return id;
1546 }
1547
1548 MonoString* 
1549 ves_icall_System_Threading_Thread_GetName_internal (MonoInternalThread *this_obj)
1550 {
1551         MonoError error;
1552         MonoString* str;
1553
1554         mono_error_init (&error);
1555
1556         LOCK_THREAD (this_obj);
1557         
1558         if (!this_obj->name)
1559                 str = NULL;
1560         else
1561                 str = mono_string_new_utf16_checked (mono_domain_get (), this_obj->name, this_obj->name_len, &error);
1562         
1563         UNLOCK_THREAD (this_obj);
1564
1565         if (mono_error_set_pending_exception (&error))
1566                 return NULL;
1567         
1568         return str;
1569 }
1570
1571 void 
1572 mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean permanent, MonoError *error)
1573 {
1574         LOCK_THREAD (this_obj);
1575
1576         mono_error_init (error);
1577
1578         if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET)) {
1579                 UNLOCK_THREAD (this_obj);
1580                 
1581                 mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
1582                 return;
1583         }
1584         if (this_obj->name) {
1585                 g_free (this_obj->name);
1586                 this_obj->name_len = 0;
1587         }
1588         if (name) {
1589                 this_obj->name = g_new (gunichar2, mono_string_length (name));
1590                 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
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, &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         mono_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         mono_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         mono_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         /* The finalizer thread is not a background thread */
3213         if (!mono_native_thread_id_equals (thread_get_tid (thread), self)
3214              && (thread->state & ThreadState_Background) != 0
3215              && (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE) == 0
3216         ) {
3217                 wait->handles[wait->num] = mono_threads_open_thread_handle (thread->handle);
3218                 wait->threads[wait->num] = thread;
3219                 wait->num++;
3220
3221                 THREAD_DEBUG (g_print ("%s: Aborting id: %"G_GSIZE_FORMAT"\n", __func__, (gsize)thread->tid));
3222                 mono_thread_internal_abort (thread);
3223                 return TRUE;
3224         }
3225
3226         return !mono_native_thread_id_equals (thread_get_tid (thread), self)
3227                 && !mono_gc_is_finalizer_internal_thread (thread);
3228 }
3229
3230 /** 
3231  * mono_threads_set_shutting_down:
3232  *
3233  * Is called by a thread that wants to shut down Mono. If the runtime is already
3234  * shutting down, the calling thread is suspended/stopped, and this function never
3235  * returns.
3236  */
3237 void
3238 mono_threads_set_shutting_down (void)
3239 {
3240         MonoInternalThread *current_thread = mono_thread_internal_current ();
3241
3242         mono_threads_lock ();
3243
3244         if (shutting_down) {
3245                 mono_threads_unlock ();
3246
3247                 /* Make sure we're properly suspended/stopped */
3248
3249                 LOCK_THREAD (current_thread);
3250
3251                 if ((current_thread->state & ThreadState_SuspendRequested) ||
3252                     (current_thread->state & ThreadState_AbortRequested) ||
3253                     (current_thread->state & ThreadState_StopRequested)) {
3254                         UNLOCK_THREAD (current_thread);
3255                         mono_thread_execute_interruption ();
3256                 } else {
3257                         current_thread->state |= ThreadState_Stopped;
3258                         UNLOCK_THREAD (current_thread);
3259                 }
3260
3261                 /*since we're killing the thread, detach it.*/
3262                 mono_thread_detach_internal (current_thread);
3263
3264                 /* Wake up other threads potentially waiting for us */
3265                 mono_thread_info_exit (0);
3266         } else {
3267                 shutting_down = TRUE;
3268
3269                 /* Not really a background state change, but this will
3270                  * interrupt the main thread if it is waiting for all
3271                  * the other threads.
3272                  */
3273                 mono_os_event_set (&background_change_event);
3274                 
3275                 mono_threads_unlock ();
3276         }
3277 }
3278
3279 void mono_thread_manage (void)
3280 {
3281         struct wait_data wait_data;
3282         struct wait_data *wait = &wait_data;
3283
3284         memset (wait, 0, sizeof (struct wait_data));
3285         /* join each thread that's still running */
3286         THREAD_DEBUG (g_message ("%s: Joining each running thread...", __func__));
3287         
3288         mono_threads_lock ();
3289         if(threads==NULL) {
3290                 THREAD_DEBUG (g_message("%s: No threads", __func__));
3291                 mono_threads_unlock ();
3292                 return;
3293         }
3294         mono_threads_unlock ();
3295         
3296         do {
3297                 mono_threads_lock ();
3298                 if (shutting_down) {
3299                         /* somebody else is shutting down */
3300                         mono_threads_unlock ();
3301                         break;
3302                 }
3303                 THREAD_DEBUG (g_message ("%s: There are %d threads to join", __func__, mono_g_hash_table_size (threads));
3304                         mono_g_hash_table_foreach (threads, print_tids, NULL));
3305         
3306                 mono_os_event_reset (&background_change_event);
3307                 wait->num=0;
3308                 /* We must zero all InternalThread pointers to avoid making the GC unhappy. */
3309                 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3310                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
3311                 mono_threads_unlock ();
3312                 if (wait->num > 0)
3313                         /* Something to wait for */
3314                         wait_for_tids (wait, MONO_INFINITE_WAIT, TRUE);
3315                 THREAD_DEBUG (g_message ("%s: I have %d threads after waiting.", __func__, wait->num));
3316         } while(wait->num>0);
3317
3318         /* Mono is shutting down, so just wait for the end */
3319         if (!mono_runtime_try_shutdown ()) {
3320                 /*FIXME mono_thread_suspend probably should call mono_thread_execute_interruption when self interrupting. */
3321                 mono_thread_suspend (mono_thread_internal_current ());
3322                 mono_thread_execute_interruption ();
3323         }
3324
3325         /* 
3326          * Remove everything but the finalizer thread and self.
3327          * Also abort all the background threads
3328          * */
3329         do {
3330                 mono_threads_lock ();
3331
3332                 wait->num = 0;
3333                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3334                 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3335                 mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
3336
3337                 mono_threads_unlock ();
3338
3339                 THREAD_DEBUG (g_message ("%s: wait->num is now %d", __func__, wait->num));
3340                 if (wait->num > 0) {
3341                         /* Something to wait for */
3342                         wait_for_tids (wait, MONO_INFINITE_WAIT, FALSE);
3343                 }
3344         } while (wait->num > 0);
3345         
3346         /* 
3347          * give the subthreads a chance to really quit (this is mainly needed
3348          * to get correct user and system times from getrusage/wait/time(1)).
3349          * This could be removed if we avoid pthread_detach() and use pthread_join().
3350          */
3351         mono_thread_info_yield ();
3352 }
3353
3354 static void
3355 collect_threads_for_suspend (gpointer key, gpointer value, gpointer user_data)
3356 {
3357         MonoInternalThread *thread = (MonoInternalThread*)value;
3358         struct wait_data *wait = (struct wait_data*)user_data;
3359
3360         /* 
3361          * We try to exclude threads early, to avoid running into the MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS
3362          * limitation.
3363          * This needs no locking.
3364          */
3365         if ((thread->state & ThreadState_Suspended) != 0 || 
3366                 (thread->state & ThreadState_Stopped) != 0)
3367                 return;
3368
3369         if (wait->num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3370                 wait->handles [wait->num] = mono_threads_open_thread_handle (thread->handle);
3371                 wait->threads [wait->num] = thread;
3372                 wait->num++;
3373         }
3374 }
3375
3376 /*
3377  * mono_thread_suspend_all_other_threads:
3378  *
3379  *  Suspend all managed threads except the finalizer thread and this thread. It is
3380  * not possible to resume them later.
3381  */
3382 void mono_thread_suspend_all_other_threads (void)
3383 {
3384         struct wait_data wait_data;
3385         struct wait_data *wait = &wait_data;
3386         int i;
3387         MonoNativeThreadId self = mono_native_thread_id_get ();
3388         guint32 eventidx = 0;
3389         gboolean starting, finished;
3390
3391         memset (wait, 0, sizeof (struct wait_data));
3392         /*
3393          * The other threads could be in an arbitrary state at this point, i.e.
3394          * they could be starting up, shutting down etc. This means that there could be
3395          * threads which are not even in the threads hash table yet.
3396          */
3397
3398         /* 
3399          * First we set a barrier which will be checked by all threads before they
3400          * are added to the threads hash table, and they will exit if the flag is set.
3401          * This ensures that no threads could be added to the hash later.
3402          * We will use shutting_down as the barrier for now.
3403          */
3404         g_assert (shutting_down);
3405
3406         /*
3407          * We make multiple calls to WaitForMultipleObjects since:
3408          * - we can only wait for MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS threads
3409          * - some threads could exit without becoming suspended
3410          */
3411         finished = FALSE;
3412         while (!finished) {
3413                 /*
3414                  * Make a copy of the hashtable since we can't do anything with
3415                  * threads while threads_mutex is held.
3416                  */
3417                 wait->num = 0;
3418                 /*We must zero all InternalThread pointers to avoid making the GC unhappy.*/
3419                 memset (wait->threads, 0, MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS * SIZEOF_VOID_P);
3420                 mono_threads_lock ();
3421                 mono_g_hash_table_foreach (threads, collect_threads_for_suspend, wait);
3422                 mono_threads_unlock ();
3423
3424                 eventidx = 0;
3425                 /* Get the suspended events that we'll be waiting for */
3426                 for (i = 0; i < wait->num; ++i) {
3427                         MonoInternalThread *thread = wait->threads [i];
3428
3429                         if (mono_native_thread_id_equals (thread_get_tid (thread), self)
3430                              || mono_gc_is_finalizer_internal_thread (thread)
3431                              || (thread->flags & MONO_THREAD_FLAG_DONT_MANAGE)
3432                         ) {
3433                                 mono_threads_close_thread_handle (wait->handles [i]);
3434                                 wait->threads [i] = NULL;
3435                                 continue;
3436                         }
3437
3438                         LOCK_THREAD (thread);
3439
3440                         if ((thread->state & ThreadState_Suspended) != 0 || 
3441                                 (thread->state & ThreadState_StopRequested) != 0 ||
3442                                 (thread->state & ThreadState_Stopped) != 0) {
3443                                 UNLOCK_THREAD (thread);
3444                                 mono_threads_close_thread_handle (wait->handles [i]);
3445                                 wait->threads [i] = NULL;
3446                                 continue;
3447                         }
3448
3449                         ++eventidx;
3450
3451                         /* Convert abort requests into suspend requests */
3452                         if ((thread->state & ThreadState_AbortRequested) != 0)
3453                                 thread->state &= ~ThreadState_AbortRequested;
3454                         
3455                         thread->state |= ThreadState_SuspendRequested;
3456                         mono_os_event_reset (thread->suspended);
3457
3458                         /* Signal the thread to suspend + calls UNLOCK_THREAD (thread) */
3459                         async_suspend_internal (thread, TRUE);
3460
3461                         mono_threads_close_thread_handle (wait->handles [i]);
3462                         wait->threads [i] = NULL;
3463                 }
3464                 if (eventidx <= 0) {
3465                         /* 
3466                          * If there are threads which are starting up, we wait until they
3467                          * are suspended when they try to register in the threads hash.
3468                          * This is guaranteed to finish, since the threads which can create new
3469                          * threads get suspended after a while.
3470                          * FIXME: The finalizer thread can still create new threads.
3471                          */
3472                         mono_threads_lock ();
3473                         if (threads_starting_up)
3474                                 starting = mono_g_hash_table_size (threads_starting_up) > 0;
3475                         else
3476                                 starting = FALSE;
3477                         mono_threads_unlock ();
3478                         if (starting)
3479                                 mono_thread_info_sleep (100, NULL);
3480                         else
3481                                 finished = TRUE;
3482                 }
3483         }
3484 }
3485
3486 typedef struct {
3487         MonoInternalThread *thread;
3488         MonoStackFrameInfo *frames;
3489         int nframes, max_frames;
3490         int nthreads, max_threads;
3491         MonoInternalThread **threads;
3492 } ThreadDumpUserData;
3493
3494 static gboolean thread_dump_requested;
3495
3496 /* This needs to be async safe */
3497 static gboolean
3498 collect_frame (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
3499 {
3500         ThreadDumpUserData *ud = (ThreadDumpUserData *)data;
3501
3502         if (ud->nframes < ud->max_frames) {
3503                 memcpy (&ud->frames [ud->nframes], frame, sizeof (MonoStackFrameInfo));
3504                 ud->nframes ++;
3505         }
3506
3507         return FALSE;
3508 }
3509
3510 /* This needs to be async safe */
3511 static SuspendThreadResult
3512 get_thread_dump (MonoThreadInfo *info, gpointer ud)
3513 {
3514         ThreadDumpUserData *user_data = (ThreadDumpUserData *)ud;
3515         MonoInternalThread *thread = user_data->thread;
3516
3517 #if 0
3518 /* This no longer works with remote unwinding */
3519         g_string_append_printf (text, " tid=0x%p this=0x%p ", (gpointer)(gsize)thread->tid, thread);
3520         mono_thread_internal_describe (thread, text);
3521         g_string_append (text, "\n");
3522 #endif
3523
3524         if (thread == mono_thread_internal_current ())
3525                 mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (collect_frame, NULL, MONO_UNWIND_SIGNAL_SAFE, ud);
3526         else
3527                 mono_get_eh_callbacks ()->mono_walk_stack_with_state (collect_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, ud);
3528
3529         return MonoResumeThread;
3530 }
3531
3532 typedef struct {
3533         int nthreads, max_threads;
3534         MonoInternalThread **threads;
3535 } CollectThreadsUserData;
3536
3537 static void
3538 collect_thread (gpointer key, gpointer value, gpointer user)
3539 {
3540         CollectThreadsUserData *ud = (CollectThreadsUserData *)user;
3541         MonoInternalThread *thread = (MonoInternalThread *)value;
3542
3543         if (ud->nthreads < ud->max_threads)
3544                 ud->threads [ud->nthreads ++] = thread;
3545 }
3546
3547 /*
3548  * Collect running threads into the THREADS array.
3549  * THREADS should be an array allocated on the stack.
3550  */
3551 static int
3552 collect_threads (MonoInternalThread **thread_array, int max_threads)
3553 {
3554         CollectThreadsUserData ud;
3555
3556         memset (&ud, 0, sizeof (ud));
3557         /* This array contains refs, but its on the stack, so its ok */
3558         ud.threads = thread_array;
3559         ud.max_threads = max_threads;
3560
3561         mono_threads_lock ();
3562         mono_g_hash_table_foreach (threads, collect_thread, &ud);
3563         mono_threads_unlock ();
3564
3565         return ud.nthreads;
3566 }
3567
3568 static void
3569 dump_thread (MonoInternalThread *thread, ThreadDumpUserData *ud)
3570 {
3571         GString* text = g_string_new (0);
3572         char *name;
3573         GError *error = NULL;
3574         int i;
3575
3576         ud->thread = thread;
3577         ud->nframes = 0;
3578
3579         /* Collect frames for the thread */
3580         if (thread == mono_thread_internal_current ()) {
3581                 get_thread_dump (mono_thread_info_current (), ud);
3582         } else {
3583                 mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, ud);
3584         }
3585
3586         /*
3587          * Do all the non async-safe work outside of get_thread_dump.
3588          */
3589         if (thread->name) {
3590                 name = g_utf16_to_utf8 (thread->name, thread->name_len, NULL, NULL, &error);
3591                 g_assert (!error);
3592                 g_string_append_printf (text, "\n\"%s\"", name);
3593                 g_free (name);
3594         }
3595         else if (thread->threadpool_thread) {
3596                 g_string_append (text, "\n\"<threadpool thread>\"");
3597         } else {
3598                 g_string_append (text, "\n\"<unnamed thread>\"");
3599         }
3600
3601         for (i = 0; i < ud->nframes; ++i) {
3602                 MonoStackFrameInfo *frame = &ud->frames [i];
3603                 MonoMethod *method = NULL;
3604
3605                 if (frame->type == FRAME_TYPE_MANAGED)
3606                         method = mono_jit_info_get_method (frame->ji);
3607
3608                 if (method) {
3609                         gchar *location = mono_debug_print_stack_frame (method, frame->native_offset, frame->domain);
3610                         g_string_append_printf (text, "  %s\n", location);
3611                         g_free (location);
3612                 } else {
3613                         g_string_append_printf (text, "  at <unknown> <0x%05x>\n", frame->native_offset);
3614                 }
3615         }
3616
3617         fprintf (stdout, "%s", text->str);
3618
3619 #if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG
3620         OutputDebugStringA(text->str);
3621 #endif
3622
3623         g_string_free (text, TRUE);
3624         fflush (stdout);
3625 }
3626
3627 void
3628 mono_threads_perform_thread_dump (void)
3629 {
3630         ThreadDumpUserData ud;
3631         MonoInternalThread *thread_array [128];
3632         int tindex, nthreads;
3633
3634         if (!thread_dump_requested)
3635                 return;
3636
3637         printf ("Full thread dump:\n");
3638
3639         /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3640         nthreads = collect_threads (thread_array, 128);
3641
3642         memset (&ud, 0, sizeof (ud));
3643         ud.frames = g_new0 (MonoStackFrameInfo, 256);
3644         ud.max_frames = 256;
3645
3646         for (tindex = 0; tindex < nthreads; ++tindex)
3647                 dump_thread (thread_array [tindex], &ud);
3648
3649         g_free (ud.frames);
3650
3651         thread_dump_requested = FALSE;
3652 }
3653
3654 /* Obtain the thread dump of all threads */
3655 static gboolean
3656 mono_threads_get_thread_dump (MonoArray **out_threads, MonoArray **out_stack_frames, MonoError *error)
3657 {
3658
3659         ThreadDumpUserData ud;
3660         MonoInternalThread *thread_array [128];
3661         MonoDomain *domain = mono_domain_get ();
3662         MonoDebugSourceLocation *location;
3663         int tindex, nthreads;
3664
3665         mono_error_init (error);
3666         
3667         *out_threads = NULL;
3668         *out_stack_frames = NULL;
3669
3670         /* Make a copy of the threads hash to avoid doing work inside threads_lock () */
3671         nthreads = collect_threads (thread_array, 128);
3672
3673         memset (&ud, 0, sizeof (ud));
3674         ud.frames = g_new0 (MonoStackFrameInfo, 256);
3675         ud.max_frames = 256;
3676
3677         *out_threads = mono_array_new_checked (domain, mono_defaults.thread_class, nthreads, error);
3678         if (!is_ok (error))
3679                 goto leave;
3680         *out_stack_frames = mono_array_new_checked (domain, mono_defaults.array_class, nthreads, error);
3681         if (!is_ok (error))
3682                 goto leave;
3683
3684         for (tindex = 0; tindex < nthreads; ++tindex) {
3685                 MonoInternalThread *thread = thread_array [tindex];
3686                 MonoArray *thread_frames;
3687                 int i;
3688
3689                 ud.thread = thread;
3690                 ud.nframes = 0;
3691
3692                 /* Collect frames for the thread */
3693                 if (thread == mono_thread_internal_current ()) {
3694                         get_thread_dump (mono_thread_info_current (), &ud);
3695                 } else {
3696                         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), FALSE, get_thread_dump, &ud);
3697                 }
3698
3699                 mono_array_setref_fast (*out_threads, tindex, mono_thread_current_for_thread (thread));
3700
3701                 thread_frames = mono_array_new_checked (domain, mono_defaults.stack_frame_class, ud.nframes, error);
3702                 if (!is_ok (error))
3703                         goto leave;
3704                 mono_array_setref_fast (*out_stack_frames, tindex, thread_frames);
3705
3706                 for (i = 0; i < ud.nframes; ++i) {
3707                         MonoStackFrameInfo *frame = &ud.frames [i];
3708                         MonoMethod *method = NULL;
3709                         MonoStackFrame *sf = (MonoStackFrame *)mono_object_new_checked (domain, mono_defaults.stack_frame_class, error);
3710                         if (!is_ok (error))
3711                                 goto leave;
3712
3713                         sf->native_offset = frame->native_offset;
3714
3715                         if (frame->type == FRAME_TYPE_MANAGED)
3716                                 method = mono_jit_info_get_method (frame->ji);
3717
3718                         if (method) {
3719                                 sf->method_address = (gsize) frame->ji->code_start;
3720
3721                                 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
3722                                 if (!is_ok (error))
3723                                         goto leave;
3724                                 MONO_OBJECT_SETREF (sf, method, rm);
3725
3726                                 location = mono_debug_lookup_source_location (method, frame->native_offset, domain);
3727                                 if (location) {
3728                                         sf->il_offset = location->il_offset;
3729
3730                                         if (location && location->source_file) {
3731                                                 MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file));
3732                                                 sf->line = location->row;
3733                                                 sf->column = location->column;
3734                                         }
3735                                         mono_debug_free_source_location (location);
3736                                 } else {
3737                                         sf->il_offset = -1;
3738                                 }
3739                         }
3740                         mono_array_setref (thread_frames, i, sf);
3741                 }
3742         }
3743
3744 leave:
3745         g_free (ud.frames);
3746         return is_ok (error);
3747 }
3748
3749 /**
3750  * mono_threads_request_thread_dump:
3751  *
3752  *   Ask all threads except the current to print their stacktrace to stdout.
3753  */
3754 void
3755 mono_threads_request_thread_dump (void)
3756 {
3757         /*The new thread dump code runs out of the finalizer thread. */
3758         thread_dump_requested = TRUE;
3759         mono_gc_finalize_notify ();
3760 }
3761
3762 struct ref_stack {
3763         gpointer *refs;
3764         gint allocated; /* +1 so that refs [allocated] == NULL */
3765         gint bottom;
3766 };
3767
3768 typedef struct ref_stack RefStack;
3769
3770 static RefStack *
3771 ref_stack_new (gint initial_size)
3772 {
3773         RefStack *rs;
3774
3775         initial_size = MAX (initial_size, 16) + 1;
3776         rs = g_new0 (RefStack, 1);
3777         rs->refs = g_new0 (gpointer, initial_size);
3778         rs->allocated = initial_size;
3779         return rs;
3780 }
3781
3782 static void
3783 ref_stack_destroy (gpointer ptr)
3784 {
3785         RefStack *rs = (RefStack *)ptr;
3786
3787         if (rs != NULL) {
3788                 g_free (rs->refs);
3789                 g_free (rs);
3790         }
3791 }
3792
3793 static void
3794 ref_stack_push (RefStack *rs, gpointer ptr)
3795 {
3796         g_assert (rs != NULL);
3797
3798         if (rs->bottom >= rs->allocated) {
3799                 rs->refs = (void **)g_realloc (rs->refs, rs->allocated * 2 * sizeof (gpointer) + 1);
3800                 rs->allocated <<= 1;
3801                 rs->refs [rs->allocated] = NULL;
3802         }
3803         rs->refs [rs->bottom++] = ptr;
3804 }
3805
3806 static void
3807 ref_stack_pop (RefStack *rs)
3808 {
3809         if (rs == NULL || rs->bottom == 0)
3810                 return;
3811
3812         rs->bottom--;
3813         rs->refs [rs->bottom] = NULL;
3814 }
3815
3816 static gboolean
3817 ref_stack_find (RefStack *rs, gpointer ptr)
3818 {
3819         gpointer *refs;
3820
3821         if (rs == NULL)
3822                 return FALSE;
3823
3824         for (refs = rs->refs; refs && *refs; refs++) {
3825                 if (*refs == ptr)
3826                         return TRUE;
3827         }
3828         return FALSE;
3829 }
3830
3831 /*
3832  * mono_thread_push_appdomain_ref:
3833  *
3834  *   Register that the current thread may have references to objects in domain 
3835  * @domain on its stack. Each call to this function should be paired with a 
3836  * call to pop_appdomain_ref.
3837  */
3838 void 
3839 mono_thread_push_appdomain_ref (MonoDomain *domain)
3840 {
3841         MonoInternalThread *thread = mono_thread_internal_current ();
3842
3843         if (thread) {
3844                 /* printf ("PUSH REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, domain->friendly_name); */
3845                 SPIN_LOCK (thread->lock_thread_id);
3846                 if (thread->appdomain_refs == NULL)
3847                         thread->appdomain_refs = ref_stack_new (16);
3848                 ref_stack_push ((RefStack *)thread->appdomain_refs, domain);
3849                 SPIN_UNLOCK (thread->lock_thread_id);
3850         }
3851 }
3852
3853 void
3854 mono_thread_pop_appdomain_ref (void)
3855 {
3856         MonoInternalThread *thread = mono_thread_internal_current ();
3857
3858         if (thread) {
3859                 /* printf ("POP REF: %"G_GSIZE_FORMAT" -> %s.\n", (gsize)thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
3860                 SPIN_LOCK (thread->lock_thread_id);
3861                 ref_stack_pop ((RefStack *)thread->appdomain_refs);
3862                 SPIN_UNLOCK (thread->lock_thread_id);
3863         }
3864 }
3865
3866 gboolean
3867 mono_thread_internal_has_appdomain_ref (MonoInternalThread *thread, MonoDomain *domain)
3868 {
3869         gboolean res;
3870         SPIN_LOCK (thread->lock_thread_id);
3871         res = ref_stack_find ((RefStack *)thread->appdomain_refs, domain);
3872         SPIN_UNLOCK (thread->lock_thread_id);
3873         return res;
3874 }
3875
3876 gboolean
3877 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
3878 {
3879         return mono_thread_internal_has_appdomain_ref (thread->internal_thread, domain);
3880 }
3881
3882 typedef struct abort_appdomain_data {
3883         struct wait_data wait;
3884         MonoDomain *domain;
3885 } abort_appdomain_data;
3886
3887 static void
3888 collect_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
3889 {
3890         MonoInternalThread *thread = (MonoInternalThread*)value;
3891         abort_appdomain_data *data = (abort_appdomain_data*)user_data;
3892         MonoDomain *domain = data->domain;
3893
3894         if (mono_thread_internal_has_appdomain_ref (thread, domain)) {
3895                 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
3896
3897                 if(data->wait.num<MONO_W32HANDLE_MAXIMUM_WAIT_OBJECTS) {
3898                         data->wait.handles [data->wait.num] = mono_threads_open_thread_handle (thread->handle);
3899                         data->wait.threads [data->wait.num] = thread;
3900                         data->wait.num++;
3901                 } else {
3902                         /* Just ignore the rest, we can't do anything with
3903                          * them yet
3904                          */
3905                 }
3906         }
3907 }
3908
3909 /*
3910  * mono_threads_abort_appdomain_threads:
3911  *
3912  *   Abort threads which has references to the given appdomain.
3913  */
3914 gboolean
3915 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
3916 {
3917 #ifdef __native_client__
3918         return FALSE;
3919 #endif
3920
3921         abort_appdomain_data user_data;
3922         gint64 start_time;
3923         int orig_timeout = timeout;
3924         int i;
3925
3926         THREAD_DEBUG (g_message ("%s: starting abort", __func__));
3927
3928         start_time = mono_msec_ticks ();
3929         do {
3930                 mono_threads_lock ();
3931
3932                 user_data.domain = domain;
3933                 user_data.wait.num = 0;
3934                 /* This shouldn't take any locks */
3935                 mono_g_hash_table_foreach (threads, collect_appdomain_thread, &user_data);
3936                 mono_threads_unlock ();
3937
3938                 if (user_data.wait.num > 0) {
3939                         /* Abort the threads outside the threads lock */
3940                         for (i = 0; i < user_data.wait.num; ++i)
3941                                 mono_thread_internal_abort (user_data.wait.threads [i]);
3942
3943                         /*
3944                          * We should wait for the threads either to abort, or to leave the
3945                          * domain. We can't do the latter, so we wait with a timeout.
3946                          */
3947                         wait_for_tids (&user_data.wait, 100, FALSE);
3948                 }
3949
3950                 /* Update remaining time */
3951                 timeout -= mono_msec_ticks () - start_time;
3952                 start_time = mono_msec_ticks ();
3953
3954                 if (orig_timeout != -1 && timeout < 0)
3955                         return FALSE;
3956         }
3957         while (user_data.wait.num > 0);
3958
3959         THREAD_DEBUG (g_message ("%s: abort done", __func__));
3960
3961         return TRUE;
3962 }
3963
3964 static void
3965 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
3966 {
3967         MonoInternalThread *thread = (MonoInternalThread*)value;
3968         MonoDomain *domain = (MonoDomain*)user_data;
3969         int i;
3970
3971         /* No locking needed here */
3972         /* FIXME: why no locking? writes to the cache are protected with synch_cs above */
3973
3974         if (thread->cached_culture_info) {
3975                 for (i = 0; i < NUM_CACHED_CULTURES * 2; ++i) {
3976                         MonoObject *obj = mono_array_get (thread->cached_culture_info, MonoObject*, i);
3977                         if (obj && obj->vtable->domain == domain)
3978                                 mono_array_set (thread->cached_culture_info, MonoObject*, i, NULL);
3979                 }
3980         }
3981 }
3982         
3983 /*
3984  * mono_threads_clear_cached_culture:
3985  *
3986  *   Clear the cached_current_culture from all threads if it is in the
3987  * given appdomain.
3988  */
3989 void
3990 mono_threads_clear_cached_culture (MonoDomain *domain)
3991 {
3992         mono_threads_lock ();
3993         mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
3994         mono_threads_unlock ();
3995 }
3996
3997 /*
3998  * mono_thread_get_undeniable_exception:
3999  *
4000  *   Return an exception which needs to be raised when leaving a catch clause.
4001  * This is used for undeniable exception propagation.
4002  */
4003 MonoException*
4004 mono_thread_get_undeniable_exception (void)
4005 {
4006         MonoInternalThread *thread = mono_thread_internal_current ();
4007
4008         if (!(thread && thread->abort_exc && !is_running_protected_wrapper ()))
4009                 return NULL;
4010
4011         // We don't want to have our exception effect calls made by
4012         // the catching block
4013
4014         if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
4015                 return NULL;
4016
4017         /*
4018          * FIXME: Clear the abort exception and return an AppDomainUnloaded 
4019          * exception if the thread no longer references a dying appdomain.
4020          */ 
4021         thread->abort_exc->trace_ips = NULL;
4022         thread->abort_exc->stack_trace = NULL;
4023         return thread->abort_exc;
4024 }
4025
4026 #if MONO_SMALL_CONFIG
4027 #define NUM_STATIC_DATA_IDX 4
4028 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
4029         64, 256, 1024, 4096
4030 };
4031 #else
4032 #define NUM_STATIC_DATA_IDX 8
4033 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
4034         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
4035 };
4036 #endif
4037
4038 static MonoBitSet *thread_reference_bitmaps [NUM_STATIC_DATA_IDX];
4039 static MonoBitSet *context_reference_bitmaps [NUM_STATIC_DATA_IDX];
4040
4041 static void
4042 mark_slots (void *addr, MonoBitSet **bitmaps, MonoGCMarkFunc mark_func, void *gc_data)
4043 {
4044         gpointer *static_data = (gpointer *)addr;
4045
4046         for (int i = 0; i < NUM_STATIC_DATA_IDX; ++i) {
4047                 void **ptr = (void **)static_data [i];
4048
4049                 if (!ptr)
4050                         continue;
4051
4052                 MONO_BITSET_FOREACH (bitmaps [i], idx, {
4053                         void **p = ptr + idx;
4054
4055                         if (*p)
4056                                 mark_func ((MonoObject**)p, gc_data);
4057                 });
4058         }
4059 }
4060
4061 static void
4062 mark_tls_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4063 {
4064         mark_slots (addr, thread_reference_bitmaps, mark_func, gc_data);
4065 }
4066
4067 static void
4068 mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data)
4069 {
4070         mark_slots (addr, context_reference_bitmaps, mark_func, gc_data);
4071 }
4072
4073 /*
4074  *  mono_alloc_static_data
4075  *
4076  *   Allocate memory blocks for storing threads or context static data
4077  */
4078 static void 
4079 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal)
4080 {
4081         guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4082         int i;
4083
4084         gpointer* static_data = *static_data_ptr;
4085         if (!static_data) {
4086                 static MonoGCDescriptor tls_desc = MONO_GC_DESCRIPTOR_NULL;
4087                 static MonoGCDescriptor ctx_desc = MONO_GC_DESCRIPTOR_NULL;
4088
4089                 if (mono_gc_user_markers_supported ()) {
4090                         if (tls_desc == MONO_GC_DESCRIPTOR_NULL)
4091                                 tls_desc = mono_gc_make_root_descr_user (mark_tls_slots);
4092
4093                         if (ctx_desc == MONO_GC_DESCRIPTOR_NULL)
4094                                 ctx_desc = mono_gc_make_root_descr_user (mark_ctx_slots);
4095                 }
4096
4097                 static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc,
4098                         threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4099                         threadlocal ? "managed thread-static variables" : "managed context-static variables");
4100                 *static_data_ptr = static_data;
4101                 static_data [0] = static_data;
4102         }
4103
4104         for (i = 1; i <= idx; ++i) {
4105                 if (static_data [i])
4106                         continue;
4107
4108                 if (mono_gc_user_markers_supported ())
4109                         static_data [i] = g_malloc0 (static_data_size [i]);
4110                 else
4111                         static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL,
4112                                 threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC,
4113                                 threadlocal ? "managed thread-static variables" : "managed context-static variables");
4114         }
4115 }
4116
4117 static void 
4118 mono_free_static_data (gpointer* static_data)
4119 {
4120         int i;
4121         for (i = 1; i < NUM_STATIC_DATA_IDX; ++i) {
4122                 gpointer p = static_data [i];
4123                 if (!p)
4124                         continue;
4125                 /*
4126                  * At this point, the static data pointer array is still registered with the
4127                  * GC, so must ensure that mark_tls_slots() will not encounter any invalid
4128                  * data.  Freeing the individual arrays without first nulling their slots
4129                  * would make it possible for mark_tls/ctx_slots() to encounter a pointer to
4130                  * such an already freed array.  See bug #13813.
4131                  */
4132                 static_data [i] = NULL;
4133                 mono_memory_write_barrier ();
4134                 if (mono_gc_user_markers_supported ())
4135                         g_free (p);
4136                 else
4137                         mono_gc_free_fixed (p);
4138         }
4139         mono_gc_free_fixed (static_data);
4140 }
4141
4142 /*
4143  *  mono_init_static_data_info
4144  *
4145  *   Initializes static data counters
4146  */
4147 static void mono_init_static_data_info (StaticDataInfo *static_data)
4148 {
4149         static_data->idx = 0;
4150         static_data->offset = 0;
4151         static_data->freelist = NULL;
4152 }
4153
4154 /*
4155  *  mono_alloc_static_data_slot
4156  *
4157  *   Generates an offset for static data. static_data contains the counters
4158  *  used to generate it.
4159  */
4160 static guint32
4161 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
4162 {
4163         if (!static_data->idx && !static_data->offset) {
4164                 /* 
4165                  * we use the first chunk of the first allocation also as
4166                  * an array for the rest of the data 
4167                  */
4168                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
4169         }
4170         static_data->offset += align - 1;
4171         static_data->offset &= ~(align - 1);
4172         if (static_data->offset + size >= static_data_size [static_data->idx]) {
4173                 static_data->idx ++;
4174                 g_assert (size <= static_data_size [static_data->idx]);
4175                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
4176                 static_data->offset = 0;
4177         }
4178         guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (static_data->idx, static_data->offset, 0);
4179         static_data->offset += size;
4180         return offset;
4181 }
4182
4183 /*
4184  * LOCKING: requires that threads_mutex is held
4185  */
4186 static void
4187 context_adjust_static_data (MonoAppContext *ctx)
4188 {
4189         if (context_static_info.offset || context_static_info.idx > 0) {
4190                 guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0);
4191                 mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4192                 ctx->data->static_data = ctx->static_data;
4193         }
4194 }
4195
4196 /*
4197  * LOCKING: requires that threads_mutex is held
4198  */
4199 static void 
4200 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4201 {
4202         MonoInternalThread *thread = (MonoInternalThread *)value;
4203         guint32 offset = GPOINTER_TO_UINT (user);
4204
4205         mono_alloc_static_data (&(thread->static_data), offset, TRUE);
4206 }
4207
4208 /*
4209  * LOCKING: requires that threads_mutex is held
4210  */
4211 static void
4212 alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4213 {
4214         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4215
4216         if (!ctx)
4217                 return;
4218
4219         guint32 offset = GPOINTER_TO_UINT (user);
4220         mono_alloc_static_data (&ctx->static_data, offset, FALSE);
4221         ctx->data->static_data = ctx->static_data;
4222 }
4223
4224 static StaticDataFreeList*
4225 search_slot_in_freelist (StaticDataInfo *static_data, guint32 size, guint32 align)
4226 {
4227         StaticDataFreeList* prev = NULL;
4228         StaticDataFreeList* tmp = static_data->freelist;
4229         while (tmp) {
4230                 if (tmp->size == size) {
4231                         if (prev)
4232                                 prev->next = tmp->next;
4233                         else
4234                                 static_data->freelist = tmp->next;
4235                         return tmp;
4236                 }
4237                 prev = tmp;
4238                 tmp = tmp->next;
4239         }
4240         return NULL;
4241 }
4242
4243 #if SIZEOF_VOID_P == 4
4244 #define ONE_P 1
4245 #else
4246 #define ONE_P 1ll
4247 #endif
4248
4249 static void
4250 update_reference_bitmap (MonoBitSet **sets, guint32 offset, uintptr_t *bitmap, int numbits)
4251 {
4252         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4253         if (!sets [idx])
4254                 sets [idx] = mono_bitset_new (static_data_size [idx] / sizeof (uintptr_t), 0);
4255         MonoBitSet *rb = sets [idx];
4256         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4257         offset /= sizeof (uintptr_t);
4258         /* offset is now the bitmap offset */
4259         for (int i = 0; i < numbits; ++i) {
4260                 if (bitmap [i / sizeof (uintptr_t)] & (ONE_P << (i & (sizeof (uintptr_t) * 8 -1))))
4261                         mono_bitset_set_fast (rb, offset + i);
4262         }
4263 }
4264
4265 static void
4266 clear_reference_bitmap (MonoBitSet **sets, guint32 offset, guint32 size)
4267 {
4268         int idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index);
4269         MonoBitSet *rb = sets [idx];
4270         offset = ACCESS_SPECIAL_STATIC_OFFSET (offset, offset);
4271         offset /= sizeof (uintptr_t);
4272         /* offset is now the bitmap offset */
4273         for (int i = 0; i < size / sizeof (uintptr_t); i++)
4274                 mono_bitset_clear_fast (rb, offset + i);
4275 }
4276
4277 guint32
4278 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align, uintptr_t *bitmap, int numbits)
4279 {
4280         g_assert (static_type == SPECIAL_STATIC_THREAD || static_type == SPECIAL_STATIC_CONTEXT);
4281
4282         StaticDataInfo *info;
4283         MonoBitSet **sets;
4284
4285         if (static_type == SPECIAL_STATIC_THREAD) {
4286                 info = &thread_static_info;
4287                 sets = thread_reference_bitmaps;
4288         } else {
4289                 info = &context_static_info;
4290                 sets = context_reference_bitmaps;
4291         }
4292
4293         mono_threads_lock ();
4294
4295         StaticDataFreeList *item = search_slot_in_freelist (info, size, align);
4296         guint32 offset;
4297
4298         if (item) {
4299                 offset = item->offset;
4300                 g_free (item);
4301         } else {
4302                 offset = mono_alloc_static_data_slot (info, size, align);
4303         }
4304
4305         update_reference_bitmap (sets, offset, bitmap, numbits);
4306
4307         if (static_type == SPECIAL_STATIC_THREAD) {
4308                 /* This can be called during startup */
4309                 if (threads != NULL)
4310                         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
4311         } else {
4312                 if (contexts != NULL)
4313                         g_hash_table_foreach (contexts, alloc_context_static_data_helper, GUINT_TO_POINTER (offset));
4314
4315                 ACCESS_SPECIAL_STATIC_OFFSET (offset, type) = SPECIAL_STATIC_OFFSET_TYPE_CONTEXT;
4316         }
4317
4318         mono_threads_unlock ();
4319
4320         return offset;
4321 }
4322
4323 gpointer
4324 mono_get_special_static_data_for_thread (MonoInternalThread *thread, guint32 offset)
4325 {
4326         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4327
4328         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4329                 return get_thread_static_data (thread, offset);
4330         } else {
4331                 return get_context_static_data (thread->current_appcontext, offset);
4332         }
4333 }
4334
4335 gpointer
4336 mono_get_special_static_data (guint32 offset)
4337 {
4338         return mono_get_special_static_data_for_thread (mono_thread_internal_current (), offset);
4339 }
4340
4341 typedef struct {
4342         guint32 offset;
4343         guint32 size;
4344 } OffsetSize;
4345
4346 /*
4347  * LOCKING: requires that threads_mutex is held
4348  */
4349 static void 
4350 free_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
4351 {
4352         MonoInternalThread *thread = (MonoInternalThread *)value;
4353         OffsetSize *data = (OffsetSize *)user;
4354         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4355         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4356         char *ptr;
4357
4358         if (!thread->static_data || !thread->static_data [idx])
4359                 return;
4360         ptr = ((char*) thread->static_data [idx]) + off;
4361         mono_gc_bzero_atomic (ptr, data->size);
4362 }
4363
4364 /*
4365  * LOCKING: requires that threads_mutex is held
4366  */
4367 static void
4368 free_context_static_data_helper (gpointer key, gpointer value, gpointer user)
4369 {
4370         MonoAppContext *ctx = (MonoAppContext *) mono_gchandle_get_target (GPOINTER_TO_INT (key));
4371
4372         if (!ctx)
4373                 return;
4374
4375         OffsetSize *data = (OffsetSize *)user;
4376         int idx = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, index);
4377         int off = ACCESS_SPECIAL_STATIC_OFFSET (data->offset, offset);
4378         char *ptr;
4379
4380         if (!ctx->static_data || !ctx->static_data [idx])
4381                 return;
4382
4383         ptr = ((char*) ctx->static_data [idx]) + off;
4384         mono_gc_bzero_atomic (ptr, data->size);
4385 }
4386
4387 static void
4388 do_free_special_slot (guint32 offset, guint32 size)
4389 {
4390         guint32 static_type = ACCESS_SPECIAL_STATIC_OFFSET (offset, type);
4391         MonoBitSet **sets;
4392         StaticDataInfo *info;
4393
4394         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4395                 info = &thread_static_info;
4396                 sets = thread_reference_bitmaps;
4397         } else {
4398                 info = &context_static_info;
4399                 sets = context_reference_bitmaps;
4400         }
4401
4402         guint32 data_offset = offset;
4403         ACCESS_SPECIAL_STATIC_OFFSET (data_offset, type) = 0;
4404         OffsetSize data = { data_offset, size };
4405
4406         clear_reference_bitmap (sets, data.offset, data.size);
4407
4408         if (static_type == SPECIAL_STATIC_OFFSET_TYPE_THREAD) {
4409                 if (threads != NULL)
4410                         mono_g_hash_table_foreach (threads, free_thread_static_data_helper, &data);
4411         } else {
4412                 if (contexts != NULL)
4413                         g_hash_table_foreach (contexts, free_context_static_data_helper, &data);
4414         }
4415
4416         if (!mono_runtime_is_shutting_down ()) {
4417                 StaticDataFreeList *item = g_new0 (StaticDataFreeList, 1);
4418
4419                 item->offset = offset;
4420                 item->size = size;
4421
4422                 item->next = info->freelist;
4423                 info->freelist = item;
4424         }
4425 }
4426
4427 static void
4428 do_free_special (gpointer key, gpointer value, gpointer data)
4429 {
4430         MonoClassField *field = (MonoClassField *)key;
4431         guint32 offset = GPOINTER_TO_UINT (value);
4432         gint32 align;
4433         guint32 size;
4434         size = mono_type_size (field->type, &align);
4435         do_free_special_slot (offset, size);
4436 }
4437
4438 void
4439 mono_alloc_special_static_data_free (GHashTable *special_static_fields)
4440 {
4441         mono_threads_lock ();
4442
4443         g_hash_table_foreach (special_static_fields, do_free_special, NULL);
4444
4445         mono_threads_unlock ();
4446 }
4447
4448 #ifdef HOST_WIN32
4449 static void CALLBACK dummy_apc (ULONG_PTR param)
4450 {
4451 }
4452 #endif
4453
4454 /*
4455  * mono_thread_execute_interruption
4456  * 
4457  * Performs the operation that the requested thread state requires (abort,
4458  * suspend or stop)
4459  */
4460 static MonoException*
4461 mono_thread_execute_interruption (void)
4462 {
4463         MonoInternalThread *thread = mono_thread_internal_current ();
4464         MonoThread *sys_thread = mono_thread_current ();
4465
4466         LOCK_THREAD (thread);
4467
4468         /* MonoThread::interruption_requested can only be changed with atomics */
4469         if (mono_thread_clear_interruption_requested (thread)) {
4470                 /* this will consume pending APC calls */
4471 #ifdef HOST_WIN32
4472                 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
4473 #endif
4474                 InterlockedDecrement (&thread_interruption_requested);
4475
4476                 /* Clear the interrupted flag of the thread so it can wait again */
4477                 mono_thread_info_clear_self_interrupt ();
4478         }
4479
4480         /* If there's a pending exception and an AbortRequested, the pending exception takes precedence */
4481         if (sys_thread->pending_exception) {
4482                 MonoException *exc;
4483
4484                 exc = sys_thread->pending_exception;
4485                 sys_thread->pending_exception = NULL;
4486
4487                 UNLOCK_THREAD (thread);
4488                 return exc;
4489         } else if ((thread->state & ThreadState_AbortRequested) != 0) {
4490                 UNLOCK_THREAD (thread);
4491                 g_assert (sys_thread->pending_exception == NULL);
4492                 if (thread->abort_exc == NULL) {
4493                         /* 
4494                          * This might be racy, but it has to be called outside the lock
4495                          * since it calls managed code.
4496                          */
4497                         MONO_OBJECT_SETREF (thread, abort_exc, mono_get_exception_thread_abort ());
4498                 }
4499                 return thread->abort_exc;
4500         }
4501         else if ((thread->state & ThreadState_SuspendRequested) != 0) {
4502                 /* calls UNLOCK_THREAD (thread) */
4503                 self_suspend_internal ();
4504                 return NULL;
4505         }
4506         else if ((thread->state & ThreadState_StopRequested) != 0) {
4507                 /* FIXME: do this through the JIT? */
4508
4509                 UNLOCK_THREAD (thread);
4510                 
4511                 mono_thread_exit ();
4512                 return NULL;
4513         } else if (thread->thread_interrupt_requested) {
4514
4515                 thread->thread_interrupt_requested = FALSE;
4516                 UNLOCK_THREAD (thread);
4517                 
4518                 return(mono_get_exception_thread_interrupted ());
4519         }
4520         
4521         UNLOCK_THREAD (thread);
4522         
4523         return NULL;
4524 }
4525
4526 /*
4527  * mono_thread_request_interruption
4528  *
4529  * A signal handler can call this method to request the interruption of a
4530  * thread. The result of the interruption will depend on the current state of
4531  * the thread. If the result is an exception that needs to be throw, it is 
4532  * provided as return value.
4533  */
4534 MonoException*
4535 mono_thread_request_interruption (gboolean running_managed)
4536 {
4537         MonoInternalThread *thread = mono_thread_internal_current ();
4538
4539         /* The thread may already be stopping */
4540         if (thread == NULL) 
4541                 return NULL;
4542
4543 #ifdef HOST_WIN32
4544         if (thread->interrupt_on_stop && 
4545                 thread->state & ThreadState_StopRequested && 
4546                 thread->state & ThreadState_Background)
4547                 ExitThread (1);
4548 #endif
4549         if (!mono_thread_set_interruption_requested (thread))
4550                 return NULL;
4551         InterlockedIncrement (&thread_interruption_requested);
4552
4553         if (!running_managed || is_running_protected_wrapper ()) {
4554                 /* Can't stop while in unmanaged code. Increase the global interruption
4555                    request count. When exiting the unmanaged method the count will be
4556                    checked and the thread will be interrupted. */
4557
4558                 /* this will awake the thread if it is in WaitForSingleObject 
4559                    or similar */
4560                 /* Our implementation of this function ignores the func argument */
4561 #ifdef HOST_WIN32
4562                 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->native_handle, (ULONG_PTR)NULL);
4563 #else
4564                 mono_thread_info_self_interrupt ();
4565 #endif
4566                 return NULL;
4567         }
4568         else {
4569                 return mono_thread_execute_interruption ();
4570         }
4571 }
4572
4573 /*This function should be called by a thread after it has exited all of
4574  * its handle blocks at interruption time.*/
4575 MonoException*
4576 mono_thread_resume_interruption (void)
4577 {
4578         MonoInternalThread *thread = mono_thread_internal_current ();
4579         gboolean still_aborting;
4580
4581         /* The thread may already be stopping */
4582         if (thread == NULL)
4583                 return NULL;
4584
4585         LOCK_THREAD (thread);
4586         still_aborting = (thread->state & (ThreadState_AbortRequested|ThreadState_StopRequested)) != 0;
4587         UNLOCK_THREAD (thread);
4588
4589         /*This can happen if the protected block called Thread::ResetAbort*/
4590         if (!still_aborting)
4591                 return FALSE;
4592
4593         if (!mono_thread_set_interruption_requested (thread))
4594                 return NULL;
4595         InterlockedIncrement (&thread_interruption_requested);
4596
4597         mono_thread_info_self_interrupt ();
4598
4599         return mono_thread_execute_interruption ();
4600 }
4601
4602 gboolean mono_thread_interruption_requested ()
4603 {
4604         if (thread_interruption_requested) {
4605                 MonoInternalThread *thread = mono_thread_internal_current ();
4606                 /* The thread may already be stopping */
4607                 if (thread != NULL) 
4608                         return mono_thread_get_interruption_requested (thread);
4609         }
4610         return FALSE;
4611 }
4612
4613 static MonoException*
4614 mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
4615 {
4616         MonoInternalThread *thread = mono_thread_internal_current ();
4617
4618         /* The thread may already be stopping */
4619         if (!thread)
4620                 return NULL;
4621         if (!mono_thread_get_interruption_requested (thread))
4622                 return NULL;
4623         if (!bypass_abort_protection && is_running_protected_wrapper ())
4624                 return NULL;
4625
4626         return mono_thread_execute_interruption ();
4627 }
4628
4629 /*
4630  * Performs the interruption of the current thread, if one has been requested,
4631  * and the thread is not running a protected wrapper.
4632  * Return the exception which needs to be thrown, if any.
4633  */
4634 MonoException*
4635 mono_thread_interruption_checkpoint (void)
4636 {
4637         return mono_thread_interruption_checkpoint_request (FALSE);
4638 }
4639
4640 /*
4641  * Performs the interruption of the current thread, if one has been requested.
4642  * Return the exception which needs to be thrown, if any.
4643  */
4644 MonoException*
4645 mono_thread_force_interruption_checkpoint_noraise (void)
4646 {
4647         return mono_thread_interruption_checkpoint_request (TRUE);
4648 }
4649
4650 /*
4651  * mono_set_pending_exception:
4652  *
4653  *   Set the pending exception of the current thread to EXC.
4654  * The exception will be thrown when execution returns to managed code.
4655  */
4656 void
4657 mono_set_pending_exception (MonoException *exc)
4658 {
4659         MonoThread *thread = mono_thread_current ();
4660
4661         /* The thread may already be stopping */
4662         if (thread == NULL)
4663                 return;
4664
4665         MONO_OBJECT_SETREF (thread, pending_exception, exc);
4666
4667     mono_thread_request_interruption (FALSE);
4668 }
4669
4670 /**
4671  * mono_thread_interruption_request_flag:
4672  *
4673  * Returns the address of a flag that will be non-zero if an interruption has
4674  * been requested for a thread. The thread to interrupt may not be the current
4675  * thread, so an additional call to mono_thread_interruption_requested() or
4676  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
4677  * zero.
4678  */
4679 gint32* mono_thread_interruption_request_flag ()
4680 {
4681         return &thread_interruption_requested;
4682 }
4683
4684 void 
4685 mono_thread_init_apartment_state (void)
4686 {
4687 #ifdef HOST_WIN32
4688         MonoInternalThread* thread = mono_thread_internal_current ();
4689
4690         /* Positive return value indicates success, either
4691          * S_OK if this is first CoInitialize call, or
4692          * S_FALSE if CoInitialize already called, but with same
4693          * threading model. A negative value indicates failure,
4694          * probably due to trying to change the threading model.
4695          */
4696         if (CoInitializeEx(NULL, (thread->apartment_state == ThreadApartmentState_STA) 
4697                         ? COINIT_APARTMENTTHREADED 
4698                         : COINIT_MULTITHREADED) < 0) {
4699                 thread->apartment_state = ThreadApartmentState_Unknown;
4700         }
4701 #endif
4702 }
4703
4704 void 
4705 mono_thread_cleanup_apartment_state (void)
4706 {
4707 #ifdef HOST_WIN32
4708         MonoInternalThread* thread = mono_thread_internal_current ();
4709
4710         if (thread && thread->apartment_state != ThreadApartmentState_Unknown) {
4711                 CoUninitialize ();
4712         }
4713 #endif
4714 }
4715
4716 void
4717 mono_thread_set_state (MonoInternalThread *thread, MonoThreadState state)
4718 {
4719         LOCK_THREAD (thread);
4720         thread->state |= state;
4721         UNLOCK_THREAD (thread);
4722 }
4723
4724 /**
4725  * mono_thread_test_and_set_state:
4726  *
4727  * Test if current state of @thread include @test. If it does not, OR @set into the state.
4728  *
4729  * Returns TRUE is @set was OR'd in.
4730  */
4731 gboolean
4732 mono_thread_test_and_set_state (MonoInternalThread *thread, MonoThreadState test, MonoThreadState set)
4733 {
4734         LOCK_THREAD (thread);
4735
4736         if ((thread->state & test) != 0) {
4737                 UNLOCK_THREAD (thread);
4738                 return FALSE;
4739         }
4740
4741         thread->state |= set;
4742         UNLOCK_THREAD (thread);
4743
4744         return TRUE;
4745 }
4746
4747 void
4748 mono_thread_clr_state (MonoInternalThread *thread, MonoThreadState state)
4749 {
4750         LOCK_THREAD (thread);
4751         thread->state &= ~state;
4752         UNLOCK_THREAD (thread);
4753 }
4754
4755 gboolean
4756 mono_thread_test_state (MonoInternalThread *thread, MonoThreadState test)
4757 {
4758         gboolean ret = FALSE;
4759
4760         LOCK_THREAD (thread);
4761
4762         if ((thread->state & test) != 0) {
4763                 ret = TRUE;
4764         }
4765         
4766         UNLOCK_THREAD (thread);
4767         
4768         return ret;
4769 }
4770
4771 static void
4772 self_interrupt_thread (void *_unused)
4773 {
4774         MonoException *exc;
4775         MonoThreadInfo *info;
4776
4777         exc = mono_thread_execute_interruption ();
4778         if (!exc) {
4779                 if (mono_threads_is_coop_enabled ()) {
4780                         /* We can return from an async call in coop, as
4781                          * it's simply called when exiting the safepoint */
4782                         return;
4783                 }
4784
4785                 g_error ("%s: we can't resume from an async call", __func__);
4786         }
4787
4788         info = mono_thread_info_current ();
4789
4790         /* We must use _with_context since we didn't trampoline into the runtime */
4791         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. */
4792 }
4793
4794 static gboolean
4795 mono_jit_info_match (MonoJitInfo *ji, gpointer ip)
4796 {
4797         if (!ji)
4798                 return FALSE;
4799         return ji->code_start <= ip && (char*)ip < (char*)ji->code_start + ji->code_size;
4800 }
4801
4802 static gboolean
4803 last_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
4804 {
4805         MonoJitInfo **dest = (MonoJitInfo **)data;
4806         *dest = frame->ji;
4807         return TRUE;
4808 }
4809
4810 static MonoJitInfo*
4811 mono_thread_info_get_last_managed (MonoThreadInfo *info)
4812 {
4813         MonoJitInfo *ji = NULL;
4814         if (!info)
4815                 return NULL;
4816
4817         /*
4818          * The suspended thread might be holding runtime locks. Make sure we don't try taking
4819          * any runtime locks while unwinding. In coop case we shouldn't safepoint in regions
4820          * where we hold runtime locks.
4821          */
4822         if (!mono_threads_is_coop_enabled ())
4823                 mono_thread_info_set_is_async_context (TRUE);
4824         mono_get_eh_callbacks ()->mono_walk_stack_with_state (last_managed, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &ji);
4825         if (!mono_threads_is_coop_enabled ())
4826                 mono_thread_info_set_is_async_context (FALSE);
4827         return ji;
4828 }
4829
4830 typedef struct {
4831         MonoInternalThread *thread;
4832         gboolean install_async_abort;
4833         MonoThreadInfoInterruptToken *interrupt_token;
4834 } AbortThreadData;
4835
4836 static SuspendThreadResult
4837 async_abort_critical (MonoThreadInfo *info, gpointer ud)
4838 {
4839         AbortThreadData *data = (AbortThreadData *)ud;
4840         MonoInternalThread *thread = data->thread;
4841         MonoJitInfo *ji = NULL;
4842         gboolean protected_wrapper;
4843         gboolean running_managed;
4844
4845         if (mono_get_eh_callbacks ()->mono_install_handler_block_guard (mono_thread_info_get_suspend_state (info)))
4846                 return MonoResumeThread;
4847
4848         /*
4849         The target thread is running at least one protected block, which must not be interrupted, so we give up.
4850         The protected block code will give them a chance when appropriate.
4851         */
4852         if (mono_thread_get_abort_prot_block_count (thread) > 0)
4853                 return MonoResumeThread;
4854
4855         /*someone is already interrupting it*/
4856         if (!mono_thread_set_interruption_requested (thread))
4857                 return MonoResumeThread;
4858
4859         InterlockedIncrement (&thread_interruption_requested);
4860
4861         ji = mono_thread_info_get_last_managed (info);
4862         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4863         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4864
4865         if (!protected_wrapper && running_managed) {
4866                 /*We are in managed code*/
4867                 /*Set the thread to call */
4868                 if (data->install_async_abort)
4869                         mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4870                 return MonoResumeThread;
4871         } else {
4872                 /* 
4873                  * This will cause waits to be broken.
4874                  * It will also prevent the thread from entering a wait, so if the thread returns
4875                  * from the wait before it receives the abort signal, it will just spin in the wait
4876                  * functions in the io-layer until the signal handler calls QueueUserAPC which will
4877                  * make it return.
4878                  */
4879                 data->interrupt_token = mono_thread_info_prepare_interrupt (info);
4880
4881                 return MonoResumeThread;
4882         }
4883 }
4884
4885 static void
4886 async_abort_internal (MonoInternalThread *thread, gboolean install_async_abort)
4887 {
4888         AbortThreadData data;
4889
4890         g_assert (thread != mono_thread_internal_current ());
4891
4892         data.thread = thread;
4893         data.install_async_abort = install_async_abort;
4894         data.interrupt_token = NULL;
4895
4896         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), TRUE, async_abort_critical, &data);
4897         if (data.interrupt_token)
4898                 mono_thread_info_finish_interrupt (data.interrupt_token);
4899         /*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
4900 }
4901
4902 static void
4903 self_abort_internal (MonoError *error)
4904 {
4905         MonoException *exc;
4906
4907         mono_error_init (error);
4908
4909         /* FIXME this is insanely broken, it doesn't cause interruption to happen synchronously
4910          * since passing FALSE to mono_thread_request_interruption makes sure it returns NULL */
4911
4912         /*
4913         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.
4914         */
4915         exc = mono_thread_request_interruption (TRUE);
4916         if (exc)
4917                 mono_error_set_exception_instance (error, exc);
4918         else
4919                 mono_thread_info_self_interrupt ();
4920 }
4921
4922 typedef struct {
4923         MonoInternalThread *thread;
4924         gboolean interrupt;
4925         MonoThreadInfoInterruptToken *interrupt_token;
4926 } SuspendThreadData;
4927
4928 static SuspendThreadResult
4929 async_suspend_critical (MonoThreadInfo *info, gpointer ud)
4930 {
4931         SuspendThreadData *data = (SuspendThreadData *)ud;
4932         MonoInternalThread *thread = data->thread;
4933         MonoJitInfo *ji = NULL;
4934         gboolean protected_wrapper;
4935         gboolean running_managed;
4936
4937         ji = mono_thread_info_get_last_managed (info);
4938         protected_wrapper = ji && !ji->is_trampoline && !ji->async && mono_threads_is_critical_method (mono_jit_info_get_method (ji));
4939         running_managed = mono_jit_info_match (ji, MONO_CONTEXT_GET_IP (&mono_thread_info_get_suspend_state (info)->ctx));
4940
4941         if (running_managed && !protected_wrapper) {
4942                 if (mono_threads_is_coop_enabled ()) {
4943                         mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
4944                         return MonoResumeThread;
4945                 } else {
4946                         thread->state &= ~ThreadState_SuspendRequested;
4947                         thread->state |= ThreadState_Suspended;
4948                         return KeepSuspended;
4949                 }
4950         } else {
4951                 if (mono_thread_set_interruption_requested (thread))
4952                         InterlockedIncrement (&thread_interruption_requested);
4953                 if (data->interrupt)
4954                         data->interrupt_token = mono_thread_info_prepare_interrupt ((MonoThreadInfo *)thread->thread_info);
4955
4956                 return MonoResumeThread;
4957         }
4958 }
4959
4960 /* LOCKING: called with @thread synch_cs held, and releases it */
4961 static void
4962 async_suspend_internal (MonoInternalThread *thread, gboolean interrupt)
4963 {
4964         SuspendThreadData data;
4965
4966         g_assert (thread != mono_thread_internal_current ());
4967
4968         // MOSTLY_ASYNC_SAFE_PRINTF ("ASYNC SUSPEND thread %p\n", thread_get_tid (thread));
4969
4970         thread->self_suspended = FALSE;
4971
4972         data.thread = thread;
4973         data.interrupt = interrupt;
4974         data.interrupt_token = NULL;
4975
4976         mono_thread_info_safe_suspend_and_run (thread_get_tid (thread), interrupt, async_suspend_critical, &data);
4977         if (data.interrupt_token)
4978                 mono_thread_info_finish_interrupt (data.interrupt_token);
4979
4980         UNLOCK_THREAD (thread);
4981 }
4982
4983 /* LOCKING: called with @thread synch_cs held, and releases it */
4984 static void
4985 self_suspend_internal (void)
4986 {
4987         MonoInternalThread *thread;
4988         MonoOSEvent *event;
4989         MonoOSEventWaitRet res;
4990
4991         thread = mono_thread_internal_current ();
4992
4993         // MOSTLY_ASYNC_SAFE_PRINTF ("SELF SUSPEND thread %p\n", thread_get_tid (thread));
4994
4995         thread->self_suspended = TRUE;
4996
4997         thread->state &= ~ThreadState_SuspendRequested;
4998         thread->state |= ThreadState_Suspended;
4999
5000         UNLOCK_THREAD (thread);
5001
5002         event = thread->suspended;
5003
5004         MONO_ENTER_GC_SAFE;
5005         res = mono_os_event_wait_one (event, MONO_INFINITE_WAIT);
5006         g_assert (res == MONO_OS_EVENT_WAIT_RET_SUCCESS_0 || res == MONO_OS_EVENT_WAIT_RET_ALERTED);
5007         MONO_EXIT_GC_SAFE;
5008 }
5009
5010 /*
5011  * mono_thread_is_foreign:
5012  * @thread: the thread to query
5013  *
5014  * This function allows one to determine if a thread was created by the mono runtime and has
5015  * a well defined lifecycle or it's a foreigh one, created by the native environment.
5016  *
5017  * Returns: TRUE if @thread was not created by the runtime.
5018  */
5019 mono_bool
5020 mono_thread_is_foreign (MonoThread *thread)
5021 {
5022         MonoThreadInfo *info = (MonoThreadInfo *)thread->internal_thread->thread_info;
5023         return info->runtime_thread == FALSE;
5024 }
5025
5026 /*
5027  * mono_add_joinable_thread:
5028  *
5029  *   Add TID to the list of joinable threads.
5030  * LOCKING: Acquires the threads lock.
5031  */
5032 void
5033 mono_threads_add_joinable_thread (gpointer tid)
5034 {
5035 #ifndef HOST_WIN32
5036         /*
5037          * We cannot detach from threads because it causes problems like
5038          * 2fd16f60/r114307. So we collect them and join them when
5039          * we have time (in he finalizer thread).
5040          */
5041         joinable_threads_lock ();
5042         if (!joinable_threads)
5043                 joinable_threads = g_hash_table_new (NULL, NULL);
5044         g_hash_table_insert (joinable_threads, tid, tid);
5045         joinable_thread_count ++;
5046         joinable_threads_unlock ();
5047
5048         mono_gc_finalize_notify ();
5049 #endif
5050 }
5051
5052 /*
5053  * mono_threads_join_threads:
5054  *
5055  *   Join all joinable threads. This is called from the finalizer thread.
5056  * LOCKING: Acquires the threads lock.
5057  */
5058 void
5059 mono_threads_join_threads (void)
5060 {
5061 #ifndef HOST_WIN32
5062         GHashTableIter iter;
5063         gpointer key;
5064         gpointer tid;
5065         pthread_t thread;
5066         gboolean found;
5067
5068         /* Fastpath */
5069         if (!joinable_thread_count)
5070                 return;
5071
5072         while (TRUE) {
5073                 joinable_threads_lock ();
5074                 found = FALSE;
5075                 if (g_hash_table_size (joinable_threads)) {
5076                         g_hash_table_iter_init (&iter, joinable_threads);
5077                         g_hash_table_iter_next (&iter, &key, (void**)&tid);
5078                         thread = (pthread_t)tid;
5079                         g_hash_table_remove (joinable_threads, key);
5080                         joinable_thread_count --;
5081                         found = TRUE;
5082                 }
5083                 joinable_threads_unlock ();
5084                 if (found) {
5085                         if (thread != pthread_self ()) {
5086                                 MONO_ENTER_GC_SAFE;
5087                                 /* This shouldn't block */
5088                                 mono_threads_join_lock ();
5089                                 mono_native_thread_join (thread);
5090                                 mono_threads_join_unlock ();
5091                                 MONO_EXIT_GC_SAFE;
5092                         }
5093                 } else {
5094                         break;
5095                 }
5096         }
5097 #endif
5098 }
5099
5100 /*
5101  * mono_thread_join:
5102  *
5103  *   Wait for thread TID to exit.
5104  * LOCKING: Acquires the threads lock.
5105  */
5106 void
5107 mono_thread_join (gpointer tid)
5108 {
5109 #ifndef HOST_WIN32
5110         pthread_t thread;
5111         gboolean found = FALSE;
5112
5113         joinable_threads_lock ();
5114         if (!joinable_threads)
5115                 joinable_threads = g_hash_table_new (NULL, NULL);
5116         if (g_hash_table_lookup (joinable_threads, tid)) {
5117                 g_hash_table_remove (joinable_threads, tid);
5118                 joinable_thread_count --;
5119                 found = TRUE;
5120         }
5121         joinable_threads_unlock ();
5122         if (!found)
5123                 return;
5124         thread = (pthread_t)tid;
5125         MONO_ENTER_GC_SAFE;
5126         mono_native_thread_join (thread);
5127         MONO_EXIT_GC_SAFE;
5128 #endif
5129 }
5130
5131 void
5132 mono_thread_internal_check_for_interruption_critical (MonoInternalThread *thread)
5133 {
5134         if ((thread->state & (ThreadState_StopRequested | ThreadState_SuspendRequested)) != 0)
5135                 mono_thread_interruption_checkpoint ();
5136 }
5137
5138 void
5139 mono_thread_internal_unhandled_exception (MonoObject* exc)
5140 {
5141         MonoClass *klass = exc->vtable->klass;
5142         if (is_threadabort_exception (klass)) {
5143                 mono_thread_internal_reset_abort (mono_thread_internal_current ());
5144         } else if (!is_appdomainunloaded_exception (klass)
5145                 && mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT) {
5146                 mono_unhandled_exception (exc);
5147                 if (mono_environment_exitcode_get () == 1) {
5148                         mono_environment_exitcode_set (255);
5149                         mono_invoke_unhandled_exception_hook (exc);
5150                         g_assert_not_reached ();
5151                 }
5152         }
5153 }
5154
5155 void
5156 ves_icall_System_Threading_Thread_GetStackTraces (MonoArray **out_threads, MonoArray **out_stack_traces)
5157 {
5158         MonoError error;
5159         mono_threads_get_thread_dump (out_threads, out_stack_traces, &error);
5160         mono_error_set_pending_exception (&error);
5161 }
5162
5163 /*
5164  * mono_threads_attach_coop: called by native->managed wrappers
5165  *
5166  * In non-coop mode:
5167  *  - @dummy: is NULL
5168  *  - @return: the original domain which needs to be restored, or NULL.
5169  *
5170  * In coop mode:
5171  *  - @dummy: contains the original domain
5172  *  - @return: a cookie containing current MonoThreadInfo*.
5173  */
5174 gpointer
5175 mono_threads_attach_coop (MonoDomain *domain, gpointer *dummy)
5176 {
5177         MonoDomain *orig;
5178         gboolean fresh_thread = FALSE;
5179
5180         if (!domain) {
5181                 /* Happens when called from AOTed code which is only used in the root domain. */
5182                 domain = mono_get_root_domain ();
5183         }
5184
5185         g_assert (domain);
5186
5187         /* On coop, when we detached, we moved the thread from  RUNNING->BLOCKING.
5188          * If we try to reattach we do a BLOCKING->RUNNING transition.  If the thread
5189          * is fresh, mono_thread_attach() will do a STARTING->RUNNING transition so
5190          * we're only responsible for making the cookie. */
5191         if (mono_threads_is_coop_enabled ()) {
5192                 MonoThreadInfo *info = mono_thread_info_current_unchecked ();
5193                 fresh_thread = !info || !mono_thread_info_is_live (info);
5194         }
5195
5196         if (!mono_thread_internal_current ()) {
5197                 mono_thread_attach_full (domain, FALSE);
5198
5199                 // #678164
5200                 mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
5201         }
5202
5203         orig = mono_domain_get ();
5204         if (orig != domain)
5205                 mono_domain_set (domain, TRUE);
5206
5207         if (!mono_threads_is_coop_enabled ())
5208                 return orig != domain ? orig : NULL;
5209
5210         if (fresh_thread) {
5211                 *dummy = NULL;
5212                 /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
5213                  * return the right cookie. */
5214                 return mono_threads_enter_gc_unsafe_region_cookie ();
5215         } else {
5216                 *dummy = orig;
5217                 /* thread state (BLOCKING|RUNNING) -> RUNNING */
5218                 return mono_threads_enter_gc_unsafe_region (dummy);
5219         }
5220 }
5221
5222 /*
5223  * mono_threads_detach_coop: called by native->managed wrappers
5224  *
5225  * In non-coop mode:
5226  *  - @cookie: the original domain which needs to be restored, or NULL.
5227  *  - @dummy: is NULL
5228  *
5229  * In coop mode:
5230  *  - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
5231  *  - @dummy: contains the original domain
5232  */
5233 void
5234 mono_threads_detach_coop (gpointer cookie, gpointer *dummy)
5235 {
5236         MonoDomain *domain, *orig;
5237
5238         if (!mono_threads_is_coop_enabled ()) {
5239                 orig = (MonoDomain*) cookie;
5240                 if (orig)
5241                         mono_domain_set (orig, TRUE);
5242         } else {
5243                 orig = (MonoDomain*) *dummy;
5244
5245                 domain = mono_domain_get ();
5246                 g_assert (domain);
5247
5248                 /* it won't do anything if cookie is NULL
5249                  * thread state RUNNING -> (RUNNING|BLOCKING) */
5250                 mono_threads_exit_gc_unsafe_region (cookie, dummy);
5251
5252                 if (orig != domain) {
5253                         if (!orig)
5254                                 mono_domain_unset ();
5255                         else
5256                                 mono_domain_set (orig, TRUE);
5257                 }
5258         }
5259 }
5260
5261 MonoException*
5262 mono_thread_try_resume_interruption (void)
5263 {
5264         MonoInternalThread *thread;
5265
5266         thread = mono_thread_internal_current ();
5267         if (!mono_get_eh_callbacks ()->mono_above_abort_threshold ())
5268                 return NULL;
5269         if (mono_thread_get_abort_prot_block_count (thread) > 0 || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ())
5270                 return NULL;
5271
5272         return mono_thread_resume_interruption ();
5273 }
5274
5275 #if 0
5276 /* Returns TRUE if the current thread is ready to be interrupted. */
5277 gboolean
5278 mono_threads_is_ready_to_be_interrupted (void)
5279 {
5280         MonoInternalThread *thread;
5281
5282         thread = mono_thread_internal_current ();
5283         LOCK_THREAD (thread);
5284         if (thread->state & (MonoThreadState)(ThreadState_StopRequested | ThreadState_SuspendRequested | ThreadState_AbortRequested)) {
5285                 UNLOCK_THREAD (thread);
5286                 return FALSE;
5287         }
5288
5289         if (mono_thread_get_abort_prot_block_count (thread) || mono_get_eh_callbacks ()->mono_current_thread_has_handle_block_guard ()) {
5290                 UNLOCK_THREAD (thread);
5291                 return FALSE;
5292         }
5293
5294         UNLOCK_THREAD (thread);
5295         return TRUE;
5296 }
5297 #endif
5298
5299 void
5300 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
5301 {
5302         g_string_append_printf (text, ", thread handle : %p", internal->handle);
5303
5304         if (internal->thread_info) {
5305                 g_string_append (text, ", state : ");
5306                 mono_thread_info_describe_interrupt_token ((MonoThreadInfo*) internal->thread_info, text);
5307         }
5308
5309         if (internal->owned_mutexes) {
5310                 int i;
5311
5312                 g_string_append (text, ", owns : [");
5313                 for (i = 0; i < internal->owned_mutexes->len; i++)
5314                         g_string_append_printf (text, i == 0 ? "%p" : ", %p", g_ptr_array_index (internal->owned_mutexes, i));
5315                 g_string_append (text, "]");
5316         }
5317 }
5318
5319 gboolean
5320 mono_thread_internal_is_current (MonoInternalThread *internal)
5321 {
5322         g_assert (internal);
5323         return mono_native_thread_id_equals (mono_native_thread_id_get (), MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid));
5324 }