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