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