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/exceptions.h"
25 #include "vm/global.h"
26 #include "vm/loader.h"
27 #include "vm/tables.h"
28 #include "vm/jit/asmpart.h"
29
30 #include <pthread.h>
31 #include <semaphore.h>
32
33 #if !defined(__DARWIN__)
34 #if defined(__LINUX__)
35 #define GC_LINUX_THREADS
36 #elif defined(__MIPS__)
37 #define GC_IRIX_THREADS
38 #endif
39 #include "boehm-gc/include/gc.h"
40 #endif
41
42 #ifdef MUTEXSIM
43
44 /* We need this for older MacOSX (10.1.x) */
45
46 typedef struct {
47         pthread_mutex_t mutex;
48         pthread_t owner;
49         int count;
50 } pthread_mutex_rec_t;
51
52 static void pthread_mutex_init_rec(pthread_mutex_rec_t *m)
53 {
54         pthread_mutex_init(&m->mutex, NULL);
55         m->count = 0;
56 }
57
58 static void pthread_mutex_destroy_rec(pthread_mutex_rec_t *m)
59 {
60         pthread_mutex_destroy(&m->mutex);
61 }
62
63 static void pthread_mutex_lock_rec(pthread_mutex_rec_t *m)
64 {
65         for (;;)
66                 if (!m->count)
67                 {
68                         pthread_mutex_lock(&m->mutex);
69                         m->owner = pthread_self();
70                         m->count++;
71                         break;
72                 } else {
73                         if (m->owner != pthread_self())
74                                 pthread_mutex_lock(&m->mutex);
75                         else
76                         {
77                                 m->count++;
78                                 break;
79                         }
80                 }
81 }
82
83 static void pthread_mutex_unlock_rec(pthread_mutex_rec_t *m)
84 {
85         if (!--m->count)
86                 pthread_mutex_unlock(&m->mutex);
87 }
88
89 #else /* MUTEXSIM */
90
91 #define pthread_mutex_lock_rec pthread_mutex_lock
92 #define pthread_mutex_unlock_rec pthread_mutex_unlock
93 #define pthread_mutex_rec_t pthread_mutex_t
94
95 #endif /* MUTEXSIM */
96
97 static void setPriority(pthread_t tid, int priority)
98 {
99         struct sched_param schedp;
100         int policy;
101
102         pthread_getschedparam(tid, &policy, &schedp);
103         schedp.sched_priority = priority;
104         pthread_setschedparam(tid, policy, &schedp);
105 }
106
107 #include "machine-instr.h"
108
109 static struct avl_table *criticaltree;
110 static threadobject *mainthreadobj;
111
112 #ifndef HAVE___THREAD
113 pthread_key_t tkey_threadinfo;
114 #else
115 __thread threadobject *threadobj;
116 #endif
117
118 static pthread_mutex_rec_t compiler_mutex;
119 static pthread_mutex_rec_t tablelock;
120
121 void compiler_lock()
122 {
123         pthread_mutex_lock_rec(&compiler_mutex);
124 }
125
126 void compiler_unlock()
127 {
128         pthread_mutex_unlock_rec(&compiler_mutex);
129 }
130
131 void tables_lock()
132 {
133     pthread_mutex_lock_rec(&tablelock);
134 }
135
136 void tables_unlock()
137 {
138     pthread_mutex_unlock_rec(&tablelock);
139 }
140
141 static int criticalcompare(const void *pa, const void *pb, void *param)
142 {
143         const threadcritnode *na = pa;
144         const threadcritnode *nb = pb;
145
146         if (na->mcodebegin < nb->mcodebegin)
147                 return -1;
148         if (na->mcodebegin > nb->mcodebegin)
149                 return 1;
150         return 0;
151 }
152
153 static const threadcritnode *findcritical(u1 *mcodeptr)
154 {
155     struct avl_node *n = criticaltree->avl_root;
156     const threadcritnode *m = NULL;
157     if (!n)
158         return NULL;
159     for (;;)
160     {
161         const threadcritnode *d = n->avl_data;
162         if (mcodeptr == d->mcodebegin)
163             return d;
164         if (mcodeptr < d->mcodebegin) {
165             if (n->avl_link[0])
166                 n = n->avl_link[0];
167             else
168                 return m;
169         } else {
170             if (n->avl_link[1]) {
171                 m = n->avl_data;
172                 n = n->avl_link[1];
173             } else
174                 return n->avl_data;
175         }
176     }
177 }
178
179 void thread_registercritical(threadcritnode *n)
180 {
181         avl_insert(criticaltree, n);
182 }
183
184 u1 *thread_checkcritical(u1 *mcodeptr)
185 {
186         const threadcritnode *n = findcritical(mcodeptr);
187         return (n && mcodeptr < n->mcodeend && mcodeptr > n->mcodebegin) ? n->mcoderestart : NULL;
188 }
189
190 static void thread_addstaticcritical()
191 {
192         threadcritnode *n = &asm_criticalsections;
193
194         while (n->mcodebegin)
195                 thread_registercritical(n++);
196 }
197
198 static pthread_mutex_t threadlistlock;
199
200 static pthread_mutex_t stopworldlock;
201 volatile int stopworldwhere;
202
203 static sem_t suspend_ack;
204 #if defined(__MIPS__)
205 static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
206 static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
207 #endif
208
209 /*
210  * where - 1 from within GC
211            2 class numbering
212  */
213 void lock_stopworld(int where)
214 {
215         pthread_mutex_lock(&stopworldlock);
216         stopworldwhere = where;
217 }
218
219 void unlock_stopworld()
220 {
221         stopworldwhere = 0;
222         pthread_mutex_unlock(&stopworldlock);
223 }
224
225 #if !defined(__DARWIN__)
226 /* Caller must hold threadlistlock */
227 static int cast_sendsignals(int sig, int count)
228 {
229         /* Count threads */
230         threadobject *tobj = mainthreadobj;
231         nativethread *infoself = THREADINFO;
232
233         if (count == 0)
234                 do {
235                         count++;
236                         tobj = tobj->info.next;
237                 } while (tobj != mainthreadobj);
238
239         do {
240                 nativethread *info = &tobj->info;
241                 if (info != infoself)
242                         pthread_kill(info->tid, sig);
243                 tobj = tobj->info.next;
244         } while (tobj != mainthreadobj);
245
246         return count-1;
247 }
248
249 #else
250
251 static void cast_darwinstop()
252 {
253         threadobject *tobj = mainthreadobj;
254         nativethread *infoself = THREADINFO;
255
256         do {
257                 nativethread *info = &tobj->info;
258                 if (info != infoself)
259                 {
260                         thread_state_flavor_t flavor = PPC_THREAD_STATE;
261                         mach_msg_type_number_t thread_state_count = PPC_THREAD_STATE_COUNT;
262                         ppc_thread_state_t thread_state;
263                         mach_port_t thread = info->mach_thread;
264                         kern_return_t r;
265
266                         r = thread_suspend(thread);
267                         if (r != KERN_SUCCESS)
268                                 panic("thread_suspend failed");
269
270                         r = thread_get_state(thread, flavor,
271                                 (natural_t*)&thread_state, &thread_state_count);
272                         if (r != KERN_SUCCESS)
273                                 panic("thread_get_state failed");
274
275                         thread_restartcriticalsection(&thread_state);
276
277                         r = thread_set_state(thread, flavor,
278                                 (natural_t*)&thread_state, thread_state_count);
279                         if (r != KERN_SUCCESS)
280                                 panic("thread_set_state failed");
281                 }
282                 tobj = tobj->info.next;
283         } while (tobj != mainthreadobj);
284 }
285
286 static void cast_darwinresume()
287 {
288         threadobject *tobj = mainthreadobj;
289         nativethread *infoself = THREADINFO;
290
291         do {
292                 nativethread *info = &tobj->info;
293                 if (info != infoself)
294                 {
295                         mach_port_t thread = info->mach_thread;
296                         kern_return_t r;
297
298                         r = thread_resume(thread);
299                         if (r != KERN_SUCCESS)
300                                 panic("thread_resume failed");
301                 }
302                 tobj = tobj->info.next;
303         } while (tobj != mainthreadobj);
304 }
305
306 #endif
307
308 #if defined(__MIPS__)
309 static void cast_irixresume()
310 {
311         pthread_mutex_lock(&suspend_ack_lock);
312         pthread_cond_broadcast(&suspend_cond);
313         pthread_mutex_unlock(&suspend_ack_lock);
314 }
315 #endif
316
317 void cast_stopworld()
318 {
319         int count, i;
320         lock_stopworld(2);
321         pthread_mutex_lock(&threadlistlock);
322 #if defined(__DARWIN__)
323         cast_darwinstop();
324 #else
325         count = cast_sendsignals(GC_signum1(), 0);
326         for (i=0; i<count; i++)
327                 sem_wait(&suspend_ack);
328 #endif
329         pthread_mutex_unlock(&threadlistlock);
330 }
331
332 void cast_startworld()
333 {
334         pthread_mutex_lock(&threadlistlock);
335 #if defined(__DARWIN__)
336         cast_darwinresume();
337 #elif defined(__MIPS__)
338         cast_irixresume();
339 #else
340         cast_sendsignals(GC_signum2(), -1);
341 #endif
342         pthread_mutex_unlock(&threadlistlock);
343         unlock_stopworld();
344 }
345
346 #if !defined(__DARWIN__)
347 static void sigsuspend_handler(ucontext_t *ctx)
348 {
349         int sig;
350         sigset_t sigs;
351         
352         thread_restartcriticalsection(ctx);
353
354         /* Do as Boehm does. On IRIX a condition variable is used for wake-up
355            (not POSIX async-safe). */
356 #if defined(__IRIX__)
357         pthread_mutex_lock(&suspend_ack_lock);
358         sem_post(&suspend_ack);
359         pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
360         pthread_mutex_unlock(&suspend_ack_lock);
361 #else
362         sem_post(&suspend_ack);
363
364         sig = GC_signum2();
365         sigfillset(&sigs);
366         sigdelset(&sigs, sig);
367         sigsuspend(&sigs);
368 #endif
369 }
370
371 int cacao_suspendhandler(ucontext_t *ctx)
372 {
373         if (stopworldwhere != 2)
374                 return 0;
375
376         sigsuspend_handler(ctx);
377         return 1;
378 }
379 #endif
380
381 static void setthreadobject(threadobject *thread)
382 {
383 #if !defined(HAVE___THREAD)
384         pthread_setspecific(tkey_threadinfo, thread);
385 #else
386         threadobj = thread;
387 #endif
388 }
389
390 static monitorLockRecord *dummyLR;
391
392 static void initPools();
393
394 /*
395  * Initialize threads.
396  */
397 void
398 initThreadsEarly()
399 {
400 #ifndef MUTEXSIM
401         pthread_mutexattr_t mutexattr;
402         pthread_mutexattr_init(&mutexattr);
403         pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
404         pthread_mutex_init(&compiler_mutex, &mutexattr);
405         pthread_mutex_init(&tablelock, &mutexattr);
406         pthread_mutexattr_destroy(&mutexattr);
407 #else
408         pthread_mutex_init_rec(&compiler_mutex);
409         pthread_mutex_init_rec(&tablelock);
410 #endif
411
412         pthread_mutex_init(&threadlistlock, NULL);
413         pthread_mutex_init(&stopworldlock, NULL);
414
415         /* Allocate something so the garbage collector's signal handlers are  */
416         /* installed. */
417         heap_allocate(1, false, NULL);
418
419         mainthreadobj = NEW(threadobject);
420         memset(mainthreadobj, 0, sizeof(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 = mem_alloc(sizeof(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  */