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