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