* src/threads/native/threads.c: Let's see if this improves the dead lock situation...
[cacao.git] / src / threads / native / threads.c
1 /* src/threads/native/threads.c - native threads support
2
3    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Stefan Ring
28
29    Changes: Christian Thalinger
30
31    $Id: threads.c 4443 2006-02-05 13:39:34Z stefan $
32
33 */
34
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <assert.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41 #include <signal.h>
42 #include <sys/time.h>
43 #include <time.h>
44 #include <errno.h>
45
46 #include <pthread.h>
47 #include <semaphore.h>
48
49 #include "config.h"
50 #include "vm/types.h"
51
52 #include "arch.h"
53
54 #ifndef USE_MD_THREAD_STUFF
55 #include "machine-instr.h"
56 #else
57 #include "threads/native/generic-primitives.h"
58 #endif
59
60 #include "cacao/cacao.h"
61 #include "mm/boehm.h"
62 #include "mm/memory.h"
63 #include "native/native.h"
64 #include "native/include/java_lang_Object.h"
65 #include "native/include/java_lang_Throwable.h"
66 #include "native/include/java_lang_Thread.h"
67 #include "native/include/java_lang_ThreadGroup.h"
68 #include "native/include/java_lang_VMThread.h"
69 #include "threads/native/threads.h"
70 #include "toolbox/avl.h"
71 #include "toolbox/logging.h"
72 #include "vm/builtin.h"
73 #include "vm/exceptions.h"
74 #include "vm/global.h"
75 #include "vm/loader.h"
76 #include "vm/options.h"
77 #include "vm/stringlocal.h"
78 #include "vm/jit/asmpart.h"
79
80 #if !defined(__DARWIN__)
81 #if defined(__LINUX__)
82 #define GC_LINUX_THREADS
83 #elif defined(__MIPS__)
84 #define GC_IRIX_THREADS
85 #endif
86 #include "boehm-gc/include/gc.h"
87 #endif
88
89 #ifdef USE_MD_THREAD_STUFF
90 pthread_mutex_t _atomic_add_lock = PTHREAD_MUTEX_INITIALIZER;
91 pthread_mutex_t _cas_lock = PTHREAD_MUTEX_INITIALIZER;
92 pthread_mutex_t _mb_lock = PTHREAD_MUTEX_INITIALIZER;
93 #endif
94
95 #ifdef MUTEXSIM
96
97 /* We need this for older MacOSX (10.1.x) */
98
99 typedef struct {
100         pthread_mutex_t mutex;
101         pthread_t owner;
102         int count;
103 } pthread_mutex_rec_t;
104
105 static void pthread_mutex_init_rec(pthread_mutex_rec_t *m)
106 {
107         pthread_mutex_init(&m->mutex, NULL);
108         m->count = 0;
109 }
110
111 static void pthread_mutex_destroy_rec(pthread_mutex_rec_t *m)
112 {
113         pthread_mutex_destroy(&m->mutex);
114 }
115
116 static void pthread_mutex_lock_rec(pthread_mutex_rec_t *m)
117 {
118         for (;;)
119                 if (!m->count)
120                 {
121                         pthread_mutex_lock(&m->mutex);
122                         m->owner = pthread_self();
123                         m->count++;
124                         break;
125                 } else {
126                         if (m->owner != pthread_self())
127                                 pthread_mutex_lock(&m->mutex);
128                         else
129                         {
130                                 m->count++;
131                                 break;
132                         }
133                 }
134 }
135
136 static void pthread_mutex_unlock_rec(pthread_mutex_rec_t *m)
137 {
138         if (!--m->count)
139                 pthread_mutex_unlock(&m->mutex);
140 }
141
142 #else /* MUTEXSIM */
143
144 #define pthread_mutex_lock_rec pthread_mutex_lock
145 #define pthread_mutex_unlock_rec pthread_mutex_unlock
146 #define pthread_mutex_rec_t pthread_mutex_t
147
148 #endif /* MUTEXSIM */
149
150 static void setPriority(pthread_t tid, int priority)
151 {
152         struct sched_param schedp;
153         int policy;
154
155         pthread_getschedparam(tid, &policy, &schedp);
156         schedp.sched_priority = priority;
157         pthread_setschedparam(tid, policy, &schedp);
158 }
159
160
161 static avl_tree *criticaltree;
162 threadobject *mainthreadobj;
163
164 #ifndef HAVE___THREAD
165 pthread_key_t tkey_threadinfo;
166 #else
167 __thread threadobject *threadobj;
168 #endif
169
170 static pthread_mutex_rec_t compiler_mutex;
171 static pthread_mutex_rec_t tablelock;
172
173 void compiler_lock()
174 {
175         pthread_mutex_lock_rec(&compiler_mutex);
176 }
177
178 void compiler_unlock()
179 {
180         pthread_mutex_unlock_rec(&compiler_mutex);
181 }
182
183 void tables_lock()
184 {
185     pthread_mutex_lock_rec(&tablelock);
186 }
187
188 void tables_unlock()
189 {
190     pthread_mutex_unlock_rec(&tablelock);
191 }
192
193
194 static s4 criticalcompare(const void *pa, const void *pb)
195 {
196         const threadcritnode *na = pa;
197         const threadcritnode *nb = pb;
198
199         if (na->mcodebegin < nb->mcodebegin)
200                 return -1;
201         if (na->mcodebegin > nb->mcodebegin)
202                 return 1;
203         return 0;
204 }
205
206
207 static const threadcritnode *findcritical(u1 *mcodeptr)
208 {
209     avl_node *n;
210     const threadcritnode *m;
211
212     n = criticaltree->root;
213         m = NULL;
214
215     if (!n)
216         return NULL;
217
218     for (;;) {
219         const threadcritnode *d = n->data;
220
221         if (mcodeptr == d->mcodebegin)
222             return d;
223
224         if (mcodeptr < d->mcodebegin) {
225             if (n->childs[0])
226                 n = n->childs[0];
227             else
228                 return m;
229
230         } else {
231             if (n->childs[1]) {
232                 m = n->data;
233                 n = n->childs[1];
234             } else
235                 return n->data;
236         }
237     }
238 }
239
240
241 void thread_registercritical(threadcritnode *n)
242 {
243         avl_insert(criticaltree, n);
244 }
245
246 u1 *thread_checkcritical(u1 *mcodeptr)
247 {
248         const threadcritnode *n = findcritical(mcodeptr);
249         return (n && mcodeptr < n->mcodeend && mcodeptr > n->mcodebegin) ? n->mcoderestart : NULL;
250 }
251
252 static void thread_addstaticcritical()
253 {
254         /* XXX TWISTI: this is just a quick hack */
255 #if defined(ENABLE_JIT)
256         threadcritnode *n = &asm_criticalsections;
257
258         while (n->mcodebegin)
259                 thread_registercritical(n++);
260 #endif
261 }
262
263 static pthread_mutex_t threadlistlock;
264
265 static pthread_mutex_t stopworldlock;
266 volatile int stopworldwhere;
267
268 static sem_t suspend_ack;
269 #if defined(__MIPS__)
270 static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
271 static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
272 #endif
273
274 /*
275  * where - 1 from within GC
276            2 class numbering
277  */
278 void lock_stopworld(int where)
279 {
280         pthread_mutex_lock(&stopworldlock);
281         stopworldwhere = where;
282 }
283
284 void unlock_stopworld()
285 {
286         stopworldwhere = 0;
287         pthread_mutex_unlock(&stopworldlock);
288 }
289
290 #if !defined(__DARWIN__)
291 /* Caller must hold threadlistlock */
292 static int cast_sendsignals(int sig, int count)
293 {
294         /* Count threads */
295         threadobject *tobj = mainthreadobj;
296         nativethread *infoself = THREADINFO;
297
298         if (count == 0)
299                 do {
300                         count++;
301                         tobj = tobj->info.next;
302                 } while (tobj != mainthreadobj);
303
304         do {
305                 nativethread *info = &tobj->info;
306                 if (info != infoself)
307                         pthread_kill(info->tid, sig);
308                 tobj = tobj->info.next;
309         } while (tobj != mainthreadobj);
310
311         return count-1;
312 }
313
314 #else
315
316 static void cast_darwinstop()
317 {
318         threadobject *tobj = mainthreadobj;
319         nativethread *infoself = THREADINFO;
320
321         do {
322                 nativethread *info = &tobj->info;
323                 if (info != infoself)
324                 {
325                         thread_state_flavor_t flavor = PPC_THREAD_STATE;
326                         mach_msg_type_number_t thread_state_count = PPC_THREAD_STATE_COUNT;
327                         ppc_thread_state_t thread_state;
328                         mach_port_t thread = info->mach_thread;
329                         kern_return_t r;
330
331                         r = thread_suspend(thread);
332                         if (r != KERN_SUCCESS) {
333                                 log_text("thread_suspend failed");
334                                 assert(0);
335                         }
336
337                         r = thread_get_state(thread, flavor,
338                                 (natural_t*)&thread_state, &thread_state_count);
339                         if (r != KERN_SUCCESS) {
340                                 log_text("thread_get_state failed");
341                                 assert(0);
342                         }
343
344                         thread_restartcriticalsection(&thread_state);
345
346                         r = thread_set_state(thread, flavor,
347                                 (natural_t*)&thread_state, thread_state_count);
348                         if (r != KERN_SUCCESS) {
349                                 log_text("thread_set_state failed");
350                                 assert(0);
351                         }
352                 }
353                 tobj = tobj->info.next;
354         } while (tobj != mainthreadobj);
355 }
356
357 static void cast_darwinresume()
358 {
359         threadobject *tobj = mainthreadobj;
360         nativethread *infoself = THREADINFO;
361
362         do {
363                 nativethread *info = &tobj->info;
364                 if (info != infoself)
365                 {
366                         mach_port_t thread = info->mach_thread;
367                         kern_return_t r;
368
369                         r = thread_resume(thread);
370                         if (r != KERN_SUCCESS) {
371                                 log_text("thread_resume failed");
372                                 assert(0);
373                         }
374                 }
375                 tobj = tobj->info.next;
376         } while (tobj != mainthreadobj);
377 }
378
379 #endif
380
381 #if defined(__MIPS__)
382 static void cast_irixresume()
383 {
384         pthread_mutex_lock(&suspend_ack_lock);
385         pthread_cond_broadcast(&suspend_cond);
386         pthread_mutex_unlock(&suspend_ack_lock);
387 }
388 #endif
389
390 void cast_stopworld()
391 {
392         int count, i;
393         lock_stopworld(2);
394         pthread_mutex_lock(&threadlistlock);
395 #if defined(__DARWIN__)
396         cast_darwinstop();
397 #else
398         count = cast_sendsignals(GC_signum1(), 0);
399         for (i=0; i<count; i++)
400                 sem_wait(&suspend_ack);
401 #endif
402         pthread_mutex_unlock(&threadlistlock);
403 }
404
405 void cast_startworld()
406 {
407         pthread_mutex_lock(&threadlistlock);
408 #if defined(__DARWIN__)
409         cast_darwinresume();
410 #elif defined(__MIPS__)
411         cast_irixresume();
412 #else
413         cast_sendsignals(GC_signum2(), -1);
414 #endif
415         pthread_mutex_unlock(&threadlistlock);
416         unlock_stopworld();
417 }
418
419 #if !defined(__DARWIN__)
420 static void sigsuspend_handler(ucontext_t *ctx)
421 {
422         int sig;
423         sigset_t sigs;
424         
425         /* XXX TWISTI: this is just a quick hack */
426 #if defined(ENABLE_JIT)
427         thread_restartcriticalsection(ctx);
428 #endif
429
430         /* Do as Boehm does. On IRIX a condition variable is used for wake-up
431            (not POSIX async-safe). */
432 #if defined(__IRIX__)
433         pthread_mutex_lock(&suspend_ack_lock);
434         sem_post(&suspend_ack);
435         pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
436         pthread_mutex_unlock(&suspend_ack_lock);
437 #else
438         sem_post(&suspend_ack);
439
440         sig = GC_signum2();
441         sigfillset(&sigs);
442         sigdelset(&sigs, sig);
443         sigsuspend(&sigs);
444 #endif
445 }
446
447 int cacao_suspendhandler(ucontext_t *ctx)
448 {
449         if (stopworldwhere != 2)
450                 return 0;
451
452         sigsuspend_handler(ctx);
453         return 1;
454 }
455 #endif
456
457 static void setthreadobject(threadobject *thread)
458 {
459 #if !defined(HAVE___THREAD)
460         pthread_setspecific(tkey_threadinfo, thread);
461 #else
462         threadobj = thread;
463 #endif
464 }
465
466
467 /* thread_setself **************************************************************
468
469    XXX
470
471 *******************************************************************************/
472
473 void *thread_getself(void)
474 {
475         return THREADOBJECT;
476 }
477
478
479 static monitorLockRecord *dummyLR;
480
481 static void initPools();
482
483
484 /* thread_preinit **************************************************************
485
486    Do some early initialization of stuff required.
487
488 *******************************************************************************/
489
490 void threads_preinit(void)
491 {
492 #ifndef MUTEXSIM
493         pthread_mutexattr_t mutexattr;
494         pthread_mutexattr_init(&mutexattr);
495         pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
496         pthread_mutex_init(&compiler_mutex, &mutexattr);
497         pthread_mutex_init(&tablelock, &mutexattr);
498         pthread_mutexattr_destroy(&mutexattr);
499 #else
500         pthread_mutex_init_rec(&compiler_mutex);
501         pthread_mutex_init_rec(&tablelock);
502 #endif
503
504         pthread_mutex_init(&threadlistlock, NULL);
505         pthread_mutex_init(&stopworldlock, NULL);
506
507         /* Allocate something so the garbage collector's signal handlers
508            are installed. */
509         heap_allocate(1, false, NULL);
510
511         mainthreadobj = NEW(threadobject);
512         mainthreadobj->info.tid = pthread_self();
513 #if !defined(HAVE___THREAD)
514         pthread_key_create(&tkey_threadinfo, NULL);
515 #endif
516         setthreadobject(mainthreadobj);
517         initPools();
518
519         /* Every newly created object's monitorPtr points here so we save
520            a check against NULL */
521
522         dummyLR = NEW(monitorLockRecord);
523         dummyLR->o = NULL;
524         dummyLR->ownerThread = NULL;
525         dummyLR->waiting = NULL;
526         dummyLR->incharge = dummyLR;
527
528         /* we need a working dummyLR before initializing the critical
529            section tree */
530
531     criticaltree = avl_create(&criticalcompare);
532
533         thread_addstaticcritical();
534         sem_init(&suspend_ack, 0, 0);
535 }
536
537
538 static pthread_attr_t threadattr;
539
540 static void freeLockRecordPools(lockRecordPool *);
541
542
543 /* threads_init ****************************************************************
544
545    Initializes the threads required by the JVM: main, finalizer.
546
547 *******************************************************************************/
548
549 bool threads_init(u1 *stackbottom)
550 {
551         java_lang_String      *threadname;
552         java_lang_Thread      *mainthread;
553         java_lang_ThreadGroup *threadgroup;
554         threadobject          *tempthread;
555         methodinfo            *method;
556
557         tempthread = mainthreadobj;
558
559         freeLockRecordPools(mainthreadobj->ee.lrpool);
560
561         /* This is kinda tricky, we grow the java.lang.Thread object so we
562            can keep the execution environment there. No Thread object must
563            have been created at an earlier time. */
564
565         class_java_lang_VMThread->instancesize = sizeof(threadobject);
566
567         /* create a VMThread */
568
569         mainthreadobj = (threadobject *) builtin_new(class_java_lang_VMThread);
570
571         if (!mainthreadobj)
572                 return false;
573
574         FREE(tempthread, threadobject);
575
576         initThread(&mainthreadobj->o);
577
578         setthreadobject(mainthreadobj);
579
580         initLocks();
581
582         mainthreadobj->info.next = mainthreadobj;
583         mainthreadobj->info.prev = mainthreadobj;
584
585 #if defined(ENABLE_INTRP)
586         /* create interpreter stack */
587
588         if (opt_intrp) {
589                 MSET(intrp_main_stack, 0, u1, opt_stacksize);
590                 mainthreadobj->info._global_sp = intrp_main_stack + opt_stacksize;
591         }
592 #endif
593
594         threadname = javastring_new(utf_new_char("main"));
595
596         /* allocate and init ThreadGroup */
597
598         threadgroup = (java_lang_ThreadGroup *)
599                 native_new_and_init(class_java_lang_ThreadGroup);
600
601         if (!threadgroup)
602                 throw_exception_exit();
603
604         /* create a Thread */
605
606         mainthread = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
607
608         if (!mainthread)
609                 throw_exception_exit();
610
611         mainthreadobj->o.thread = mainthread;
612
613         /* call Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
614
615         method = class_resolveclassmethod(class_java_lang_Thread,
616                                                                           utf_init,
617                                                                           utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
618                                                                           class_java_lang_Thread,
619                                                                           true);
620
621         if (!method)
622                 return false;
623
624         ASM_CALLJAVAFUNCTION(method, mainthread, mainthreadobj, threadname,
625                                                  (void *) 5);
626
627         if (*exceptionptr)
628                 return false;
629
630         mainthread->group = threadgroup;
631         /* XXX This is a hack because the fourth argument was omitted */
632         mainthread->daemon = false;
633
634         /* add mainthread to ThreadGroup */
635
636         method = class_resolveclassmethod(class_java_lang_ThreadGroup,
637                                                                           utf_new_char("addThread"),
638                                                                           utf_new_char("(Ljava/lang/Thread;)V"),
639                                                                           class_java_lang_ThreadGroup,
640                                                                           true);
641
642         if (!method)
643                 return false;
644
645         ASM_CALLJAVAFUNCTION(method, threadgroup, mainthread, NULL, NULL);
646
647         if (*exceptionptr)
648                 return false;
649
650         setPriority(pthread_self(), 5);
651
652         pthread_attr_init(&threadattr);
653         pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
654
655         /* everything's ok */
656
657         return true;
658 }
659
660
661 void initThread(java_lang_VMThread *t)
662 {
663         threadobject *thread = (threadobject*) t;
664         nativethread *info = &thread->info;
665         info->tid = pthread_self();
666         /* TODO destroy all those things */
667         pthread_mutex_init(&info->joinMutex, NULL);
668         pthread_cond_init(&info->joinCond, NULL);
669
670         pthread_mutex_init(&thread->waitLock, NULL);
671         pthread_cond_init(&thread->waitCond, NULL);
672         thread->interrupted = false;
673         thread->signaled = false;
674         thread->isSleeping = false;
675 }
676
677 static void initThreadLocks(threadobject *);
678
679
680 typedef struct {
681         threadobject *thread;
682         functionptr   function;
683         sem_t        *psem;
684         sem_t        *psem_first;
685 } startupinfo;
686
687
688 /* threads_startup *************************************************************
689
690    Thread startup function called by pthread_create.
691
692 ******************************************************************************/
693
694 static void *threads_startup_thread(void *t)
695 {
696         startupinfo  *startup;
697         threadobject *thread;
698         sem_t        *psem;
699         nativethread *info;
700         threadobject *tnext;
701         methodinfo   *method;
702         functionptr   function;
703
704 #if defined(ENABLE_INTRP)
705         u1 *intrp_thread_stack;
706
707         /* create interpreter stack */
708
709         if (opt_intrp) {
710                 intrp_thread_stack = (u1 *) alloca(opt_stacksize);
711                 MSET(intrp_thread_stack, 0, u1, opt_stacksize);
712         }
713 #endif
714
715         /* get passed startupinfo structure and the values in there */
716
717         startup = t;
718
719         thread   = startup->thread;
720         function = startup->function;
721         psem     = startup->psem;
722
723         info = &thread->info;
724
725         /* Seems like we've encountered a situation where info->tid was not set by
726          * pthread_create. We alleviate this problem by waiting for pthread_create
727          * to return. */
728         sem_wait(startup->psem_first);
729
730         t = NULL;
731 #if defined(__DARWIN__)
732         info->mach_thread = mach_thread_self();
733 #endif
734         setthreadobject(thread);
735
736         /* insert the thread into the threadlist */
737
738         pthread_mutex_lock(&threadlistlock);
739
740         info->prev = mainthreadobj;
741         info->next = tnext = mainthreadobj->info.next;
742         mainthreadobj->info.next = thread;
743         tnext->info.prev = thread;
744
745         pthread_mutex_unlock(&threadlistlock);
746
747         initThreadLocks(thread);
748
749         startup = NULL;
750         sem_post(psem);
751
752         setPriority(info->tid, thread->o.thread->priority);
753
754 #if defined(ENABLE_INTRP)
755         /* set interpreter stack */
756
757         if (opt_intrp)
758                 THREADINFO->_global_sp = (void *) (intrp_thread_stack + opt_stacksize);
759 #endif
760
761         /* find and run the Thread.run()V method if no other function was passed */
762
763         if (function == NULL) {
764                 method = class_resolveclassmethod(thread->o.header.vftbl->class,
765                                                                                   utf_run,
766                                                                                   utf_void__void,
767                                                                                   thread->o.header.vftbl->class,
768                                                                                   true);
769
770                 if (!method)
771                         throw_exception();
772
773                 ASM_CALLJAVAFUNCTION(method, thread, NULL, NULL, NULL);
774
775         } else {
776                 /* call passed function, e.g. finalizer_thread */
777
778                 (function)();
779         }
780
781         /* Allow lock record pools to be used by other threads. They
782            cannot be deleted so we'd better not waste them. */
783
784         freeLockRecordPools(thread->ee.lrpool);
785
786         /* remove thread from thread list, do this inside a lock */
787
788         pthread_mutex_lock(&threadlistlock);
789         info->next->info.prev = info->prev;
790         info->prev->info.next = info->next;
791         pthread_mutex_unlock(&threadlistlock);
792
793         /* reset thread id (lock on joinMutex? TWISTI) */
794
795         pthread_mutex_lock(&info->joinMutex);
796         info->tid = 0;
797         pthread_mutex_unlock(&info->joinMutex);
798
799         pthread_cond_broadcast(&info->joinCond);
800
801         return NULL;
802 }
803
804
805 /* threads_start_thread ********************************************************
806
807    Start a thread in the JVM.
808
809 ******************************************************************************/
810
811 void threads_start_thread(thread *t, functionptr function)
812 {
813         nativethread *info;
814         sem_t         sem;
815         sem_t         sem_first;
816         startupinfo   startup;
817
818         info = &((threadobject *) t->vmThread)->info;
819
820         /* fill startupinfo structure passed by pthread_create to XXX */
821
822         startup.thread     = (threadobject*) t->vmThread;
823         startup.function   = function;       /* maybe we don't call Thread.run()V */
824         startup.psem       = &sem;
825         startup.psem_first = &sem_first;
826
827         sem_init(&sem, 0, 0);
828         sem_init(&sem_first, 0, 0);
829         
830         if (pthread_create(&info->tid, &threadattr, threads_startup_thread,
831                                            &startup)) {
832                 log_text("pthread_create failed");
833                 assert(0);
834         }
835
836         sem_post(&sem_first);
837
838         /* wait here until the thread has entered itself into the thread list */
839
840         sem_wait(&sem);
841         sem_destroy(&sem);
842         sem_destroy(&sem_first);
843 }
844
845
846 /* At the end of the program, we wait for all running non-daemon threads to die
847  */
848
849 static threadobject *findNonDaemon(threadobject *thread)
850 {
851         while (thread != mainthreadobj) {
852                 if (!thread->o.thread->daemon)
853                         return thread;
854                 thread = thread->info.prev;
855         }
856
857         return NULL;
858 }
859
860 void joinAllThreads()
861 {
862         threadobject *thread;
863         pthread_mutex_lock(&threadlistlock);
864         while ((thread = findNonDaemon(mainthreadobj->info.prev)) != NULL) {
865                 nativethread *info = &thread->info;
866                 pthread_mutex_lock(&info->joinMutex);
867                 pthread_mutex_unlock(&threadlistlock);
868                 while (info->tid)
869                         pthread_cond_wait(&info->joinCond, &info->joinMutex);
870                 pthread_mutex_unlock(&info->joinMutex);
871                 pthread_mutex_lock(&threadlistlock);
872         }
873         pthread_mutex_unlock(&threadlistlock);
874 }
875
876 static void initLockRecord(monitorLockRecord *r, threadobject *t)
877 {
878         r->lockCount = 1;
879         r->ownerThread = t;
880         r->queuers = 0;
881         r->o = NULL;
882         r->waiter = NULL;
883         r->incharge = (monitorLockRecord *) &dummyLR;
884         r->waiting = NULL;
885         sem_init(&r->queueSem, 0, 0);
886         pthread_mutex_init(&r->resolveLock, NULL);
887         pthread_cond_init(&r->resolveWait, NULL);
888 }
889
890 /* No lock record must ever be destroyed because there may still be references
891  * to it.
892
893 static void destroyLockRecord(monitorLockRecord *r)
894 {
895         sem_destroy(&r->queueSem);
896         pthread_mutex_destroy(&r->resolveLock);
897         pthread_cond_destroy(&r->resolveWait);
898 }
899 */
900
901 void initLocks()
902 {
903         initThreadLocks(mainthreadobj);
904 }
905
906 static void initThreadLocks(threadobject *thread)
907 {
908         thread->ee.firstLR = NULL;
909         thread->ee.lrpool = NULL;
910         thread->ee.numlr = 0;
911 }
912
913 static lockRecordPool *allocNewLockRecordPool(threadobject *thread, int size)
914 {
915         lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
916         int i;
917
918         p->header.size = size;
919         for (i=0; i<size; i++) {
920                 initLockRecord(&p->lr[i], thread);
921                 p->lr[i].nextFree = &p->lr[i+1];
922         }
923         p->lr[i-1].nextFree = NULL;
924         return p;
925 }
926
927 #define INITIALLOCKRECORDS 8
928
929 pthread_mutex_t pool_lock;
930 lockRecordPool *global_pool;
931
932 static void initPools()
933 {
934         pthread_mutex_init(&pool_lock, NULL);
935 }
936
937 static lockRecordPool *allocLockRecordPool(threadobject *t, int size)
938 {
939         pthread_mutex_lock(&pool_lock);
940         if (global_pool) {
941                 int i;
942                 lockRecordPool *pool = global_pool;
943                 global_pool = pool->header.next;
944                 pthread_mutex_unlock(&pool_lock);
945
946                 for (i=0; i < pool->header.size; i++)
947                         pool->lr[i].ownerThread = t;
948                 
949                 return pool;
950         }
951         pthread_mutex_unlock(&pool_lock);
952
953         return allocNewLockRecordPool(t, size);
954 }
955
956 static void freeLockRecordPools(lockRecordPool *pool)
957 {
958         lockRecordPoolHeader *last;
959         pthread_mutex_lock(&pool_lock);
960         last = &pool->header;
961         while (last->next)
962                 last = &last->next->header;
963         last->next = global_pool;
964         global_pool = pool;
965         pthread_mutex_unlock(&pool_lock);
966 }
967
968 static monitorLockRecord *allocLockRecordSimple(threadobject *t)
969 {
970         monitorLockRecord *r = t->ee.firstLR;
971
972         if (!r) {
973                 int poolsize = t->ee.numlr ? t->ee.numlr * 2 : INITIALLOCKRECORDS;
974                 lockRecordPool *pool = allocLockRecordPool(t, poolsize);
975                 pool->header.next = t->ee.lrpool;
976                 t->ee.lrpool = pool;
977                 r = &pool->lr[0];
978                 t->ee.numlr += pool->header.size;
979         }
980         
981         t->ee.firstLR = r->nextFree;
982         return r;
983 }
984
985 static inline void recycleLockRecord(threadobject *t, monitorLockRecord *r)
986 {
987         r->nextFree = t->ee.firstLR;
988         t->ee.firstLR = r;
989 }
990
991 void initObjectLock(java_objectheader *o)
992 {
993         o->monitorPtr = dummyLR;
994 }
995
996
997 /* get_dummyLR *****************************************************************
998
999    Returns the global dummy monitor lock record. The pointer is
1000    required in the code generator to set up a virtual
1001    java_objectheader for code patch locking.
1002
1003 *******************************************************************************/
1004
1005 monitorLockRecord *get_dummyLR(void)
1006 {
1007         return dummyLR;
1008 }
1009
1010
1011 static void queueOnLockRecord(monitorLockRecord *lr, java_objectheader *o)
1012 {
1013         atomic_add(&lr->queuers, 1);
1014
1015         MEMORY_BARRIER_AFTER_ATOMIC();
1016
1017         if (lr->o == o)
1018                 sem_wait(&lr->queueSem);
1019
1020         atomic_add(&lr->queuers, -1);
1021 }
1022
1023 static void freeLockRecord(monitorLockRecord *lr)
1024 {
1025         int q;
1026         lr->o = NULL;
1027         MEMORY_BARRIER();
1028         q = lr->queuers;
1029         while (q--)
1030                 sem_post(&lr->queueSem);
1031 }
1032
1033 static inline void handleWaiter(monitorLockRecord *mlr, monitorLockRecord *lr, java_objectheader *o)
1034 {
1035         if (lr->waiting == o)
1036                 mlr->waiter = lr;
1037 }
1038
1039 monitorLockRecord *monitorEnter(threadobject *t, java_objectheader *o)
1040 {
1041         for (;;) {
1042                 monitorLockRecord *lr = o->monitorPtr;
1043                 if (lr->o != o) {
1044                         monitorLockRecord *nlr, *mlr = allocLockRecordSimple(t);
1045                         mlr->o = o;
1046                         if (mlr == lr) {
1047                                 MEMORY_BARRIER();
1048                                 nlr = o->monitorPtr;
1049                                 if (nlr == lr) {
1050                                         handleWaiter(mlr, lr, o);
1051                                         return mlr;
1052                                 }
1053                         } else {
1054                                 if (lr->ownerThread != t)
1055                                         mlr->incharge = lr;
1056                                 MEMORY_BARRIER_BEFORE_ATOMIC();
1057                                 nlr = (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) mlr);
1058                         }
1059                         if (nlr == lr) {
1060                                 if (mlr == lr || lr->o != o) {
1061                                         handleWaiter(mlr, lr, o);
1062                                         return mlr;
1063                                 }
1064                                 while (lr->o == o)
1065                                         queueOnLockRecord(lr, o);
1066                                 handleWaiter(mlr, lr, o);
1067                                 return mlr;
1068                         }
1069                         freeLockRecord(mlr);
1070                         recycleLockRecord(t, mlr);
1071                         queueOnLockRecord(nlr, o);
1072                 } else {
1073                         if (lr->ownerThread == t) {
1074                                 lr->lockCount++;
1075                                 return lr;
1076                         }
1077                         queueOnLockRecord(lr, o);
1078                 }
1079         }
1080 }
1081
1082 static void wakeWaiters(monitorLockRecord *lr)
1083 {
1084         monitorLockRecord *tmplr;
1085         s4 q;
1086
1087         /* assign lock record to a temporary variable */
1088
1089         tmplr = lr;
1090
1091         do {
1092                 q = tmplr->queuers;
1093
1094                 while (q--)
1095                         sem_post(&tmplr->queueSem);
1096
1097                 tmplr = tmplr->waiter;
1098         } while (tmplr != NULL && tmplr != lr);
1099 }
1100
1101 #define GRAB_LR(lr,t) \
1102     if (lr->ownerThread != t) { \
1103                 lr = lr->incharge; \
1104         }
1105
1106 #define CHECK_MONITORSTATE(lr,t,mo,a) \
1107     if (lr->o != mo || lr->ownerThread != t) { \
1108                 *exceptionptr = new_illegalmonitorstateexception(); \
1109                 a; \
1110         }
1111
1112 bool monitorExit(threadobject *t, java_objectheader *o)
1113 {
1114         monitorLockRecord *lr = o->monitorPtr;
1115         GRAB_LR(lr, t);
1116         CHECK_MONITORSTATE(lr, t, o, return false);
1117         if (lr->lockCount > 1) {
1118                 lr->lockCount--;
1119                 return true;
1120         }
1121         if (lr->waiter) {
1122                 monitorLockRecord *wlr = lr->waiter;
1123                 if (o->monitorPtr != lr ||
1124                         (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) wlr) != lr)
1125                 {
1126                         monitorLockRecord *nlr = o->monitorPtr;
1127                         nlr->waiter = wlr;
1128                         STORE_ORDER_BARRIER();
1129                 } else
1130                         wakeWaiters(wlr);
1131                 lr->waiter = NULL;
1132         }
1133         freeLockRecord(lr);
1134         recycleLockRecord(t, lr);
1135         return true;
1136 }
1137
1138 static void removeFromWaiters(monitorLockRecord *lr, monitorLockRecord *wlr)
1139 {
1140         do {
1141                 if (lr->waiter == wlr) {
1142                         lr->waiter = wlr->waiter;
1143                         break;
1144                 }
1145                 lr = lr->waiter;
1146         } while (lr);
1147 }
1148
1149 static inline bool timespec_less(const struct timespec *tv1, const struct timespec *tv2)
1150 {
1151         return tv1->tv_sec < tv2->tv_sec || (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
1152 }
1153
1154 static bool timeIsEarlier(const struct timespec *tv)
1155 {
1156         struct timeval tvnow;
1157         struct timespec tsnow;
1158         gettimeofday(&tvnow, NULL);
1159         tsnow.tv_sec = tvnow.tv_sec;
1160         tsnow.tv_nsec = tvnow.tv_usec * 1000;
1161         return timespec_less(&tsnow, tv);
1162 }
1163
1164
1165 /* waitWithTimeout *************************************************************
1166
1167    XXX
1168
1169 *******************************************************************************/
1170
1171 static bool waitWithTimeout(threadobject *t, monitorLockRecord *lr, struct timespec *wakeupTime)
1172 {
1173         bool wasinterrupted;
1174
1175         pthread_mutex_lock(&t->waitLock);
1176
1177         t->isSleeping = true;
1178
1179         if (wakeupTime->tv_sec || wakeupTime->tv_nsec)
1180                 while (!t->interrupted && !t->signaled && timeIsEarlier(wakeupTime))
1181                         pthread_cond_timedwait(&t->waitCond, &t->waitLock, wakeupTime);
1182         else
1183                 while (!t->interrupted && !t->signaled)
1184                         pthread_cond_wait(&t->waitCond, &t->waitLock);
1185
1186         wasinterrupted = t->interrupted;
1187         t->interrupted = false;
1188         t->signaled = false;
1189         t->isSleeping = false;
1190
1191         pthread_mutex_unlock(&t->waitLock);
1192
1193         return wasinterrupted;
1194 }
1195
1196
1197 static void calcAbsoluteTime(struct timespec *tm, s8 millis, s4 nanos)
1198 {
1199         if (millis || nanos) {
1200                 struct timeval tv;
1201                 long nsec;
1202                 gettimeofday(&tv, NULL);
1203                 tv.tv_sec += millis / 1000;
1204                 millis %= 1000;
1205                 nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
1206                 tm->tv_sec = tv.tv_sec + nsec / 1000000000;
1207                 tm->tv_nsec = nsec % 1000000000;
1208         } else {
1209                 tm->tv_sec = 0;
1210                 tm->tv_nsec = 0;
1211         }
1212 }
1213
1214 void monitorWait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
1215 {
1216         bool wasinterrupted;
1217         struct timespec wakeupTime;
1218         monitorLockRecord *mlr, *lr = o->monitorPtr;
1219         GRAB_LR(lr, t);
1220         CHECK_MONITORSTATE(lr, t, o, return);
1221
1222         calcAbsoluteTime(&wakeupTime, millis, nanos);
1223         
1224         if (lr->waiter)
1225                 wakeWaiters(lr->waiter);
1226         lr->waiting = o;
1227         STORE_ORDER_BARRIER();
1228         freeLockRecord(lr);
1229         wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
1230         mlr = monitorEnter(t, o);
1231         removeFromWaiters(mlr, lr);
1232         mlr->lockCount = lr->lockCount;
1233         lr->lockCount = 1;
1234         lr->waiting = NULL;
1235         lr->waiter = NULL;
1236         recycleLockRecord(t, lr);
1237
1238         if (wasinterrupted)
1239                 *exceptionptr = new_exception(string_java_lang_InterruptedException);
1240 }
1241
1242 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
1243 {
1244         monitorLockRecord *lr = o->monitorPtr;
1245         GRAB_LR(lr, t);
1246         CHECK_MONITORSTATE(lr, t, o, return);
1247         do {
1248                 threadobject *wthread;
1249                 monitorLockRecord *wlr = lr->waiter;
1250                 if (!wlr)
1251                         break;
1252                 wthread = wlr->ownerThread;
1253                 pthread_mutex_lock(&wthread->waitLock);
1254                 if (wthread->isSleeping)
1255                         pthread_cond_signal(&wthread->waitCond);
1256                 wthread->signaled = true;
1257                 pthread_mutex_unlock(&wthread->waitLock);
1258                 lr = wlr;
1259         } while (!one);
1260 }
1261
1262 bool threadHoldsLock(threadobject *t, java_objectheader *o)
1263 {
1264         monitorLockRecord *lr = o->monitorPtr;
1265         GRAB_LR(lr, t);
1266         /* The reason why we have to check against NULL is that
1267          * dummyLR->incharge == NULL */
1268         return lr->o == o && lr->ownerThread == t;
1269 }
1270
1271 void interruptThread(java_lang_VMThread *thread)
1272 {
1273         threadobject *t = (threadobject*) thread;
1274
1275         pthread_mutex_lock(&t->waitLock);
1276         if (t->isSleeping)
1277                 pthread_cond_signal(&t->waitCond);
1278         t->interrupted = true;
1279         pthread_mutex_unlock(&t->waitLock);
1280 }
1281
1282 bool interruptedThread()
1283 {
1284         threadobject *t = (threadobject*) THREADOBJECT;
1285         bool intr = t->interrupted;
1286         t->interrupted = false;
1287         return intr;
1288 }
1289
1290 bool isInterruptedThread(java_lang_VMThread *thread)
1291 {
1292         threadobject *t = (threadobject*) thread;
1293         return t->interrupted;
1294 }
1295
1296 void sleepThread(s8 millis, s4 nanos)
1297 {
1298         bool wasinterrupted;
1299         threadobject *t = (threadobject*) THREADOBJECT;
1300         monitorLockRecord *lr;
1301         struct timespec wakeupTime;
1302         calcAbsoluteTime(&wakeupTime, millis, nanos);
1303
1304         lr = allocLockRecordSimple(t);
1305         wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
1306         recycleLockRecord(t, lr);
1307
1308         if (wasinterrupted)
1309                 *exceptionptr = new_exception(string_java_lang_InterruptedException);
1310 }
1311
1312 void yieldThread()
1313 {
1314         sched_yield();
1315 }
1316
1317 void setPriorityThread(thread *t, s4 priority)
1318 {
1319         nativethread *info = &((threadobject*) t->vmThread)->info;
1320         setPriority(info->tid, priority);
1321 }
1322
1323 void wait_cond_for_object(java_objectheader *o, s8 time, s4 nanos)
1324 {
1325         threadobject *t = (threadobject*) THREADOBJECT;
1326         monitorWait(t, o, time, nanos);
1327 }
1328
1329 void signal_cond_for_object(java_objectheader *o)
1330 {
1331         threadobject *t = (threadobject*) THREADOBJECT;
1332         notifyOneOrAll(t, o, true);
1333 }
1334
1335 void broadcast_cond_for_object(java_objectheader *o)
1336 {
1337         threadobject *t = (threadobject*) THREADOBJECT;
1338         notifyOneOrAll(t, o, false);
1339 }
1340
1341
1342 /* threads_dump ****************************************************************
1343
1344    Dumps info for all threads running in the JVM. This function is
1345    called when SIGQUIT (<ctrl>-\) is sent to CACAO.
1346
1347 *******************************************************************************/
1348
1349 void threads_dump(void)
1350 {
1351         threadobject       *tobj;
1352         java_lang_VMThread *vmt;
1353         nativethread       *nt;
1354         ExecEnvironment    *ee;
1355         java_lang_Thread   *t;
1356         utf                *name;
1357
1358         tobj = mainthreadobj;
1359
1360         printf("Full thread dump CACAO "VERSION":\n");
1361
1362         /* iterate over all started threads */
1363
1364         do {
1365                 /* get thread objects */
1366
1367                 vmt = &tobj->o;
1368                 nt  = &tobj->info;
1369                 ee  = &tobj->ee;
1370                 t   = vmt->thread;
1371
1372                 /* the thread may be currently in initalization, don't print it */
1373
1374                 if (t) {
1375                         /* get thread name */
1376
1377                         name = javastring_toutf(t->name, false);
1378
1379                         printf("\n\"");
1380                         utf_display(name);
1381                         printf("\" ");
1382
1383                         if (t->daemon)
1384                                 printf("daemon ");
1385
1386 #if SIZEOF_VOID_P == 8
1387                         printf("prio=%d tid=0x%016lx\n", t->priority, nt->tid);
1388 #else
1389                         printf("prio=%d tid=0x%08lx\n", t->priority, nt->tid);
1390 #endif
1391
1392                         /* send SIGUSR1 to thread to print stacktrace */
1393
1394                         pthread_kill(nt->tid, SIGUSR1);
1395
1396                         /* sleep this thread a bit, so the signal can reach the thread */
1397
1398                         sleepThread(10, 0);
1399                 }
1400
1401                 tobj = tobj->info.next;
1402         } while (tobj && (tobj != mainthreadobj));
1403 }
1404
1405
1406 /*
1407  * These are local overrides for various environment variables in Emacs.
1408  * Please do not remove this and leave it at the end of the file, where
1409  * Emacs will automagically detect them.
1410  * ---------------------------------------------------------------------
1411  * Local variables:
1412  * mode: c
1413  * indent-tabs-mode: t
1414  * c-basic-offset: 4
1415  * tab-width: 4
1416  * End:
1417  */