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