bf0f6ca134d782783dae3f95c427e5d47ea31292
[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         mainthreadobj->info.tid = pthread_self();
422 #if !defined(HAVE___THREAD)
423         pthread_key_create(&tkey_threadinfo, NULL);
424 #endif
425         setthreadobject(mainthreadobj);
426         initPools();
427
428     criticaltree = avl_create(criticalcompare, NULL, NULL);
429         thread_addstaticcritical();
430         sem_init(&suspend_ack, 0, 0);
431
432         /* Every newly created object's monitorPtr points here so we save a check
433          * against NULL */
434         dummyLR = NEW(monitorLockRecord);
435         dummyLR->o = NULL;
436         dummyLR->ownerThread = NULL;
437         dummyLR->waiting = false;
438 }
439
440 static pthread_attr_t threadattr;
441
442 static void freeLockRecordPools(lockRecordPool *);
443
444 void
445 initThreads(u1 *stackbottom)
446 {
447         classinfo *threadclass;
448         classinfo *threadgroupclass;
449         java_lang_String *threadname;
450         java_lang_Thread *mainthread;
451         java_lang_ThreadGroup *threadgroup;
452         threadobject *tempthread = mainthreadobj;
453         methodinfo *method;
454
455         threadclass = class_new(utf_new_char("java/lang/VMThread"));
456         class_load(threadclass);
457         class_link(threadclass);
458
459         if (!threadclass)
460                 throw_exception_exit();
461
462         freeLockRecordPools(mainthreadobj->ee.lrpool);
463         /* This is kinda tricky, we grow the java.lang.Thread object so we can keep
464          * the execution environment there. No Thread object must have been created
465          * at an earlier time */
466         threadclass->instancesize = sizeof(threadobject);
467
468         /* Create a VMThread */
469         mainthreadobj = (threadobject *) builtin_new(threadclass);
470
471         if (!mainthreadobj)
472                 throw_exception_exit();
473
474         FREE(tempthread, threadobject);
475         initThread(&mainthreadobj->o);
476
477         setthreadobject(mainthreadobj);
478
479         initLocks();
480         mainthreadobj->info.next = mainthreadobj;
481         mainthreadobj->info.prev = mainthreadobj;
482
483         threadname = javastring_new(utf_new_char("main"));
484
485         /* Allocate and init ThreadGroup */
486         threadgroupclass = class_new(utf_new_char("java/lang/ThreadGroup"));
487         threadgroup =
488                 (java_lang_ThreadGroup *) native_new_and_init(threadgroupclass);
489
490         if (!threadgroup)
491                 throw_exception_exit();
492
493         /* Create a Thread */
494         threadclass = class_new(utf_new_char("java/lang/Thread"));
495         mainthread = (java_lang_Thread*) builtin_new(threadclass);
496         mainthreadobj->o.thread = mainthread;
497
498         if (!mainthread)
499                 throw_exception_exit();
500
501         /* Call Thread constructor */
502         method = class_resolveclassmethod(threadclass,
503                                                                           utf_new_char("<init>"),
504                                                                           utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
505                                                                           threadclass,
506                                                                           true);
507
508         if (!method)
509                 throw_exception_exit();
510
511         asm_calljavafunction(method, mainthread, mainthreadobj, threadname, (void*) 5);
512         if (*exceptionptr)
513                 throw_exception_exit();
514
515         mainthread->group = threadgroup;
516         /* XXX This is a hack because the fourth argument was omitted */
517         mainthread->daemon = false;
518
519         /* Add mainthread to ThreadGroup */
520         method = class_resolveclassmethod(threadgroupclass,
521                                                                           utf_new_char("addThread"),
522                                                                           utf_new_char("(Ljava/lang/Thread;)V"),
523                                                                           threadgroupclass,
524                                                                           true);
525
526         if (!method)
527                 throw_exception_exit();
528
529         asm_calljavafunction(method, threadgroup, mainthread, NULL, NULL);
530         if (*exceptionptr)
531                 throw_exception_exit();
532
533         setPriority(pthread_self(), 5);
534
535         pthread_attr_init(&threadattr);
536         pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
537 }
538
539 void initThread(java_lang_VMThread *t)
540 {
541         threadobject *thread = (threadobject*) t;
542         nativethread *info = &thread->info;
543         info->tid = pthread_self();
544         /* TODO destroy all those things */
545         pthread_mutex_init(&info->joinMutex, NULL);
546         pthread_cond_init(&info->joinCond, NULL);
547
548         pthread_mutex_init(&thread->waitLock, NULL);
549         pthread_cond_init(&thread->waitCond, NULL);
550         thread->interrupted = false;
551         thread->signaled = false;
552         thread->isSleeping = false;
553 }
554
555 static void initThreadLocks(threadobject *);
556
557 typedef struct {
558         threadobject *thread;
559         sem_t *psem;
560 } startupinfo;
561
562 static void *threadstartup(void *t)
563 {
564         startupinfo *startup = t;
565         threadobject *thread = startup->thread;
566         sem_t *psem = startup->psem;
567         nativethread *info = &thread->info;
568         threadobject *tnext;
569         methodinfo *method;
570
571         t = NULL;
572 #if defined(__DARWIN__)
573         info->mach_thread = mach_thread_self();
574 #endif
575         setthreadobject(thread);
576
577         pthread_mutex_lock(&threadlistlock);
578         info->prev = mainthreadobj;
579         info->next = tnext = mainthreadobj->info.next;
580         mainthreadobj->info.next = thread;
581         tnext->info.prev = thread;
582         pthread_mutex_unlock(&threadlistlock);
583
584         initThreadLocks(thread);
585
586         startup = NULL;
587         sem_post(psem);
588
589         setPriority(info->tid, thread->o.thread->priority);
590         sched_yield();
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                 while (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 = (monitorLockRecord *) &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 }
686
687 /* No lock record must ever be destroyed because there may still be references
688  * to it.
689
690 static void destroyLockRecord(monitorLockRecord *r)
691 {
692         sem_destroy(&r->queueSem);
693         pthread_mutex_destroy(&r->resolveLock);
694         pthread_cond_destroy(&r->resolveWait);
695 }
696 */
697
698 void initLocks()
699 {
700         initThreadLocks(mainthreadobj);
701 }
702
703 static void initThreadLocks(threadobject *thread)
704 {
705         thread->ee.firstLR = NULL;
706         thread->ee.lrpool = NULL;
707         thread->ee.numlr = 0;
708 }
709
710 static lockRecordPool *allocNewLockRecordPool(threadobject *thread, int size)
711 {
712         lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
713         int i;
714
715         p->header.size = size;
716         for (i=0; i<size; i++) {
717                 initLockRecord(&p->lr[i], thread);
718                 p->lr[i].nextFree = &p->lr[i+1];
719         }
720         p->lr[i-1].nextFree = NULL;
721         return p;
722 }
723
724 #define INITIALLOCKRECORDS 8
725
726 static pthread_mutex_t pool_lock;
727 static lockRecordPool *global_pool;
728
729 static void initPools()
730 {
731         pthread_mutex_init(&pool_lock, NULL);
732 }
733
734 static lockRecordPool *allocLockRecordPool(threadobject *t, int size)
735 {
736         pthread_mutex_lock(&pool_lock);
737         if (global_pool) {
738                 int i;
739                 lockRecordPool *pool = global_pool;
740                 global_pool = pool->header.next;
741                 pthread_mutex_unlock(&pool_lock);
742
743                 for (i=0; i < pool->header.size; i++)
744                         pool->lr[i].ownerThread = t;
745                 
746                 return pool;
747         }
748         pthread_mutex_unlock(&pool_lock);
749
750         return allocNewLockRecordPool(t, size);
751 }
752
753 static void freeLockRecordPools(lockRecordPool *pool)
754 {
755         lockRecordPoolHeader *last;
756         pthread_mutex_lock(&pool_lock);
757         last = &pool->header;
758         while (last->next)
759                 last = &last->next->header;
760         last->next = global_pool;
761         global_pool = pool;
762         pthread_mutex_unlock(&pool_lock);
763 }
764
765 static monitorLockRecord *allocLockRecordSimple(threadobject *t)
766 {
767         monitorLockRecord *r = t->ee.firstLR;
768
769         if (!r) {
770                 int poolsize = t->ee.numlr ? t->ee.numlr * 2 : INITIALLOCKRECORDS;
771                 lockRecordPool *pool = allocLockRecordPool(t, poolsize);
772                 pool->header.next = t->ee.lrpool;
773                 t->ee.lrpool = pool;
774                 r = &pool->lr[0];
775                 t->ee.numlr += pool->header.size;
776         }
777         
778         t->ee.firstLR = r->nextFree;
779         return r;
780 }
781
782 static inline void recycleLockRecord(threadobject *t, monitorLockRecord *r)
783 {
784         r->nextFree = t->ee.firstLR;
785         t->ee.firstLR = r;
786 }
787
788 void initObjectLock(java_objectheader *o)
789 {
790         o->monitorPtr = dummyLR;
791 }
792
793 static void queueOnLockRecord(monitorLockRecord *lr, java_objectheader *o)
794 {
795         atomic_add(&lr->queuers, 1);
796         MEMORY_BARRIER_AFTER_ATOMIC();
797         while (lr->o == o)
798                 sem_wait(&lr->queueSem);
799         atomic_add(&lr->queuers, -1);
800 }
801
802 static void freeLockRecord(monitorLockRecord *lr)
803 {
804         int q;
805         lr->o = NULL;
806         MEMORY_BARRIER();
807         q = lr->queuers;
808         while (q--)
809                 sem_post(&lr->queueSem);
810 }
811
812 static inline void handleWaiter(monitorLockRecord *mlr, monitorLockRecord *lr)
813 {
814         if (lr->waiting)
815                 mlr->waiter = lr;
816 }
817
818 monitorLockRecord *monitorEnter(threadobject *t, java_objectheader *o)
819 {
820         for (;;) {
821                 monitorLockRecord *lr = o->monitorPtr;
822                 if (lr->o != o) {
823                         monitorLockRecord *nlr, *mlr = allocLockRecordSimple(t);
824                         mlr->o = o;
825                         if (mlr == lr) {
826                                 MEMORY_BARRIER();
827                                 nlr = o->monitorPtr;
828                                 if (nlr == lr) {
829                                         handleWaiter(mlr, lr);
830                                         return mlr;
831                                 }
832                         } else {
833                                 if (lr->ownerThread != t)
834                                         mlr->incharge = lr;
835                                 MEMORY_BARRIER_BEFORE_ATOMIC();
836                                 nlr = (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) mlr);
837                         }
838                         if (nlr == lr) {
839                                 if (mlr == lr || lr->o != o) {
840                                         handleWaiter(mlr, lr);
841                                         return mlr;
842                                 }
843                                 while (lr->o == o)
844                                         queueOnLockRecord(lr, o);
845                                 handleWaiter(mlr, lr);
846                                 return mlr;
847                         }
848                         freeLockRecord(mlr);
849                         recycleLockRecord(t, mlr);
850                         queueOnLockRecord(nlr, o);
851                 } else {
852                         if (lr->ownerThread == t) {
853                                 lr->lockCount++;
854                                 return lr;
855                         }
856                         queueOnLockRecord(lr, o);
857                 }
858         }
859 }
860
861 static void wakeWaiters(monitorLockRecord *lr)
862 {
863         do {
864                 int q = lr->queuers;
865                 while (q--)
866                         sem_post(&lr->queueSem);
867                 lr = lr->waiter;
868         } while (lr);
869 }
870
871 #define GRAB_LR(lr,t) \
872     if (lr->ownerThread != t) { \
873                 lr = lr->incharge; \
874         }
875
876 #define CHECK_MONITORSTATE(lr,t,mo,a) \
877     if (lr->o != mo || lr->ownerThread != t) { \
878                 *exceptionptr = new_exception(string_java_lang_IllegalMonitorStateException); \
879                 a; \
880         }
881
882 bool monitorExit(threadobject *t, java_objectheader *o)
883 {
884         monitorLockRecord *lr = o->monitorPtr;
885         GRAB_LR(lr, t);
886         CHECK_MONITORSTATE(lr, t, o, return false);
887         if (lr->lockCount > 1) {
888                 lr->lockCount--;
889                 return true;
890         }
891         if (lr->waiter) {
892                 monitorLockRecord *wlr = lr->waiter;
893                 if (o->monitorPtr != lr ||
894                         (void*) compare_and_swap((long*) &o->monitorPtr, (long) lr, (long) wlr) != lr)
895                 {
896                         monitorLockRecord *nlr = o->monitorPtr;
897                         nlr->waiter = wlr;
898                         STORE_ORDER_BARRIER();
899                 } else
900                         wakeWaiters(wlr);
901                 lr->waiter = NULL;
902         }
903         freeLockRecord(lr);
904         recycleLockRecord(t, lr);
905         return true;
906 }
907
908 static void removeFromWaiters(monitorLockRecord *lr, monitorLockRecord *wlr)
909 {
910         do {
911                 if (lr->waiter == wlr) {
912                         lr->waiter = wlr->waiter;
913                         break;
914                 }
915                 lr = lr->waiter;
916         } while (lr);
917 }
918
919 static inline bool timespec_less(const struct timespec *tv1, const struct timespec *tv2)
920 {
921         return tv1->tv_sec < tv2->tv_sec || (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
922 }
923
924 static bool timeIsEarlier(const struct timespec *tv)
925 {
926         struct timeval tvnow;
927         struct timespec tsnow;
928         gettimeofday(&tvnow, NULL);
929         tsnow.tv_sec = tvnow.tv_sec;
930         tsnow.tv_nsec = tvnow.tv_usec * 1000;
931         return timespec_less(&tsnow, tv);
932 }
933
934 bool waitWithTimeout(threadobject *t, monitorLockRecord *lr, struct timespec *wakeupTime)
935 {
936         bool wasinterrupted;
937
938         pthread_mutex_lock(&t->waitLock);
939         t->isSleeping = true;
940         if (wakeupTime->tv_sec || wakeupTime->tv_nsec)
941                 while (!t->interrupted && !t->signaled && timeIsEarlier(wakeupTime))
942                         pthread_cond_timedwait(&t->waitCond, &t->waitLock, wakeupTime);
943         else
944                 while (!t->interrupted && !t->signaled)
945                         pthread_cond_wait(&t->waitCond, &t->waitLock);
946         wasinterrupted = t->interrupted;
947         t->interrupted = false;
948         t->signaled = false;
949         t->isSleeping = false;
950         pthread_mutex_unlock(&t->waitLock);
951         return wasinterrupted;
952 }
953
954 static void calcAbsoluteTime(struct timespec *tm, s8 millis, s4 nanos)
955 {
956         if (millis || nanos) {
957                 struct timeval tv;
958                 long nsec;
959                 gettimeofday(&tv, NULL);
960                 tv.tv_sec += millis / 1000;
961                 millis %= 1000;
962                 nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
963                 tm->tv_sec = tv.tv_sec + nsec / 1000000000;
964                 tm->tv_nsec = nsec % 1000000000;
965         } else {
966                 tm->tv_sec = 0;
967                 tm->tv_nsec = 0;
968         }
969 }
970
971 void monitorWait(threadobject *t, java_objectheader *o, s8 millis, s4 nanos)
972 {
973         bool wasinterrupted;
974         struct timespec wakeupTime;
975         monitorLockRecord *mlr, *lr = o->monitorPtr;
976         GRAB_LR(lr, t);
977         CHECK_MONITORSTATE(lr, t, o, return);
978
979         calcAbsoluteTime(&wakeupTime, millis, nanos);
980         
981         if (lr->waiter)
982                 wakeWaiters(lr->waiter);
983         lr->waiting = true;
984         STORE_ORDER_BARRIER();
985         freeLockRecord(lr);
986         wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
987         mlr = monitorEnter(t, o);
988         removeFromWaiters(mlr, lr);
989         mlr->lockCount = lr->lockCount;
990         lr->lockCount = 1;
991         lr->waiting = false;
992         lr->waiter = NULL;
993         recycleLockRecord(t, lr);
994
995         if (wasinterrupted)
996                 *exceptionptr = new_exception(string_java_lang_InterruptedException);
997 }
998
999 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
1000 {
1001         monitorLockRecord *lr = o->monitorPtr;
1002         GRAB_LR(lr, t);
1003         CHECK_MONITORSTATE(lr, t, o, return);
1004         do {
1005                 threadobject *wthread;
1006                 monitorLockRecord *wlr = lr->waiter;
1007                 if (!wlr)
1008                         break;
1009                 wthread = wlr->ownerThread;
1010                 pthread_mutex_lock(&wthread->waitLock);
1011                 if (wthread->isSleeping)
1012                         pthread_cond_signal(&wthread->waitCond);
1013                 wthread->signaled = true;
1014                 pthread_mutex_unlock(&wthread->waitLock);
1015                 lr = wlr;
1016         } while (!one);
1017 }
1018
1019 bool threadHoldsLock(threadobject *t, java_objectheader *o)
1020 {
1021         monitorLockRecord *lr = o->monitorPtr;
1022         GRAB_LR(lr, t);
1023         return lr->o == o && lr->ownerThread == t;
1024 }
1025
1026 void interruptThread(java_lang_VMThread *thread)
1027 {
1028         threadobject *t = (threadobject*) thread;
1029
1030         t->interrupted = true;
1031         pthread_mutex_lock(&t->waitLock);
1032         if (t->isSleeping)
1033                 pthread_cond_signal(&t->waitCond);
1034         pthread_mutex_unlock(&t->waitLock);
1035 }
1036
1037 bool interruptedThread()
1038 {
1039         threadobject *t = (threadobject*) THREADOBJECT;
1040         bool intr = t->interrupted;
1041         t->interrupted = false;
1042         return intr;
1043 }
1044
1045 bool isInterruptedThread(java_lang_VMThread *thread)
1046 {
1047         threadobject *t = (threadobject*) thread;
1048         return t->interrupted;
1049 }
1050
1051 void sleepThread(s8 millis, s4 nanos)
1052 {
1053         bool wasinterrupted;
1054         threadobject *t = (threadobject*) THREADOBJECT;
1055         monitorLockRecord *lr;
1056         struct timespec wakeupTime;
1057         calcAbsoluteTime(&wakeupTime, millis, nanos);
1058
1059         lr = allocLockRecordSimple(t);
1060         wasinterrupted = waitWithTimeout(t, lr, &wakeupTime);
1061         recycleLockRecord(t, lr);
1062
1063         if (wasinterrupted)
1064                 *exceptionptr = new_exception(string_java_lang_InterruptedException);
1065 }
1066
1067 void yieldThread()
1068 {
1069         sched_yield();
1070 }
1071
1072 void setPriorityThread(thread *t, s4 priority)
1073 {
1074         nativethread *info = &((threadobject*) t->vmThread)->info;
1075         setPriority(info->tid, priority);
1076 }
1077
1078 void wait_cond_for_object(java_objectheader *o, s8 time, s4 nanos)
1079 {
1080         threadobject *t = (threadobject*) THREADOBJECT;
1081         monitorWait(t, o, time, nanos);
1082 }
1083
1084 void signal_cond_for_object(java_objectheader *o)
1085 {
1086         threadobject *t = (threadobject*) THREADOBJECT;
1087         notifyOneOrAll(t, o, true);
1088 }
1089
1090 void broadcast_cond_for_object(java_objectheader *o)
1091 {
1092         threadobject *t = (threadobject*) THREADOBJECT;
1093         notifyOneOrAll(t, o, false);
1094 }
1095
1096
1097 /*
1098  * These are local overrides for various environment variables in Emacs.
1099  * Please do not remove this and leave it at the end of the file, where
1100  * Emacs will automagically detect them.
1101  * ---------------------------------------------------------------------
1102  * Local variables:
1103  * mode: c
1104  * indent-tabs-mode: t
1105  * c-basic-offset: 4
1106  * tab-width: 4
1107  * End:
1108  */