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