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