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