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