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