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