2003-11-24 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,char *name) { 
748         MONO_ARCH_SAVE_REGS;
749    
750         return(CreateMutex(NULL,owned,name));                    
751 }                                                                   
752
753 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) { 
754         MONO_ARCH_SAVE_REGS;
755
756         ReleaseMutex(handle);
757 }
758
759 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, char *name) {
760         MONO_ARCH_SAVE_REGS;
761
762         return (CreateEvent(NULL,manual,initial,name));
763 }
764
765 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
766         MONO_ARCH_SAVE_REGS;
767
768         return (SetEvent(handle));
769 }
770
771 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
772         MONO_ARCH_SAVE_REGS;
773
774         return (ResetEvent(handle));
775 }
776
777 void
778 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
779         MONO_ARCH_SAVE_REGS;
780
781         CloseHandle (handle);
782 }
783
784 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
785 {
786         MONO_ARCH_SAVE_REGS;
787
788         return InterlockedIncrement (location);
789 }
790
791 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
792 {
793         gint32 lowret;
794         gint32 highret;
795
796         MONO_ARCH_SAVE_REGS;
797
798         EnterCriticalSection(&interlocked_mutex);
799
800         lowret = InterlockedIncrement((gint32 *) location);
801         if (0 == lowret)
802                 highret = InterlockedIncrement((gint32 *) location + 1);
803         else
804                 highret = *((gint32 *) location + 1);
805
806         LeaveCriticalSection(&interlocked_mutex);
807
808         return (gint64) highret << 32 | (gint64) lowret;
809 }
810
811 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
812 {
813         MONO_ARCH_SAVE_REGS;
814
815         return InterlockedDecrement(location);
816 }
817
818 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
819 {
820         gint32 lowret;
821         gint32 highret;
822
823         MONO_ARCH_SAVE_REGS;
824
825         EnterCriticalSection(&interlocked_mutex);
826
827         lowret = InterlockedDecrement((gint32 *) location);
828         if (-1 == lowret)
829                 highret = InterlockedDecrement((gint32 *) location + 1);
830         else
831                 highret = *((gint32 *) location + 1);
832
833         LeaveCriticalSection(&interlocked_mutex);
834
835         return (gint64) highret << 32 | (gint64) lowret;
836 }
837
838 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location1, gint32 value)
839 {
840         MONO_ARCH_SAVE_REGS;
841
842         return InterlockedExchange(location1, value);
843 }
844
845 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location1, MonoObject *value)
846 {
847         MONO_ARCH_SAVE_REGS;
848
849         return (MonoObject *) InterlockedExchangePointer((gpointer *) location1, value);
850 }
851
852 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location1, gfloat value)
853 {
854         IntFloatUnion val, ret;
855
856         MONO_ARCH_SAVE_REGS;
857
858         val.fval = value;
859         ret.ival = InterlockedExchange((gint32 *) location1, val.ival);
860
861         return ret.fval;
862 }
863
864 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location1, gint32 value, gint32 comparand)
865 {
866         MONO_ARCH_SAVE_REGS;
867
868         return InterlockedCompareExchange(location1, value, comparand);
869 }
870
871 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location1, MonoObject *value, MonoObject *comparand)
872 {
873         MONO_ARCH_SAVE_REGS;
874
875         return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location1, value, comparand);
876 }
877
878 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location1, gfloat value, gfloat comparand)
879 {
880         IntFloatUnion val, ret, cmp;
881
882         MONO_ARCH_SAVE_REGS;
883
884         val.fval = value;
885         cmp.fval = comparand;
886         ret.ival = InterlockedCompareExchange((gint32 *) location1, val.ival, cmp.ival);
887
888         return ret.fval;
889 }
890
891 int  
892 mono_thread_get_abort_signal (void)
893 {
894 #ifdef __MINGW32__
895         return -1;
896 #else
897 #ifndef SIGRTMIN
898         return SIGUSR1;
899 #else
900         return SIGRTMIN;
901 #endif
902 #endif /* __MINGW32__ */
903 }
904
905 void
906 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
907 {
908         MONO_ARCH_SAVE_REGS;
909
910         thread->abort_state = state;
911         thread->abort_exc = NULL;
912
913 #ifdef THREAD_DEBUG
914         g_message (G_GNUC_PRETTY_FUNCTION
915                    ": (%d) Abort requested for %p (%d)", GetCurrentThreadId (),
916                    thread, thread->tid);
917 #endif
918         
919 #ifdef __MINGW32__
920         g_assert_not_reached ();
921 #else
922         /* fixme: store the state somewhere */
923 #ifdef PTHREAD_POINTER_ID
924         pthread_kill (GUINT_TO_POINTER(thread->tid), mono_thread_get_abort_signal ());
925 #else
926         pthread_kill (thread->tid, mono_thread_get_abort_signal ());
927 #endif
928 #endif /* __MINGW32__ */
929 }
930
931 void
932 ves_icall_System_Threading_Thread_ResetAbort (void)
933 {
934         MonoThread *thread = mono_thread_current ();
935         
936         MONO_ARCH_SAVE_REGS;
937
938         if (!thread->abort_exc) {
939                 const char *msg = "Unable to reset abort because no abort was requested";
940                 mono_raise_exception (mono_get_exception_thread_state (msg));
941         } else {
942                 thread->abort_exc = NULL;
943                 thread->abort_state = NULL;
944         }
945 }
946
947 gint8
948 ves_icall_System_Threading_Thread_VolatileRead1 (void *ptr)
949 {
950         return *((volatile gint8 *) (ptr));
951 }
952
953 gint16
954 ves_icall_System_Threading_Thread_VolatileRead2 (void *ptr)
955 {
956         return *((volatile gint16 *) (ptr));
957 }
958
959 gint32
960 ves_icall_System_Threading_Thread_VolatileRead4 (void *ptr)
961 {
962         return *((volatile gint32 *) (ptr));
963 }
964
965 gint64
966 ves_icall_System_Threading_Thread_VolatileRead8 (void *ptr)
967 {
968         return *((volatile gint64 *) (ptr));
969 }
970
971 void *
972 ves_icall_System_Threading_Thread_VolatileReadIntPtr (void *ptr)
973 {
974         return (void *)  *((volatile void **) ptr);
975 }
976
977 void
978 ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
979 {
980         *((volatile gint8 *) ptr) = value;
981 }
982
983 void
984 ves_icall_System_Threading_Thread_VolatileWrite2 (void *ptr, gint16 value)
985 {
986         *((volatile gint16 *) ptr) = value;
987 }
988
989 void
990 ves_icall_System_Threading_Thread_VolatileWrite4 (void *ptr, gint32 value)
991 {
992         *((volatile gint32 *) ptr) = value;
993 }
994
995 void
996 ves_icall_System_Threading_Thread_VolatileWrite8 (void *ptr, gint64 value)
997 {
998         *((volatile gint64 *) ptr) = value;
999 }
1000
1001 void
1002 ves_icall_System_Threading_Thread_VolatileWriteIntPtr (void *ptr, void *value)
1003 {
1004         *((volatile void **) ptr) = value;
1005 }
1006
1007 void mono_thread_init (MonoThreadStartCB start_cb,
1008                        MonoThreadAttachCB attach_cb)
1009 {
1010         InitializeCriticalSection(&threads_mutex);
1011         InitializeCriticalSection(&interlocked_mutex);
1012         InitializeCriticalSection(&contexts_mutex);
1013         
1014         mono_init_static_data_info (&thread_static_info);
1015         mono_init_static_data_info (&context_static_info);
1016
1017         current_object_key=TlsAlloc();
1018 #ifdef THREAD_DEBUG
1019         g_message (G_GNUC_PRETTY_FUNCTION ": Allocated current_object_key %d",
1020                    current_object_key);
1021 #endif
1022
1023         mono_thread_start_cb = start_cb;
1024         mono_thread_attach_cb = attach_cb;
1025
1026         slothash_key=TlsAlloc();
1027
1028         /* Get a pseudo handle to the current process.  This is just a
1029          * kludge so that wapi can build a process handle if needed.
1030          * As a pseudo handle is returned, we don't need to clean
1031          * anything up.
1032          */
1033         GetCurrentProcess ();
1034 }
1035
1036 void
1037 mono_threads_install_cleanup (MonoThreadCleanupFunc func)
1038 {
1039         mono_thread_cleanup = func;
1040 }
1041
1042 void mono_install_thread_callbacks (MonoThreadCallbacks *callbacks)
1043 {
1044         mono_thread_callbacks = callbacks;
1045 }
1046
1047 #ifdef THREAD_DEBUG
1048 static void print_tids (gpointer key, gpointer value, gpointer user)
1049 {
1050         g_message ("Waiting for: %d", GPOINTER_TO_UINT(key));
1051 }
1052 #endif
1053
1054 struct wait_data 
1055 {
1056         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1057         MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
1058         guint32 num;
1059 };
1060
1061 static void wait_for_tids (struct wait_data *wait, guint32 timeout)
1062 {
1063         guint32 i, ret;
1064         
1065 #ifdef THREAD_DEBUG
1066         g_message(G_GNUC_PRETTY_FUNCTION
1067                   ": %d threads to wait for in this batch", wait->num);
1068 #endif
1069
1070         ret=WaitForMultipleObjects(wait->num, wait->handles, TRUE, timeout);
1071         if(ret==WAIT_FAILED) {
1072                 /* See the comment in build_wait_tids() */
1073 #ifdef THREAD_DEBUG
1074                 g_message (G_GNUC_PRETTY_FUNCTION ": Wait failed");
1075 #endif
1076                 return;
1077         }
1078         
1079
1080         for(i=0; i<wait->num; i++) {
1081                 guint32 tid=wait->threads[i]->tid;
1082                 
1083                 if(mono_g_hash_table_lookup (threads, GUINT_TO_POINTER(tid))!=NULL) {
1084                         /* This thread must have been killed, because
1085                          * it hasn't cleaned itself up. (It's just
1086                          * possible that the thread exited before the
1087                          * parent thread had a chance to store the
1088                          * handle, and now there is another pointer to
1089                          * the already-exited thread stored.  In this
1090                          * case, we'll just get two
1091                          * mono_profiler_thread_end() calls for the
1092                          * same thread.)
1093                          */
1094         
1095 #ifdef THREAD_DEBUG
1096                         g_message (G_GNUC_PRETTY_FUNCTION
1097                                    ": cleaning up after thread %d", tid);
1098 #endif
1099                         thread_cleanup (wait->threads[i]);
1100                 }
1101         }
1102 }
1103
1104 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
1105 {
1106         struct wait_data *wait=(struct wait_data *)user;
1107
1108         if(wait->num<MAXIMUM_WAIT_OBJECTS) {
1109                 MonoThread *thread=(MonoThread *)value;
1110
1111                 /* BUG: For now we just ignore background threads, we should abort them
1112                 */
1113                 if (thread->state & ThreadState_Background)
1114                         return; /* just leave, ignore */
1115                 
1116                 wait->handles[wait->num]=thread->handle;
1117                 wait->threads[wait->num]=thread;
1118                 wait->num++;
1119         } else {
1120                 /* Just ignore the rest, we can't do anything with
1121                  * them yet
1122                  */
1123         }
1124 }
1125
1126 void mono_thread_manage (void)
1127 {
1128         struct wait_data *wait=g_new0 (struct wait_data, 1);
1129         
1130         /* join each thread that's still running */
1131 #ifdef THREAD_DEBUG
1132         g_message(G_GNUC_PRETTY_FUNCTION ": Joining each running thread...");
1133 #endif
1134         
1135         if(threads==NULL) {
1136 #ifdef THREAD_DEBUG
1137                 g_message(G_GNUC_PRETTY_FUNCTION ": No threads");
1138 #endif
1139                 return;
1140         }
1141         
1142         do {
1143                 EnterCriticalSection (&threads_mutex);
1144 #ifdef THREAD_DEBUG
1145                 g_message(G_GNUC_PRETTY_FUNCTION
1146                           ":There are %d threads to join",
1147                           mono_g_hash_table_size (threads));
1148                 mono_g_hash_table_foreach (threads, print_tids, NULL);
1149 #endif
1150
1151                 wait->num=0;
1152                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
1153         
1154                 LeaveCriticalSection (&threads_mutex);
1155                 if(wait->num>0) {
1156                         /* Something to wait for */
1157                         wait_for_tids (wait, INFINITE);
1158                 }
1159         } while(wait->num>0);
1160         
1161         g_free (wait);
1162         
1163         mono_g_hash_table_destroy(threads);
1164         threads=NULL;
1165 }
1166
1167 static void terminate_thread (gpointer key, gpointer value, gpointer user)
1168 {
1169         MonoThread *thread=(MonoThread *)value;
1170         guint32 self=GPOINTER_TO_UINT (user);
1171         
1172         if(thread->tid!=self) {
1173                 /*TerminateThread (thread->handle, -1);*/
1174         }
1175 }
1176
1177 void mono_thread_abort_all_other_threads (void)
1178 {
1179         guint32 self=GetCurrentThreadId ();
1180
1181         EnterCriticalSection (&threads_mutex);
1182 #ifdef THREAD_DEBUG
1183         g_message(G_GNUC_PRETTY_FUNCTION ":There are %d threads to abort",
1184                   mono_g_hash_table_size (threads));
1185         mono_g_hash_table_foreach (threads, print_tids, NULL);
1186 #endif
1187
1188         mono_g_hash_table_foreach (threads, terminate_thread,
1189                                    GUINT_TO_POINTER (self));
1190         
1191         LeaveCriticalSection (&threads_mutex);
1192 }
1193
1194 /*
1195  * mono_thread_push_appdomain_ref:
1196  *
1197  *   Register that the current thread may have references to objects in domain 
1198  * @domain on its stack. Each call to this function should be paired with a 
1199  * call to pop_appdomain_ref.
1200  */
1201 void 
1202 mono_thread_push_appdomain_ref (MonoDomain *domain)
1203 {
1204         MonoThread *thread = mono_thread_current ();
1205
1206         if (thread) {
1207                 //printf ("PUSH REF: %p -> %s.\n", thread, domain->friendly_name);
1208                 EnterCriticalSection (&threads_mutex);
1209                 thread->appdomain_refs = g_slist_prepend (thread->appdomain_refs, domain);
1210                 LeaveCriticalSection (&threads_mutex);
1211         }
1212 }
1213
1214 void
1215 mono_thread_pop_appdomain_ref (void)
1216 {
1217         MonoThread *thread = mono_thread_current ();
1218
1219         if (thread) {
1220                 //printf ("POP REF: %p -> %s.\n", thread, ((MonoDomain*)(thread->appdomain_refs->data))->friendly_name);
1221                 EnterCriticalSection (&threads_mutex);
1222                 thread->appdomain_refs = g_slist_remove (thread->appdomain_refs, thread->appdomain_refs->data);
1223                 LeaveCriticalSection (&threads_mutex);
1224         }
1225 }
1226
1227 static gboolean
1228 mono_thread_has_appdomain_ref (MonoThread *thread, MonoDomain *domain)
1229 {
1230         gboolean res;
1231         EnterCriticalSection (&threads_mutex);
1232         res = g_slist_find (thread->appdomain_refs, domain) != NULL;
1233         LeaveCriticalSection (&threads_mutex);
1234         return res;
1235 }
1236
1237 typedef struct abort_appdomain_data {
1238         struct wait_data wait;
1239         MonoDomain *domain;
1240 } abort_appdomain_data;
1241
1242 static void
1243 abort_appdomain_thread (gpointer key, gpointer value, gpointer user_data)
1244 {
1245         MonoThread *thread = (MonoThread*)value;
1246         abort_appdomain_data *data = (abort_appdomain_data*)user_data;
1247         MonoDomain *domain = data->domain;
1248
1249         if (mono_thread_has_appdomain_ref (thread, domain)) {
1250                 //printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread, domain->friendly_name);
1251                 ves_icall_System_Threading_Thread_Abort (thread, (MonoObject*)domain->domain);
1252
1253                 if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
1254                         data->wait.handles [data->wait.num] = thread->handle;
1255                         data->wait.threads [data->wait.num] = thread;
1256                         data->wait.num++;
1257                 } else {
1258                         /* Just ignore the rest, we can't do anything with
1259                          * them yet
1260                          */
1261                 }
1262         }
1263 }
1264
1265 /*
1266  * mono_threads_abort_appdomain_threads:
1267  *
1268  *   Abort threads which has references to the given appdomain.
1269  */
1270 gboolean
1271 mono_threads_abort_appdomain_threads (MonoDomain *domain, int timeout)
1272 {
1273         abort_appdomain_data user_data;
1274         guint32 start_time;
1275
1276         //printf ("ABORT BEGIN.\n");
1277
1278         start_time = GetTickCount ();
1279         do {
1280                 EnterCriticalSection (&threads_mutex);
1281
1282                 user_data.domain = domain;
1283                 user_data.wait.num = 0;
1284                 mono_g_hash_table_foreach (threads, abort_appdomain_thread, &user_data);
1285                 LeaveCriticalSection (&threads_mutex);
1286
1287                 if (user_data.wait.num > 0)
1288                         wait_for_tids (&user_data.wait, timeout);
1289
1290                 /* Update remaining time */
1291                 timeout -= GetTickCount () - start_time;
1292                 start_time = GetTickCount ();
1293
1294                 if (timeout < 0)
1295                         return FALSE;
1296         }
1297         while (user_data.wait.num > 0);
1298
1299         //printf ("ABORT DONE.\n");
1300
1301         return TRUE;
1302 }
1303
1304 /*
1305  * mono_thread_get_pending_exception:
1306  *
1307  *   Return an exception which needs to be raised when leaving a catch clause.
1308  * This is used for undeniable exception propagation.
1309  */
1310 MonoException*
1311 mono_thread_get_pending_exception (void)
1312 {
1313         MonoThread *thread = mono_thread_current ();
1314
1315         MONO_ARCH_SAVE_REGS;
1316
1317         if (thread && thread->abort_exc) {
1318                 /*
1319                  * FIXME: Clear the abort exception and return an AppDomainUnloaded 
1320                  * exception if the thread no longer references a dying appdomain.
1321                  */
1322                 thread->abort_exc->trace_ips = NULL;
1323                 thread->abort_exc->stack_trace = NULL;
1324                 return thread->abort_exc;
1325         }
1326
1327         return NULL;
1328 }
1329
1330 #define NUM_STATIC_DATA_IDX 8
1331 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
1332         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
1333 };
1334
1335
1336 /*
1337  *  mono_alloc_static_data
1338  *
1339  *   Allocate memory blocks for storing threads or context static data
1340  */
1341 static void 
1342 mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset)
1343 {
1344         guint idx = (offset >> 24) - 1;
1345         int i;
1346
1347         gpointer* static_data = *static_data_ptr;
1348         if (!static_data) {
1349 #if HAVE_BOEHM_GC
1350                 static_data = GC_MALLOC (static_data_size [0]);
1351 #else
1352                 static_data = g_malloc0 (static_data_size [0]);
1353 #endif
1354                 *static_data_ptr = static_data;
1355                 static_data [0] = static_data;
1356         }
1357         
1358         for (i = 1; i < idx; ++i) {
1359                 if (static_data [i])
1360                         continue;
1361 #if HAVE_BOEHM_GC
1362                 static_data [i] = GC_MALLOC (static_data_size [i]);
1363 #else
1364                 static_data [i] = g_malloc0 (static_data_size [i]);
1365 #endif
1366         }
1367 }
1368
1369 /*
1370  *  mono_init_static_data_info
1371  *
1372  *   Initializes static data counters
1373  */
1374 static void mono_init_static_data_info (StaticDataInfo *static_data)
1375 {
1376         static_data->idx = 0;
1377         static_data->offset = 0;
1378 }
1379
1380 /*
1381  *  mono_alloc_static_data_slot
1382  *
1383  *   Generates an offset for static data. static_data contains the counters
1384  *  used to generate it.
1385  */
1386 static guint32
1387 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align)
1388 {
1389         guint32 offset;
1390
1391         if (!static_data->idx && !static_data->offset) {
1392                 /* 
1393                  * we use the first chunk of the first allocation also as
1394                  * an array for the rest of the data 
1395                  */
1396                 static_data->offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
1397         }
1398         static_data->offset += align - 1;
1399         static_data->offset &= ~(align - 1);
1400         if (static_data->offset + size >= static_data_size [static_data->idx]) {
1401                 static_data->idx ++;
1402                 g_assert (size <= static_data_size [static_data->idx]);
1403                 /* 
1404                  * massive unloading and reloading of domains with thread-static
1405                  * data may eventually exceed the allocated storage...
1406                  * Need to check what the MS runtime does in that case.
1407                  * Note that for each appdomain, we need to allocate a separate
1408                  * thread data slot for security reasons. We could keep track
1409                  * of the slots per-domain and when the domain is unloaded
1410                  * out the slots on a sort of free list.
1411                  */
1412                 g_assert (static_data->idx < NUM_STATIC_DATA_IDX);
1413                 static_data->offset = 0;
1414         }
1415         offset = static_data->offset | ((static_data->idx + 1) << 24);
1416         static_data->offset += size;
1417         return offset;
1418 }
1419
1420 /* 
1421  * ensure thread static fields already allocated are valid for thread
1422  * This function is called when a thread is created or on thread attach.
1423  */
1424 static void
1425 thread_adjust_static_data (MonoThread *thread)
1426 {
1427         guint32 offset;
1428
1429         EnterCriticalSection (&threads_mutex);
1430         if (thread_static_info.offset || thread_static_info.idx > 0) {
1431                 /* get the current allocated size */
1432                 offset = thread_static_info.offset | ((thread_static_info.idx + 1) << 24);
1433                 mono_alloc_static_data (&(thread->static_data), offset);
1434         }
1435         LeaveCriticalSection (&threads_mutex);
1436 }
1437
1438 static void 
1439 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
1440 {
1441         MonoThread *thread = value;
1442         guint32 offset = GPOINTER_TO_UINT (user);
1443         
1444         mono_alloc_static_data (&(thread->static_data), offset);
1445 }
1446
1447 /*
1448  * The offset for a special static variable is composed of three parts:
1449  * a bit that indicates the type of static data (0:thread, 1:context),
1450  * an index in the array of chunks of memory for the thread (thread->static_data)
1451  * and an offset in that chunk of mem. This allows allocating less memory in the 
1452  * common case.
1453  */
1454
1455 guint32
1456 mono_alloc_special_static_data (guint32 static_type, guint32 size, guint32 align)
1457 {
1458         guint32 offset;
1459         if (static_type == SPECIAL_STATIC_THREAD)
1460         {
1461                 EnterCriticalSection (&threads_mutex);
1462                 offset = mono_alloc_static_data_slot (&thread_static_info, size, align);
1463                 mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
1464                 LeaveCriticalSection (&threads_mutex);
1465         }
1466         else
1467         {
1468                 g_assert (static_type == SPECIAL_STATIC_CONTEXT);
1469                 EnterCriticalSection (&contexts_mutex);
1470                 offset = mono_alloc_static_data_slot (&context_static_info, size, align);
1471                 LeaveCriticalSection (&contexts_mutex);
1472                 offset |= 0x80000000;   // Set the high bit to indicate context static data
1473         }
1474         return offset;
1475 }
1476
1477 gpointer
1478 mono_get_special_static_data (guint32 offset)
1479 {
1480         // The high bit means either thread (0) or static (1) data.
1481
1482         guint32 static_type = (offset & 0x80000000);
1483         offset &= 0x7fffffff;
1484         int idx = (offset >> 24) - 1;
1485
1486         if (static_type == 0)
1487         {
1488                 MonoThread *thread = mono_thread_current ();
1489                 return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
1490         }
1491         else
1492         {
1493                 // Allocate static data block under demand, since we don't have a list
1494                 // of contexts
1495                 MonoAppContext *context = mono_context_get ();
1496                 if (!context->static_data || !context->static_data [idx]) {
1497                         EnterCriticalSection (&contexts_mutex);
1498                         mono_alloc_static_data (&(context->static_data), offset);
1499                         LeaveCriticalSection (&contexts_mutex);
1500                 }
1501                 return ((char*) context->static_data [idx]) + (offset & 0xffffff);      
1502         }
1503 }
1504
1505 static void gc_stop_world (gpointer key, gpointer value, gpointer user)
1506 {
1507         MonoThread *thread=(MonoThread *)value;
1508         guint32 self=GPOINTER_TO_UINT (user);
1509
1510 #ifdef LIBGC_DEBUG
1511         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid);
1512 #endif
1513         
1514         if(thread->tid==self)
1515                 return;
1516
1517         SuspendThread (thread->handle);
1518 }
1519
1520 void mono_gc_stop_world (void)
1521 {
1522         guint32 self=GetCurrentThreadId ();
1523
1524 #ifdef LIBGC_DEBUG
1525         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
1526 #endif
1527
1528         EnterCriticalSection (&threads_mutex);
1529
1530         if (threads != NULL)
1531                 mono_g_hash_table_foreach (threads, gc_stop_world, GUINT_TO_POINTER (self));
1532         
1533         LeaveCriticalSection (&threads_mutex);
1534 }
1535
1536 static void gc_start_world (gpointer key, gpointer value, gpointer user)
1537 {
1538         MonoThread *thread=(MonoThread *)value;
1539         guint32 self=GPOINTER_TO_UINT (user);
1540         
1541 #ifdef LIBGC_DEBUG
1542         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid);
1543 #endif
1544         
1545         if(thread->tid==self)
1546                 return;
1547
1548         ResumeThread (thread->handle);
1549 }
1550
1551 void mono_gc_start_world (void)
1552 {
1553         guint32 self=GetCurrentThreadId ();
1554
1555 #ifdef LIBGC_DEBUG
1556         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
1557 #endif
1558
1559         EnterCriticalSection (&threads_mutex);
1560
1561         if (threads != NULL)
1562                 mono_g_hash_table_foreach (threads, gc_start_world, GUINT_TO_POINTER (self));
1563         
1564         LeaveCriticalSection (&threads_mutex);
1565 }
1566
1567 #ifdef WITH_INCLUDED_LIBGC
1568
1569 static void gc_push_all_stacks (gpointer key, gpointer value, gpointer user)
1570 {
1571         MonoThread *thread=(MonoThread *)value;
1572         guint32 *selfp=(guint32 *)user, self = *selfp;
1573
1574 #ifdef LIBGC_DEBUG
1575         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d - %p", self, thread->tid, thread->stack_ptr);
1576 #endif
1577         
1578         if(thread->tid==self) {
1579 #ifdef LIBGC_DEBUG
1580                 g_message (G_GNUC_PRETTY_FUNCTION ": %p - %p", selfp, thread->stack_ptr);
1581 #endif
1582                 GC_push_all_stack (selfp, thread->stack_ptr);
1583                 return;
1584         }
1585
1586 #ifdef PLATFORM_WIN32
1587         GC_win32_push_thread_stack (thread->handle, thread->stack_ptr);
1588 #else
1589         mono_wapi_push_thread_stack (thread->handle, thread->stack_ptr);
1590 #endif
1591 }
1592
1593 void mono_gc_push_all_stacks (void)
1594 {
1595         guint32 self=GetCurrentThreadId ();
1596
1597 #ifdef LIBGC_DEBUG
1598         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
1599 #endif
1600
1601         EnterCriticalSection (&threads_mutex);
1602
1603         if (threads != NULL)
1604                 mono_g_hash_table_foreach (threads, gc_push_all_stacks, &self);
1605         
1606         LeaveCriticalSection (&threads_mutex);
1607 }
1608
1609 #endif /* WITH_INCLUDED_LIBGC */