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