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