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