2002-04-17 Patrik Torstensson <patrik.torstensson@labs2.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  *      Patrik Torstensson (patrik.torstensson@labs2.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <glib.h>
13
14 #include <mono/metadata/object.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/profiler-private.h>
17 #include <mono/metadata/threads.h>
18 #include <mono/metadata/threads-types.h>
19 #include <mono/io-layer/io-layer.h>
20
21 #undef THREAD_DEBUG
22 #undef THREAD_LOCK_DEBUG
23 #undef THREAD_WAIT_DEBUG
24
25 struct StartInfo 
26 {
27         guint32 (*func)(void *);
28         MonoObject *obj;
29         void *this;
30         MonoDomain *domain;
31 };
32
33 /* Controls access to the 'threads' array */
34 static CRITICAL_SECTION threads_mutex;
35
36 /* Controls access to the sync field in MonoObjects, to avoid race
37  * conditions when adding sync data to an object for the first time.
38  */
39 static CRITICAL_SECTION monitor_mutex;
40
41 /* The array of existing threads that need joining before exit */
42 static GPtrArray *threads=NULL;
43
44 /* The MonoObject associated with the main thread */
45 static MonoObject *main_thread;
46
47 /* The TLS key that holds the MonoObject assigned to each thread */
48 static guint32 current_object_key;
49
50 /* The TLS key that holds the LocalDataStoreSlot hash in each thread */
51 static guint32 slothash_key;
52
53 /* Spin lock for InterlockedXXX 64 bit functions */
54 static CRITICAL_SECTION interlocked_mutex;
55
56 static guint32 start_wrapper(void *data)
57 {
58         struct StartInfo *start_info=(struct StartInfo *)data;
59         guint32 (*start_func)(void *);
60         void *this;
61         
62 #ifdef THREAD_DEBUG
63         g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper");
64 #endif
65
66         /* FIXME: GC problem here with recorded object
67          * pointer!
68          *
69          * This is recorded so CurrentThread can return the
70          * Thread object.
71          */
72         TlsSetValue (current_object_key, start_info->obj);
73         start_func = start_info->func;
74         mono_domain_set (start_info->domain);
75         this = start_info->this;
76         g_free (start_info);
77         
78         start_func (this);
79
80 #ifdef THREAD_DEBUG
81         g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper terminating");
82 #endif
83
84         return(0);
85 }
86                 
87 static void handle_store(HANDLE thread)
88 {
89 #ifdef THREAD_DEBUG
90         g_message(G_GNUC_PRETTY_FUNCTION ": thread %p", thread);
91 #endif
92
93         EnterCriticalSection(&threads_mutex);
94         if(threads==NULL) {
95                 threads=g_ptr_array_new();
96         }
97         g_ptr_array_add(threads, thread);
98         LeaveCriticalSection(&threads_mutex);
99 }
100
101 static void handle_remove(HANDLE thread)
102 {
103 #ifdef THREAD_DEBUG
104         g_message(G_GNUC_PRETTY_FUNCTION ": thread %p", thread);
105 #endif
106
107         EnterCriticalSection(&threads_mutex);
108         g_ptr_array_remove_fast(threads, thread);
109         LeaveCriticalSection(&threads_mutex);
110         CloseHandle(thread);
111 }
112
113 MonoObject *
114 mono_thread_create (MonoDomain *domain, gpointer func)
115 {
116         MonoClassField *field;
117         MonoObject *thread;
118         HANDLE thread_handle;
119         struct StartInfo *start_info;
120         guint32 tid;
121         
122         thread = mono_object_new (domain, mono_defaults.thread_class);
123
124         field=mono_class_get_field_from_name(mono_defaults.thread_class, "system_thread_handle");
125         g_assert (field);
126
127         start_info=g_new0 (struct StartInfo, 1);
128         start_info->func = func;
129         start_info->obj = thread;
130         start_info->domain = domain;
131                 
132         thread_handle = CreateThread(NULL, 0, start_wrapper, start_info, 0, &tid);
133         g_assert (thread_handle);
134
135         *(gpointer *)(((char *)thread) + field->offset) = thread_handle; 
136
137         /*
138          * This thread is not added to the threads array: why?
139          */
140         mono_profiler_thread_start (thread_handle);
141         return thread;
142 }
143
144 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoObject *this,
145                                                          MonoObject *start)
146 {
147         MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)start;
148         guint32 (*start_func)(void *);
149         struct StartInfo *start_info;
150         HANDLE thread;
151         guint32 tid;
152         
153 #ifdef THREAD_DEBUG
154         g_message(G_GNUC_PRETTY_FUNCTION
155                   ": Trying to start a new thread: this (%p) start (%p)",
156                   this, start);
157 #endif
158         
159         start_func = delegate->delegate.method_ptr;
160         
161         if(start_func==NULL) {
162                 g_warning(G_GNUC_PRETTY_FUNCTION
163                           ": Can't locate start method!");
164                 return(NULL);
165         } else {
166                 /* This is freed in start_wrapper */
167                 start_info = g_new0 (struct StartInfo, 1);
168                 start_info->func = start_func;
169                 start_info->this = delegate->delegate.target;
170                 start_info->obj = this;
171                 start_info->domain = mono_domain_get ();
172                 
173                 thread=CreateThread(NULL, 0, start_wrapper, start_info,
174                                     CREATE_SUSPENDED, &tid);
175                 if(thread==NULL) {
176                         g_warning(G_GNUC_PRETTY_FUNCTION
177                                   ": CreateThread error 0x%x", GetLastError());
178                         return(NULL);
179                 }
180                 
181 #ifdef THREAD_DEBUG
182                 g_message(G_GNUC_PRETTY_FUNCTION ": Started thread ID %d",
183                           tid);
184 #endif
185
186                 /* Store handle for cleanup later */
187                 handle_store(thread);
188                 mono_profiler_thread_start (thread);
189                 
190                 return(thread);
191         }
192 }
193
194 void ves_icall_System_Threading_Thread_Start_internal(MonoObject *this,
195                                                       HANDLE thread)
196 {
197 #ifdef THREAD_DEBUG
198         g_message(G_GNUC_PRETTY_FUNCTION ": Launching thread %p", this);
199 #endif
200
201         ResumeThread(thread);
202 }
203
204 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
205 {
206 #ifdef THREAD_DEBUG
207         g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
208 #endif
209
210         Sleep(ms);
211 }
212
213 MonoAppDomain *ves_icall_System_Threading_Thread_CurrentThreadDomain_internal(void) 
214 {
215         /* return the current app */
216         return mono_domain_get()->domain;
217 }
218
219 MonoObject *ves_icall_System_Threading_Thread_CurrentThread_internal(void)
220 {
221         MonoObject *thread;
222         
223         /* Find the current thread object */
224         thread=TlsGetValue(current_object_key);
225         return(thread);
226 }
227
228 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoObject *this,
229                                                          int ms, HANDLE thread)
230 {
231         gboolean ret;
232         
233         if(ms== -1) {
234                 ms=INFINITE;
235         }
236         
237         ret=WaitForSingleObject(thread, ms);
238         if(ret==WAIT_OBJECT_0) {
239                 /* is the handle still valid at this point? */
240                 mono_profiler_thread_end (thread);
241                 /* Clean up the handle */
242                 handle_remove(thread);
243                 return(TRUE);
244         }
245         
246         return(FALSE);
247 }
248
249 void ves_icall_System_Threading_Thread_SlotHash_store(MonoObject *data)
250 {
251 #ifdef THREAD_DEBUG
252         g_message(G_GNUC_PRETTY_FUNCTION ": Storing key %p", data);
253 #endif
254
255         /* Object location stored here */
256         TlsSetValue(slothash_key, data);
257 }
258
259 MonoObject *ves_icall_System_Threading_Thread_SlotHash_lookup(void)
260 {
261         MonoObject *data;
262
263         data=TlsGetValue(slothash_key);
264         
265 #ifdef THREAD_DEBUG
266         g_message(G_GNUC_PRETTY_FUNCTION ": Retrieved key %p", data);
267 #endif
268         
269         return(data);
270 }
271
272 static MonoThreadsSync *mon_new(void)
273 {
274         MonoThreadsSync *new;
275         
276         /* This should be freed when the object that owns it is
277          * deleted
278          */
279
280         new=(MonoThreadsSync *)g_new0(MonoThreadsSync, 1);
281         new->monitor=CreateMutex(NULL, FALSE, NULL);
282 #ifdef THREAD_LOCK_DEBUG
283         g_message(G_GNUC_PRETTY_FUNCTION ": ThreadsSync mutex created: %p",
284                   new->monitor);
285 #endif
286
287         new->waiters_count=0;
288         new->was_broadcast=FALSE;
289         InitializeCriticalSection(&new->waiters_count_lock);
290         new->sema=CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
291         new->waiters_done=CreateEvent(NULL, FALSE, FALSE, NULL);
292         
293         return(new);
294 }
295
296 gboolean ves_icall_System_Threading_Monitor_Monitor_try_enter(MonoObject *obj,
297                                                               int ms)
298 {
299         MonoThreadsSync *mon;
300         guint32 ret;
301         
302 #ifdef THREAD_LOCK_DEBUG
303         g_message(G_GNUC_PRETTY_FUNCTION
304                   ": Trying to lock %p in thread %d", obj,
305                   GetCurrentThreadId());
306 #endif
307
308         EnterCriticalSection(&monitor_mutex);
309
310         mon=obj->synchronisation;
311         if(mon==NULL) {
312                 mon=mon_new();
313                 obj->synchronisation=mon;
314         }
315         
316         /* Don't hold the monitor lock while waiting to acquire the
317          * object lock
318          */
319         LeaveCriticalSection(&monitor_mutex);
320         
321         /* Acquire the mutex */
322 #ifdef THREAD_LOCK_DEBUG
323         g_message(G_GNUC_PRETTY_FUNCTION ": Acquiring monitor mutex %p",
324                   mon->monitor);
325 #endif
326         ret=WaitForSingleObject(mon->monitor, ms);
327         if(ret==WAIT_OBJECT_0) {
328                 mon->count++;
329                 mon->tid=GetCurrentThreadId();
330         
331 #ifdef THREAD_LOCK_DEBUG
332         g_message(G_GNUC_PRETTY_FUNCTION ": %p now locked %d times", obj,
333                   mon->count);
334 #endif
335
336                 return(TRUE);
337         }
338
339         return(FALSE);
340 }
341
342 void ves_icall_System_Threading_Monitor_Monitor_exit(MonoObject *obj)
343 {
344         MonoThreadsSync *mon;
345         
346 #ifdef THREAD_LOCK_DEBUG
347         g_message(G_GNUC_PRETTY_FUNCTION ": Unlocking %p in thread %d", obj,
348                   GetCurrentThreadId());
349 #endif
350
351         /* No need to lock monitor_mutex here because we only adjust
352          * the monitor state if this thread already owns the lock
353          */
354         mon=obj->synchronisation;
355
356         if(mon==NULL) {
357                 return;
358         }
359
360         if(mon->tid!=GetCurrentThreadId()) {
361                 return;
362         }
363         
364         mon->count--;
365         
366 #ifdef THREAD_LOCK_DEBUG
367         g_message(G_GNUC_PRETTY_FUNCTION ": %p now locked %d times", obj,
368                   mon->count);
369 #endif
370
371         if(mon->count==0) {
372                 mon->tid=0;     /* FIXME: check that 0 isnt a valid id */
373         }
374         
375 #ifdef THREAD_LOCK_DEBUG
376         g_message(G_GNUC_PRETTY_FUNCTION ": Releasing mutex %p", mon->monitor);
377 #endif
378
379         ReleaseMutex(mon->monitor);
380 }
381
382 gboolean ves_icall_System_Threading_Monitor_Monitor_test_owner(MonoObject *obj)
383 {
384         MonoThreadsSync *mon;
385         gboolean ret=FALSE;
386         
387 #ifdef THREAD_LOCK_DEBUG
388         g_message(G_GNUC_PRETTY_FUNCTION
389                   ": Testing if %p is owned by thread %d", obj,
390                   GetCurrentThreadId());
391 #endif
392
393         EnterCriticalSection(&monitor_mutex);
394         
395         mon=obj->synchronisation;
396         if(mon==NULL) {
397                 goto finished;
398         }
399
400         if(mon->tid!=GetCurrentThreadId()) {
401                 goto finished;
402         }
403         
404         ret=TRUE;
405         
406 finished:
407         LeaveCriticalSection(&monitor_mutex);
408
409         return(ret);
410 }
411
412 gboolean ves_icall_System_Threading_Monitor_Monitor_test_synchronised(MonoObject *obj)
413 {
414         MonoThreadsSync *mon;
415         gboolean ret=FALSE;
416         
417 #ifdef THREAD_LOCK_DEBUG
418         g_message(G_GNUC_PRETTY_FUNCTION
419                   ": Testing if %p is owned by any thread", obj);
420 #endif
421
422         EnterCriticalSection(&monitor_mutex);
423         
424         mon=obj->synchronisation;
425         if(mon==NULL) {
426                 goto finished;
427         }
428
429         if(mon->tid==0) {
430                 goto finished;
431         }
432         
433         g_assert(mon->count);
434         
435         ret=TRUE;
436         
437 finished:
438         LeaveCriticalSection(&monitor_mutex);
439
440         return(ret);
441 }
442
443         
444 void ves_icall_System_Threading_Monitor_Monitor_pulse(MonoObject *obj)
445 {
446         gboolean have_waiters;
447         MonoThreadsSync *mon;
448         
449 #ifdef THREAD_LOCK_DEBUG
450         g_message("Pulsing %p in thread %d", obj, GetCurrentThreadId());
451 #endif
452
453         EnterCriticalSection(&monitor_mutex);
454         
455         mon=obj->synchronisation;
456         if(mon==NULL) {
457                 LeaveCriticalSection(&monitor_mutex);
458                 return;
459         }
460
461         if(mon->tid!=GetCurrentThreadId()) {
462                 LeaveCriticalSection(&monitor_mutex);
463                 return;
464         }
465         LeaveCriticalSection(&monitor_mutex);
466         
467         EnterCriticalSection(&mon->waiters_count_lock);
468         have_waiters=(mon->waiters_count>0);
469         LeaveCriticalSection(&mon->waiters_count_lock);
470         
471         if(have_waiters==TRUE) {
472                 ReleaseSemaphore(mon->sema, 1, 0);
473         }
474 }
475
476 void ves_icall_System_Threading_Monitor_Monitor_pulse_all(MonoObject *obj)
477 {
478         gboolean have_waiters=FALSE;
479         MonoThreadsSync *mon;
480         
481 #ifdef THREAD_LOCK_DEBUG
482         g_message("Pulsing all %p", obj);
483 #endif
484
485         EnterCriticalSection(&monitor_mutex);
486         
487         mon=obj->synchronisation;
488         if(mon==NULL) {
489                 LeaveCriticalSection(&monitor_mutex);
490                 return;
491         }
492
493         if(mon->tid!=GetCurrentThreadId()) {
494                 LeaveCriticalSection(&monitor_mutex);
495                 return;
496         }
497         LeaveCriticalSection(&monitor_mutex);
498         
499         EnterCriticalSection(&mon->waiters_count_lock);
500         if(mon->waiters_count>0) {
501                 mon->was_broadcast=TRUE;
502                 have_waiters=TRUE;
503         }
504         
505         if(have_waiters==TRUE) {
506                 ReleaseSemaphore(mon->sema, mon->waiters_count, 0);
507                 
508                 LeaveCriticalSection(&mon->waiters_count_lock);
509                 
510                 WaitForSingleObject(mon->waiters_done, INFINITE);
511                 mon->was_broadcast=FALSE;
512         } else {
513                 LeaveCriticalSection(&mon->waiters_count_lock);
514         }
515 }
516
517 gboolean ves_icall_System_Threading_Monitor_Monitor_wait(MonoObject *obj,
518                                                          int ms)
519 {
520         gboolean last_waiter;
521         MonoThreadsSync *mon;
522         guint32 save_count;
523         
524 #ifdef THREAD_LOCK_DEBUG
525         g_message("Trying to wait for %p in thread %d with timeout %dms", obj,
526                   GetCurrentThreadId(), ms);
527 #endif
528
529         EnterCriticalSection(&monitor_mutex);
530         
531         mon=obj->synchronisation;
532         if(mon==NULL) {
533                 LeaveCriticalSection(&monitor_mutex);
534                 return(FALSE);
535         }
536
537         if(mon->tid!=GetCurrentThreadId()) {
538                 LeaveCriticalSection(&monitor_mutex);
539                 return(FALSE);
540         }
541         LeaveCriticalSection(&monitor_mutex);
542         
543         EnterCriticalSection(&mon->waiters_count_lock);
544         mon->waiters_count++;
545         LeaveCriticalSection(&mon->waiters_count_lock);
546         
547 #ifdef THREAD_LOCK_DEBUG
548         g_message(G_GNUC_PRETTY_FUNCTION ": %p locked %d times", obj,
549                   mon->count);
550 #endif
551
552         /* We need to put the lock count back afterwards */
553         save_count=mon->count;
554         
555         while(mon->count>1) {
556 #ifdef THREAD_LOCK_DEBUG
557                 g_message(G_GNUC_PRETTY_FUNCTION ": Releasing mutex %p",
558                           mon->monitor);
559 #endif
560
561                 ReleaseMutex(mon->monitor);
562                 mon->count--;
563         }
564         
565         /* We're releasing this mutex */
566         mon->count=0;
567         mon->tid=0;
568 #ifdef THREAD_LOCK_DEBUG
569         g_message(G_GNUC_PRETTY_FUNCTION ": Signalling monitor mutex %p",
570                   mon->monitor);
571 #endif
572
573         SignalObjectAndWait(mon->monitor, mon->sema, INFINITE, FALSE);
574         
575         EnterCriticalSection(&mon->waiters_count_lock);
576         mon->waiters_count++;
577         last_waiter=mon->was_broadcast && mon->waiters_count==0;
578         LeaveCriticalSection(&mon->waiters_count_lock);
579         
580         if(last_waiter) {
581 #ifdef THREAD_LOCK_DEBUG
582         g_message(G_GNUC_PRETTY_FUNCTION ": Waiting for monitor mutex %p",
583                   mon->monitor);
584 #endif
585                 SignalObjectAndWait(mon->waiters_done, mon->monitor, INFINITE, FALSE);
586         } else {
587 #ifdef THREAD_LOCK_DEBUG
588         g_message(G_GNUC_PRETTY_FUNCTION ": Waiting for monitor mutex %p",
589                   mon->monitor);
590 #endif
591                 WaitForSingleObject(mon->monitor, INFINITE);
592         }
593
594         /* We've reclaimed this mutex */
595         mon->count=save_count;
596         mon->tid=GetCurrentThreadId();
597
598         /* Lock the mutex the required number of times */
599         while(save_count>1) {
600 #ifdef THREAD_LOCK_DEBUG
601                 g_message(G_GNUC_PRETTY_FUNCTION
602                           ": Waiting for monitor mutex %p", mon->monitor);
603 #endif
604                 WaitForSingleObject(mon->monitor, INFINITE);
605                 save_count--;
606         }
607         
608 #ifdef THREAD_LOCK_DEBUG
609         g_message(G_GNUC_PRETTY_FUNCTION ": %p still locked %d times", obj,
610                   mon->count);
611 #endif
612         
613         return(TRUE);
614 }
615
616 /* FIXME: exitContext isnt documented */
617 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
618 {
619         HANDLE *handles;
620         guint32 numhandles;
621         guint32 ret;
622         guint32 i;
623         
624         numhandles=mono_array_length(mono_handles);
625         handles=g_new0(HANDLE, numhandles);
626         for(i=0; i<numhandles; i++) {
627                 handles[i]=mono_array_get(mono_handles, HANDLE, i);
628         }
629         
630         if(ms== -1) {
631                 ms=INFINITE;
632         }
633         
634         ret=WaitForMultipleObjects(numhandles, handles, TRUE, ms);
635
636         g_free(handles);
637         
638         if(ret==WAIT_FAILED) {
639 #ifdef THREAD_WAIT_DEBUG
640                 g_message(G_GNUC_PRETTY_FUNCTION ": Wait failed");
641 #endif
642                 return(FALSE);
643         } else if(ret==WAIT_TIMEOUT) {
644 #ifdef THREAD_WAIT_DEBUG
645                 g_message(G_GNUC_PRETTY_FUNCTION ": Wait timed out");
646 #endif
647                 return(FALSE);
648         }
649         
650         return(TRUE);
651 }
652
653 /* FIXME: exitContext isnt documented */
654 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
655 {
656         HANDLE *handles;
657         guint32 numhandles;
658         guint32 ret;
659         guint32 i;
660         
661         numhandles=mono_array_length(mono_handles);
662         handles=g_new0(HANDLE, numhandles);
663         for(i=0; i<numhandles; i++) {
664                 handles[i]=mono_array_get(mono_handles, HANDLE, i);
665         }
666         
667         if(ms== -1) {
668                 ms=INFINITE;
669         }
670
671         ret=WaitForMultipleObjects(numhandles, handles, FALSE, ms);
672
673         g_free(handles);
674         
675 #ifdef THREAD_WAIT_DEBUG
676         g_message(G_GNUC_PRETTY_FUNCTION ": returning %d", ret);
677 #endif
678
679         return(ret);
680 }
681
682 /* FIXME: exitContext isnt documented */
683 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
684 {
685         guint32 ret;
686         
687 #ifdef THREAD_WAIT_DEBUG
688         g_message(G_GNUC_PRETTY_FUNCTION ": waiting for %p", handle);
689 #endif
690         
691         if(ms== -1) {
692                 ms=INFINITE;
693         }
694         
695         ret=WaitForSingleObject(handle, ms);
696         if(ret==WAIT_FAILED) {
697 #ifdef THREAD_WAIT_DEBUG
698                 g_message(G_GNUC_PRETTY_FUNCTION ": Wait failed");
699 #endif
700                 return(FALSE);
701         } else if(ret==WAIT_TIMEOUT) {
702 #ifdef THREAD_WAIT_DEBUG
703                 g_message(G_GNUC_PRETTY_FUNCTION ": Wait timed out");
704 #endif
705                 return(FALSE);
706         }
707         
708         return(TRUE);
709 }
710
711 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned,char *name) {    
712    return(CreateMutex(NULL,owned,name));                         
713 }                                                                   
714
715 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) { 
716         ReleaseMutex(handle);
717 }
718
719 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual,
720                                                                                                                           MonoBoolean initial,
721                                                                                                                           char *name) {
722         return (CreateEvent(NULL,manual,initial,name));
723 }
724
725 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
726         return (SetEvent(handle));
727 }
728
729 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
730         return (ResetEvent(handle));
731 }
732
733 void mono_thread_init(MonoDomain *domain)
734 {
735         MonoClass *thread_class;
736         
737         /* Build a System.Threading.Thread object instance to return
738          * for the main line's Thread.CurrentThread property.
739          */
740         thread_class=mono_class_from_name(mono_defaults.corlib, "System.Threading", "Thread");
741         
742         /* I wonder what happens if someone tries to destroy this
743          * object? In theory, I guess the whole program should act as
744          * though exit() were called :-)
745          */
746 #ifdef THREAD_DEBUG
747         g_message(G_GNUC_PRETTY_FUNCTION
748                   ": Starting to build main Thread object");
749 #endif
750         main_thread = mono_object_new (domain, thread_class);
751 #ifdef THREAD_DEBUG
752         g_message(G_GNUC_PRETTY_FUNCTION
753                   ": Finished to building main Thread object");
754 #endif
755
756         InitializeCriticalSection(&threads_mutex);
757         InitializeCriticalSection(&monitor_mutex);
758         InitializeCriticalSection(&interlocked_mutex);
759         
760         current_object_key=TlsAlloc();
761         TlsSetValue(current_object_key, main_thread);
762
763         slothash_key=TlsAlloc();
764 }
765
766 void mono_thread_cleanup(void)
767 {
768         HANDLE wait[MAXIMUM_WAIT_OBJECTS];
769         guint32 i, j;
770         
771         /* join each thread that's still running */
772 #ifdef THREAD_DEBUG
773         g_message("Joining each running thread...");
774 #endif
775         
776         if(threads==NULL) {
777 #ifdef THREAD_DEBUG
778                 g_message("No threads");
779 #endif
780                 return;
781         }
782         
783         /* This isnt the right way to do it.
784          *
785          * The first method call should be started in its own thread,
786          * and then the main thread should poll an event and wait for
787          * any terminated threads, until there are none left.
788          */
789 #ifdef THREAD_DEBUG
790         g_message("There are %d threads to join", threads->len);
791         for(i=0; i<threads->len; i++) {
792                 g_message("Waiting for: %p", g_ptr_array_index(threads, i));
793         }
794 #endif
795
796         for(i=0; i<threads->len; i+=MAXIMUM_WAIT_OBJECTS) {
797                 for(j=0; j<MAXIMUM_WAIT_OBJECTS && i+j<threads->len; j++) {
798 #ifdef THREAD_DEBUG
799                         g_message("Waiting for threads %d in slot %d", i+j, j);
800 #endif
801                         wait[j]=g_ptr_array_index(threads, i+j);
802                 }
803 #ifdef THREAD_DEBUG
804                 g_message("%d threads to wait for in this batch", j);
805 #endif
806
807                 WaitForMultipleObjects(j, wait, TRUE, INFINITE);
808         }
809         
810         g_ptr_array_free(threads, FALSE);
811         threads=NULL;
812 }
813
814 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
815 {
816         return InterlockedIncrement (location);
817 }
818
819 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
820 {
821         gint32 lowret;
822         gint32 highret;
823
824         EnterCriticalSection(&interlocked_mutex);
825
826         lowret = InterlockedIncrement((gint32 *) location);
827         if (0 == lowret)
828                 highret = InterlockedIncrement((gint32 *) location + 1);
829         else
830                 highret = *((gint32 *) location + 1);
831
832         LeaveCriticalSection(&interlocked_mutex);
833
834         return (gint64) highret << 32 | (gint64) lowret;
835 }
836
837 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int(gint32 *location)
838 {
839         return InterlockedDecrement(location);
840 }
841
842 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long(gint64 * location)
843 {
844         gint32 lowret;
845         gint32 highret;
846
847         EnterCriticalSection(&interlocked_mutex);
848
849         lowret = InterlockedDecrement((gint32 *) location);
850         if (-1 == lowret)
851                 highret = InterlockedDecrement((gint32 *) location + 1);
852         else
853                 highret = *((gint32 *) location + 1);
854
855         LeaveCriticalSection(&interlocked_mutex);
856
857         return (gint64) highret << 32 | (gint64) lowret;
858 }
859
860 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int(gint32 *location1, gint32 value)
861 {
862         return InterlockedExchange(location1, value);
863 }
864
865 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object(MonoObject **location1, MonoObject *value)
866 {
867         return (MonoObject *) InterlockedExchangePointer((gpointer *) location1, value);
868 }
869
870 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single(gfloat *location1, gfloat value)
871 {
872         return (gfloat) InterlockedExchange((gint32 *) location1, (gint32) value);
873 }
874
875 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location1, gint32 value, gint32 comparand)
876 {
877         return InterlockedCompareExchange(location1, value, comparand);
878 }
879
880 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object(MonoObject **location1, MonoObject *value, MonoObject *comparand)
881 {
882         return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location1, value, comparand);
883 }
884
885 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single(gfloat *location1, gfloat value, gfloat comparand)
886 {
887         return (gfloat) InterlockedCompareExchange((gint32 *) location1, (gint32) value, (gint32) comparand);
888 }