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