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