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