2003-06-17 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/threads-types.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/environment.h>
23 #include <mono/metadata/monitor.h>
24 #include <mono/io-layer/io-layer.h>
25
26 #include <mono/os/gc_wrapper.h>
27
28 #undef THREAD_DEBUG
29 #undef THREAD_WAIT_DEBUG
30
31 struct StartInfo 
32 {
33         guint32 (*func)(void *);
34         MonoThread *obj;
35         void *this;
36         MonoDomain *domain;
37 };
38
39 typedef union {
40         gint32 ival;
41         gfloat fval;
42 } IntFloatUnion;
43  
44 /*
45  * The "os_handle" field of the WaitHandle class.
46  */
47 static MonoClassField *wait_handle_os_handle_field = NULL;
48
49 /* Controls access to the 'threads' hash table */
50 static CRITICAL_SECTION threads_mutex;
51
52 /* The hash of existing threads (key is thread ID) that need joining
53  * before exit
54  */
55 static MonoGHashTable *threads=NULL;
56
57 /* The TLS key that holds the MonoObject assigned to each thread */
58 static guint32 current_object_key;
59
60 /* function called at thread start */
61 static MonoThreadStartCB mono_thread_start_cb = NULL;
62
63 /* function called at thread attach */
64 static MonoThreadAttachCB mono_thread_attach_cb = NULL;
65
66 /* function called when a new thread has been created */
67 static MonoThreadCallbacks *mono_thread_callbacks = NULL;
68
69 /* The TLS key that holds the LocalDataStoreSlot hash in each thread */
70 static guint32 slothash_key;
71
72 static void thread_adjust_static_data (MonoThread *thread);
73
74 /* Spin lock for InterlockedXXX 64 bit functions */
75 static CRITICAL_SECTION interlocked_mutex;
76
77 /* handle_store() and handle_remove() manage the array of threads that
78  * still need to be waited for when the main thread exits.
79  */
80 static void handle_store(MonoThread *thread)
81 {
82         EnterCriticalSection(&threads_mutex);
83
84 #ifdef THREAD_DEBUG
85         g_message(G_GNUC_PRETTY_FUNCTION ": thread %p ID %d", thread,
86                   thread->tid);
87 #endif
88
89         if(threads==NULL) {
90                 threads=mono_g_hash_table_new(g_direct_hash, g_direct_equal);
91         }
92
93         /* We don't need to duplicate thread->handle, because it is
94          * only closed when the thread object is finalized by the GC.
95          */
96         mono_g_hash_table_insert(threads, GUINT_TO_POINTER(thread->tid), thread);
97         LeaveCriticalSection(&threads_mutex);
98 }
99
100 static void handle_remove(guint32 tid)
101 {
102 #ifdef THREAD_DEBUG
103         g_message(G_GNUC_PRETTY_FUNCTION ": thread ID %d", tid);
104 #endif
105
106         EnterCriticalSection(&threads_mutex);
107
108         mono_g_hash_table_remove (threads, GUINT_TO_POINTER(tid));
109         
110         LeaveCriticalSection(&threads_mutex);
111
112         /* Don't close the handle here, wait for the object finalizer
113          * to do it. Otherwise, the following race condition applies:
114          *
115          * 1) Thread exits (and handle_remove() closes the handle)
116          *
117          * 2) Some other handle is reassigned the same slot
118          *
119          * 3) Another thread tries to join the first thread, and
120          * blocks waiting for the reassigned handle to be signalled
121          * (which might never happen).  This is possible, because the
122          * thread calling Join() still has a reference to the first
123          * thread's object.
124          */
125 }
126
127 static void thread_cleanup (MonoThread *thread)
128 {
129         mono_monitor_try_enter ((MonoObject *)thread, INFINITE);
130         thread->state |= ThreadState_Stopped;
131         mono_monitor_exit ((MonoObject *)thread);
132         
133         mono_profiler_thread_end (thread->tid);
134         handle_remove (thread->tid);
135 }
136
137 static guint32 start_wrapper(void *data)
138 {
139         struct StartInfo *start_info=(struct StartInfo *)data;
140         guint32 (*start_func)(void *);
141         void *this;
142         guint32 tid;
143         MonoThread *thread=start_info->obj;
144         
145 #ifdef THREAD_DEBUG
146         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper",
147                   GetCurrentThreadId ());
148 #endif
149         
150         /* We can be sure start_info->obj->tid and
151          * start_info->obj->handle have been set, because the thread
152          * was created suspended, and these values were set before the
153          * thread resumed
154          */
155
156         tid=thread->tid;
157         
158         mono_domain_set (start_info->domain);
159
160         start_func = start_info->func;
161         this = start_info->this;
162
163         /* This MUST be called before any managed code can be
164          * executed, as it calls the callback function that (for the
165          * jit) sets the lmf marker.
166          */
167         mono_thread_new_init (tid, &tid, start_func);
168         thread->stack_ptr = &tid;
169
170 #ifdef LIBGC_DEBUG
171         g_message (G_GNUC_PRETTY_FUNCTION
172                    ": (%d,%d) Setting thread stack to %p",
173                    GetCurrentThreadId (), getpid (), thread->stack_ptr);
174 #endif
175
176 #ifdef THREAD_DEBUG
177         g_message (G_GNUC_PRETTY_FUNCTION
178                    ": (%d) Setting current_object_key to %p",
179                    GetCurrentThreadId (), thread);
180 #endif
181
182         TlsSetValue (current_object_key, thread);
183
184         mono_profiler_thread_start (tid);
185
186         if(thread->start_notify!=NULL) {
187                 /* Let the thread that called Start() know we're
188                  * ready
189                  */
190                 ReleaseSemaphore (thread->start_notify, 1, NULL);
191         }
192         
193         g_free (start_info);
194
195         thread_adjust_static_data (thread);
196
197         start_func (this);
198
199         /* If the thread calls ExitThread at all, this remaining code
200          * will not be executed, but the main thread will eventually
201          * call thread_cleanup() on this thread's behalf.
202          */
203
204 #ifdef THREAD_DEBUG
205         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper terminating",
206                   GetCurrentThreadId ());
207 #endif
208
209         /* Remove the reference to the thread object in the TLS data,
210          * so the thread object can be finalized.  This won't be
211          * reached if the thread threw an uncaught exception, so those
212          * thread handles will stay referenced :-( (This is due to
213          * missing support for scanning thread-specific data in the
214          * Boehm GC - the io-layer keeps a GC-visible hash of pointers
215          * to TLS data.)
216          */
217         TlsSetValue (current_object_key, NULL);
218         
219         thread_cleanup (thread);
220         
221         return(0);
222 }
223
224 void mono_thread_new_init (guint32 tid, gpointer stack_start, gpointer func)
225 {
226         if (mono_thread_start_cb) {
227                 mono_thread_start_cb (tid, stack_start, func);
228         }
229
230         if (mono_thread_callbacks)
231                 (* mono_thread_callbacks->thread_created) (tid, stack_start, func);
232 }
233
234 void mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
235 {
236         MonoThread *thread;
237         HANDLE thread_handle;
238         struct StartInfo *start_info;
239         guint32 tid;
240         
241         thread=(MonoThread *)mono_object_new (domain,
242                                               mono_defaults.thread_class);
243
244         start_info=g_new0 (struct StartInfo, 1);
245         start_info->func = func;
246         start_info->obj = thread;
247         start_info->domain = domain;
248         start_info->this = arg;
249                 
250         /* Create suspended, so we can do some housekeeping before the thread
251          * starts
252          */
253         thread_handle = CreateThread(NULL, 0, start_wrapper, start_info,
254                                      CREATE_SUSPENDED, &tid);
255 #ifdef THREAD_DEBUG
256         g_message(G_GNUC_PRETTY_FUNCTION ": Started thread ID %d (handle %p)",
257                   tid, thread_handle);
258 #endif
259         g_assert (thread_handle);
260
261         thread->handle=thread_handle;
262         thread->tid=tid;
263
264         handle_store(thread);
265
266         ResumeThread (thread_handle);
267 }
268
269 MonoThread *
270 mono_thread_attach (MonoDomain *domain)
271 {
272         MonoThread *thread;
273         HANDLE thread_handle;
274         guint32 tid;
275
276         if ((thread = mono_thread_current ())) {
277                 g_warning ("mono_thread_attach called for an already attached thread");
278                 if (mono_thread_attach_cb) {
279                         mono_thread_attach_cb (tid, &tid);
280                 }
281                 return thread;
282         }
283
284         thread = (MonoThread *)mono_object_new (domain,
285                                                 mono_defaults.thread_class);
286
287         thread_handle = GetCurrentThread ();
288         g_assert (thread_handle);
289
290         tid=GetCurrentThreadId ();
291
292         thread->handle=thread_handle;
293         thread->tid=tid;
294
295 #ifdef THREAD_DEBUG
296         g_message(G_GNUC_PRETTY_FUNCTION ": Attached thread ID %d (handle %p)",
297                   tid, thread_handle);
298 #endif
299
300         handle_store(thread);
301
302 #ifdef THREAD_DEBUG
303         g_message (G_GNUC_PRETTY_FUNCTION
304                    ": (%d) Setting current_object_key to %p",
305                    GetCurrentThreadId (), thread);
306 #endif
307
308         TlsSetValue (current_object_key, thread);
309         mono_domain_set (domain);
310
311         thread_adjust_static_data (thread);
312
313         if (mono_thread_attach_cb) {
314                 mono_thread_attach_cb (tid, &tid);
315         }
316
317         return(thread);
318 }
319
320 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
321                                                          MonoObject *start)
322 {
323         MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)start;
324         guint32 (*start_func)(void *);
325         struct StartInfo *start_info;
326         MonoMethod *im;
327         HANDLE thread;
328         guint32 tid;
329         
330         MONO_ARCH_SAVE_REGS;
331
332 #ifdef THREAD_DEBUG
333         g_message(G_GNUC_PRETTY_FUNCTION
334                   ": Trying to start a new thread: this (%p) start (%p)",
335                   this, start);
336 #endif
337         
338         im = mono_get_delegate_invoke (start->vtable->klass);
339         if (mono_thread_callbacks)
340                 start_func = (* mono_thread_callbacks->thread_start_compile_func) (im);
341         else
342                 start_func = mono_compile_method (im);
343
344         if(start_func==NULL) {
345                 g_warning(G_GNUC_PRETTY_FUNCTION
346                           ": Can't locate start method!");
347                 return(NULL);
348         } else {
349                 /* This is freed in start_wrapper */
350                 start_info = g_new0 (struct StartInfo, 1);
351                 start_info->func = start_func;
352                 start_info->this = delegate;
353                 start_info->obj = this;
354                 start_info->domain = mono_domain_get ();
355
356                 this->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
357                 if(this->start_notify==NULL) {
358                         g_warning (G_GNUC_PRETTY_FUNCTION ": CreateSemaphore error 0x%x", GetLastError ());
359                         return(NULL);
360                 }
361
362                 thread=CreateThread(NULL, 0, start_wrapper, start_info,
363                                     CREATE_SUSPENDED, &tid);
364                 if(thread==NULL) {
365                         g_warning(G_GNUC_PRETTY_FUNCTION
366                                   ": CreateThread error 0x%x", GetLastError());
367                         return(NULL);
368                 }
369                 
370                 this->handle=thread;
371                 this->tid=tid;
372
373                 /* Don't call handle_store() here, delay it to Start.
374                  * We can't join a thread (trying to will just block
375                  * forever) until it actually starts running, so don't
376                  * store the handle till then.
377                  */
378
379 #ifdef THREAD_DEBUG
380                 g_message(G_GNUC_PRETTY_FUNCTION
381                           ": Started thread ID %d (handle %p)", tid, thread);
382 #endif
383
384                 return(thread);
385         }
386 }
387
388 void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
389                                                              HANDLE thread)
390 {
391         MONO_ARCH_SAVE_REGS;
392
393 #ifdef THREAD_DEBUG
394         g_message (G_GNUC_PRETTY_FUNCTION ": Closing thread %p, handle %p",
395                    this, thread);
396 #endif
397
398         CloseHandle (thread);
399 }
400
401 void ves_icall_System_Threading_Thread_Start_internal(MonoThread *this,
402                                                       HANDLE thread)
403 {
404         MONO_ARCH_SAVE_REGS;
405
406 #ifdef THREAD_DEBUG
407         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Launching thread %p (%d)",
408                   GetCurrentThreadId (), this, this->tid);
409 #endif
410
411         /* Only store the handle when the thread is about to be
412          * launched, to avoid the main thread deadlocking while trying
413          * to clean up a thread that will never be signalled.
414          */
415         handle_store(this);
416
417         if (mono_thread_callbacks)
418                 (* mono_thread_callbacks->start_resume) (this->tid);
419
420         ResumeThread(thread);
421
422         if (mono_thread_callbacks)
423                 (* mono_thread_callbacks->end_resume) (this->tid);
424
425         if(this->start_notify!=NULL) {
426                 /* Wait for the thread to set up its TLS data etc, so
427                  * theres no potential race condition if someone tries
428                  * to look up the data believing the thread has
429                  * started
430                  */
431
432 #ifdef THREAD_DEBUG
433                 g_message(G_GNUC_PRETTY_FUNCTION
434                           ": (%d) waiting for thread %p (%d) to start",
435                           GetCurrentThreadId (), this, this->tid);
436 #endif
437
438                 WaitForSingleObject (this->start_notify, INFINITE);
439                 CloseHandle (this->start_notify);
440                 this->start_notify=NULL;
441         }
442
443 #ifdef THREAD_DEBUG
444         g_message(G_GNUC_PRETTY_FUNCTION
445                   ": (%d) Done launching thread %p (%d)",
446                   GetCurrentThreadId (), this, this->tid);
447 #endif
448 }
449
450 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
451 {
452         MONO_ARCH_SAVE_REGS;
453
454 #ifdef THREAD_DEBUG
455         g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
456 #endif
457
458         Sleep(ms);
459 }
460
461 gint32
462 ves_icall_System_Threading_Thread_GetDomainID (void) 
463 {
464         MONO_ARCH_SAVE_REGS;
465
466         return mono_domain_get()->domain_id;
467 }
468
469 MonoThread *
470 mono_thread_current (void)
471 {
472         MonoThread *thread;
473         
474         MONO_ARCH_SAVE_REGS;
475
476         /* Find the current thread object */
477         thread=TlsGetValue (current_object_key);
478         
479 #ifdef THREAD_DEBUG
480         g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", thread);
481 #endif
482
483         return (thread);
484 }
485
486 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
487                                                          int ms, HANDLE thread)
488 {
489         gboolean ret;
490         
491         MONO_ARCH_SAVE_REGS;
492
493         if(ms== -1) {
494                 ms=INFINITE;
495         }
496 #ifdef THREAD_DEBUG
497         g_message (G_GNUC_PRETTY_FUNCTION ": joining thread handle %p, %d ms",
498                    thread, ms);
499 #endif
500         
501         ret=WaitForSingleObject(thread, ms);
502         if(ret==WAIT_OBJECT_0) {
503 #ifdef THREAD_DEBUG
504                 g_message (G_GNUC_PRETTY_FUNCTION ": join successful");
505 #endif
506
507                 return(TRUE);
508         }
509         
510 #ifdef THREAD_DEBUG
511                 g_message (G_GNUC_PRETTY_FUNCTION ": join failed");
512 #endif
513
514         return(FALSE);
515 }
516
517 void ves_icall_System_Threading_Thread_SlotHash_store(MonoObject *data)
518 {
519         MONO_ARCH_SAVE_REGS;
520
521 #ifdef THREAD_DEBUG
522         g_message(G_GNUC_PRETTY_FUNCTION ": Storing key %p", data);
523 #endif
524
525         /* Object location stored here */
526         TlsSetValue(slothash_key, data);
527 }
528
529 MonoObject *ves_icall_System_Threading_Thread_SlotHash_lookup(void)
530 {
531         MonoObject *data;
532
533         MONO_ARCH_SAVE_REGS;
534
535         data=TlsGetValue(slothash_key);
536         
537 #ifdef THREAD_DEBUG
538         g_message(G_GNUC_PRETTY_FUNCTION ": Retrieved key %p", data);
539 #endif
540         
541         return(data);
542 }
543
544 /* FIXME: exitContext isnt documented */
545 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
546 {
547         HANDLE *handles;
548         guint32 numhandles;
549         guint32 ret;
550         guint32 i;
551         MonoObject *waitHandle;
552         MonoClass *klass;
553                 
554         MONO_ARCH_SAVE_REGS;
555
556         numhandles = mono_array_length(mono_handles);
557         handles = g_new0(HANDLE, numhandles);
558
559         if (wait_handle_os_handle_field == 0) {
560                 /* Get the field os_handle which will contain the actual handle */
561                 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");   
562                 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
563         }
564                 
565         for(i = 0; i < numhandles; i++) {       
566                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);              
567                 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
568         }
569         
570         if(ms== -1) {
571                 ms=INFINITE;
572         }
573         
574         ret=WaitForMultipleObjects(numhandles, handles, TRUE, ms);
575
576         g_free(handles);
577         
578         if(ret==WAIT_FAILED) {
579 #ifdef THREAD_WAIT_DEBUG
580                 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
581                           GetCurrentThreadId ());
582 #endif
583                 return(FALSE);
584         } else if(ret==WAIT_TIMEOUT) {
585 #ifdef THREAD_WAIT_DEBUG
586                 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
587                           GetCurrentThreadId ());
588 #endif
589                 return(FALSE);
590         }
591         
592         return(TRUE);
593 }
594
595 /* FIXME: exitContext isnt documented */
596 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
597 {
598         HANDLE *handles;
599         guint32 numhandles;
600         guint32 ret;
601         guint32 i;
602         MonoObject *waitHandle;
603         MonoClass *klass;
604                 
605         MONO_ARCH_SAVE_REGS;
606
607         numhandles = mono_array_length(mono_handles);
608         handles = g_new0(HANDLE, numhandles);
609
610         if (wait_handle_os_handle_field == 0) {
611                 /* Get the field os_handle which will contain the actual handle */
612                 klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");   
613                 wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
614         }
615                 
616         for(i = 0; i < numhandles; i++) {       
617                 waitHandle = mono_array_get(mono_handles, MonoObject*, i);              
618                 mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
619         }
620         
621         if(ms== -1) {
622                 ms=INFINITE;
623         }
624
625         ret=WaitForMultipleObjects(numhandles, handles, FALSE, ms);
626
627         g_free(handles);
628         
629 #ifdef THREAD_WAIT_DEBUG
630         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) returning %d",
631                   GetCurrentThreadId (), ret);
632 #endif
633
634         /*
635          * These need to be here.  See MSDN dos on WaitForMultipleObjects.
636          */
637         if (ret >= WAIT_OBJECT_0 && ret <= WAIT_OBJECT_0 + numhandles - 1) {
638                 return ret - WAIT_OBJECT_0;
639         }
640         else if (ret >= WAIT_ABANDONED_0 && ret <= WAIT_ABANDONED_0 + numhandles - 1) {
641                 return ret - WAIT_ABANDONED_0;
642         }
643         else {
644                 return ret;
645         }
646 }
647
648 /* FIXME: exitContext isnt documented */
649 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
650 {
651         guint32 ret;
652         
653         MONO_ARCH_SAVE_REGS;
654
655 #ifdef THREAD_WAIT_DEBUG
656         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) waiting for %p, %d ms",
657                   GetCurrentThreadId (), handle, ms);
658 #endif
659         
660         if(ms== -1) {
661                 ms=INFINITE;
662         }
663         
664         ret=WaitForSingleObject(handle, ms);
665         if(ret==WAIT_FAILED) {
666 #ifdef THREAD_WAIT_DEBUG
667                 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
668                           GetCurrentThreadId ());
669 #endif
670                 return(FALSE);
671         } else if(ret==WAIT_TIMEOUT) {
672 #ifdef THREAD_WAIT_DEBUG
673                 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
674                           GetCurrentThreadId ());
675 #endif
676                 return(FALSE);
677         }
678         
679         return(TRUE);
680 }
681
682 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned,char *name) { 
683         MONO_ARCH_SAVE_REGS;
684    
685         return(CreateMutex(NULL,owned,name));                    
686 }                                                                   
687
688 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) { 
689         MONO_ARCH_SAVE_REGS;
690
691         ReleaseMutex(handle);
692 }
693
694 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual, MonoBoolean initial, char *name) {
695         MONO_ARCH_SAVE_REGS;
696
697         return (CreateEvent(NULL,manual,initial,name));
698 }
699
700 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
701         MONO_ARCH_SAVE_REGS;
702
703         return (SetEvent(handle));
704 }
705
706 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
707         MONO_ARCH_SAVE_REGS;
708
709         return (ResetEvent(handle));
710 }
711
712 void
713 ves_icall_System_Threading_Events_CloseEvent_internal (HANDLE handle) {
714         MONO_ARCH_SAVE_REGS;
715
716         CloseHandle (handle);
717 }
718
719 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
720 {
721         MONO_ARCH_SAVE_REGS;
722
723         return InterlockedIncrement (location);
724 }
725
726 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
727 {
728         gint32 lowret;
729         gint32 highret;
730
731         MONO_ARCH_SAVE_REGS;
732
733         EnterCriticalSection(&interlocked_mutex);
734
735         lowret = InterlockedIncrement((gint32 *) location);
736         if (0 == lowret)
737                 highret = InterlockedIncrement((gint32 *) location + 1);
738         else
739                 highret = *((gint32 *) location + 1);
740
741         LeaveCriticalSection(&interlocked_mutex);
742
743         return (gint64) highret << 32 | (gint64) lowret;
744 }
745
746 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
747 {
748         MONO_ARCH_SAVE_REGS;
749
750         return InterlockedDecrement(location);
751 }
752
753 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
754 {
755         gint32 lowret;
756         gint32 highret;
757
758         MONO_ARCH_SAVE_REGS;
759
760         EnterCriticalSection(&interlocked_mutex);
761
762         lowret = InterlockedDecrement((gint32 *) location);
763         if (-1 == lowret)
764                 highret = InterlockedDecrement((gint32 *) location + 1);
765         else
766                 highret = *((gint32 *) location + 1);
767
768         LeaveCriticalSection(&interlocked_mutex);
769
770         return (gint64) highret << 32 | (gint64) lowret;
771 }
772
773 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location1, gint32 value)
774 {
775         MONO_ARCH_SAVE_REGS;
776
777         return InterlockedExchange(location1, value);
778 }
779
780 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location1, MonoObject *value)
781 {
782         MONO_ARCH_SAVE_REGS;
783
784         return (MonoObject *) InterlockedExchangePointer((gpointer *) location1, value);
785 }
786
787 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location1, gfloat value)
788 {
789         IntFloatUnion val, ret;
790
791         MONO_ARCH_SAVE_REGS;
792
793         val.fval = value;
794         ret.ival = InterlockedExchange((gint32 *) location1, val.ival);
795
796         return ret.fval;
797 }
798
799 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location1, gint32 value, gint32 comparand)
800 {
801         MONO_ARCH_SAVE_REGS;
802
803         return InterlockedCompareExchange(location1, value, comparand);
804 }
805
806 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location1, MonoObject *value, MonoObject *comparand)
807 {
808         MONO_ARCH_SAVE_REGS;
809
810         return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location1, value, comparand);
811 }
812
813 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location1, gfloat value, gfloat comparand)
814 {
815         IntFloatUnion val, ret, cmp;
816
817         MONO_ARCH_SAVE_REGS;
818
819         val.fval = value;
820         cmp.fval = comparand;
821         ret.ival = InterlockedCompareExchange((gint32 *) location1, val.ival, cmp.ival);
822
823         return ret.fval;
824 }
825
826 int  
827 mono_thread_get_abort_signal (void)
828 {
829 #ifdef __MINGW32__
830         return -1;
831 #else
832 #ifndef SIGRTMIN
833         return SIGUSR1;
834 #else
835         return SIGRTMIN;
836 #endif
837 #endif /* __MINGW32__ */
838 }
839
840 void
841 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
842 {
843         MONO_ARCH_SAVE_REGS;
844
845         thread->abort_state = state;
846         thread->abort_exc = mono_get_exception_thread_abort ();
847
848 #ifdef THREAD_DEBUG
849         g_message (G_GNUC_PRETTY_FUNCTION
850                    ": (%d) Abort requested for %p (%d)", GetCurrentThreadId (),
851                    thread, thread->tid);
852 #endif
853         
854 #ifdef __MINGW32__
855         g_assert_not_reached ();
856 #else
857         /* fixme: store the state somewhere */
858 #ifdef PTHREAD_POINTER_ID
859         pthread_kill (GUINT_TO_POINTER(thread->tid), mono_thread_get_abort_signal ());
860 #else
861         pthread_kill (thread->tid, mono_thread_get_abort_signal ());
862 #endif
863 #endif /* __MINGW32__ */
864 }
865
866 void
867 ves_icall_System_Threading_Thread_ResetAbort (void)
868 {
869         MonoThread *thread = mono_thread_current ();
870         
871         MONO_ARCH_SAVE_REGS;
872
873         if (!thread->abort_exc) {
874                 const char *msg = "Unable to reset abort because no abort was requested";
875                 mono_raise_exception (mono_get_exception_thread_state (msg));
876         } else {
877                 thread->abort_exc = NULL;
878                 thread->abort_state = NULL;
879         }
880 }
881
882 void mono_thread_init (MonoThreadStartCB start_cb,
883                        MonoThreadAttachCB attach_cb)
884 {
885         InitializeCriticalSection(&threads_mutex);
886         InitializeCriticalSection(&interlocked_mutex);
887         
888         current_object_key=TlsAlloc();
889 #ifdef THREAD_DEBUG
890         g_message (G_GNUC_PRETTY_FUNCTION ": Allocated current_object_key %d",
891                    current_object_key);
892 #endif
893
894         mono_thread_start_cb = start_cb;
895         mono_thread_attach_cb = attach_cb;
896
897         slothash_key=TlsAlloc();
898
899         /* Get a pseudo handle to the current process.  This is just a
900          * kludge so that wapi can build a process handle if needed.
901          * As a pseudo handle is returned, we don't need to clean
902          * anything up.
903          */
904         GetCurrentProcess ();
905 }
906
907 void mono_install_thread_callbacks (MonoThreadCallbacks *callbacks)
908 {
909         mono_thread_callbacks = callbacks;
910 }
911
912 #ifdef THREAD_DEBUG
913 static void print_tids (gpointer key, gpointer value, gpointer user)
914 {
915         g_message ("Waiting for: %d", GPOINTER_TO_UINT(key));
916 }
917 #endif
918
919 struct wait_data 
920 {
921         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
922         MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
923         guint32 num;
924 };
925
926 static void wait_for_tids (struct wait_data *wait)
927 {
928         guint32 i, ret;
929         
930 #ifdef THREAD_DEBUG
931         g_message(G_GNUC_PRETTY_FUNCTION
932                   ": %d threads to wait for in this batch", wait->num);
933 #endif
934
935         ret=WaitForMultipleObjects(wait->num, wait->handles, TRUE, INFINITE);
936         if(ret==WAIT_FAILED) {
937                 /* See the comment in build_wait_tids() */
938 #ifdef THREAD_DEBUG
939                 g_message (G_GNUC_PRETTY_FUNCTION ": Wait failed");
940 #endif
941                 return;
942         }
943         
944
945         for(i=0; i<wait->num; i++) {
946                 guint32 tid=wait->threads[i]->tid;
947                 
948                 if(mono_g_hash_table_lookup (threads, GUINT_TO_POINTER(tid))!=NULL) {
949                         /* This thread must have been killed, because
950                          * it hasn't cleaned itself up. (It's just
951                          * possible that the thread exited before the
952                          * parent thread had a chance to store the
953                          * handle, and now there is another pointer to
954                          * the already-exited thread stored.  In this
955                          * case, we'll just get two
956                          * mono_profiler_thread_end() calls for the
957                          * same thread.)
958                          */
959         
960 #ifdef THREAD_DEBUG
961                         g_message (G_GNUC_PRETTY_FUNCTION
962                                    ": cleaning up after thread %d", tid);
963 #endif
964                         thread_cleanup (wait->threads[i]);
965                 }
966         }
967 }
968
969 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
970 {
971         struct wait_data *wait=(struct wait_data *)user;
972
973         if(wait->num<MAXIMUM_WAIT_OBJECTS) {
974                 MonoThread *thread=(MonoThread *)value;
975
976                 /* BUG: For now we just ignore background threads, we should abort them
977                 */
978                 if (thread->state & ThreadState_Background)
979                         return; /* just leave, ignore */
980                 
981                 wait->handles[wait->num]=thread->handle;
982                 wait->threads[wait->num]=thread;
983                 wait->num++;
984         } else {
985                 /* Just ignore the rest, we can't do anything with
986                  * them yet
987                  */
988         }
989 }
990
991 void mono_thread_manage (void)
992 {
993         struct wait_data *wait=g_new0 (struct wait_data, 1);
994         
995         /* join each thread that's still running */
996 #ifdef THREAD_DEBUG
997         g_message(G_GNUC_PRETTY_FUNCTION ": Joining each running thread...");
998 #endif
999         
1000         if(threads==NULL) {
1001 #ifdef THREAD_DEBUG
1002                 g_message(G_GNUC_PRETTY_FUNCTION ": No threads");
1003 #endif
1004                 return;
1005         }
1006         
1007         do {
1008                 EnterCriticalSection (&threads_mutex);
1009 #ifdef THREAD_DEBUG
1010                 g_message(G_GNUC_PRETTY_FUNCTION
1011                           ":There are %d threads to join",
1012                           mono_g_hash_table_size (threads));
1013                 mono_g_hash_table_foreach (threads, print_tids, NULL);
1014 #endif
1015
1016                 wait->num=0;
1017                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
1018         
1019                 LeaveCriticalSection (&threads_mutex);
1020                 if(wait->num>0) {
1021                         /* Something to wait for */
1022                         wait_for_tids (wait);
1023                 }
1024         } while(wait->num>0);
1025         
1026         g_free (wait);
1027         
1028         mono_g_hash_table_destroy(threads);
1029         threads=NULL;
1030 }
1031
1032 static void terminate_thread (gpointer key, gpointer value, gpointer user)
1033 {
1034         MonoThread *thread=(MonoThread *)value;
1035         guint32 self=GPOINTER_TO_UINT (user);
1036         
1037         if(thread->tid!=self) {
1038                 /*TerminateThread (thread->handle, -1);*/
1039         }
1040 }
1041
1042 void mono_thread_abort_all_other_threads (void)
1043 {
1044         guint32 self=GetCurrentThreadId ();
1045
1046         EnterCriticalSection (&threads_mutex);
1047 #ifdef THREAD_DEBUG
1048         g_message(G_GNUC_PRETTY_FUNCTION ":There are %d threads to abort",
1049                   mono_g_hash_table_size (threads));
1050         mono_g_hash_table_foreach (threads, print_tids, NULL);
1051 #endif
1052
1053         mono_g_hash_table_foreach (threads, terminate_thread,
1054                                    GUINT_TO_POINTER (self));
1055         
1056         LeaveCriticalSection (&threads_mutex);
1057 }
1058
1059 static int static_data_idx = 0;
1060 static int static_data_offset = 0;
1061 #define NUM_STATIC_DATA_IDX 8
1062 static const int static_data_size [NUM_STATIC_DATA_IDX] = {
1063         1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
1064 };
1065
1066 static void 
1067 thread_alloc_static_data (MonoThread *thread, guint32 offset)
1068 {
1069         guint idx = (offset >> 24) - 1;
1070         int i;
1071
1072         if (!thread->static_data) {
1073 #if HAVE_BOEHM_GC
1074                 thread->static_data = GC_MALLOC (static_data_size [0]);
1075 #else
1076                 thread->static_data = g_malloc0 (static_data_size [0]);
1077 #endif
1078                 thread->static_data [0] = thread->static_data;
1079         }
1080         for (i = 1; i < idx; ++i) {
1081                 if (thread->static_data [i])
1082                         continue;
1083 #if HAVE_BOEHM_GC
1084                 thread->static_data [i] = GC_MALLOC (static_data_size [i]);
1085 #else
1086                 thread->static_data [i] = g_malloc0 (static_data_size [i]);
1087 #endif
1088         }
1089         
1090 }
1091
1092 /* 
1093  * ensure thread static fields already allocated are valid for thread
1094  * This function is called when a thread is created or on thread attach.
1095  */
1096 static void
1097 thread_adjust_static_data (MonoThread *thread)
1098 {
1099         guint32 offset;
1100
1101         EnterCriticalSection (&threads_mutex);
1102         if (static_data_offset || static_data_idx > 0) {
1103                 /* get the current allocated size */
1104                 offset = static_data_offset | ((static_data_idx + 1) << 24);
1105                 thread_alloc_static_data (thread, offset);
1106         }
1107         LeaveCriticalSection (&threads_mutex);
1108 }
1109
1110 static void 
1111 alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
1112 {
1113         MonoThread *thread = value;
1114         guint32 offset = GPOINTER_TO_UINT (user);
1115         
1116         thread_alloc_static_data (thread, offset);
1117 }
1118
1119 /*
1120  * The offset for a thread static variable is composed of two parts:
1121  * an index in the array of chunks of memory for the thread (thread->static_data)
1122  * and an offset in that chunk of mem. This allows allocating less memory in the 
1123  * common case.
1124  */
1125 guint32
1126 mono_threads_alloc_static_data (guint32 size, guint32 align)
1127 {
1128         guint32 offset;
1129         
1130         EnterCriticalSection (&threads_mutex);
1131
1132         if (!static_data_idx && !static_data_offset) {
1133                 /* 
1134                  * we use the first chunk of the first allocation also as
1135                  * an array for the rest of the data 
1136                  */
1137                 static_data_offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
1138         }
1139         static_data_offset += align - 1;
1140         static_data_offset &= ~(align - 1);
1141         if (static_data_offset + size >= static_data_size [static_data_idx]) {
1142                 static_data_idx ++;
1143                 g_assert (size <= static_data_size [static_data_idx]);
1144                 /* 
1145                  * massive unloading and reloading of domains with thread-static
1146                  * data may eventually exceed the allocated storage...
1147                  * Need to check what the MS runtime does in that case.
1148                  * Note that for each appdomain, we need to allocate a separate
1149                  * thread data slot for security reasons. We could keep track
1150                  * of the slots per-domain and when the domain is unloaded
1151                  * out the slots on a sort of free list.
1152                  */
1153                 g_assert (static_data_idx < NUM_STATIC_DATA_IDX);
1154                 static_data_offset = 0;
1155         }
1156         offset = static_data_offset | ((static_data_idx + 1) << 24);
1157         static_data_offset += size;
1158         
1159         mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
1160
1161         LeaveCriticalSection (&threads_mutex);
1162         return offset;
1163 }
1164
1165 gpointer
1166 mono_threads_get_static_data (guint32 offset)
1167 {
1168         MonoThread *thread = mono_thread_current ();
1169         int idx = offset >> 24;
1170         
1171         return ((char*) thread->static_data [idx - 1]) + (offset & 0xffffff);
1172 }
1173
1174 #ifdef WITH_INCLUDED_LIBGC
1175
1176 static void gc_stop_world (gpointer key, gpointer value, gpointer user)
1177 {
1178         MonoThread *thread=(MonoThread *)value;
1179         guint32 self=GPOINTER_TO_UINT (user);
1180
1181 #ifdef LIBGC_DEBUG
1182         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid);
1183 #endif
1184         
1185         if(thread->tid==self)
1186                 return;
1187
1188         SuspendThread (thread->handle);
1189 }
1190
1191 void mono_gc_stop_world (void)
1192 {
1193         guint32 self=GetCurrentThreadId ();
1194
1195 #ifdef LIBGC_DEBUG
1196         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
1197 #endif
1198
1199         EnterCriticalSection (&threads_mutex);
1200
1201         if (threads != NULL)
1202                 mono_g_hash_table_foreach (threads, gc_stop_world, GUINT_TO_POINTER (self));
1203         
1204         LeaveCriticalSection (&threads_mutex);
1205 }
1206
1207 static void gc_start_world (gpointer key, gpointer value, gpointer user)
1208 {
1209         MonoThread *thread=(MonoThread *)value;
1210         guint32 self=GPOINTER_TO_UINT (user);
1211         
1212 #ifdef LIBGC_DEBUG
1213         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid);
1214 #endif
1215         
1216         if(thread->tid==self)
1217                 return;
1218
1219         ResumeThread (thread->handle);
1220 }
1221
1222 void mono_gc_start_world (void)
1223 {
1224         guint32 self=GetCurrentThreadId ();
1225
1226 #ifdef LIBGC_DEBUG
1227         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
1228 #endif
1229
1230         EnterCriticalSection (&threads_mutex);
1231
1232         if (threads != NULL)
1233                 mono_g_hash_table_foreach (threads, gc_start_world, GUINT_TO_POINTER (self));
1234         
1235         LeaveCriticalSection (&threads_mutex);
1236 }
1237
1238 static void gc_push_all_stacks (gpointer key, gpointer value, gpointer user)
1239 {
1240         MonoThread *thread=(MonoThread *)value;
1241         guint32 *selfp=(guint32 *)user, self = *selfp;
1242
1243 #ifdef LIBGC_DEBUG
1244         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d - %p", self, thread->tid, thread->stack_ptr);
1245 #endif
1246         
1247         if(thread->tid==self) {
1248 #ifdef LIBGC_DEBUG
1249                 g_message (G_GNUC_PRETTY_FUNCTION ": %p - %p", selfp, thread->stack_ptr);
1250 #endif
1251                 GC_push_all_stack (selfp, thread->stack_ptr);
1252                 return;
1253         }
1254
1255 #ifdef PLATFORM_WIN32
1256         GC_win32_push_thread_stack (thread->handle, thread->stack_ptr);
1257 #else
1258         mono_wapi_push_thread_stack (thread->handle, thread->stack_ptr);
1259 #endif
1260 }
1261
1262 void mono_gc_push_all_stacks (void)
1263 {
1264         guint32 self=GetCurrentThreadId ();
1265
1266 #ifdef LIBGC_DEBUG
1267         g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
1268 #endif
1269
1270         EnterCriticalSection (&threads_mutex);
1271
1272         if (threads != NULL)
1273                 mono_g_hash_table_foreach (threads, gc_push_all_stacks, &self);
1274         
1275         LeaveCriticalSection (&threads_mutex);
1276 }
1277
1278 #endif /* WITH_INCLUDED_LIBGC */