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