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