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