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