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