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