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