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