2005-06-05 Gonzalo Paniagua Javier <gonzalo@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  * (C) 2001 Ximian, Inc.
10  */
11
12 #include <config.h>
13 #ifdef PLATFORM_WIN32
14 #define _WIN32_WINNT 0x0500
15 #endif
16
17 #include <glib.h>
18 #include <signal.h>
19 #include <string.h>
20
21 #include <mono/metadata/object.h>
22 #include <mono/metadata/domain-internals.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/threads.h>
25 #include <mono/metadata/threadpool.h>
26 #include <mono/metadata/threads-types.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/environment.h>
29 #include <mono/metadata/monitor.h>
30 #include <mono/metadata/gc-internal.h>
31 #include <mono/metadata/marshal.h>
32 #include <mono/io-layer/io-layer.h>
33 #include <mono/metadata/object-internals.h>
34 #include <mono/utils/mono-compiler.h>
35
36 #include <mono/os/gc_wrapper.h>
37
38 /*#define THREAD_DEBUG(a) do { a; } while (0)*/
39 #define THREAD_DEBUG(a)
40 /*#define THREAD_WAIT_DEBUG(a) do { a; } while (0)*/
41 #define THREAD_WAIT_DEBUG(a)
42 /*#define LIBGC_DEBUG(a) do { a; } while (0)*/
43 #define LIBGC_DEBUG(a)
44
45 struct StartInfo 
46 {
47         guint32 (*func)(void *);
48         MonoThread *obj;
49         MonoObject *delegate;
50         void *start_arg;
51         MonoDomain *domain;
52 };
53
54 typedef union {
55         gint32 ival;
56         gfloat fval;
57 } IntFloatUnion;
58
59 typedef union {
60         gint64 ival;
61         gdouble fval;
62 } LongDoubleUnion;
63  
64 typedef struct {
65         int idx;
66         int offset;
67 } StaticDataInfo;
68
69 /* Number of cached culture objects in the MonoThread->culture_info array */
70 #define NUM_CACHED_CULTURES 4
71
72 /*
73  * The "os_handle" field of the WaitHandle class.
74  */
75 static MonoClassField *wait_handle_os_handle_field = NULL;
76
77 /* Controls access to the 'threads' hash table */
78 static CRITICAL_SECTION threads_mutex;
79
80 /* Controls access to context static data */
81 static CRITICAL_SECTION contexts_mutex;
82
83 /* Holds current status of static data heap */
84 static StaticDataInfo thread_static_info;
85 static StaticDataInfo context_static_info;
86
87 /* The hash of existing threads (key is thread ID) that need joining
88  * before exit
89  */
90 static MonoGHashTable *threads=NULL;
91
92 /* The TLS key that holds the MonoObject assigned to each thread */
93 static guint32 current_object_key = -1;
94
95 #ifdef HAVE_KW_THREAD
96 /* we need to use both the Tls* functions and __thread because
97  * the gc needs to see all the threads 
98  */
99 static __thread MonoThread * tls_current_object MONO_TLS_FAST;
100 #define SET_CURRENT_OBJECT(x) do { \
101         tls_current_object = x; \
102         TlsSetValue (current_object_key, x); \
103 } while (FALSE)
104 #define GET_CURRENT_OBJECT() tls_current_object
105 #else
106 #define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x);
107 #define GET_CURRENT_OBJECT() (MonoThread*) TlsGetValue (current_object_key);
108 #endif
109
110 /* function called at thread start */
111 static MonoThreadStartCB mono_thread_start_cb = NULL;
112
113 /* function called at thread attach */
114 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
115
116 /* function called at thread cleanup */
117 static MonoThreadCleanupFunc mono_thread_cleanup = NULL;
118
119 /* function called when a new thread has been created */
120 static MonoThreadCallbacks *mono_thread_callbacks = NULL;
121
122 /* The default stack size for each thread */
123 static guint32 default_stacksize = 0;
124 #define default_stacksize_for_thread(thread) ((thread)->stack_size? (thread)->stack_size: default_stacksize)
125
126 static void thread_adjust_static_data (MonoThread *thread);
127 static void mono_init_static_data_info (StaticDataInfo *static_data);
128 static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
129 static gboolean mono_thread_resume (MonoThread* thread);
130 static void mono_thread_start (MonoThread *thread);
131
132 /* Spin lock for InterlockedXXX 64 bit functions */
133 static CRITICAL_SECTION interlocked_mutex;
134
135 /* global count of thread interruptions requested */
136 static gint32 thread_interruption_requested = 0;
137
138 /* Event signaled when a thread changes its background mode */
139 static HANDLE background_change_event;
140
141 guint32
142 mono_thread_get_tls_key (void)
143 {
144         return current_object_key;
145 }
146
147 gint32
148 mono_thread_get_tls_offset (void)
149 {
150         int offset;
151         MONO_THREAD_VAR_OFFSET (tls_current_object,offset);
152         return offset;
153 }
154
155 /* handle_store() and handle_remove() manage the array of threads that
156  * still need to be waited for when the main thread exits.
157  */
158 static void handle_store(MonoThread *thread)
159 {
160         EnterCriticalSection(&threads_mutex);
161
162         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": thread %p ID %d", thread, thread->tid));
163
164         if(threads==NULL) {
165                 MONO_GC_REGISTER_ROOT (threads);
166                 threads=mono_g_hash_table_new(NULL, NULL);
167         }
168
169         /* We don't need to duplicate thread->handle, because it is
170          * only closed when the thread object is finalized by the GC.
171          */
172         mono_g_hash_table_insert(threads, GUINT_TO_POINTER(thread->tid), thread);
173         LeaveCriticalSection(&threads_mutex);
174 }
175
176 static void handle_remove(guint32 tid)
177 {
178         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": thread ID %d", tid));
179
180         EnterCriticalSection(&threads_mutex);
181
182         if (threads)
183                 mono_g_hash_table_remove (threads, GUINT_TO_POINTER(tid));
184         
185         LeaveCriticalSection(&threads_mutex);
186
187         /* Don't close the handle here, wait for the object finalizer
188          * to do it. Otherwise, the following race condition applies:
189          *
190          * 1) Thread exits (and handle_remove() closes the handle)
191          *
192          * 2) Some other handle is reassigned the same slot
193          *
194          * 3) Another thread tries to join the first thread, and
195          * blocks waiting for the reassigned handle to be signalled
196          * (which might never happen).  This is possible, because the
197          * thread calling Join() still has a reference to the first
198          * thread's object.
199          */
200 }
201
202 static void thread_cleanup (MonoThread *thread)
203 {
204         mono_release_type_locks (thread);
205
206         if (!mono_monitor_enter (thread->synch_lock))
207                 return;
208
209         thread->state |= ThreadState_Stopped;
210         mono_monitor_exit (thread->synch_lock);
211
212         mono_profiler_thread_end (thread->tid);
213         handle_remove (thread->tid);
214
215         mono_thread_pop_appdomain_ref ();
216
217         if (thread->serialized_culture_info)
218                 g_free (thread->serialized_culture_info);
219
220         mono_gc_free_fixed (thread->culture_info);
221         mono_gc_free_fixed (thread->ui_culture_info);
222
223         if (mono_thread_cleanup)
224                 mono_thread_cleanup (thread);
225 }
226
227 static guint32 WINAPI start_wrapper(void *data)
228 {
229         struct StartInfo *start_info=(struct StartInfo *)data;
230         guint32 (*start_func)(void *);
231         void *start_arg;
232         guint32 tid;
233         MonoThread *thread=start_info->obj;
234         MonoObject *start_delegate = start_info->delegate;
235
236         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper", GetCurrentThreadId ()));
237         
238         /* We can be sure start_info->obj->tid and
239          * start_info->obj->handle have been set, because the thread
240          * was created suspended, and these values were set before the
241          * thread resumed
242          */
243
244         tid=thread->tid;
245
246         SET_CURRENT_OBJECT (thread);
247         
248         if (!mono_domain_set (start_info->domain, FALSE)) {
249                 /* No point in raising an appdomain_unloaded exception here */
250                 /* FIXME: Cleanup here */
251                 return 0;
252         }
253
254         start_func = start_info->func;
255         start_arg = start_info->start_arg;
256
257         /* This MUST be called before any managed code can be
258          * executed, as it calls the callback function that (for the
259          * jit) sets the lmf marker.
260          */
261         mono_thread_new_init (tid, &tid, start_func);
262         thread->stack_ptr = &tid;
263
264         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
265                    ": (%d,%d) Setting thread stack to %p",
266                    GetCurrentThreadId (), getpid (), thread->stack_ptr));
267
268         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
269                    ": (%d) Setting current_object_key to %p",
270                    GetCurrentThreadId (), thread));
271
272         mono_profiler_thread_start (tid);
273
274         if(thread->start_notify!=NULL) {
275                 /* Let the thread that called Start() know we're
276                  * ready
277                  */
278                 ReleaseSemaphore (thread->start_notify, 1, NULL);
279         }
280         
281         g_free (start_info);
282
283         /* Every thread references the appdomain which created it */
284         mono_thread_push_appdomain_ref (mono_domain_get ());
285
286         thread_adjust_static_data (thread);
287 #ifdef DEBUG
288         g_message (G_GNUC_PRETTY_FUNCTION "start_wrapper for %d\n", thread->tid);
289 #endif
290
291         /* start_func is set only for unamanged start functions */
292         if (start_func) {
293                 start_func (start_arg);
294         } else {
295                 void *args [1];
296                 g_assert (start_delegate != NULL);
297                 args [0] = start_arg;
298                 /* we may want to handle the exception here. See comment below on unhandled exceptions */
299                 mono_runtime_delegate_invoke (start_delegate, args, NULL);
300         }
301
302         /* If the thread calls ExitThread at all, this remaining code
303          * will not be executed, but the main thread will eventually
304          * call thread_cleanup() on this thread's behalf.
305          */
306
307         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper terminating",
308                   GetCurrentThreadId ()));
309
310         /* Remove the reference to the thread object in the TLS data,
311          * so the thread object can be finalized.  This won't be
312          * reached if the thread threw an uncaught exception, so those
313          * thread handles will stay referenced :-( (This is due to
314          * missing support for scanning thread-specific data in the
315          * Boehm GC - the io-layer keeps a GC-visible hash of pointers
316          * to TLS data.)
317          */
318         SET_CURRENT_OBJECT (NULL);
319
320         thread_cleanup (thread);
321
322         return(0);
323 }
324
325 void mono_thread_new_init (guint32 tid, gpointer stack_start, gpointer func)
326 {
327         if (mono_thread_start_cb) {
328                 mono_thread_start_cb (tid, stack_start, func);
329         }
330
331         if (mono_thread_callbacks)
332                 (* mono_thread_callbacks->thread_created) (tid, stack_start, func);
333 }
334
335 void mono_threads_set_default_stacksize (guint32 stacksize)
336 {
337         default_stacksize = stacksize;
338 }
339
340 guint32 mono_threads_get_default_stacksize (void)
341 {
342         return default_stacksize;
343 }
344
345 void mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
346 {
347         MonoThread *thread;
348         HANDLE thread_handle;
349         struct StartInfo *start_info;
350         guint32 tid;
351         
352         thread=(MonoThread *)mono_object_new (domain,
353                                               mono_defaults.thread_class);
354
355         start_info=g_new0 (struct StartInfo, 1);
356         start_info->func = func;
357         start_info->obj = thread;
358         start_info->domain = domain;
359         start_info->start_arg = arg;
360         
361         /* Create suspended, so we can do some housekeeping before the thread
362          * starts
363          */
364         thread_handle = CreateThread(NULL, default_stacksize_for_thread (thread), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
365                                      CREATE_SUSPENDED, &tid);
366         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Started thread ID %d (handle %p)",
367                   tid, thread_handle));
368         if (thread_handle == NULL) {
369                 /* The thread couldn't be created, so throw an exception */
370                 mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
371                 return;
372         }
373
374         thread->handle=thread_handle;
375         thread->tid=tid;
376
377         thread->synch_lock=mono_object_new (domain, mono_defaults.object_class);
378                                                   
379         handle_store(thread);
380
381         ResumeThread (thread_handle);
382 }
383
384 MonoThread *
385 mono_thread_attach (MonoDomain *domain)
386 {
387         MonoThread *thread;
388         HANDLE thread_handle;
389         guint32 tid;
390
391         if ((thread = mono_thread_current ())) {
392                 /* Already attached */
393                 return thread;
394         }
395
396         if (!mono_gc_is_gc_thread ()) {
397                 g_error ("Thread %p 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.", GetCurrentThread ());
398         }
399
400         thread = (MonoThread *)mono_object_new (domain,
401                                                 mono_defaults.thread_class);
402
403         thread_handle = GetCurrentThread ();
404         g_assert (thread_handle);
405
406         tid=GetCurrentThreadId ();
407
408 #ifdef PLATFORM_WIN32
409         /* 
410          * The handle returned by GetCurrentThread () is a pseudo handle, so it can't be used to
411          * refer to the thread from other threads for things like aborting.
412          */
413         DuplicateHandle (GetCurrentProcess (), thread_handle, GetCurrentProcess (), &thread_handle, 
414                                          THREAD_ALL_ACCESS, TRUE, 0);
415 #endif
416
417         thread->handle=thread_handle;
418         thread->tid=tid;
419         thread->synch_lock=mono_object_new (domain, mono_defaults.object_class);
420
421         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Attached thread ID %d (handle %p)",
422                   tid, thread_handle));
423
424         handle_store(thread);
425
426         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Setting current_object_key to %p",
427                    GetCurrentThreadId (), thread));
428
429         SET_CURRENT_OBJECT (thread);
430         mono_domain_set (domain, TRUE);
431
432         thread_adjust_static_data (thread);
433
434         if (mono_thread_attach_cb) {
435                 mono_thread_attach_cb (tid, &tid);
436         }
437
438         return(thread);
439 }
440
441 void
442 mono_thread_detach (MonoThread *thread)
443 {
444         g_return_if_fail (thread != NULL);
445
446         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION "mono_thread_detach for %d\n", thread->tid));
447         SET_CURRENT_OBJECT (NULL);
448         
449         thread_cleanup (thread);
450 }
451
452 void
453 mono_thread_exit ()
454 {
455         MonoThread *thread = mono_thread_current ();
456
457         SET_CURRENT_OBJECT (NULL);
458         thread_cleanup (thread);
459
460         /* we could add a callback here for embedders to use. */
461         if (thread == mono_thread_get_main ())
462                 exit (mono_environment_exitcode_get ());
463         ExitThread (-1);
464 }
465
466 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
467                                                          MonoObject *start)
468 {
469         guint32 (*start_func)(void *);
470         struct StartInfo *start_info;
471         MonoMethod *im;
472         HANDLE thread;
473         guint32 tid;
474         
475         MONO_ARCH_SAVE_REGS;
476
477         THREAD_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION
478                   ": Trying to start a new thread: this (%p) start (%p)", this, start));
479
480         mono_monitor_enter (this->synch_lock);
481
482         if ((this->state & ThreadState_Unstarted) == 0 ||
483             (this->state & ThreadState_Aborted) != 0) {
484                 mono_monitor_exit (this->synch_lock);
485                 mono_raise_exception (mono_get_exception_thread_state ("Thread has already been started."));
486                 return NULL;
487         }
488
489 /* FIXME: remove the code inside BROKEN_THREAD_START once martin gets rid of the
490  * thread_start_compile_func stuff.
491  */
492 #define BROKEN_THREAD_START
493 #ifdef BROKEN_THREAD_START
494         im = mono_get_delegate_invoke (start->vtable->klass);
495         im = mono_marshal_get_delegate_invoke (im);
496         if (mono_thread_callbacks)
497                 start_func = (* mono_thread_callbacks->thread_start_compile_func) (im);
498         else
499                 start_func = mono_compile_method (im);
500
501         if(start_func==NULL) {
502                 mono_monitor_exit (this->synch_lock);
503                 g_warning(G_GNUC_PRETTY_FUNCTION
504                           ": Can't locate start method!");
505                 return(NULL);
506         } else {
507 #else
508         start_func = NULL;
509         {
510 #endif
511                 /* This is freed in start_wrapper */
512                 start_info = g_new0 (struct StartInfo, 1);
513                 start_info->func = start_func;
514 #ifdef BROKEN_THREAD_START
515                 start_info->start_arg = start;
516 #else
517                 start_info->start_arg = this->start_obj;
518 #endif
519                 start_info->delegate = start;
520                 start_info->obj = this;
521                 start_info->domain = mono_domain_get ();
522
523                 this->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
524                 if(this->start_notify==NULL) {
525                         mono_monitor_exit (this->synch_lock);
526                         g_warning (G_GNUC_PRETTY_FUNCTION ": CreateSemaphore error 0x%x", GetLastError ());
527                         return(NULL);
528                 }
529
530                 thread=CreateThread(NULL, default_stacksize_for_thread (this), (LPTHREAD_START_ROUTINE)start_wrapper, start_info,
531                                     CREATE_SUSPENDED, &tid);
532                 if(thread==NULL) {
533                         mono_monitor_exit (this->synch_lock);
534                         g_warning(G_GNUC_PRETTY_FUNCTION
535                                   ": CreateThread error 0x%x", GetLastError());
536                         return(NULL);
537                 }
538                 
539                 this->handle=thread;
540                 this->tid=tid;
541
542                 /* Don't call handle_store() here, delay it to Start.
543                  * We can't join a thread (trying to will just block
544                  * forever) until it actually starts running, so don't
545                  * store the handle till then.
546                  */
547
548                 mono_thread_start (this);
549                 
550                 this->state &= ~ThreadState_Unstarted;
551
552                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
553                           ": Started thread ID %d (handle %p)", tid, thread));
554
555                 mono_monitor_exit (this->synch_lock);
556                 return(thread);
557         }
558 }
559
560 void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
561                                                              HANDLE thread)
562 {
563         MONO_ARCH_SAVE_REGS;
564
565         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Closing thread %p, handle %p",
566                    this, thread));
567
568         CloseHandle (thread);
569 }
570
571 static void mono_thread_start (MonoThread *thread)
572 {
573         MONO_ARCH_SAVE_REGS;
574
575         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Launching thread %p (%d)",
576                   GetCurrentThreadId (), thread, thread->tid));
577
578         /* Only store the handle when the thread is about to be
579          * launched, to avoid the main thread deadlocking while trying
580          * to clean up a thread that will never be signalled.
581          */
582         handle_store (thread);
583
584         if (mono_thread_callbacks)
585                 (* mono_thread_callbacks->start_resume) (thread->tid);
586
587         ResumeThread (thread->handle);
588
589         if (mono_thread_callbacks)
590                 (* mono_thread_callbacks->end_resume) (thread->tid);
591
592         if(thread->start_notify!=NULL) {
593                 /* Wait for the thread to set up its TLS data etc, so
594                  * theres no potential race condition if someone tries
595                  * to look up the data believing the thread has
596                  * started
597                  */
598
599                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
600                           ": (%d) waiting for thread %p (%d) to start",
601                           GetCurrentThreadId (), thread, thread->tid));
602
603                 WaitForSingleObjectEx (thread->start_notify, INFINITE, FALSE);
604                 CloseHandle (thread->start_notify);
605                 thread->start_notify = NULL;
606         }
607
608         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
609                   ": (%d) Done launching thread %p (%d)",
610                   GetCurrentThreadId (), thread, thread->tid));
611 }
612
613 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
614 {
615         MonoThread *thread = mono_thread_current ();
616         
617         MONO_ARCH_SAVE_REGS;
618
619         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms));
620
621         mono_monitor_enter (thread->synch_lock);
622         thread->state |= ThreadState_WaitSleepJoin;
623         mono_monitor_exit (thread->synch_lock);
624         
625         SleepEx(ms,TRUE);
626         
627         mono_monitor_enter (thread->synch_lock);
628         thread->state &= ~ThreadState_WaitSleepJoin;
629         mono_monitor_exit (thread->synch_lock);
630 }
631
632 gint32
633 ves_icall_System_Threading_Thread_GetDomainID (void) 
634 {
635         MONO_ARCH_SAVE_REGS;
636
637         return mono_domain_get()->domain_id;
638 }
639
640 MonoString* 
641 ves_icall_System_Threading_Thread_GetName_internal (MonoThread *this_obj)
642 {
643         MonoString* str;
644         mono_monitor_enter (this_obj->synch_lock);
645         
646         if (!this_obj->name)
647                 str = NULL;
648         else
649                 str = mono_string_new_utf16 (mono_domain_get (), this_obj->name, this_obj->name_len);
650         
651         mono_monitor_exit (this_obj->synch_lock);
652         return str;
653 }
654
655 void 
656 ves_icall_System_Threading_Thread_SetName_internal (MonoThread *this_obj, MonoString *name)
657 {
658         mono_monitor_enter (this_obj->synch_lock);
659         
660         if (this_obj->name) {
661                 mono_monitor_exit (this_obj->synch_lock);
662                 mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
663                 return;
664         }
665         if (name) {
666                 this_obj->name = g_new (gunichar2, mono_string_length (name));
667                 memcpy (this_obj->name, mono_string_chars (name), mono_string_length (name) * 2);
668                 this_obj->name_len = mono_string_length (name);
669         }
670         else
671                 this_obj->name = NULL;
672         
673         mono_monitor_exit (this_obj->synch_lock);
674 }
675
676 MonoObject*
677 ves_icall_System_Threading_Thread_GetCachedCurrentCulture (MonoThread *this)
678 {
679         MonoObject *res;
680         MonoDomain *domain;
681         int i;
682
683         /* No need to lock here */
684         if (this->culture_info) {
685                 domain = mono_domain_get ();
686                 for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
687                         res = this->culture_info [i];
688                         if (res && res->vtable->domain == domain)
689                                 return res;
690                 }
691         }
692
693         return NULL;
694 }
695
696 MonoArray*
697 ves_icall_System_Threading_Thread_GetSerializedCurrentCulture (MonoThread *this)
698 {
699         MonoArray *res;
700
701         mono_monitor_enter (this->synch_lock);
702         if (this->serialized_culture_info) {
703                 res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_culture_info_len);
704                 memcpy (mono_array_addr (res, guint8, 0), this->serialized_culture_info, this->serialized_culture_info_len);
705         }
706         else
707                 res = NULL;
708         mono_monitor_exit (this->synch_lock);
709
710         return res;
711 }
712
713 void
714 ves_icall_System_Threading_Thread_SetCachedCurrentCulture (MonoThread *this, MonoObject *culture)
715 {
716         int i;
717         MonoDomain *domain = mono_domain_get ();
718
719         mono_monitor_enter (this->synch_lock);
720         if (!this->culture_info) {
721                 this->culture_info = mono_gc_alloc_fixed (sizeof (MonoObject*) * NUM_CACHED_CULTURES, NULL);
722         }
723
724         for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
725                 if (this->culture_info [i]) {
726                         if (this->culture_info [i]->vtable->domain == domain)
727                                 /* Replace */
728                                 break;
729                 }
730                 else
731                         /* Free entry */
732                         break;
733         }
734         if (i < NUM_CACHED_CULTURES)
735                 this->culture_info [i] = culture;
736         mono_monitor_exit (this->synch_lock);
737 }
738
739 void
740 ves_icall_System_Threading_Thread_SetSerializedCurrentCulture (MonoThread *this, MonoArray *arr)
741 {
742         mono_monitor_enter (this->synch_lock);
743         if (this->serialized_culture_info)
744                 g_free (this->serialized_culture_info);
745         this->serialized_culture_info = g_new0 (guint8, mono_array_length (arr));
746         this->serialized_culture_info_len = mono_array_length (arr);
747         memcpy (this->serialized_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
748         mono_monitor_exit (this->synch_lock);
749 }
750
751
752 MonoObject*
753 ves_icall_System_Threading_Thread_GetCachedCurrentUICulture (MonoThread *this)
754 {
755         MonoObject *res;
756         MonoDomain *domain;
757         int i;
758
759         /* No need to lock here */
760         if (this->ui_culture_info) {
761                 domain = mono_domain_get ();
762                 for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
763                         res = this->ui_culture_info [i];
764                         if (res && res->vtable->domain == domain)
765                                 return res;
766                 }
767         }
768
769         return NULL;
770 }
771
772 MonoArray*
773 ves_icall_System_Threading_Thread_GetSerializedCurrentUICulture (MonoThread *this)
774 {
775         MonoArray *res;
776
777         mono_monitor_enter (this->synch_lock);
778         if (this->serialized_ui_culture_info) {
779                 res = mono_array_new (mono_domain_get (), mono_defaults.byte_class, this->serialized_ui_culture_info_len);
780                 memcpy (mono_array_addr (res, guint8, 0), this->serialized_ui_culture_info, this->serialized_ui_culture_info_len);
781         }
782         else
783                 res = NULL;
784         mono_monitor_exit (this->synch_lock);
785
786         return res;
787 }
788
789 void
790 ves_icall_System_Threading_Thread_SetCachedCurrentUICulture (MonoThread *this, MonoObject *culture)
791 {
792         int i;
793         MonoDomain *domain = mono_domain_get ();
794
795         mono_monitor_enter (this->synch_lock);
796         if (!this->ui_culture_info) {
797                 this->ui_culture_info = mono_gc_alloc_fixed (sizeof (MonoObject*) * NUM_CACHED_CULTURES, NULL);
798         }
799
800         for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
801                 if (this->ui_culture_info [i]) {
802                         if (this->ui_culture_info [i]->vtable->domain == domain)
803                                 /* Replace */
804                                 break;
805                 }
806                 else
807                         /* Free entry */
808                         break;
809         }
810         if (i < NUM_CACHED_CULTURES)
811                 this->ui_culture_info [i] = culture;
812         mono_monitor_exit (this->synch_lock);
813 }
814
815 void
816 ves_icall_System_Threading_Thread_SetSerializedCurrentUICulture (MonoThread *this, MonoArray *arr)
817 {
818         mono_monitor_enter (this->synch_lock);
819         if (this->serialized_ui_culture_info)
820                 g_free (this->serialized_ui_culture_info);
821         this->serialized_ui_culture_info = g_new0 (guint8, mono_array_length (arr));
822         this->serialized_ui_culture_info_len = mono_array_length (arr);
823         memcpy (this->serialized_ui_culture_info, mono_array_addr (arr, guint8, 0), mono_array_length (arr));
824         mono_monitor_exit (this->synch_lock);
825 }
826
827 /* the jit may read the compiled code of this function */
828 MonoThread *
829 mono_thread_current (void)
830 {
831         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", GET_CURRENT_OBJECT ()));
832         return GET_CURRENT_OBJECT ();
833 }
834
835 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
836                                                          int ms, HANDLE thread)
837 {
838         gboolean ret;
839         
840         MONO_ARCH_SAVE_REGS;
841
842         mono_monitor_enter (this->synch_lock);
843         
844         if ((this->state & ThreadState_Unstarted) != 0) {
845                 mono_monitor_exit (this->synch_lock);
846                 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started."));
847                 return FALSE;
848         }
849         
850         this->state |= ThreadState_WaitSleepJoin;
851         mono_monitor_exit (this->synch_lock);
852
853         if(ms== -1) {
854                 ms=INFINITE;
855         }
856         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": joining thread handle %p, %d ms",
857                    thread, ms));
858         
859         ret=WaitForSingleObjectEx (thread, ms, TRUE);
860
861         mono_monitor_enter (this->synch_lock);
862         this->state &= ~ThreadState_WaitSleepJoin;
863         mono_monitor_exit (this->synch_lock);
864         
865         if(ret==WAIT_OBJECT_0) {
866                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": join successful"));
867
868                 return(TRUE);
869         }
870         
871         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": join failed"));
872
873         return(FALSE);
874 }
875
876 /* FIXME: exitContext isnt documented */
877 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
878 {
879         HANDLE *handles;
880         guint32 numhandles;
881         guint32 ret;
882         guint32 i;
883         MonoObject *waitHandle;
884         MonoClass *klass;
885         MonoThread *thread = mono_thread_current ();
886                 
887         MONO_ARCH_SAVE_REGS;
888
889         numhandles = mono_array_length(mono_handles);
890         handles = g_new0(HANDLE, numhandles);
891
892         if (wait_handle_os_handle_field == 0) {
893                 /* Get the field os_handle which will contain the actual handle */
894                 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");   
895                 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
896         }
897                 
898         for(i = 0; i < numhandles; i++) {       
899                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);              
900                 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
901         }
902         
903         if(ms== -1) {
904                 ms=INFINITE;
905         }
906
907         mono_monitor_enter (thread->synch_lock);
908         thread->state |= ThreadState_WaitSleepJoin;
909         mono_monitor_exit (thread->synch_lock);
910         
911         ret=WaitForMultipleObjectsEx(numhandles, handles, TRUE, ms, TRUE);
912
913         mono_monitor_enter (thread->synch_lock);
914         thread->state &= ~ThreadState_WaitSleepJoin;
915         mono_monitor_exit (thread->synch_lock);
916
917         g_free(handles);
918
919         if(ret==WAIT_FAILED) {
920                 THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
921                           GetCurrentThreadId ()));
922                 return(FALSE);
923         } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
924                 /* Do we want to try again if we get
925                  * WAIT_IO_COMPLETION? The documentation for
926                  * WaitHandle doesn't give any clues.  (We'd have to
927                  * fiddle with the timeout if we retry.)
928                  */
929                 THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
930                           GetCurrentThreadId ()));
931                 return(FALSE);
932         }
933         
934         return(TRUE);
935 }
936
937 /* FIXME: exitContext isnt documented */
938 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
939 {
940         HANDLE *handles;
941         guint32 numhandles;
942         guint32 ret;
943         guint32 i;
944         MonoObject *waitHandle;
945         MonoClass *klass;
946         MonoThread *thread = mono_thread_current ();
947                 
948         MONO_ARCH_SAVE_REGS;
949
950         numhandles = mono_array_length(mono_handles);
951         handles = g_new0(HANDLE, numhandles);
952
953         if (wait_handle_os_handle_field == 0) {
954                 /* Get the field os_handle which will contain the actual handle */
955                 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");   
956                 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
957         }
958                 
959         for(i = 0; i < numhandles; i++) {       
960                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);              
961                 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
962         }
963         
964         if(ms== -1) {
965                 ms=INFINITE;
966         }
967
968         mono_monitor_enter (thread->synch_lock);
969         thread->state |= ThreadState_WaitSleepJoin;
970         mono_monitor_exit (thread->synch_lock);
971
972         ret=WaitForMultipleObjectsEx(numhandles, handles, FALSE, ms, TRUE);
973
974         mono_monitor_enter (thread->synch_lock);
975         thread->state &= ~ThreadState_WaitSleepJoin;
976         mono_monitor_exit (thread->synch_lock);
977
978         g_free(handles);
979
980         THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) returning %d",
981                   GetCurrentThreadId (), ret));
982
983         /*
984          * These need to be here.  See MSDN dos on WaitForMultipleObjects.
985          */
986         if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
987                 return ret - WAIT_OBJECT_0;
988         }
989         else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
990                 return ret - WAIT_ABANDONED_0;
991         }
992         else {
993                 return ret;
994         }
995 }
996
997 /* FIXME: exitContext isnt documented */
998 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
999 {
1000         guint32 ret;
1001         MonoThread *thread = mono_thread_current ();
1002         
1003         MONO_ARCH_SAVE_REGS;
1004
1005         THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) waiting for %p, %d ms",
1006                   GetCurrentThreadId (), handle, ms));
1007         
1008         if(ms== -1) {
1009                 ms=INFINITE;
1010         }
1011         
1012         mono_monitor_enter (thread->synch_lock);
1013         thread->state |= ThreadState_WaitSleepJoin;
1014         mono_monitor_exit (thread->synch_lock);
1015
1016         ret=WaitForSingleObjectEx (handle, ms, TRUE);
1017         
1018         mono_monitor_enter (thread->synch_lock);
1019         thread->state &= ~ThreadState_WaitSleepJoin;
1020         mono_monitor_exit (thread->synch_lock);
1021
1022         if(ret==WAIT_FAILED) {
1023                 THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
1024                           GetCurrentThreadId ()));
1025                 return(FALSE);
1026         } else if(ret==WAIT_TIMEOUT || ret == WAIT_IO_COMPLETION) {
1027                 /* Do we want to try again if we get
1028                  * WAIT_IO_COMPLETION? The documentation for
1029                  * WaitHandle doesn't give any clues.  (We'd have to
1030                  * fiddle with the timeout if we retry.)
1031                  */
1032                 THREAD_WAIT_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
1033                           GetCurrentThreadId ()));
1034                 return(FALSE);
1035         }
1036         
1037         return(TRUE);
1038 }
1039
1040 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned, MonoString *name, MonoBoolean *created)
1041
1042         HANDLE mutex;
1043         
1044         MONO_ARCH_SAVE_REGS;
1045    
1046         *created = TRUE;
1047         
1048         if (name == NULL) {
1049                 mutex = CreateMutex (NULL, owned, NULL);
1050         } else {
1051                 mutex = CreateMutex (NULL, owned, mono_string_chars (name));
1052                 
1053                 if (GetLastError () == ERROR_ALREADY_EXISTS) {
1054                         *created = FALSE;
1055                 }
1056         }
1057
1058         return(mutex);
1059 }                                                                   
1060
1061 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) { 
1062         MONO_ARCH_SAVE_REGS;
1063
1064         ReleaseMutex(handle);
1065 }
1066
1067 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, MonoString *name) {
1068         MONO_ARCH_SAVE_REGS;
1069
1070         return(CreateEvent (NULL, manual, initial,
1071                             name==NULL?NULL:mono_string_chars (name)));
1072 }
1073
1074 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
1075         MONO_ARCH_SAVE_REGS;
1076
1077         return (SetEvent(handle));
1078 }
1079
1080 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
1081         MONO_ARCH_SAVE_REGS;
1082
1083         return (ResetEvent(handle));
1084 }
1085
1086 void
1087 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
1088         MONO_ARCH_SAVE_REGS;
1089
1090         CloseHandle (handle);
1091 }
1092
1093 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
1094 {
1095         MONO_ARCH_SAVE_REGS;
1096
1097         return InterlockedIncrement (location);
1098 }
1099
1100 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
1101 {
1102         gint64 ret;
1103
1104         MONO_ARCH_SAVE_REGS;
1105
1106         EnterCriticalSection(&interlocked_mutex);
1107
1108         ret = ++ *location;
1109         
1110         LeaveCriticalSection(&interlocked_mutex);
1111
1112         
1113         return ret;
1114 }
1115
1116 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
1117 {
1118         MONO_ARCH_SAVE_REGS;
1119
1120         return InterlockedDecrement(location);
1121 }
1122
1123 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
1124 {
1125         gint64 ret;
1126
1127         MONO_ARCH_SAVE_REGS;
1128
1129         EnterCriticalSection(&interlocked_mutex);
1130
1131         ret = -- *location;
1132         
1133         LeaveCriticalSection(&interlocked_mutex);
1134
1135         return ret;
1136 }
1137
1138 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location, gint32 value)
1139 {
1140         MONO_ARCH_SAVE_REGS;
1141
1142         return InterlockedExchange(location, value);
1143 }
1144
1145 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location, MonoObject *value)
1146 {
1147         MONO_ARCH_SAVE_REGS;
1148
1149         return (MonoObject *) InterlockedExchangePointer((gpointer *) location, value);
1150 }
1151
1152 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location, gfloat value)
1153 {
1154         IntFloatUnion val, ret;
1155
1156         MONO_ARCH_SAVE_REGS;
1157
1158         val.fval = value;
1159         ret.ival = InterlockedExchange((gint32 *) location, val.ival);
1160
1161         return ret.fval;
1162 }
1163
1164 gint64 
1165 ves_icall_System_Threading_Interlocked_Exchange_Long (gint64 *location, gint64 value)
1166 {
1167 #if SIZEOF_VOID_P == 8
1168         return (gint64) InterlockedExchangePointer((gpointer *) location, (gpointer)value);
1169 #else
1170         gint64 res;
1171
1172         /* 
1173          * According to MSDN, this function is only atomic with regards to the 
1174          * other Interlocked functions on 32 bit platforms.
1175          */
1176         EnterCriticalSection(&interlocked_mutex);
1177         res = *location;
1178         *location = value;
1179         LeaveCriticalSection(&interlocked_mutex);
1180
1181         return res;
1182 #endif
1183 }
1184
1185 gdouble 
1186 ves_icall_System_Threading_Interlocked_Exchange_Double (gdouble *location, gdouble value)
1187 {
1188 #if SIZEOF_VOID_P == 8
1189         LongDoubleUnion val, ret;
1190
1191         val.fval = value;
1192         ret.ival = (gint64)InterlockedExchangePointer((gpointer *) location, (gpointer)val.ival);
1193
1194         return ret.fval;
1195 #else
1196         gdouble res;
1197
1198         /* 
1199          * According to MSDN, this function is only atomic with regards to the 
1200          * other Interlocked functions on 32 bit platforms.
1201          */
1202         EnterCriticalSection(&interlocked_mutex);
1203         res = *location;
1204         *location = value;
1205         LeaveCriticalSection(&interlocked_mutex);
1206
1207         return res;
1208 #endif
1209 }
1210
1211 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location, gint32 value, gint32 comparand)
1212 {
1213         MONO_ARCH_SAVE_REGS;
1214
1215         return InterlockedCompareExchange(location, value, comparand);
1216 }
1217
1218 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location, MonoObject *value, MonoObject *comparand)
1219 {
1220         MONO_ARCH_SAVE_REGS;
1221
1222         return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location, value, comparand);
1223 }
1224
1225 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location, gfloat value, gfloat comparand)
1226 {
1227         IntFloatUnion val, ret, cmp;
1228
1229         MONO_ARCH_SAVE_REGS;
1230
1231         val.fval = value;
1232         cmp.fval = comparand;
1233         ret.ival = InterlockedCompareExchange((gint32 *) location, val.ival, cmp.ival);
1234
1235         return ret.fval;
1236 }
1237
1238 gdouble
1239 ves_icall_System_Threading_Interlocked_CompareExchange_Double (gdouble *location, gdouble value, gdouble comparand)
1240 {
1241 #if SIZEOF_VOID_P == 8
1242         LongDoubleUnion val, comp, ret;
1243
1244         val.fval = value;
1245         comp.fval = comparand;
1246         ret.ival = (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)val.ival, (gpointer)comp.ival);
1247
1248         return ret.fval;
1249 #else
1250         gdouble old;
1251
1252         EnterCriticalSection(&interlocked_mutex);
1253         old = *location;
1254         if (old == comparand)
1255                 *location = value;
1256         LeaveCriticalSection(&interlocked_mutex);
1257
1258         return old;
1259 #endif
1260 }
1261
1262 gint64 
1263 ves_icall_System_Threading_Interlocked_CompareExchange_Long (gint64 *location, gint64 value, gint64 comparand)
1264 {
1265 #if SIZEOF_VOID_P == 8
1266         return (gint64)InterlockedCompareExchangePointer((gpointer *) location, (gpointer)value, (gpointer)comparand);
1267 #else
1268         gint64 old;
1269
1270         EnterCriticalSection(&interlocked_mutex);
1271         old = *location;
1272         if (old == comparand)
1273                 *location = value;
1274         LeaveCriticalSection(&interlocked_mutex);
1275         
1276         return old;
1277 #endif
1278 }
1279
1280 gint32 
1281 ves_icall_System_Threading_Interlocked_Add_Int (gint32 *location, gint32 value)
1282 {
1283 #if SIZEOF_VOID_P == 8
1284         /* Should be implemented as a JIT intrinsic */
1285         mono_raise_exception (mono_get_exception_not_implemented (NULL));
1286         return 0;
1287 #else
1288         gint32 orig;
1289
1290         EnterCriticalSection(&interlocked_mutex);
1291         orig = *location;
1292         *location = orig + value;
1293         LeaveCriticalSection(&interlocked_mutex);
1294
1295         return orig;
1296 #endif
1297 }
1298
1299 gint64 
1300 ves_icall_System_Threading_Interlocked_Add_Long (gint64 *location, gint64 value)
1301 {
1302 #if SIZEOF_VOID_P == 8
1303         /* Should be implemented as a JIT intrinsic */
1304         mono_raise_exception (mono_get_exception_not_implemented (NULL));
1305         return 0;
1306 #else
1307         gint64 orig;
1308
1309         EnterCriticalSection(&interlocked_mutex);
1310         orig = *location;
1311         *location = orig + value;
1312         LeaveCriticalSection(&interlocked_mutex);
1313
1314         return orig;
1315 #endif
1316 }
1317
1318 gint64 
1319 ves_icall_System_Threading_Interlocked_Read_Long (gint64 *location)
1320 {
1321 #if SIZEOF_VOID_P == 8
1322         /* 64 bit reads are already atomic */
1323         return *location;
1324 #else
1325         gint64 res;
1326
1327         EnterCriticalSection(&interlocked_mutex);
1328         res = *location;
1329         LeaveCriticalSection(&interlocked_mutex);
1330
1331         return res;
1332 #endif
1333 }
1334
1335 void
1336 ves_icall_System_Threading_Thread_ClrState (MonoThread* this, guint32 state)
1337 {
1338         mono_monitor_enter (this->synch_lock);
1339         this->state &= ~state;
1340         if (state & ThreadState_Background) {
1341                 /* If the thread changes the background mode, the main thread has to
1342                  * be notified, since it has to rebuild the list of threads to
1343                  * wait for.
1344                  */
1345                 SetEvent (background_change_event);
1346         }
1347         mono_monitor_exit (this->synch_lock);
1348 }
1349
1350 void
1351 ves_icall_System_Threading_Thread_SetState (MonoThread* this, guint32 state)
1352 {
1353         mono_monitor_enter (this->synch_lock);
1354         this->state |= state;
1355         if (state & ThreadState_Background) {
1356                 /* If the thread changes the background mode, the main thread has to
1357                  * be notified, since it has to rebuild the list of threads to
1358                  * wait for.
1359                  */
1360                 SetEvent (background_change_event);
1361         }
1362         mono_monitor_exit (this->synch_lock);
1363 }
1364
1365 guint32
1366 ves_icall_System_Threading_Thread_GetState (MonoThread* this)
1367 {
1368         guint32 state;
1369         mono_monitor_enter (this->synch_lock);
1370         state = this->state;
1371         mono_monitor_exit (this->synch_lock);
1372         return state;
1373 }
1374
1375 int  
1376 mono_thread_get_abort_signal (void)
1377 {
1378 #if defined (__MINGW32__) || defined (_MSC_VER)
1379         return -1;
1380 #else
1381 #ifndef SIGRTMIN
1382         return SIGUSR1;
1383 #else
1384         return SIGRTMIN;
1385 #endif
1386 #endif /*defined (__MINGW32__) || defined (_MSC_VER) */
1387 }
1388
1389 #if defined (__MINGW32__) || defined (_MSC_VER)
1390 static void CALLBACK interruption_request_apc (ULONG_PTR param)
1391 {
1392         MonoException* exc = mono_thread_request_interruption (FALSE);
1393         if (exc) mono_raise_exception (exc);
1394 }
1395 #endif /* defined (__MINGW32__) || defined (_MSC_VER) */
1396
1397 /*
1398  * signal_thread_state_change
1399  *
1400  * Tells the thread that his state has changed and it has to enter the new
1401  * state as soon as possible.
1402  */
1403 static void signal_thread_state_change (MonoThread *thread)
1404 {
1405         if (thread == mono_thread_current ()) {
1406                 /* Do it synchronously */
1407                 MonoException *exc = mono_thread_request_interruption (FALSE); 
1408                 if (exc)
1409                         mono_raise_exception (exc);
1410         }
1411
1412 #if defined (__MINGW32__) || defined (_MSC_VER)
1413         QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
1414 #else
1415         /* fixme: store the state somewhere */
1416 #ifdef PTHREAD_POINTER_ID
1417         pthread_kill (GUINT_TO_POINTER(thread->tid), mono_thread_get_abort_signal ());
1418 #else
1419         pthread_kill (thread->tid, mono_thread_get_abort_signal ());
1420 #endif
1421 #endif /* defined (__MINGW32__) || defined (__MSC_VER) */
1422 }
1423
1424 void
1425 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
1426 {
1427         MONO_ARCH_SAVE_REGS;
1428
1429         mono_monitor_enter (thread->synch_lock);
1430
1431         if ((thread->state & ThreadState_AbortRequested) != 0 || 
1432                 (thread->state & ThreadState_StopRequested) != 0) 
1433         {
1434                 mono_monitor_exit (thread->synch_lock);
1435                 return;
1436         }
1437
1438         if ((thread->state & ThreadState_Unstarted) != 0) {
1439                 thread->state |= ThreadState_Aborted;
1440                 mono_monitor_exit (thread->synch_lock);
1441                 return;
1442         }
1443
1444         thread->state |= ThreadState_AbortRequested;
1445         thread->abort_state = state;
1446         thread->abort_exc = NULL;
1447
1448         mono_monitor_exit (thread->synch_lock);
1449
1450         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
1451                    ": (%d) Abort requested for %p (%d)", GetCurrentThreadId (),
1452                    thread, thread->tid));
1453         
1454         /* Make sure the thread is awake */
1455         mono_thread_resume (thread);
1456         
1457         signal_thread_state_change (thread);
1458 }
1459
1460 void
1461 ves_icall_System_Threading_Thread_ResetAbort (void)
1462 {
1463         MonoThread *thread = mono_thread_current ();
1464
1465         MONO_ARCH_SAVE_REGS;
1466         
1467         mono_monitor_enter (thread->synch_lock);
1468         
1469         thread->state &= ~ThreadState_AbortRequested;
1470         
1471         if (!thread->abort_exc) {
1472                 const char *msg = "Unable to reset abort because no abort was requested";
1473                 mono_monitor_exit (thread->synch_lock);
1474                 mono_raise_exception (mono_get_exception_thread_state (msg));
1475         } else {
1476                 thread->abort_exc = NULL;
1477                 thread->abort_state = NULL;
1478         }
1479         
1480         mono_monitor_exit (thread->synch_lock);
1481 }
1482
1483 static gboolean
1484 mono_thread_suspend (MonoThread *thread)
1485 {
1486         MONO_ARCH_SAVE_REGS;
1487
1488         mono_monitor_enter (thread->synch_lock);
1489
1490         if ((thread->state & ThreadState_Unstarted) != 0 || 
1491                 (thread->state & ThreadState_Aborted) != 0 || 
1492                 (thread->state & ThreadState_Stopped) != 0)
1493         {
1494                 mono_monitor_exit (thread->synch_lock);
1495                 return FALSE;
1496         }
1497
1498         if ((thread->state & ThreadState_Suspended) != 0 || 
1499                 (thread->state & ThreadState_SuspendRequested) != 0 ||
1500                 (thread->state & ThreadState_StopRequested) != 0) 
1501         {
1502                 mono_monitor_exit (thread->synch_lock);
1503                 return TRUE;
1504         }
1505         
1506         thread->state |= ThreadState_SuspendRequested;
1507         mono_monitor_exit (thread->synch_lock);
1508
1509         signal_thread_state_change (thread);
1510         return TRUE;
1511 }
1512
1513 void
1514 ves_icall_System_Threading_Thread_Suspend (MonoThread *thread)
1515 {
1516         if (!mono_thread_suspend (thread))
1517                 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
1518 }
1519
1520 static gboolean
1521 mono_thread_resume (MonoThread *thread)
1522 {
1523         MONO_ARCH_SAVE_REGS;
1524
1525         mono_monitor_enter (thread->synch_lock);
1526
1527         if ((thread->state & ThreadState_SuspendRequested) != 0) {
1528                 thread->state &= ~ThreadState_SuspendRequested;
1529                 mono_monitor_exit (thread->synch_lock);
1530                 return TRUE;
1531         }
1532
1533         if ((thread->state & ThreadState_Suspended) == 0 ||
1534                 (thread->state & ThreadState_Unstarted) != 0 || 
1535                 (thread->state & ThreadState_Aborted) != 0 || 
1536                 (thread->state & ThreadState_Stopped) != 0)
1537         {
1538                 mono_monitor_exit (thread->synch_lock);
1539                 return FALSE;
1540         }
1541         
1542         thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1543         
1544         /* Awake the thread */
1545         SetEvent (thread->suspend_event);
1546
1547         mono_monitor_exit (thread->synch_lock);
1548
1549         /* Wait for the thread to awake */
1550         WaitForSingleObject (thread->resume_event, INFINITE);
1551         CloseHandle (thread->resume_event);
1552         thread->resume_event = NULL;
1553
1554         return TRUE;
1555 }
1556
1557 void
1558 ves_icall_System_Threading_Thread_Resume (MonoThread *thread)
1559 {
1560         if (!mono_thread_resume (thread))
1561                 mono_raise_exception (mono_get_exception_thread_state ("Thread has not been started, or is dead."));
1562 }
1563
1564 static gboolean
1565 find_wrapper (MonoMethod *m, gint no, gint ilo, gboolean managed, gpointer data)
1566 {
1567         if (managed)
1568                 return TRUE;
1569
1570         if (m->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
1571                 m->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE ||
1572                 m->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH) 
1573         {
1574                 *((gboolean*)data) = TRUE;
1575                 return TRUE;
1576         }
1577         return FALSE;
1578 }
1579
1580 static gboolean 
1581 is_running_protected_wrapper (void)
1582 {
1583         gboolean found = FALSE;
1584         mono_stack_walk (find_wrapper, &found);
1585         return found;
1586 }
1587
1588 void mono_thread_stop (MonoThread *thread)
1589 {
1590         mono_monitor_enter (thread->synch_lock);
1591
1592         if ((thread->state & ThreadState_StopRequested) != 0 ||
1593                 (thread->state & ThreadState_Stopped) != 0)
1594         {
1595                 mono_monitor_exit (thread->synch_lock);
1596                 return;
1597         }
1598         
1599         /* Make sure the thread is awake */
1600         mono_thread_resume (thread);
1601         
1602         thread->state |= ThreadState_StopRequested;
1603         thread->state &= ~ThreadState_AbortRequested;
1604         
1605         mono_monitor_exit (thread->synch_lock);
1606         
1607         signal_thread_state_change (thread);
1608 }
1609
1610 gint8
1611 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
1612 {
1613         return *((volatile gint8 *) (ptr));
1614 }
1615
1616 gint16
1617 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
1618 {
1619         return *((volatile gint16 *) (ptr));
1620 }
1621
1622 gint32
1623 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
1624 {
1625         return *((volatile gint32 *) (ptr));
1626 }
1627
1628 gint64
1629 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
1630 {
1631         return *((volatile gint64 *) (ptr));
1632 }
1633
1634 void *
1635 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
1636 {
1637         return (void *)  *((volatile void **) ptr);
1638 }
1639
1640 void
1641 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
1642 {
1643         *((volatile gint8 *) ptr) = value;
1644 }
1645
1646 void
1647 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
1648 {
1649         *((volatile gint16 *) ptr) = value;
1650 }
1651
1652 void
1653 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
1654 {
1655         *((volatile gint32 *) ptr) = value;
1656 }
1657
1658 void
1659 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
1660 {
1661         *((volatile gint64 *) ptr) = value;
1662 }
1663
1664 void
1665 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
1666 {
1667         *((volatile void **) ptr) = value;
1668 }
1669
1670 void mono_thread_init (MonoThreadStartCB start_cb,
1671                        MonoThreadAttachCB attach_cb)
1672 {
1673         InitializeCriticalSection(&threads_mutex);
1674         InitializeCriticalSection(&interlocked_mutex);
1675         InitializeCriticalSection(&contexts_mutex);
1676         background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1677         
1678         mono_init_static_data_info (&thread_static_info);
1679         mono_init_static_data_info (&context_static_info);
1680
1681         current_object_key=TlsAlloc();
1682         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Allocated current_object_key %d",
1683                    current_object_key));
1684
1685         mono_thread_start_cb = start_cb;
1686         mono_thread_attach_cb = attach_cb;
1687
1688         /* Get a pseudo handle to the current process.  This is just a
1689          * kludge so that wapi can build a process handle if needed.
1690          * As a pseudo handle is returned, we don't need to clean
1691          * anything up.
1692          */
1693         GetCurrentProcess ();
1694 }
1695
1696 void
1697 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
1698 {
1699         mono_thread_cleanup = func;
1700 }
1701
1702 void mono_install_thread_callbacks (MonoThreadCallbacks *callbacks)
1703 {
1704         mono_thread_callbacks = callbacks;
1705 }
1706
1707 G_GNUC_UNUSED
1708 static void print_tids (gpointer key, gpointer value, gpointer user)
1709 {
1710         g_message ("Waiting for: %d", GPOINTER_TO_UINT(key));
1711 }
1712
1713 struct wait_data 
1714 {
1715         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1716         MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
1717         guint32 num;
1718 };
1719
1720 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
1721 {
1722         guint32 i, ret;
1723         
1724         THREAD_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION
1725                   ": %d threads to wait for in this batch", wait->num));
1726
1727         ret=WaitForMultipleObjectsEx(wait->num, wait->handles, TRUE, timeout, FALSE);
1728
1729         if(ret==WAIT_FAILED) {
1730                 /* See the comment in build_wait_tids() */
1731                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Wait failed"));
1732                 return;
1733         }
1734         
1735         for(i=0; i<wait->num; i++)
1736                 CloseHandle (wait->handles[i]);
1737
1738         if (ret == WAIT_TIMEOUT)
1739                 return;
1740
1741         for(i=0; i<wait->num; i++) {
1742                 guint32 tid=wait->threads[i]->tid;
1743                 
1744                 if(mono_g_hash_table_lookup (threads, GUINT_TO_POINTER(tid))!=NULL) {
1745                         /* This thread must have been killed, because
1746                          * it hasn't cleaned itself up. (It's just
1747                          * possible that the thread exited before the
1748                          * parent thread had a chance to store the
1749                          * handle, and now there is another pointer to
1750                          * the already-exited thread stored.  In this
1751                          * case, we'll just get two
1752                          * mono_profiler_thread_end() calls for the
1753                          * same thread.)
1754                          */
1755         
1756                         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
1757                                    ": cleaning up after thread %d", tid));
1758                         thread_cleanup (wait->threads[i]);
1759                 }
1760         }
1761 }
1762
1763 static void wait_for_tids_or_state_change (struct wait_data *wait, guint32 timeout)
1764 {
1765         guint32 i, ret, count;
1766         
1767         THREAD_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION
1768                   ": %d threads to wait for in this batch", wait->num));
1769
1770         /* Add the thread state change event, so it wakes up if a thread changes
1771          * to background mode.
1772          */
1773         count = wait->num;
1774         if (count < MAXIMUM_WAIT_OBJECTS) {
1775                 wait->handles [count] = background_change_event;
1776                 count++;
1777         }
1778
1779         ret=WaitForMultipleObjectsEx (count, wait->handles, FALSE, timeout, FALSE);
1780
1781         if(ret==WAIT_FAILED) {
1782                 /* See the comment in build_wait_tids() */
1783                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Wait failed"));
1784                 return;
1785         }
1786         
1787         for(i=0; i<wait->num; i++)
1788                 CloseHandle (wait->handles[i]);
1789
1790         if (ret == WAIT_TIMEOUT)
1791                 return;
1792         
1793         if (ret < wait->num) {
1794                 guint32 tid=wait->threads[ret]->tid;
1795                 if (mono_g_hash_table_lookup (threads, GUINT_TO_POINTER(tid))!=NULL) {
1796                         /* See comment in wait_for_tids about thread cleanup */
1797                         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
1798                                    ": cleaning up after thread %d", tid));
1799                         thread_cleanup (wait->threads[i]);
1800                 }
1801         }
1802 }
1803
1804 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
1805 {
1806         struct wait_data *wait=(struct wait_data *)user;
1807
1808         if(wait->num<MAXIMUM_WAIT_OBJECTS) {
1809                 HANDLE handle;
1810                 MonoThread *thread=(MonoThread *)value;
1811
1812                 /* Ignore background threads, we abort them later */
1813                 mono_monitor_enter (thread->synch_lock);
1814                 if (thread->state & ThreadState_Background) {
1815                         mono_monitor_exit (thread->synch_lock);
1816                         return; /* just leave, ignore */
1817                 }
1818                 mono_monitor_exit (thread->synch_lock);
1819                 
1820                 if (mono_gc_is_finalizer_thread (thread))
1821                         return;
1822
1823                 if (thread == mono_thread_current ())
1824                         return;
1825
1826                 if (thread == mono_thread_get_main ())
1827                         return;
1828
1829                 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1830                 if (handle == NULL)
1831                         return;
1832                 
1833                 wait->handles[wait->num]=handle;
1834                 wait->threads[wait->num]=thread;
1835                 wait->num++;
1836         } else {
1837                 /* Just ignore the rest, we can't do anything with
1838                  * them yet
1839                  */
1840         }
1841 }
1842
1843 static gboolean
1844 remove_and_abort_threads (gpointer key, gpointer value, gpointer user)
1845 {
1846         struct wait_data *wait=(struct wait_data *)user;
1847         guint32 self = GetCurrentThreadId ();
1848         MonoThread *thread = (MonoThread *) value;
1849         HANDLE handle;
1850
1851         /* The finalizer thread is not a background thread */
1852         if (thread->tid != self && (thread->state & ThreadState_Background) != 0) {
1853         
1854                 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1855                 if (handle == NULL)
1856                         return FALSE;
1857                 
1858                 if(thread->state & ThreadState_AbortRequested ||
1859                    thread->state & ThreadState_Aborted) {
1860                         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Thread id %d already aborting", thread->tid));
1861                         return(TRUE);
1862                 }
1863
1864                 wait->handles[wait->num]=thread->handle;
1865                 wait->threads[wait->num]=thread;
1866                 wait->num++;
1867
1868                 THREAD_DEBUG (g_print (G_GNUC_PRETTY_FUNCTION ": Aborting id: %d\n", thread->tid));
1869                 mono_thread_stop (thread);
1870                 return TRUE;
1871         }
1872
1873         return (thread->tid != self && !mono_gc_is_finalizer_thread (thread)); 
1874 }
1875
1876 void mono_thread_manage (void)
1877 {
1878         struct wait_data *wait=g_new0 (struct wait_data, 1);
1879         
1880         /* join each thread that's still running */
1881         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": Joining each running thread..."));
1882         
1883         EnterCriticalSection (&threads_mutex);
1884         if(threads==NULL) {
1885                 THREAD_DEBUG (g_message(G_GNUC_PRETTY_FUNCTION ": No threads"));
1886                 LeaveCriticalSection (&threads_mutex);
1887                 return;
1888         }
1889         LeaveCriticalSection (&threads_mutex);
1890         
1891         do {
1892                 EnterCriticalSection (&threads_mutex);
1893                 THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION
1894                           ":There are %d threads to join", mono_g_hash_table_size (threads));
1895                         mono_g_hash_table_foreach (threads, print_tids, NULL));
1896         
1897                 ResetEvent (background_change_event);
1898                 wait->num=0;
1899                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
1900                 LeaveCriticalSection (&threads_mutex);
1901                 if(wait->num>0) {
1902                         /* Something to wait for */
1903                         wait_for_tids_or_state_change (wait, INFINITE);
1904                 }
1905                 THREAD_DEBUG (g_message ("I have %d threads after waiting.", wait->num));
1906         } while(wait->num>0);
1907
1908         mono_runtime_set_shutting_down ();
1909
1910         THREAD_DEBUG (g_message ("threadpool cleanup"));
1911         mono_thread_pool_cleanup ();
1912
1913         EnterCriticalSection(&threads_mutex);
1914
1915         /* 
1916          * Remove everything but the finalizer thread and self.
1917          * Also abort all the background threads
1918          * */
1919         wait->num = 0;
1920         mono_g_hash_table_foreach_remove (threads, remove_and_abort_threads, wait);
1921
1922         LeaveCriticalSection(&threads_mutex);
1923
1924         THREAD_DEBUG (g_message ("wait->num is now %d", wait->num));
1925         if(wait->num>0) {
1926                 /* Something to wait for */
1927                 wait_for_tids (wait, INFINITE);
1928         }
1929         /* 
1930          * give the subthreads a chance to really quit (this is mainly needed
1931          * to get correct user and system times from getrusage/wait/time(1)).
1932          * This could be removed if we avoid pthread_detach() and use pthread_join().
1933          */
1934 #ifndef PLATFORM_WIN32
1935         sched_yield ();
1936 #endif
1937
1938         g_free (wait);
1939 }
1940
1941 static void terminate_thread (gpointer key, gpointer value, gpointer user)
1942 {
1943         MonoThread *thread=(MonoThread *)value;
1944         guint32 self=GPOINTER_TO_UINT (user);
1945         
1946         if(thread->tid!=self) {
1947                 /*TerminateThread (thread->handle, -1);*/
1948         }
1949 }
1950
1951 void mono_thread_abort_all_other_threads (void)
1952 {
1953         guint32 self=GetCurrentThreadId ();
1954
1955         EnterCriticalSection (&threads_mutex);
1956         THREAD_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ":There are %d threads to abort",
1957                   mono_g_hash_table_size (threads));
1958                 mono_g_hash_table_foreach (threads, print_tids, NULL));
1959
1960         mono_g_hash_table_foreach (threads, terminate_thread,
1961                                    GUINT_TO_POINTER (self));
1962         
1963         LeaveCriticalSection (&threads_mutex);
1964 }
1965
1966 static void
1967 collect_threads (gpointer key, gpointer value, gpointer user_data)
1968 {
1969         MonoThread *thread = (MonoThread*)value;
1970         struct wait_data *wait = (struct wait_data*)user_data;
1971         HANDLE handle;
1972
1973         if (wait->num<MAXIMUM_WAIT_OBJECTS) {
1974                 handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
1975                 if (handle == NULL)
1976                         return;
1977
1978                 wait->handles [wait->num] = handle;
1979                 wait->threads [wait->num] = thread;
1980                 wait->num++;
1981         }
1982 }
1983
1984 /*
1985  * mono_thread_suspend_all_other_threads:
1986  *
1987  *  Suspend all managed threads except the finalizer thread and this thread.
1988  */
1989 void mono_thread_suspend_all_other_threads (void)
1990 {
1991         struct wait_data *wait = g_new0 (struct wait_data, 1);
1992         int i, waitnum;
1993         guint32 self = GetCurrentThreadId ();
1994         gpointer *events;
1995         guint32 eventidx = 0;
1996
1997         /* 
1998          * Make a copy of the hashtable since we can't do anything with
1999          * threads while threads_mutex is held.
2000          */
2001         EnterCriticalSection (&threads_mutex);
2002         mono_g_hash_table_foreach (threads, collect_threads, wait);
2003         LeaveCriticalSection (&threads_mutex);
2004
2005         events = g_new0 (gpointer, wait->num);
2006         waitnum = 0;
2007         /* Get the suspended events that we'll be waiting for */
2008         for (i = 0; i < wait->num; ++i) {
2009                 MonoThread *thread = wait->threads [i];
2010
2011                 if ((thread->tid == self) || mono_gc_is_finalizer_thread (thread)) {
2012                         //CloseHandle (wait->handles [i]);
2013                         wait->threads [i] = NULL; /* ignore this thread in next loop */
2014                         continue;
2015                 }
2016
2017                 mono_monitor_enter (thread->synch_lock);
2018
2019                 if ((thread->state & ThreadState_Suspended) != 0 || 
2020                         (thread->state & ThreadState_SuspendRequested) != 0 ||
2021                         (thread->state & ThreadState_StopRequested) != 0 ||
2022                         (thread->state & ThreadState_Stopped) != 0) {
2023                         mono_monitor_exit (thread->synch_lock);
2024                         CloseHandle (wait->handles [i]);
2025                         wait->threads [i] = NULL; /* ignore this thread in next loop */
2026                         continue;
2027                 }
2028
2029                 /* Convert abort requests into suspend requests */
2030                 if ((thread->state & ThreadState_AbortRequested) != 0)
2031                         thread->state &= ~ThreadState_AbortRequested;
2032                         
2033                 thread->state |= ThreadState_SuspendRequested;
2034
2035                 if (thread->suspended_event == NULL)
2036                         thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2037
2038                 events [eventidx++] = thread->suspended_event;
2039                 mono_monitor_exit (thread->synch_lock);
2040
2041                 /* Signal the thread to suspend */
2042                 signal_thread_state_change (thread);
2043         }
2044
2045         WaitForMultipleObjectsEx (eventidx, events, TRUE, INFINITE, FALSE);
2046         for (i = 0; i < wait->num; ++i) {
2047                 MonoThread *thread = wait->threads [i];
2048
2049                 if (thread == NULL)
2050                         continue;
2051
2052                 mono_monitor_enter (thread->synch_lock);
2053                 CloseHandle (thread->suspended_event);
2054                 thread->suspended_event = NULL;
2055                 mono_monitor_exit (thread->synch_lock);
2056         }
2057
2058         g_free (events);
2059         g_free (wait);
2060 }
2061
2062 /*
2063  * mono_thread_push_appdomain_ref:
2064  *
2065  *   Register that the current thread may have references to objects in domain 
2066  * @domain on its stack. Each call to this function should be paired with a 
2067  * call to pop_appdomain_ref.
2068  */
2069 void 
2070 mono_thread_push_appdomain_ref (MonoDomain *domain)
2071 {
2072         MonoThread *thread = mono_thread_current ();
2073
2074         if (thread) {
2075                 /* printf ("PUSH REF: %x -> %s.\n", thread->tid, domain->friendly_name); */
2076                 EnterCriticalSection (&threads_mutex);
2077                 thread->appdomain_refs = g_slist_prepend (thread->appdomain_refs, domain);
2078                 LeaveCriticalSection (&threads_mutex);
2079         }
2080 }
2081
2082 void
2083 mono_thread_pop_appdomain_ref (void)
2084 {
2085         MonoThread *thread = mono_thread_current ();
2086
2087         if (thread) {
2088                 /* printf ("POP REF: %x -> %s.\n", thread->tid, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name); */
2089                 EnterCriticalSection (&threads_mutex);
2090                 /* FIXME: How can the list be empty ? */
2091                 if (thread->appdomain_refs)
2092                         thread->appdomain_refs = g_slist_remove (thread->appdomain_refs, thread->appdomain_refs->data);
2093                 LeaveCriticalSection (&threads_mutex);
2094         }
2095 }
2096
2097 gboolean
2098 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
2099 {
2100         gboolean res;
2101         EnterCriticalSection (&threads_mutex);
2102         res = g_slist_find (thread->appdomain_refs, domain) != NULL;
2103         LeaveCriticalSection (&threads_mutex);
2104         return res;
2105 }
2106
2107 typedef struct abort_appdomain_data {
2108         struct wait_data wait;
2109         MonoDomain *domain;
2110 } abort_appdomain_data;
2111
2112 static void
2113 abort_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
2114 {
2115         MonoThread *thread = (MonoThread*)value;
2116         abort_appdomain_data *data = (abort_appdomain_data*)user_data;
2117         MonoDomain *domain = data->domain;
2118
2119         if (mono_thread_has_appdomain_ref (thread, domain)) {
2120                 /* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
2121                 HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
2122                 if (handle == NULL)
2123                         return;
2124
2125                 ves_icall_System_Threading_Thread_Abort (thread, NULL);
2126
2127                 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
2128                         data->wait.handles [data->wait.num] = handle;
2129                         data->wait.threads [data->wait.num] = thread;
2130                         data->wait.num++;
2131                 } else {
2132                         /* Just ignore the rest, we can't do anything with
2133                          * them yet
2134                          */
2135                 }
2136         }
2137 }
2138
2139 /*
2140  * mono_threads_abort_appdomain_threads:
2141  *
2142  *   Abort threads which has references to the given appdomain.
2143  */
2144 gboolean
2145 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
2146 {
2147         abort_appdomain_data user_data;
2148         guint32 start_time;
2149
2150         /* printf ("ABORT BEGIN.\n"); */
2151
2152         start_time = GetTickCount ();
2153         do {
2154                 EnterCriticalSection (&threads_mutex);
2155
2156                 user_data.domain = domain;
2157                 user_data.wait.num = 0;
2158                 mono_g_hash_table_foreach (threads, abort_appdomain_thread, &user_data);
2159                 LeaveCriticalSection (&threads_mutex);
2160
2161                 if (user_data.wait.num > 0)
2162                         wait_for_tids (&user_data.wait, timeout);
2163
2164                 /* Update remaining time */
2165                 timeout -= GetTickCount () - start_time;
2166                 start_time = GetTickCount ();
2167
2168                 if (timeout < 0)
2169                         return FALSE;
2170         }
2171         while (user_data.wait.num > 0);
2172
2173         /* printf ("ABORT DONE.\n"); */
2174
2175         return TRUE;
2176 }
2177
2178 static void
2179 clear_cached_culture (gpointer key, gpointer value, gpointer user_data)
2180 {
2181         MonoThread *thread = (MonoThread*)value;
2182         MonoDomain *domain = (MonoDomain*)user_data;
2183         int i;
2184
2185         /* No locking needed here */
2186
2187         if (thread->culture_info) {
2188                 for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
2189                         if (thread->culture_info [i] && thread->culture_info [i]->vtable->domain == domain)
2190                                 thread->culture_info [i] = NULL;
2191                 }
2192         }
2193         if (thread->ui_culture_info) {
2194                 for (i = 0; i < NUM_CACHED_CULTURES; ++i) {
2195                         if (thread->ui_culture_info [i] && thread->ui_culture_info [i]->vtable->domain == domain)
2196                                 thread->ui_culture_info [i] = NULL;
2197                 }
2198         }
2199 }
2200         
2201 /*
2202  * mono_threads_clear_cached_culture:
2203  *
2204  *   Clear the cached_current_culture from all threads if it is in the
2205  * given appdomain.
2206  */
2207 void
2208 mono_threads_clear_cached_culture (MonoDomain *domain)
2209 {
2210         EnterCriticalSection (&threads_mutex);
2211         mono_g_hash_table_foreach (threads, clear_cached_culture, domain);
2212         LeaveCriticalSection (&threads_mutex);
2213 }
2214
2215 /*
2216  * mono_thread_get_pending_exception:
2217  *
2218  *   Return an exception which needs to be raised when leaving a catch clause.
2219  * This is used for undeniable exception propagation.
2220  */
2221 MonoException*
2222 mono_thread_get_pending_exception (void)
2223 {
2224         MonoThread *thread = mono_thread_current ();
2225
2226         MONO_ARCH_SAVE_REGS;
2227
2228         if (thread && thread->abort_exc && !is_running_protected_wrapper ()) {
2229                 /*
2230                  * FIXME: Clear the abort exception and return an AppDomainUnloaded 
2231                  * exception if the thread no longer references a dying appdomain.
2232                  */
2233                 thread->abort_exc->trace_ips = NULL;
2234                 thread->abort_exc->stack_trace = NULL;
2235                 return thread->abort_exc;
2236         }
2237
2238         return NULL;
2239 }
2240
2241 #define NUM_STATIC_DATA_IDX 8
2242 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
2243         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
2244 };
2245
2246
2247 /*
2248  *  mono_alloc_static_data
2249  *
2250  *   Allocate memory blocks for storing threads or context static data
2251  */
2252 static void 
2253 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset)
2254 {
2255         guint idx = (offset >> 24) - 1;
2256         int i;
2257
2258         gpointer* static_data = *static_data_ptr;
2259         if (!static_data) {
2260                 static_data = mono_gc_alloc_fixed (static_data_size [0], NULL);
2261                 *static_data_ptr = static_data;
2262                 static_data [0] = static_data;
2263         }
2264
2265         for (i = 1; i <= idx; ++i) {
2266                 if (static_data [i])
2267                         continue;
2268                 static_data [i] = mono_gc_alloc_fixed (static_data_size [i], NULL);
2269         }
2270 }
2271
2272 /*
2273  *  mono_init_static_data_info
2274  *
2275  *   Initializes static data counters
2276  */
2277 static void mono_init_static_data_info (StaticDataInfo *static_data)
2278 {
2279         static_data->idx = 0;
2280         static_data->offset = 0;
2281 }
2282
2283 /*
2284  *  mono_alloc_static_data_slot
2285  *
2286  *   Generates an offset for static data. static_data contains the counters
2287  *  used to generate it.
2288  */
2289 static guint32
2290 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
2291 {
2292         guint32 offset;
2293
2294         if (!static_data->idx && !static_data->offset) {
2295                 /* 
2296                  * we use the first chunk of the first allocation also as
2297                  * an array for the rest of the data 
2298                  */
2299                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
2300         }
2301         static_data->offset += align - 1;
2302         static_data->offset &= ~(align - 1);
2303         if (static_data->offset + size >= static_data_size [static_data->idx]) {
2304                 static_data->idx ++;
2305                 g_assert (size <= static_data_size [static_data->idx]);
2306                 /* 
2307                  * massive unloading and reloading of domains with thread-static
2308                  * data may eventually exceed the allocated storage...
2309                  * Need to check what the MS runtime does in that case.
2310                  * Note that for each appdomain, we need to allocate a separate
2311                  * thread data slot for security reasons. We could keep track
2312                  * of the slots per-domain and when the domain is unloaded
2313                  * out the slots on a sort of free list.
2314                  */
2315                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
2316                 static_data->offset = 0;
2317         }
2318         offset = static_data->offset | ((static_data->idx + 1) << 24);
2319         static_data->offset += size;
2320         return offset;
2321 }
2322
2323 /* 
2324  * ensure thread static fields already allocated are valid for thread
2325  * This function is called when a thread is created or on thread attach.
2326  */
2327 static void
2328 thread_adjust_static_data (MonoThread *thread)
2329 {
2330         guint32 offset;
2331
2332         EnterCriticalSection (&threads_mutex);
2333         if (thread_static_info.offset || thread_static_info.idx > 0) {
2334                 /* get the current allocated size */
2335                 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
2336                 mono_alloc_static_data (&(thread->static_data), offset);
2337         }
2338         LeaveCriticalSection (&threads_mutex);
2339 }
2340
2341 static void 
2342 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
2343 {
2344         MonoThread *thread = value;
2345         guint32 offset = GPOINTER_TO_UINT (user);
2346         
2347         mono_alloc_static_data (&(thread->static_data), offset);
2348 }
2349
2350 /*
2351  * The offset for a special static variable is composed of three parts:
2352  * a bit that indicates the type of static data (0:thread, 1:context),
2353  * an index in the array of chunks of memory for the thread (thread->static_data)
2354  * and an offset in that chunk of mem. This allows allocating less memory in the 
2355  * common case.
2356  */
2357
2358 guint32
2359 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align)
2360 {
2361         guint32 offset;
2362         if (static_type == SPECIAL_STATIC_THREAD)
2363         {
2364                 EnterCriticalSection (&threads_mutex);
2365                 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
2366                 /* This can be called during startup */
2367                 if (threads != NULL)
2368                         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
2369                 LeaveCriticalSection (&threads_mutex);
2370         }
2371         else
2372         {
2373                 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
2374                 EnterCriticalSection (&contexts_mutex);
2375                 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
2376                 LeaveCriticalSection (&contexts_mutex);
2377                 offset |= 0x80000000;   /* Set the high bit to indicate context static data */
2378         }
2379         return offset;
2380 }
2381
2382 gpointer
2383 mono_get_special_static_data (guint32 offset)
2384 {
2385         /* The high bit means either thread (0) or static (1) data. */
2386
2387         guint32 static_type = (offset & 0x80000000);
2388         int idx;
2389
2390         offset &= 0x7fffffff;
2391         idx = (offset >> 24) - 1;
2392
2393         if (static_type == 0)
2394         {
2395                 MonoThread *thread = mono_thread_current ();
2396                 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
2397         }
2398         else
2399         {
2400                 /* Allocate static data block under demand, since we don't have a list
2401                 // of contexts
2402                 */
2403                 MonoAppContext *context = mono_context_get ();
2404                 if (!context->static_data || !context->static_data [idx]) {
2405                         EnterCriticalSection (&contexts_mutex);
2406                         mono_alloc_static_data (&(context->static_data), offset);
2407                         LeaveCriticalSection (&contexts_mutex);
2408                 }
2409                 return ((char*) context->static_data [idx]) + (offset & 0xffffff);      
2410         }
2411 }
2412
2413 static void gc_stop_world (gpointer key, gpointer value, gpointer user)
2414 {
2415         MonoThread *thread=(MonoThread *)value;
2416         guint32 self=GPOINTER_TO_UINT (user);
2417
2418         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid));
2419
2420         if(thread->tid==self)
2421                 return;
2422
2423         SuspendThread (thread->handle);
2424 }
2425
2426 void mono_gc_stop_world (void)
2427 {
2428         guint32 self=GetCurrentThreadId ();
2429
2430         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads));
2431
2432         EnterCriticalSection (&threads_mutex);
2433
2434         if (threads != NULL)
2435                 mono_g_hash_table_foreach (threads, gc_stop_world, GUINT_TO_POINTER (self));
2436         
2437         LeaveCriticalSection (&threads_mutex);
2438 }
2439
2440 static void gc_start_world (gpointer key, gpointer value, gpointer user)
2441 {
2442         MonoThread *thread=(MonoThread *)value;
2443         guint32 self=GPOINTER_TO_UINT (user);
2444         
2445         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid));
2446
2447         if(thread->tid==self)
2448                 return;
2449
2450         ResumeThread (thread->handle);
2451 }
2452
2453 void mono_gc_start_world (void)
2454 {
2455         guint32 self=GetCurrentThreadId ();
2456
2457         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads));
2458
2459         EnterCriticalSection (&threads_mutex);
2460
2461         if (threads != NULL)
2462                 mono_g_hash_table_foreach (threads, gc_start_world, GUINT_TO_POINTER (self));
2463         
2464         LeaveCriticalSection (&threads_mutex);
2465 }
2466
2467 #ifdef __MINGW32__
2468 static CALLBACK void dummy_apc (ULONG_PTR param)
2469 {
2470 }
2471 #else
2472 static guint32 dummy_apc (gpointer param)
2473 {
2474         return 0;
2475 }
2476 #endif
2477
2478 /*
2479  * mono_thread_execute_interruption
2480  * 
2481  * Performs the operation that the requested thread state requires (abort,
2482  * suspend or stop)
2483  */
2484 static MonoException* mono_thread_execute_interruption (MonoThread *thread)
2485 {
2486         mono_monitor_enter (thread->synch_lock);
2487
2488         if (thread->interruption_requested) {
2489                 /* this will consume pending APC calls */
2490                 WaitForSingleObjectEx (GetCurrentThread(), 0, TRUE);
2491                 InterlockedDecrement (&thread_interruption_requested);
2492                 thread->interruption_requested = FALSE;
2493         }
2494
2495         if ((thread->state & ThreadState_AbortRequested) != 0) {
2496                 if (thread->abort_exc == NULL)
2497                         thread->abort_exc = mono_get_exception_thread_abort ();
2498                 mono_monitor_exit (thread->synch_lock);
2499                 return thread->abort_exc;
2500         }
2501         else if ((thread->state & ThreadState_SuspendRequested) != 0) {
2502                 thread->state &= ~ThreadState_SuspendRequested;
2503                 thread->state |= ThreadState_Suspended;
2504                 thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
2505                 if (thread->suspended_event)
2506                         SetEvent (thread->suspended_event);
2507                 mono_monitor_exit (thread->synch_lock);
2508                 
2509                 WaitForSingleObject (thread->suspend_event, INFINITE);
2510                 
2511                 mono_monitor_enter (thread->synch_lock);
2512                 CloseHandle (thread->suspend_event);
2513                 thread->suspend_event = NULL;
2514                 thread->state &= ~ThreadState_Suspended;
2515         
2516                 /* The thread that requested the resume will have replaced this event
2517                  * and will be waiting for it
2518                  */
2519                 SetEvent (thread->resume_event);
2520                 mono_monitor_exit (thread->synch_lock);
2521                 return NULL;
2522         }
2523         else if ((thread->state & ThreadState_StopRequested) != 0) {
2524                 /* FIXME: do this through the JIT? */
2525                 mono_monitor_exit (thread->synch_lock);
2526                 mono_thread_exit ();
2527                 return NULL;
2528         }
2529         
2530         mono_monitor_exit (thread->synch_lock);
2531         return NULL;
2532 }
2533
2534 /*
2535  * mono_thread_request_interruption
2536  *
2537  * A signal handler can call this method to request the interruption of a
2538  * thread. The result of the interruption will depend on the current state of
2539  * the thread. If the result is an exception that needs to be throw, it is 
2540  * provided as return value.
2541  */
2542 MonoException* mono_thread_request_interruption (gboolean running_managed)
2543 {
2544         MonoThread *thread = mono_thread_current ();
2545
2546         /* The thread may already be stopping */
2547         if (thread == NULL) 
2548                 return NULL;
2549         
2550         mono_monitor_enter (thread->synch_lock);
2551         
2552         if (thread->interruption_requested) {
2553                 mono_monitor_exit (thread->synch_lock);
2554                 return NULL;
2555         }
2556
2557         if (!running_managed || is_running_protected_wrapper ()) {
2558                 /* Can't stop while in unmanaged code. Increase the global interruption
2559                    request count. When exiting the unmanaged method the count will be
2560                    checked and the thread will be interrupted. */
2561
2562                 InterlockedIncrement (&thread_interruption_requested);
2563                 thread->interruption_requested = TRUE;
2564                 mono_monitor_exit (thread->synch_lock);
2565
2566                 /* this will awake the thread if it is in WaitForSingleObject 
2567                    or similar */
2568                 QueueUserAPC ((PAPCFUNC)dummy_apc, thread->handle, NULL);
2569                 return NULL;
2570         }
2571         else {
2572                 mono_monitor_exit (thread->synch_lock);
2573                 return mono_thread_execute_interruption (thread);
2574         }
2575 }
2576
2577 gboolean mono_thread_interruption_requested ()
2578 {
2579         if (thread_interruption_requested) {
2580                 MonoThread *thread = mono_thread_current ();
2581                 /* The thread may already be stopping */
2582                 if (thread != NULL) 
2583                         return (thread->interruption_requested);
2584         }
2585         return FALSE;
2586 }
2587
2588 static void mono_thread_interruption_checkpoint_request (gboolean bypass_abort_protection)
2589 {
2590         MonoThread *thread = mono_thread_current ();
2591
2592         /* The thread may already be stopping */
2593         if (thread == NULL)
2594                 return;
2595         
2596         if (thread->interruption_requested && (bypass_abort_protection || !is_running_protected_wrapper ())) {
2597                 MonoException* exc = mono_thread_execute_interruption (thread);
2598                 if (exc) mono_raise_exception (exc);
2599         }
2600 }
2601
2602 /*
2603  * Performs the interruption of the current thread, if one has been requested,
2604  * and the thread is not running a protected wrapper.
2605  */
2606 void mono_thread_interruption_checkpoint ()
2607 {
2608         mono_thread_interruption_checkpoint_request (FALSE);
2609 }
2610
2611 /*
2612  * Performs the interruption of the current thread, if one has been requested.
2613  */
2614 void mono_thread_force_interruption_checkpoint ()
2615 {
2616         mono_thread_interruption_checkpoint_request (TRUE);
2617 }
2618
2619 /**
2620  * mono_thread_interruption_request_flag:
2621  *
2622  * Returns the address of a flag that will be non-zero if an interruption has
2623  * been requested for a thread. The thread to interrupt may not be the current
2624  * thread, so an additional call to mono_thread_interruption_requested() or
2625  * mono_thread_interruption_checkpoint() is allways needed if the flag is not
2626  * zero.
2627  */
2628 gint32* mono_thread_interruption_request_flag ()
2629 {
2630         return &thread_interruption_requested;
2631 }
2632
2633 #ifdef WITH_INCLUDED_LIBGC
2634
2635 static void gc_push_all_stacks (gpointer key, gpointer value, gpointer user)
2636 {
2637         MonoThread *thread=(MonoThread *)value;
2638         guint32 *selfp=(guint32 *)user, self = *selfp;
2639
2640         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d - %p", self, thread->tid, thread->stack_ptr));
2641
2642         if(thread->tid==self) {
2643                 LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %p - %p", selfp, thread->stack_ptr));
2644                 GC_push_all_stack (selfp, thread->stack_ptr);
2645                 return;
2646         }
2647
2648 #ifdef PLATFORM_WIN32
2649         GC_win32_push_thread_stack (thread->handle, thread->stack_ptr);
2650 #else
2651         mono_wapi_push_thread_stack (thread->handle, thread->stack_ptr);
2652 #endif
2653 }
2654
2655 void mono_gc_push_all_stacks (void)
2656 {
2657         guint32 self=GetCurrentThreadId ();
2658
2659         LIBGC_DEBUG (g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads));
2660
2661         EnterCriticalSection (&threads_mutex);
2662
2663         if (threads != NULL)
2664                 mono_g_hash_table_foreach (threads, gc_push_all_stacks, &self);
2665         
2666         LeaveCriticalSection (&threads_mutex);
2667 }
2668
2669 #endif /* WITH_INCLUDED_LIBGC */