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