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