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