2002-11-20 Dick Porter <dick@ximian.com>
[mono.git] / mono / metadata / threads.c
1 /*
2  * threads.c: Thread support internal calls
3  *
4  * Author:
5  *      Dick Porter (dick@ximian.com)
6  *      Patrik Torstensson (patrik.torstensson@labs2.com)
7  *
8  * (C) 2001 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <signal.h>
14
15 #include <mono/metadata/object.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/profiler-private.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/metadata/threads-types.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/io-layer/io-layer.h>
22
23 #include <mono/os/gc_wrapper.h>
24
25 #undef THREAD_DEBUG
26 #undef THREAD_LOCK_DEBUG
27 #undef THREAD_WAIT_DEBUG
28
29 struct StartInfo 
30 {
31         guint32 (*func)(void *);
32         MonoThread *obj;
33         void *this;
34         MonoDomain *domain;
35 };
36
37 typedef union {
38         gint32 ival;
39         gfloat fval;
40 } IntFloatUnion;
41  
42 /* Controls access to the 'threads' array */
43 static CRITICAL_SECTION threads_mutex;
44
45 /* Controls access to the sync field in MonoObjects, to avoid race
46  * conditions when adding sync data to an object for the first time.
47  */
48 static CRITICAL_SECTION monitor_mutex;
49
50 /* The hash of existing threads (key is thread ID) that need joining
51  * before exit
52  */
53 static MonoGHashTable *threads=NULL;
54
55 /* The MonoObject associated with the main thread */
56 static MonoThread *main_thread;
57
58 /* The TLS key that holds the MonoObject assigned to each thread */
59 static guint32 current_object_key;
60
61 /* function called at thread start */
62 static MonoThreadStartCB mono_thread_start_cb = NULL;
63
64 /* function called at thread attach */
65 static MonoThreadStartCB mono_thread_attach_cb = NULL;
66
67 /* The TLS key that holds the LocalDataStoreSlot hash in each thread */
68 static guint32 slothash_key;
69
70 /* Spin lock for InterlockedXXX 64 bit functions */
71 static CRITICAL_SECTION interlocked_mutex;
72
73 /* handle_store() and handle_remove() manage the array of threads that
74  * still need to be waited for when the main thread exits.
75  */
76 static void handle_store(MonoThread *thread)
77 {
78         EnterCriticalSection(&threads_mutex);
79
80 #ifdef THREAD_DEBUG
81         g_message(G_GNUC_PRETTY_FUNCTION ": thread %p ID %d", thread,
82                   thread->tid);
83 #endif
84
85         if(threads==NULL) {
86                 threads=mono_g_hash_table_new(g_int_hash, g_int_equal);
87         }
88
89         /* GHashTable will remove a previous entry if a duplicate key
90          * is stored, which is exactly what we want: we store the
91          * thread both in the start_wrapper (in the subthread), and as
92          * soon as possible in the parent thread.  This is to minimise
93          * the window in which the thread exists but we haven't
94          * recorded it.
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, &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, &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 (guint32 tid)
132 {
133         mono_profiler_thread_end (tid);
134         handle_remove (tid);
135 }
136
137 static guint32 start_wrapper(void *data)
138 {
139         struct StartInfo *start_info=(struct StartInfo *)data;
140         guint32 (*start_func)(void *);
141         void *this;
142         guint32 tid;
143         
144 #ifdef THREAD_DEBUG
145         g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper");
146 #endif
147         
148         start_func = start_info->func;
149         mono_domain_set (start_info->domain);
150         this = start_info->this;
151
152         tid=GetCurrentThreadId ();
153         /* Set the thread ID here as well as in the parent thread,
154          * because we don't know whether the thread object will
155          * already have its ID set before we get to it.  This isn't a
156          * race condition, because if we're not guaranteed to get the
157          * same number in both the parent and child threads, then
158          * something else is seriously broken.
159          */
160         start_info->obj->tid=tid;
161         
162         handle_store(start_info->obj);
163
164         mono_profiler_thread_start (tid);
165
166         mono_new_thread_init (start_info->obj, &tid);
167
168         g_free (start_info);
169
170         start_func (this);
171
172         /* If the thread calls ExitThread at all, this remaining code
173          * will not be executed, but the main thread will eventually
174          * call thread_cleanup() on this thread's behalf.
175          */
176
177 #ifdef THREAD_DEBUG
178         g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper terminating");
179 #endif
180         
181         thread_cleanup (tid);
182         
183         return(0);
184 }
185
186 void mono_new_thread_init (MonoThread *thread_object, gpointer stack_start)
187 {
188         /* FIXME: GC problem here with recorded object
189          * pointer!
190          *
191          * This is recorded so CurrentThread can return the
192          * Thread object.
193          */
194         TlsSetValue (current_object_key, thread_object);
195
196         if (mono_thread_start_cb) {
197                 mono_thread_start_cb (stack_start);
198         }
199 }
200
201 MonoThread *mono_thread_create (MonoDomain *domain, gpointer func,
202                                 gpointer arg)
203 {
204         MonoThread *thread;
205         HANDLE thread_handle;
206         struct StartInfo *start_info;
207         guint32 tid;
208         
209         thread = (MonoThread *)mono_object_new (domain,
210                                                 mono_defaults.thread_class);
211
212         start_info=g_new0 (struct StartInfo, 1);
213         start_info->func = func;
214         start_info->obj = thread;
215         start_info->domain = domain;
216         start_info->this = arg;
217                 
218         thread_handle = CreateThread(NULL, 0, start_wrapper, start_info, 0, &tid);
219 #ifdef THREAD_DEBUG
220         g_message(G_GNUC_PRETTY_FUNCTION ": Started thread ID %d (handle %p)",
221                   tid, thread_handle);
222 #endif
223         g_assert (thread_handle);
224
225         thread->handle=thread_handle;
226         thread->tid=tid;
227
228         handle_store(thread);
229
230         return thread;
231 }
232
233 MonoThread *
234 mono_thread_attach (MonoDomain *domain)
235 {
236         MonoThread *thread;
237         HANDLE thread_handle;
238         guint32 tid;
239
240         thread = (MonoThread *)mono_object_new (domain,
241                                                 mono_defaults.thread_class);
242
243         thread_handle = GetCurrentThread ();
244         g_assert (thread_handle);
245
246         tid=GetCurrentThreadId ();
247
248         thread->handle=thread_handle;
249         thread->tid=tid;
250
251 #ifdef THREAD_DEBUG
252         g_message(G_GNUC_PRETTY_FUNCTION ": Attached thread ID %d (handle %p)",
253                   tid, thread_handle);
254 #endif
255
256         handle_store(thread);
257
258         TlsSetValue (current_object_key, thread);
259         mono_domain_set (domain);
260
261         if (mono_thread_attach_cb) {
262                 mono_thread_attach_cb (&tid);
263         }
264
265         return(thread);
266 }
267
268 HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
269                                                          MonoObject *start)
270 {
271         MonoMulticastDelegate *delegate = (MonoMulticastDelegate*)start;
272         guint32 (*start_func)(void *);
273         struct StartInfo *start_info;
274         MonoMethod *im;
275         HANDLE thread;
276         guint32 tid;
277         
278 #ifdef THREAD_DEBUG
279         g_message(G_GNUC_PRETTY_FUNCTION
280                   ": Trying to start a new thread: this (%p) start (%p)",
281                   this, start);
282 #endif
283         
284         im = mono_get_delegate_invoke (start->vtable->klass);
285         start_func = mono_compile_method (im);
286
287         if(start_func==NULL) {
288                 g_warning(G_GNUC_PRETTY_FUNCTION
289                           ": Can't locate start method!");
290                 return(NULL);
291         } else {
292                 /* This is freed in start_wrapper */
293                 start_info = g_new0 (struct StartInfo, 1);
294                 start_info->func = start_func;
295                 start_info->this = delegate;
296                 start_info->obj = this;
297                 start_info->domain = mono_domain_get ();
298
299                 thread=CreateThread(NULL, 0, start_wrapper, start_info,
300                                     CREATE_SUSPENDED, &tid);
301                 if(thread==NULL) {
302                         g_warning(G_GNUC_PRETTY_FUNCTION
303                                   ": CreateThread error 0x%x", GetLastError());
304                         return(NULL);
305                 }
306
307                 this->handle=thread;
308                 this->tid=tid;
309
310                 /* Don't call handle_store() here, delay it to Start.
311                  * We can't join a thread (trying to will just block
312                  * forever) until it actually starts running, so don't
313                  * store the handle till then.
314                  */
315
316 #ifdef THREAD_DEBUG
317                 g_message(G_GNUC_PRETTY_FUNCTION
318                           ": Started thread ID %d (handle %p)", tid, thread);
319 #endif
320                 
321                 return(thread);
322         }
323 }
324
325 void ves_icall_System_Threading_Thread_Thread_free_internal (MonoThread *this,
326                                                              HANDLE thread)
327 {
328 #ifdef THREAD_DEBUG
329         g_message (G_GNUC_PRETTY_FUNCTION ": Closing thread %p, handle %p",
330                    this, thread);
331 #endif
332
333         CloseHandle (thread);
334 }
335
336 void ves_icall_System_Threading_Thread_Start_internal(MonoThread *this,
337                                                       HANDLE thread)
338 {
339 #ifdef THREAD_DEBUG
340         g_message(G_GNUC_PRETTY_FUNCTION ": Launching thread %p", this);
341 #endif
342
343         /* Only store the handle when the thread is about to be
344          * launched, to avoid the main thread deadlocking while trying
345          * to clean up a thread that will never be signalled.
346          */
347         handle_store(this);
348
349         ResumeThread(thread);
350 }
351
352 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
353 {
354 #ifdef THREAD_DEBUG
355         g_message(G_GNUC_PRETTY_FUNCTION ": Sleeping for %d ms", ms);
356 #endif
357
358         Sleep(ms);
359 }
360
361 gint32
362 ves_icall_System_Threading_Thread_GetDomainID (void) 
363 {
364         return mono_domain_get()->domain_id;
365 }
366
367 MonoThread *
368 mono_thread_current (void)
369 {
370         MonoThread *thread;
371         
372         /* Find the current thread object */
373         thread=TlsGetValue (current_object_key);
374         
375 #ifdef THREAD_DEBUG
376         g_message (G_GNUC_PRETTY_FUNCTION ": returning %p", thread);
377 #endif
378
379         return (thread);
380 }
381
382 gboolean ves_icall_System_Threading_Thread_Join_internal(MonoThread *this,
383                                                          int ms, HANDLE thread)
384 {
385         gboolean ret;
386         
387         if(ms== -1) {
388                 ms=INFINITE;
389         }
390 #ifdef THREAD_DEBUG
391         g_message (G_GNUC_PRETTY_FUNCTION ": joining thread handle %p, %d ms",
392                    thread, ms);
393 #endif
394         
395         ret=WaitForSingleObject(thread, ms);
396         if(ret==WAIT_OBJECT_0) {
397 #ifdef THREAD_DEBUG
398                 g_message (G_GNUC_PRETTY_FUNCTION ": join successful");
399 #endif
400
401                 return(TRUE);
402         }
403         
404 #ifdef THREAD_DEBUG
405                 g_message (G_GNUC_PRETTY_FUNCTION ": join failed");
406 #endif
407
408         return(FALSE);
409 }
410
411 void ves_icall_System_Threading_Thread_SlotHash_store(MonoObject *data)
412 {
413 #ifdef THREAD_DEBUG
414         g_message(G_GNUC_PRETTY_FUNCTION ": Storing key %p", data);
415 #endif
416
417         /* Object location stored here */
418         TlsSetValue(slothash_key, data);
419 }
420
421 MonoObject *ves_icall_System_Threading_Thread_SlotHash_lookup(void)
422 {
423         MonoObject *data;
424
425         data=TlsGetValue(slothash_key);
426         
427 #ifdef THREAD_DEBUG
428         g_message(G_GNUC_PRETTY_FUNCTION ": Retrieved key %p", data);
429 #endif
430         
431         return(data);
432 }
433
434 static void mon_finalize (void *o, void *unused)
435 {
436         MonoThreadsSync *mon=(MonoThreadsSync *)o;
437         
438 #ifdef THREAD_LOCK_DEBUG
439         g_message (G_GNUC_PRETTY_FUNCTION ": Finalizing sync");
440 #endif
441         
442         CloseHandle (mon->monitor);
443         CloseHandle (mon->sema);
444         CloseHandle (mon->waiters_done);
445 }
446
447 static MonoThreadsSync *mon_new(void)
448 {
449         MonoThreadsSync *new;
450         
451 #if HAVE_BOEHM_GC
452         new=(MonoThreadsSync *)GC_MALLOC (sizeof(MonoThreadsSync));
453         GC_REGISTER_FINALIZER (new, mon_finalize, NULL, NULL, NULL);
454 #else
455         /* This should be freed when the object that owns it is
456          * deleted
457          */
458         new=(MonoThreadsSync *)g_new0 (MonoThreadsSync, 1);
459 #endif
460         
461         new->monitor=CreateMutex(NULL, FALSE, NULL);
462         if(new->monitor==NULL) {
463                 /* Throw some sort of system exception? (ditto for the
464                  * sem and event handles below)
465                  */
466         }
467
468         new->waiters_count=0;
469         new->was_broadcast=FALSE;
470         InitializeCriticalSection(&new->waiters_count_lock);
471         new->sema=CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
472         new->waiters_done=CreateEvent(NULL, FALSE, FALSE, NULL);
473         
474 #ifdef THREAD_LOCK_DEBUG
475         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) ThreadsSync %p mutex created: %p, sem: %p, event: %p", GetCurrentThreadId (), new, new->monitor, new->sema, new->waiters_done);
476 #endif
477         
478         return(new);
479 }
480
481 gboolean ves_icall_System_Threading_Monitor_Monitor_try_enter(MonoObject *obj,
482                                                               int ms)
483 {
484         MonoThreadsSync *mon;
485         guint32 ret;
486         
487 #ifdef THREAD_LOCK_DEBUG
488         g_message(G_GNUC_PRETTY_FUNCTION
489                   ": (%d) Trying to lock object %p", GetCurrentThreadId(),
490                   obj);
491 #endif
492
493         EnterCriticalSection(&monitor_mutex);
494
495         mon=obj->synchronisation;
496         if(mon==NULL) {
497                 mon=mon_new();
498                 obj->synchronisation=mon;
499         }
500         
501         /* Don't hold the monitor lock while waiting to acquire the
502          * object lock
503          */
504         LeaveCriticalSection(&monitor_mutex);
505         
506         /* Acquire the mutex */
507 #ifdef THREAD_LOCK_DEBUG
508         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Acquiring monitor mutex %p",
509                   GetCurrentThreadId (), mon->monitor);
510 #endif
511         ret=WaitForSingleObject(mon->monitor, ms);
512         if(ret==WAIT_OBJECT_0) {
513                 mon->count++;
514                 mon->tid=GetCurrentThreadId();
515         
516 #ifdef THREAD_LOCK_DEBUG
517                 g_message(G_GNUC_PRETTY_FUNCTION
518                           ": (%d) object %p now locked %d times",
519                           GetCurrentThreadId (), obj, mon->count);
520 #endif
521
522                 return(TRUE);
523         }
524
525         return(FALSE);
526 }
527
528 void ves_icall_System_Threading_Monitor_Monitor_exit(MonoObject *obj)
529 {
530         MonoThreadsSync *mon;
531         
532 #ifdef THREAD_LOCK_DEBUG
533         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Unlocking %p",
534                   GetCurrentThreadId (), obj);
535 #endif
536
537         /* No need to lock monitor_mutex here because we only adjust
538          * the monitor state if this thread already owns the lock
539          */
540         mon=obj->synchronisation;
541
542         if(mon==NULL) {
543                 return;
544         }
545
546         if(mon->tid!=GetCurrentThreadId()) {
547                 return;
548         }
549         
550         mon->count--;
551         
552 #ifdef THREAD_LOCK_DEBUG
553         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p now locked %d times",
554                   GetCurrentThreadId (), obj, mon->count);
555 #endif
556
557         if(mon->count==0) {
558                 mon->tid=0;     /* FIXME: check that 0 isnt a valid id */
559         }
560         
561 #ifdef THREAD_LOCK_DEBUG
562         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Releasing mutex %p",
563                   GetCurrentThreadId (), mon->monitor);
564 #endif
565
566         ReleaseMutex(mon->monitor);
567 }
568
569 gboolean ves_icall_System_Threading_Monitor_Monitor_test_owner(MonoObject *obj)
570 {
571         MonoThreadsSync *mon;
572         gboolean ret=FALSE;
573         
574 #ifdef THREAD_LOCK_DEBUG
575         g_message(G_GNUC_PRETTY_FUNCTION
576                   ": Testing if %p is owned by thread %d", obj,
577                   GetCurrentThreadId());
578 #endif
579
580         EnterCriticalSection(&monitor_mutex);
581         
582         mon=obj->synchronisation;
583         if(mon==NULL) {
584                 goto finished;
585         }
586
587         if(mon->tid!=GetCurrentThreadId()) {
588 #ifdef THREAD_LOCK_DEBUG
589                 g_message (G_GNUC_PRETTY_FUNCTION
590                            ": (%d) object %p is owned by thread %d",
591                            GetCurrentThreadId (), obj, mon->tid);
592 #endif
593
594                 goto finished;
595         }
596         
597         ret=TRUE;
598         
599 finished:
600         LeaveCriticalSection(&monitor_mutex);
601
602         return(ret);
603 }
604
605 gboolean ves_icall_System_Threading_Monitor_Monitor_test_synchronised(MonoObject *obj)
606 {
607         MonoThreadsSync *mon;
608         gboolean ret=FALSE;
609         
610 #ifdef THREAD_LOCK_DEBUG
611         g_message(G_GNUC_PRETTY_FUNCTION
612                   ": (%d) Testing if %p is owned by any thread",
613                   GetCurrentThreadId (), obj);
614 #endif
615
616         EnterCriticalSection(&monitor_mutex);
617         
618         mon=obj->synchronisation;
619         if(mon==NULL) {
620                 goto finished;
621         }
622
623         if(mon->tid==0) {
624                 goto finished;
625         }
626         
627         g_assert(mon->count);
628         
629         ret=TRUE;
630         
631 finished:
632         LeaveCriticalSection(&monitor_mutex);
633
634         return(ret);
635 }
636
637         
638 void ves_icall_System_Threading_Monitor_Monitor_pulse(MonoObject *obj)
639 {
640         gboolean have_waiters;
641         MonoThreadsSync *mon;
642         
643 #ifdef THREAD_LOCK_DEBUG
644         g_message("(%d) Pulsing %p", GetCurrentThreadId (), obj);
645 #endif
646
647         EnterCriticalSection(&monitor_mutex);
648         
649         mon=obj->synchronisation;
650         if(mon==NULL) {
651                 LeaveCriticalSection(&monitor_mutex);
652                 return;
653         }
654
655         if(mon->tid!=GetCurrentThreadId()) {
656                 LeaveCriticalSection(&monitor_mutex);
657                 return;
658         }
659         LeaveCriticalSection(&monitor_mutex);
660         
661         EnterCriticalSection(&mon->waiters_count_lock);
662         have_waiters=(mon->waiters_count>0);
663         LeaveCriticalSection(&mon->waiters_count_lock);
664         
665         if(have_waiters==TRUE) {
666                 ReleaseSemaphore(mon->sema, 1, 0);
667         }
668 }
669
670 void ves_icall_System_Threading_Monitor_Monitor_pulse_all(MonoObject *obj)
671 {
672         gboolean have_waiters=FALSE;
673         MonoThreadsSync *mon;
674         
675 #ifdef THREAD_LOCK_DEBUG
676         g_message("(%d) Pulsing all %p", GetCurrentThreadId (), obj);
677 #endif
678
679         EnterCriticalSection(&monitor_mutex);
680         
681         mon=obj->synchronisation;
682         if(mon==NULL) {
683                 LeaveCriticalSection(&monitor_mutex);
684                 return;
685         }
686
687         if(mon->tid!=GetCurrentThreadId()) {
688                 LeaveCriticalSection(&monitor_mutex);
689                 return;
690         }
691         LeaveCriticalSection(&monitor_mutex);
692         
693         EnterCriticalSection(&mon->waiters_count_lock);
694         if(mon->waiters_count>0) {
695                 mon->was_broadcast=TRUE;
696                 have_waiters=TRUE;
697         }
698         
699         if(have_waiters==TRUE) {
700                 ReleaseSemaphore(mon->sema, mon->waiters_count, 0);
701                 
702                 LeaveCriticalSection(&mon->waiters_count_lock);
703                 
704                 WaitForSingleObject(mon->waiters_done, INFINITE);
705                 mon->was_broadcast=FALSE;
706         } else {
707                 LeaveCriticalSection(&mon->waiters_count_lock);
708         }
709 }
710
711 gboolean ves_icall_System_Threading_Monitor_Monitor_wait(MonoObject *obj,
712                                                          int ms)
713 {
714         gboolean last_waiter;
715         MonoThreadsSync *mon;
716         guint32 save_count;
717         
718 #ifdef THREAD_LOCK_DEBUG
719         g_message("(%d) Trying to wait for %p with timeout %dms",
720                   GetCurrentThreadId (), obj, ms);
721 #endif
722
723         EnterCriticalSection(&monitor_mutex);
724         
725         mon=obj->synchronisation;
726         if(mon==NULL) {
727                 LeaveCriticalSection(&monitor_mutex);
728                 return(FALSE);
729         }
730
731         if(mon->tid!=GetCurrentThreadId()) {
732                 LeaveCriticalSection(&monitor_mutex);
733                 return(FALSE);
734         }
735         LeaveCriticalSection(&monitor_mutex);
736         
737         EnterCriticalSection(&mon->waiters_count_lock);
738         mon->waiters_count++;
739         LeaveCriticalSection(&mon->waiters_count_lock);
740         
741 #ifdef THREAD_LOCK_DEBUG
742         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p locked %d times",
743                   GetCurrentThreadId (), obj, mon->count);
744 #endif
745
746         /* We need to put the lock count back afterwards */
747         save_count=mon->count;
748         
749         while(mon->count>1) {
750 #ifdef THREAD_LOCK_DEBUG
751                 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Releasing mutex %p",
752                           GetCurrentThreadId (), mon->monitor);
753 #endif
754
755                 ReleaseMutex(mon->monitor);
756                 mon->count--;
757         }
758         
759         /* We're releasing this mutex */
760         mon->count=0;
761         mon->tid=0;
762 #ifdef THREAD_LOCK_DEBUG
763         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Signalling monitor mutex %p",
764                   GetCurrentThreadId (), mon->monitor);
765 #endif
766
767         SignalObjectAndWait(mon->monitor, mon->sema, INFINITE, FALSE);
768         
769         EnterCriticalSection(&mon->waiters_count_lock);
770         mon->waiters_count++;
771         last_waiter=mon->was_broadcast && mon->waiters_count==0;
772         LeaveCriticalSection(&mon->waiters_count_lock);
773         
774         if(last_waiter) {
775 #ifdef THREAD_LOCK_DEBUG
776         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Waiting for monitor mutex %p",
777                   GetCurrentThreadId (), mon->monitor);
778 #endif
779                 SignalObjectAndWait(mon->waiters_done, mon->monitor, INFINITE, FALSE);
780         } else {
781 #ifdef THREAD_LOCK_DEBUG
782         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Waiting for monitor mutex %p",
783                   GetCurrentThreadId (), mon->monitor);
784 #endif
785                 WaitForSingleObject(mon->monitor, INFINITE);
786         }
787
788         /* We've reclaimed this mutex */
789         mon->count=save_count;
790         mon->tid=GetCurrentThreadId();
791
792         /* Lock the mutex the required number of times */
793         while(save_count>1) {
794 #ifdef THREAD_LOCK_DEBUG
795                 g_message(G_GNUC_PRETTY_FUNCTION
796                           ": (%d) Waiting for monitor mutex %p",
797                           GetCurrentThreadId (), mon->monitor);
798 #endif
799                 WaitForSingleObject(mon->monitor, INFINITE);
800                 save_count--;
801         }
802         
803 #ifdef THREAD_LOCK_DEBUG
804         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p still locked %d times",
805                   GetCurrentThreadId (), obj, mon->count);
806 #endif
807         
808         return(TRUE);
809 }
810
811 /* FIXME: exitContext isnt documented */
812 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
813 {
814         HANDLE *handles;
815         guint32 numhandles;
816         guint32 ret;
817         guint32 i;
818         
819         numhandles=mono_array_length(mono_handles);
820         handles=g_new0(HANDLE, numhandles);
821         for(i=0; i<numhandles; i++) {
822                 handles[i]=mono_array_get(mono_handles, HANDLE, i);
823         }
824         
825         if(ms== -1) {
826                 ms=INFINITE;
827         }
828         
829         ret=WaitForMultipleObjects(numhandles, handles, TRUE, ms);
830
831         g_free(handles);
832         
833         if(ret==WAIT_FAILED) {
834 #ifdef THREAD_WAIT_DEBUG
835                 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
836                           GetCurrentThreadId ());
837 #endif
838                 return(FALSE);
839         } else if(ret==WAIT_TIMEOUT) {
840 #ifdef THREAD_WAIT_DEBUG
841                 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
842                           GetCurrentThreadId ());
843 #endif
844                 return(FALSE);
845         }
846         
847         return(TRUE);
848 }
849
850 /* FIXME: exitContext isnt documented */
851 gint32 ves_icall_System_Threading_WaitHandle_WaitAny_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
852 {
853         HANDLE *handles;
854         guint32 numhandles;
855         guint32 ret;
856         guint32 i;
857         
858         numhandles=mono_array_length(mono_handles);
859         handles=g_new0(HANDLE, numhandles);
860         for(i=0; i<numhandles; i++) {
861                 handles[i]=mono_array_get(mono_handles, HANDLE, i);
862         }
863         
864         if(ms== -1) {
865                 ms=INFINITE;
866         }
867
868         ret=WaitForMultipleObjects(numhandles, handles, FALSE, ms);
869
870         g_free(handles);
871         
872 #ifdef THREAD_WAIT_DEBUG
873         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) returning %d",
874                   GetCurrentThreadId (), ret);
875 #endif
876
877         return(ret);
878 }
879
880 /* FIXME: exitContext isnt documented */
881 gboolean ves_icall_System_Threading_WaitHandle_WaitOne_internal(MonoObject *this, HANDLE handle, gint32 ms, gboolean exitContext)
882 {
883         guint32 ret;
884         
885 #ifdef THREAD_WAIT_DEBUG
886         g_message(G_GNUC_PRETTY_FUNCTION ": (%d) waiting for %p",
887                   GetCurrentThreadId (), handle);
888 #endif
889         
890         if(ms== -1) {
891                 ms=INFINITE;
892         }
893         
894         ret=WaitForSingleObject(handle, ms);
895         if(ret==WAIT_FAILED) {
896 #ifdef THREAD_WAIT_DEBUG
897                 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait failed",
898                           GetCurrentThreadId ());
899 #endif
900                 return(FALSE);
901         } else if(ret==WAIT_TIMEOUT) {
902 #ifdef THREAD_WAIT_DEBUG
903                 g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Wait timed out",
904                           GetCurrentThreadId ());
905 #endif
906                 return(FALSE);
907         }
908         
909         return(TRUE);
910 }
911
912 HANDLE ves_icall_System_Threading_Mutex_CreateMutex_internal (MonoBoolean owned,char *name) {    
913    return(CreateMutex(NULL,owned,name));                         
914 }                                                                   
915
916 void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) { 
917         ReleaseMutex(handle);
918 }
919
920 HANDLE ves_icall_System_Threading_Events_CreateEvent_internal (MonoBoolean manual,
921                                                                                                                           MonoBoolean initial,
922                                                                                                                           char *name) {
923         return (CreateEvent(NULL,manual,initial,name));
924 }
925
926 gboolean ves_icall_System_Threading_Events_SetEvent_internal (HANDLE handle) {
927         return (SetEvent(handle));
928 }
929
930 gboolean ves_icall_System_Threading_Events_ResetEvent_internal (HANDLE handle) {
931         return (ResetEvent(handle));
932 }
933
934 gint32 ves_icall_System_Threading_Interlocked_Increment_Int (gint32 *location)
935 {
936         return InterlockedIncrement (location);
937 }
938
939 gint64 ves_icall_System_Threading_Interlocked_Increment_Long (gint64 *location)
940 {
941         gint32 lowret;
942         gint32 highret;
943
944         EnterCriticalSection(&interlocked_mutex);
945
946         lowret = InterlockedIncrement((gint32 *) location);
947         if (0 == lowret)
948                 highret = InterlockedIncrement((gint32 *) location + 1);
949         else
950                 highret = *((gint32 *) location + 1);
951
952         LeaveCriticalSection(&interlocked_mutex);
953
954         return (gint64) highret << 32 | (gint64) lowret;
955 }
956
957 gint32 ves_icall_System_Threading_Interlocked_Decrement_Int (gint32 *location)
958 {
959         return InterlockedDecrement(location);
960 }
961
962 gint64 ves_icall_System_Threading_Interlocked_Decrement_Long (gint64 * location)
963 {
964         gint32 lowret;
965         gint32 highret;
966
967         EnterCriticalSection(&interlocked_mutex);
968
969         lowret = InterlockedDecrement((gint32 *) location);
970         if (-1 == lowret)
971                 highret = InterlockedDecrement((gint32 *) location + 1);
972         else
973                 highret = *((gint32 *) location + 1);
974
975         LeaveCriticalSection(&interlocked_mutex);
976
977         return (gint64) highret << 32 | (gint64) lowret;
978 }
979
980 gint32 ves_icall_System_Threading_Interlocked_Exchange_Int (gint32 *location1, gint32 value)
981 {
982         return InterlockedExchange(location1, value);
983 }
984
985 MonoObject * ves_icall_System_Threading_Interlocked_Exchange_Object (MonoObject **location1, MonoObject *value)
986 {
987         return (MonoObject *) InterlockedExchangePointer((gpointer *) location1, value);
988 }
989
990 gfloat ves_icall_System_Threading_Interlocked_Exchange_Single (gfloat *location1, gfloat value)
991 {
992         IntFloatUnion val, ret;
993
994         val.fval = value;
995         ret.ival = InterlockedExchange((gint32 *) location1, val.ival);
996
997         return ret.fval;
998 }
999
1000 gint32 ves_icall_System_Threading_Interlocked_CompareExchange_Int(gint32 *location1, gint32 value, gint32 comparand)
1001 {
1002         return InterlockedCompareExchange(location1, value, comparand);
1003 }
1004
1005 MonoObject * ves_icall_System_Threading_Interlocked_CompareExchange_Object (MonoObject **location1, MonoObject *value, MonoObject *comparand)
1006 {
1007         return (MonoObject *) InterlockedCompareExchangePointer((gpointer *) location1, value, comparand);
1008 }
1009
1010 gfloat ves_icall_System_Threading_Interlocked_CompareExchange_Single (gfloat *location1, gfloat value, gfloat comparand)
1011 {
1012         IntFloatUnion val, ret, cmp;
1013
1014         val.fval = value;
1015         cmp.fval = comparand;
1016         ret.ival = InterlockedCompareExchange((gint32 *) location1, val.ival, cmp.ival);
1017
1018         return ret.fval;
1019 }
1020
1021 void
1022 ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
1023 {
1024         thread->abort_state = state;
1025         thread->abort_exc = mono_get_exception_thread_abort ();
1026
1027
1028         /* fixme: store the state somewhere */
1029 #ifndef __MINGW32__
1030 #ifdef PTHREAD_POINTER_ID
1031         pthread_kill (GUINT_TO_POINTER(thread->tid), SIGUSR1);
1032 #else
1033         pthread_kill (thread->tid, SIGUSR1);
1034 #endif
1035 #else
1036         g_assert_not_reached ();
1037 #endif
1038 }
1039
1040 void
1041 ves_icall_System_Threading_Thread_ResetAbort (void)
1042 {
1043         MonoThread *thread = mono_thread_current ();
1044         
1045         if (!thread->abort_exc) {
1046                 const char *msg = "Unable to reset abort because no abort was requested";
1047                 mono_raise_exception (mono_get_exception_thread_state (msg));
1048         } else {
1049                 thread->abort_exc = NULL;
1050                 thread->abort_state = NULL;
1051         }
1052 }
1053
1054 void mono_thread_init (MonoDomain *domain, MonoThreadStartCB start_cb,
1055                        MonoThreadStartCB attach_cb)
1056 {
1057         /* Build a System.Threading.Thread object instance to return
1058          * for the main line's Thread.CurrentThread property.
1059          */
1060         
1061         /* I wonder what happens if someone tries to destroy this
1062          * object? In theory, I guess the whole program should act as
1063          * though exit() were called :-)
1064          */
1065 #ifdef THREAD_DEBUG
1066         g_message(G_GNUC_PRETTY_FUNCTION
1067                   ": Starting to build main Thread object");
1068 #endif
1069         main_thread = (MonoThread *)mono_object_new (domain, mono_defaults.thread_class);
1070
1071         main_thread->handle = GetCurrentThread ();
1072
1073 #ifdef THREAD_DEBUG
1074         g_message(G_GNUC_PRETTY_FUNCTION
1075                   ": Finished building main Thread object: %p", main_thread);
1076 #endif
1077
1078         InitializeCriticalSection(&threads_mutex);
1079         InitializeCriticalSection(&monitor_mutex);
1080         InitializeCriticalSection(&interlocked_mutex);
1081         
1082         current_object_key=TlsAlloc();
1083 #ifdef THREAD_DEBUG
1084         g_message (G_GNUC_PRETTY_FUNCTION ": Allocated current_object_key %d",
1085                    current_object_key);
1086 #endif
1087
1088         TlsSetValue(current_object_key, main_thread);
1089
1090         mono_thread_start_cb = start_cb;
1091         mono_thread_attach_cb = attach_cb;
1092
1093         slothash_key=TlsAlloc();
1094
1095         /* Get a pseudo handle to the current process.  This is just a
1096          * kludge so that wapi can build a process handle if needed.
1097          * As a pseudo handle is returned, we don't need to clean
1098          * anything up.
1099          */
1100         GetCurrentProcess ();
1101 }
1102
1103 #ifdef THREAD_DEBUG
1104 static void print_tids (gpointer key, gpointer value, gpointer user)
1105 {
1106         g_message ("Waiting for: %d", *(guint32 *)key);
1107 }
1108 #endif
1109
1110 struct wait_data 
1111 {
1112         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1113         MonoThread *threads[MAXIMUM_WAIT_OBJECTS];
1114         guint32 num;
1115 };
1116
1117 static void wait_for_tids (struct wait_data *wait)
1118 {
1119         guint32 i, ret;
1120         
1121 #ifdef THREAD_DEBUG
1122         g_message(G_GNUC_PRETTY_FUNCTION
1123                   ": %d threads to wait for in this batch", wait->num);
1124 #endif
1125
1126         ret=WaitForMultipleObjects(wait->num, wait->handles, TRUE, INFINITE);
1127         if(ret==WAIT_FAILED) {
1128                 /* See the comment in build_wait_tids() */
1129 #ifdef THREAD_DEBUG
1130                 g_message (G_GNUC_PRETTY_FUNCTION ": Wait failed");
1131 #endif
1132                 return;
1133         }
1134         
1135
1136         for(i=0; i<wait->num; i++) {
1137                 guint32 tid=wait->threads[i]->tid;
1138                 
1139                 if(mono_g_hash_table_lookup (threads, &tid)!=NULL) {
1140                         /* This thread must have been killed, because
1141                          * it hasn't cleaned itself up. (It's just
1142                          * possible that the thread exited before the
1143                          * parent thread had a chance to store the
1144                          * handle, and now there is another pointer to
1145                          * the already-exited thread stored.  In this
1146                          * case, we'll just get two
1147                          * mono_profiler_thread_end() calls for the
1148                          * same thread.)
1149                          */
1150         
1151 #ifdef THREAD_DEBUG
1152                         g_message (G_GNUC_PRETTY_FUNCTION
1153                                    ": cleaning up after thread %d", tid);
1154 #endif
1155                         thread_cleanup (tid);
1156                 }
1157         }
1158 }
1159
1160 static void build_wait_tids (gpointer key, gpointer value, gpointer user)
1161 {
1162         struct wait_data *wait=(struct wait_data *)user;
1163
1164         if(wait->num<MAXIMUM_WAIT_OBJECTS) {
1165                 MonoThread *thread=(MonoThread *)value;
1166                 
1167                 /* Theres a theoretical chance that thread->handle
1168                  * might be NULL if the child thread has called
1169                  * handle_store() but the parent thread hasn't set the
1170                  * handle pointer yet.  WaitForMultipleObjects will
1171                  * fail, and we'll just go round the loop again.  By
1172                  * that time the handle should be stored properly.
1173                  */
1174                 wait->handles[wait->num]=thread->handle;
1175                 wait->threads[wait->num]=thread;
1176                 wait->num++;
1177         } else {
1178                 /* Just ignore the rest, we can't do anything with
1179                  * them yet
1180                  */
1181         }
1182 }
1183
1184 void mono_thread_cleanup(void)
1185 {
1186         struct wait_data *wait=g_new0 (struct wait_data, 1);
1187         
1188         /* join each thread that's still running */
1189 #ifdef THREAD_DEBUG
1190         g_message(G_GNUC_PRETTY_FUNCTION ": Joining each running thread...");
1191 #endif
1192         
1193         if(threads==NULL) {
1194 #ifdef THREAD_DEBUG
1195                 g_message(G_GNUC_PRETTY_FUNCTION ": No threads");
1196 #endif
1197                 return;
1198         }
1199         
1200         do {
1201                 EnterCriticalSection (&threads_mutex);
1202 #ifdef THREAD_DEBUG
1203                 g_message(G_GNUC_PRETTY_FUNCTION
1204                           ":There are %d threads to join",
1205                           mono_g_hash_table_size (threads));
1206                 mono_g_hash_table_foreach (threads, print_tids, NULL);
1207 #endif
1208
1209                 wait->num=0;
1210                 mono_g_hash_table_foreach (threads, build_wait_tids, wait);
1211         
1212                 LeaveCriticalSection (&threads_mutex);
1213                 if(wait->num>0) {
1214                         /* Something to wait for */
1215                         wait_for_tids (wait);
1216                 }
1217         } while(wait->num>0);
1218         
1219         g_free (wait);
1220         
1221         mono_g_hash_table_destroy(threads);
1222         threads=NULL;
1223 }