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