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