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