5c130cc701e6b8934967019ac38ed0f6fbeb3fe3
[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 = &dummyLR;
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 void initObjectLock(java_objectheader *o)
793 {
794         o->monitorPtr = dummyLR;
795 }
796
797 static void queueOnLockRecord(monitorLockRecord *lr, java_objectheader *o)
798 {
799         atomic_add(&lr->queuers, 1);
800         MEMORY_BARRIER_AFTER_ATOMIC();
801         if (lr->o == o)
802                 sem_wait(&lr->queueSem);
803         atomic_add(&lr->queuers, -1);
804 }
805
806 static void freeLockRecord(monitorLockRecord *lr)
807 {
808         int q;
809         lr->o = NULL;
810         MEMORY_BARRIER();
811         q = lr->queuers;
812         while (q--)
813                 sem_post(&lr->queueSem);
814 }
815
816 static inline void handleWaiter(monitorLockRecord *mlr, monitorLockRecord *lr)
817 {
818         if (lr->waiting)
819                 mlr->waiter = lr;
820 }
821
822 monitorLockRecord *monitorEnter(threadobject *t, java_objectheader *o)
823 {
824         for (;;) {
825                 monitorLockRecord *lr = o->monitorPtr;
826                 if (lr->o != o) {
827                         monitorLockRecord *nlr, *mlr = allocLockRecordSimple(t);
828                         mlr->o = o;
829                         if (mlr == lr) {
830                                 MEMORY_BARRIER();
831                                 nlr = o->monitorPtr;
832                                 if (nlr == lr) {
833                                         handleWaiter(mlr, lr);
834                                         return mlr;
835                                 }
836                         } else {
837                                 if (lr->ownerThread != t)
838                                         mlr->incharge = lr;
839                                 MEMORY_BARRIER_BEFORE_ATOMIC();
840                                 nlr = (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) mlr);
841                         }
842                         if (nlr == lr) {
843                                 if (mlr == lr || lr->o != o) {
844                                         handleWaiter(mlr, lr);
845                                         return mlr;
846                                 }
847                                 while (lr->o == o)
848                                         queueOnLockRecord(lr, o);
849                                 handleWaiter(mlr, lr);
850                                 return mlr;
851                         }
852                         freeLockRecord(mlr);
853                         recycleLockRecord(t, mlr);
854                         queueOnLockRecord(nlr, o);
855                 } else {
856                         if (lr->ownerThread == t) {
857                                 lr->lockCount++;
858                                 return lr;
859                         }
860                         queueOnLockRecord(lr, o);
861                 }
862         }
863 }
864
865 static void wakeWaiters(monitorLockRecord *lr)
866 {
867         do {
868                 int q = lr->queuers;
869                 while (q--)
870                         sem_post(&lr->queueSem);
871                 lr = lr->waiter;
872         } while (lr);
873 }
874
875 #define GRAB_LR(lr,t) \
876     if (lr->ownerThread != t) { \
877                 lr = lr->incharge; \
878         }
879
880 #define CHECK_MONITORSTATE(lr,t,mo,a) \
881     if (lr->o != mo || lr->ownerThread != t) { \
882                 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException); \
883                 a; \
884         }
885
886 bool monitorExit(threadobject *t, java_objectheader *o)
887 {
888         monitorLockRecord *lr = o->monitorPtr;
889         GRAB_LR(lr, t);
890         CHECK_MONITORSTATE(lr, t, o, return false);
891         if (lr->lockCount > 1) {
892                 lr->lockCount--;
893                 return true;
894         }
895         if (lr->waiter) {
896                 monitorLockRecord *wlr = lr->waiter;
897                 if (o->monitorPtr != lr ||
898                         (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) wlr) != lr)
899                 {
900                         monitorLockRecord *nlr = o->monitorPtr;
901                         nlr->waiter = wlr;
902                         STORE_ORDER_BARRIER();
903                 } else
904                         wakeWaiters(wlr);
905                 lr->waiter = NULL;
906         }
907         freeLockRecord(lr);
908         recycleLockRecord(t, lr);
909         return true;
910 }
911
912 static void removeFromWaiters(monitorLockRecord *lr, monitorLockRecord *wlr)
913 {
914         do {
915                 if (lr->waiter == wlr) {
916                         lr->waiter = wlr->waiter;
917                         break;
918                 }
919                 lr = lr->waiter;
920         } while (lr);
921 }
922
923 bool waitWithTimeout(threadobject *t, monitorLockRecord *lr, struct timespec *wakeupTime)
924 {
925         bool wasinterrupted;
926
927         pthread_mutex_lock(&lr->waitLock);
928         t->waiting = lr;
929         if (wakeupTime->tv_sec || wakeupTime->tv_nsec)
930                 pthread_cond_timedwait(&lr->waitCond, &lr->waitLock, wakeupTime);
931         else
932                 pthread_cond_wait(&lr->waitCond, &lr->waitLock);
933         wasinterrupted = t->waiting == NULL;
934         t->waiting = NULL;
935         pthread_mutex_unlock(&lr->waitLock);
936         return wasinterrupted;
937 }
938
939 static void calcAbsoluteTime(struct timespec *tm, s8 millis, s4 nanos)
940 {
941         if (millis || nanos) {
942                 struct timeval tv;
943                 long nsec;
944                 gettimeofday(&tv, NULL);
945                 tv.tv_sec += millis / 1000;
946                 millis %= 1000;
947                 nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
948                 tm->tv_sec = tv.tv_sec + nsec / 1000000000;
949                 tm->tv_nsec = nsec % 1000000000;
950         } else {
951                 tm->tv_sec = 0;
952                 tm->tv_nsec = 0;
953         }
954 }
955
956 void monitorWait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
957 {
958         bool wasinterrupted;
959         struct timespec wakeupTime;
960         monitorLockRecord *mlr, *lr = o->monitorPtr;
961         GRAB_LR(lr, t);
962         CHECK_MONITORSTATE(lr, t, o, return);
963
964         calcAbsoluteTime(&wakeupTime, millis, nanos);
965         
966         if (lr->waiter)
967                 wakeWaiters(lr->waiter);
968         lr->waiting = true;
969         STORE_ORDER_BARRIER();
970         freeLockRecord(lr);
971         wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
972         mlr = monitorEnter(t, o);
973         removeFromWaiters(mlr, lr);
974         mlr->lockCount = lr->lockCount;
975         lr->lockCount = 1;
976         lr->waiting = false;
977         lr->waiter = NULL;
978         recycleLockRecord(t, lr);
979
980         if (wasinterrupted)
981                 *exceptionptr = new_exception(string_java_lang_InterruptedException);
982 }
983
984 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
985 {
986         monitorLockRecord *lr = o->monitorPtr;
987         GRAB_LR(lr, t);
988         CHECK_MONITORSTATE(lr, t, o, return);
989         do {
990                 monitorLockRecord *wlr = lr->waiter;
991                 if (!wlr)
992                         break;
993                 pthread_cond_signal(&wlr->waitCond);
994                 lr = wlr;
995         } while (!one);
996 }
997
998 bool threadHoldsLock(threadobject *t, java_objectheader *o)
999 {
1000         monitorLockRecord *lr = o->monitorPtr;
1001         GRAB_LR(lr, t);
1002         return lr->o == o && lr->ownerThread == t;
1003 }
1004
1005 void interruptThread(java_lang_VMThread *thread)
1006 {
1007         threadobject *t = (threadobject*) thread;
1008
1009         monitorLockRecord *lr = t->waiting;
1010         if (lr) {
1011                 pthread_mutex_lock(&lr->waitLock);
1012                 if (t->waiting == lr) {
1013                         t->waiting = NULL;
1014                         pthread_cond_signal(&lr->waitCond);
1015                 }
1016                 pthread_mutex_unlock(&lr->waitLock);
1017                 return;
1018         }
1019         
1020         t->interrupted = 1;
1021 }
1022
1023 bool interruptedThread()
1024 {
1025         threadobject *t = (threadobject*) THREADOBJECT;
1026         long intr = t->interrupted;
1027         t->interrupted = 0;
1028         return intr;
1029 }
1030
1031 bool isInterruptedThread(java_lang_VMThread *thread)
1032 {
1033         threadobject *t = (threadobject*) thread;
1034         return t->interrupted;
1035 }
1036
1037 void sleepThread(s8 millis, s4 nanos)
1038 {
1039         bool wasinterrupted;
1040         threadobject *t = (threadobject*) THREADOBJECT;
1041         monitorLockRecord *lr;
1042         struct timespec wakeupTime;
1043         calcAbsoluteTime(&wakeupTime, millis, nanos);
1044
1045         lr = allocLockRecordSimple(t);
1046         wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
1047         recycleLockRecord(t, lr);
1048
1049         if (wasinterrupted)
1050                 *exceptionptr = new_exception(string_java_lang_InterruptedException);
1051 }
1052
1053 void yieldThread()
1054 {
1055         sched_yield();
1056 }
1057
1058 void setPriorityThread(thread *t, s4 priority)
1059 {
1060         nativethread *info = &((threadobject*) t->vmThread)->info;
1061         setPriority(info->tid, priority);
1062 }
1063
1064 void wait_cond_for_object(java_objectheader *o, s8 time, s4 nanos)
1065 {
1066         threadobject *t = (threadobject*) THREADOBJECT;
1067         monitorWait(t, o, time, nanos);
1068 }
1069
1070 void signal_cond_for_object(java_objectheader *o)
1071 {
1072         threadobject *t = (threadobject*) THREADOBJECT;
1073         notifyOneOrAll(t, o, true);
1074 }
1075
1076 void broadcast_cond_for_object(java_objectheader *o)
1077 {
1078         threadobject *t = (threadobject*) THREADOBJECT;
1079         notifyOneOrAll(t, o, false);
1080 }
1081
1082 #endif
1083
1084
1085 /*
1086  * These are local overrides for various environment variables in Emacs.
1087  * Please do not remove this and leave it at the end of the file, where
1088  * Emacs will automagically detect them.
1089  * ---------------------------------------------------------------------
1090  * Local variables:
1091  * mode: c
1092  * indent-tabs-mode: t
1093  * c-basic-offset: 4
1094  * tab-width: 4
1095  * End:
1096  */