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