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