*** empty log message ***
[cacao.git] / threads / nativethread.c
1 #include "global.h"
2
3 #if defined(NATIVE_THREADS)
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <assert.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10 #include <signal.h>
11 #include <sys/time.h>
12 #include <time.h>
13 #include <errno.h>
14
15 #include "config.h"
16 #include "thread.h"
17 #include "locks.h"
18 #include "tables.h"
19 #include "native.h"
20 #include "loader.h"
21 #include "builtin.h"
22 #include "asmpart.h"
23 #include "toolbox/loging.h"
24 #include "toolbox/memory.h"
25 #include "toolbox/avl.h"
26 #include "mm/boehm.h"
27
28 #include "nat/java_lang_Object.h"
29 #include "nat/java_lang_Throwable.h"
30 #include "nat/java_lang_Thread.h"
31 #include "nat/java_lang_ThreadGroup.h"
32
33 #include <pthread.h>
34 #include <semaphore.h>
35
36 #if defined(__LINUX__)
37 #define GC_LINUX_THREADS
38 #include "../mm/boehm-gc/include/gc.h"
39 #endif
40
41 #include "machine-instr.h"
42
43 static struct avl_table *criticaltree;
44 static threadobject *mainthreadobj;
45
46 #ifndef HAVE___THREAD
47 pthread_key_t tkey_threadinfo;
48 #else
49 __thread threadobject *threadobj;
50 #endif
51
52 /* CAST has to die */
53
54 static pthread_mutex_t cast_mutex = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
55 static pthread_mutex_t compiler_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
56
57 int cast_counter;
58
59 void cast_lock()
60 {
61         pthread_mutex_lock(&cast_mutex);
62 }
63
64 void cast_unlock()
65 {
66         pthread_mutex_unlock(&cast_mutex);
67 }
68
69 void compiler_lock()
70 {
71         pthread_mutex_lock(&compiler_mutex);
72 }
73
74 void compiler_unlock()
75 {
76         pthread_mutex_unlock(&compiler_mutex);
77 }
78
79 /* END CAST */
80
81 static int criticalcompare(const void *pa, const void *pb, void *param)
82 {
83         const threadcritnode *na = pa;
84         const threadcritnode *nb = pb;
85
86         if (na->mcodebegin < nb->mcodebegin)
87                 return -1;
88         if (na->mcodebegin > nb->mcodebegin)
89                 return 1;
90         return 0;
91 }
92
93 static const threadcritnode *findcritical(u1 *mcodeptr)
94 {
95     struct avl_node *n = criticaltree->avl_root;
96     const threadcritnode *m = NULL;
97     if (!n)
98         return NULL;
99     for (;;)
100     {
101         const threadcritnode *d = n->avl_data;
102         if (mcodeptr == d->mcodebegin)
103             return d;
104         if (mcodeptr < d->mcodebegin) {
105             if (n->avl_link[0])
106                 n = n->avl_link[0];
107             else
108                 return m;
109         } else {
110             if (n->avl_link[1]) {
111                 m = n->avl_data;
112                 n = n->avl_link[1];
113             } else
114                 return n->avl_data;
115         }
116     }
117 }
118
119 void thread_registercritical(threadcritnode *n)
120 {
121         avl_insert(criticaltree, n);
122 }
123
124 static u1 *thread_checkcritical(u1 *mcodeptr)
125 {
126         const threadcritnode *n = findcritical(mcodeptr);
127         return (n && mcodeptr < n->mcodeend) ? n->mcodebegin : NULL;
128 }
129
130 static pthread_mutex_t stopworldlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
131 volatile int stopworldwhere;
132
133 /*
134  * where - 1 from within GC
135            2 class numbering
136  */
137 void lock_stopworld(int where)
138 {
139         pthread_mutex_lock(&stopworldlock);
140         stopworldwhere = where;
141 }
142
143 void unlock_stopworld()
144 {
145         stopworldwhere = 0;
146         pthread_mutex_unlock(&stopworldlock);
147 }
148
149 static sem_t suspend_ack;
150
151 static void sigsuspend_handler(struct sigcontext *ctx)
152 {
153         int sig;
154         sigset_t sigs;
155         void *critical;
156         
157 #ifdef __I386__
158         if ((critical = thread_checkcritical((void*) ctx->eip)) != NULL)
159                 ctx->eip = (long) critical;
160 #endif
161
162         sem_post(&suspend_ack);
163
164         sig = GC_signum2();
165         sigfillset(&sigs);
166         sigdelset(&sigs, sig);
167         sigsuspend(&sigs);
168 }
169
170 int cacao_suspendhandler(struct sigcontext *ctx)
171 {
172         if (stopworldwhere != 2)
173                 return 0;
174
175         sigsuspend_handler(ctx);
176         return 1;
177 }
178
179 static void setthreadobject(threadobject *thread)
180 {
181 #if !defined(HAVE___THREAD)
182         pthread_setspecific(tkey_threadinfo, thread);
183 #else
184         threadobj = thread;
185 #endif
186 }
187
188 /*
189  * Initialize threads.
190  */
191 void
192 initThreadsEarly()
193 {
194         struct sigaction sa;
195 //      int sig1 = GC_signum1(), sig2 = GC_signum2();
196
197         /* Allocate something so the garbage collector's signal handlers are  */
198         /* initalized. */
199         heap_allocate(1, false, NULL);
200
201         mainthreadobj = NEW(threadobject);
202         memset(mainthreadobj, 0, sizeof(threadobject));
203 #if !defined(HAVE___THREAD)
204         pthread_key_create(&tkey_threadinfo, NULL);
205 #endif
206         setthreadobject(mainthreadobj);
207
208     criticaltree = avl_create(criticalcompare, NULL, NULL);
209 }
210
211 static void freeLockRecordPools(lockRecordPool *);
212
213 void
214 initThreads(u1 *stackbottom)
215 {
216         classinfo *threadclass;
217         java_lang_Thread *mainthread;
218         threadobject *tempthread = mainthreadobj;
219
220 //      exit(1);
221
222         threadclass = loader_load_sysclass(NULL,utf_new_char("java/lang/Thread"));
223         assert(threadclass);
224         freeLockRecordPools(mainthreadobj->ee.lrpool);
225         threadclass->instancesize = sizeof(threadobject);
226         mainthreadobj = (threadobject*) builtin_new(threadclass);
227         assert(mainthreadobj);
228         FREE(tempthread, threadobject);
229         initThread(&mainthreadobj->o);
230
231 #if !defined(HAVE___THREAD)
232         pthread_setspecific(tkey_threadinfo, mainthreadobj);
233 #else
234         threadobj = mainthreadobj;
235 #endif
236
237         mainthread = &mainthreadobj->o;
238         initLocks();
239         mainthreadobj->info.next = mainthreadobj;
240         mainthreadobj->info.prev = mainthreadobj;
241
242         mainthread->name=javastring_new(utf_new_char("main"));
243
244         /* Allocate and init ThreadGroup */
245         mainthread->group = (java_lang_ThreadGroup*)native_new_and_init(loader_load(utf_new_char("java/lang/ThreadGroup")));
246         assert(mainthread->group != 0);
247 }
248
249 void initThread(java_lang_Thread *t)
250 {
251         nativethread *info = &((threadobject*) t)->info;
252         pthread_mutex_init(&info->joinMutex, NULL);
253         pthread_cond_init(&info->joinCond, NULL);
254 }
255
256 static pthread_mutex_t threadlistlock = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
257
258 static void initThreadLocks(threadobject *);
259
260 static void *threadstartup(void *t)
261 {
262         threadobject *thread = t;
263         nativethread *info = &thread->info;
264         threadobject *tnext;
265         methodinfo *method;
266
267         setthreadobject(thread);
268
269         pthread_mutex_lock(&threadlistlock);
270         info->prev = mainthreadobj;
271         info->next = tnext = mainthreadobj->info.next;
272         mainthreadobj->info.next = t;
273         tnext->info.prev = t;
274         pthread_mutex_unlock(&threadlistlock);
275
276         initThreadLocks(thread);
277
278         /* Find the run()V method and call it */
279         method = class_findmethod(thread->o.header.vftbl->class,
280                                                           utf_new_char("run"), utf_new_char("()V"));
281         if (method == 0)
282                 panic("Cannot find method \'void run ()\'");
283
284         asm_calljavafunction(method, thread, NULL, NULL, NULL);
285
286     if (info->_exceptionptr) {
287         utf_display((info->_exceptionptr)->vftbl->class->name);
288         printf("\n");
289     }
290
291         freeLockRecordPools(thread->ee.lrpool);
292
293         pthread_mutex_lock(&threadlistlock);
294         info->next->info.prev = info->prev;
295         info->prev->info.next = info->next;
296         pthread_mutex_unlock(&threadlistlock);
297
298         pthread_mutex_lock(&info->joinMutex);
299         info->tid = 0;
300         pthread_mutex_unlock(&info->joinMutex);
301         pthread_cond_broadcast(&info->joinCond);
302
303         return NULL;
304 }
305
306 void startThread(threadobject *t)
307 {
308         nativethread *info = &t->info;
309         pthread_create(&info->tid, NULL, threadstartup, t);
310         pthread_detach(info->tid);
311 }
312
313 void joinAllThreads()
314 {
315         pthread_mutex_lock(&threadlistlock);
316         while (mainthreadobj->info.prev != mainthreadobj) {
317                 nativethread *info = &mainthreadobj->info.prev->info;
318                 pthread_mutex_lock(&info->joinMutex);
319                 pthread_mutex_unlock(&threadlistlock);
320                 if (info->tid)
321                         pthread_cond_wait(&info->joinCond, &info->joinMutex);
322                 pthread_mutex_unlock(&info->joinMutex);
323                 pthread_mutex_lock(&threadlistlock);
324         }
325         pthread_mutex_unlock(&threadlistlock);
326 }
327
328 bool aliveThread(java_lang_Thread *t)
329 {
330         return ((threadobject*) t)->info.tid != 0;
331 }
332
333 void sleepThread(s8 millis)
334 {
335         struct timespec tv;
336         tv.tv_sec = millis / 1000;
337         tv.tv_nsec = millis % 1000 * 1000000;
338         do { } while (nanosleep(&tv, &tv) == EINTR);
339 }
340
341 void yieldThread()
342 {
343         sched_yield();
344 }
345
346 static void timedCondWait(pthread_cond_t *cond, pthread_mutex_t *mutex, s8 millis)
347 {
348         struct timeval now;
349         struct timespec desttime;
350         gettimeofday(&now, NULL);
351         desttime.tv_sec = millis / 1000;
352         desttime.tv_nsec = millis % 1000 * 1000000;
353         pthread_cond_timedwait(cond, mutex, &desttime);
354 }
355
356
357 #define NEUTRAL 0
358 #define LOCKED 1
359 #define WAITERS 2
360 #define BUSY 3
361
362 static void initExecutionEnvironment(ExecEnvironment *ee)
363 {
364         pthread_mutex_init(&ee->metaLockMutex, NULL);
365         pthread_cond_init(&ee->metaLockCond, NULL);
366         pthread_mutex_init(&ee->monitorLockMutex, NULL);
367         pthread_cond_init(&ee->monitorLockCond, NULL);
368 }
369
370 static void initLockRecord(monitorLockRecord *r, threadobject *t)
371 {
372         r->owner = t;
373         r->lockCount = 1;
374         r->queue = NULL;
375 }
376
377 void initLocks()
378 {
379         initThreadLocks(mainthreadobj);
380 }
381
382 static void initThreadLocks(threadobject *thread)
383 {
384         int i;
385
386         initExecutionEnvironment(&thread->ee);
387         for (i=0; i<INITIALLOCKRECORDS; i++) {
388                 monitorLockRecord *r = &thread->ee.lr[i];
389                 initLockRecord(r, thread);
390                 r->nextFree = &thread->ee.lr[i+1];
391         }
392         thread->ee.lr[i-1].nextFree = NULL;
393         thread->ee.firstLR = &thread->ee.lr[0];
394 }
395
396 static inline int lockState(long r)
397 {
398         return r & 3;
399 }
400
401 static inline void *lockRecord(long r)
402 {
403         return (void*) (r & ~3);
404 }
405
406 static inline long makeLockBits(void *r, long l)
407 {
408         return ((long) r) | l;
409 }
410
411 static lockRecordPool *allocLockRecordPool(threadobject *thread, int size)
412 {
413         lockRecordPool *p = mem_alloc(sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * size);
414         int i;
415
416         p->header.size = size;
417         for (i=0; i<size; i++) {
418                 initLockRecord(&p->lr[i], thread);
419                 p->lr[i].nextFree = &p->lr[i+1];
420         }
421         p->lr[i-1].nextFree = NULL;
422         return p;
423 }
424
425 static void freeLockRecordPools(lockRecordPool *pool)
426 {
427         while (pool) {
428                 lockRecordPool *n = pool->header.next;
429                 mem_free(pool, sizeof(lockRecordPoolHeader) + sizeof(monitorLockRecord) * pool->header.size);
430                 pool = n;
431         }
432 }
433
434 static monitorLockRecord *allocLockRecord(threadobject *t)
435 {
436         monitorLockRecord *r = t->ee.firstLR;
437
438         if (!r) {
439                 int poolsize = t->ee.lrpool ? t->ee.lrpool->header.size * 2 : INITIALLOCKRECORDS * 2;
440                 lockRecordPool *pool = allocLockRecordPool(t, poolsize);
441                 pool->header.next = t->ee.lrpool;
442                 t->ee.lrpool = pool;
443                 r = &pool->lr[0];
444         }
445         
446         t->ee.firstLR = r->nextFree;
447         return r;
448 }
449
450 static void recycleLockRecord(threadobject *t, monitorLockRecord *r)
451 {
452         r->nextFree = t->ee.firstLR;
453         t->ee.firstLR = r;
454 }
455
456 static monitorLockRecord *appendToQueue(monitorLockRecord *queue, monitorLockRecord *lr)
457 {
458         monitorLockRecord *queuestart = queue;
459         if (!queue)
460                 return lr;
461         while (queue->queue)
462                 queue = queue->queue;
463         queue->queue = lr;
464         return queuestart;
465 }
466
467 static monitorLockRecord *moveMyLRToFront(threadobject *t, monitorLockRecord *lr)
468 {
469         monitorLockRecord *pred = NULL;
470         monitorLockRecord *firstLR = lr;
471         while (lr->owner != t) {
472                 pred = lr;
473                 lr = lr->queue;
474         }
475         if (!pred)
476                 return lr;
477         pred->queue = lr->queue;
478         lr->queue = firstLR;
479         lr->storedBits = firstLR->storedBits;
480         return lr;
481 }
482
483 static long getMetaLockSlow(threadobject *t, long predBits);
484 static void releaseMetaLockSlow(threadobject *t, long releaseBits);
485
486 static long getMetaLock(threadobject *t, java_objectheader *o)
487 {
488         long busyBits = makeLockBits(t, BUSY);
489         long lockBits = atomic_swap(&o->monitorBits, busyBits);
490         return lockState(lockBits) != BUSY ? lockBits : getMetaLockSlow(t, lockBits);
491 }
492
493 static long getMetaLockSlow(threadobject *t, long predBits)
494 {
495         long bits;
496         threadobject *pred = lockRecord(predBits);
497         pthread_mutex_lock(&pred->ee.metaLockMutex);
498         if (!pred->ee.bitsForGrab) {
499                 pred->ee.succ = t;
500                 do {
501                         pthread_cond_wait(&pred->ee.metaLockCond, &pred->ee.metaLockMutex);
502                 } while (!t->ee.gotMetaLockSlow);
503                 t->ee.gotMetaLockSlow = false;
504                 bits = t->ee.metaLockBits;
505         } else {
506                 bits = pred->ee.metaLockBits;
507                 pred->ee.bitsForGrab = false;
508                 pthread_cond_signal(&pred->ee.metaLockCond);
509         }
510         pthread_mutex_unlock(&pred->ee.metaLockMutex);
511         return bits;
512 }
513
514 static void releaseMetaLock(threadobject *t, java_objectheader *o, long releaseBits)
515 {
516         long busyBits = makeLockBits(t, BUSY);
517         long lockBits = compare_and_swap(&o->monitorBits, busyBits, releaseBits);
518         
519         if (lockBits != busyBits)
520                 releaseMetaLockSlow(t, releaseBits);
521 }
522
523 static void releaseMetaLockSlow(threadobject *t, long releaseBits)
524 {
525         pthread_mutex_lock(&t->ee.metaLockMutex);
526         if (t->ee.succ) {
527                 assert(!t->ee.succ->ee.bitsForGrab);
528                 assert(!t->ee.bitsForGrab);
529                 assert(!t->ee.succ->ee.gotMetaLockSlow);
530                 t->ee.succ->ee.metaLockBits = releaseBits;
531                 t->ee.succ->ee.gotMetaLockSlow = true;
532                 t->ee.succ = NULL;
533                 pthread_cond_signal(&t->ee.metaLockCond);
534         } else {
535                 t->ee.metaLockBits = releaseBits;
536                 t->ee.bitsForGrab = true;
537                 do {
538                         pthread_cond_wait(&t->ee.metaLockCond, &t->ee.metaLockMutex);
539                 } while (t->ee.bitsForGrab);
540         }
541         pthread_mutex_unlock(&t->ee.metaLockMutex);
542 }
543
544 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r);
545
546 void monitorEnter(threadobject *t, java_objectheader *o)
547 {
548         long r = getMetaLock(t, o);
549         int state = lockState(r);
550
551         if (state == NEUTRAL) {
552                 monitorLockRecord *lr = allocLockRecord(t);
553                 lr->storedBits = r;
554                 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
555         } else if (state == LOCKED) {
556                 monitorLockRecord *ownerLR = lockRecord(r);
557                 if (ownerLR->owner == t) {
558                         ownerLR->lockCount++;
559                         releaseMetaLock(t, o, r);
560                 } else {
561                         monitorLockRecord *lr = allocLockRecord(t);
562                         ownerLR->queue = appendToQueue(ownerLR->queue, lr);
563                         monitorEnterSlow(t, o, r);
564                 }
565         } else if (state == WAITERS) {
566                 monitorLockRecord *lr = allocLockRecord(t);
567                 monitorLockRecord *firstWaiterLR = lockRecord(r);
568                 lr->queue = firstWaiterLR;
569                 lr->storedBits = firstWaiterLR->storedBits;
570                 releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
571         }
572 }
573
574 static void monitorEnterSlow(threadobject *t, java_objectheader *o, long r)
575 {
576         monitorLockRecord *lr;
577         monitorLockRecord *firstWaiterLR;
578         while (lockState(r) == LOCKED) {
579                 pthread_mutex_lock(&t->ee.monitorLockMutex);
580                 releaseMetaLock(t, o, r);
581                 pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
582                 pthread_mutex_unlock(&t->ee.monitorLockMutex);
583                 r = getMetaLock(t, o);
584         }
585         assert(lockState(r) == WAITERS);
586         lr = moveMyLRToFront(t, lockRecord(r));
587         releaseMetaLock(t, o, makeLockBits(lr, LOCKED));
588 }
589
590 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr);
591
592 void monitorExit(threadobject *t, java_objectheader *o)
593 {
594         long r = getMetaLock(t, o);
595         monitorLockRecord *ownerLR = lockRecord(r);
596         int state = lockState(r);
597         if (state == LOCKED && ownerLR->owner == t) {
598                 assert(ownerLR->lockCount >= 1);
599                 if (ownerLR->lockCount == 1) {
600                         if (ownerLR->queue == NULL) {
601                                 assert(lockState(ownerLR->storedBits) == NEUTRAL);
602                                 releaseMetaLock(t, o, ownerLR->storedBits);
603                         } else {
604                                 ownerLR->queue->storedBits = ownerLR->storedBits;
605                                 monitorExitSlow(t, o, ownerLR->queue);
606                                 ownerLR->queue = NULL;
607                         }
608                         recycleLockRecord(t, ownerLR);
609                 } else {
610                         ownerLR->lockCount--;
611                         releaseMetaLock(t, o, r);
612                 }
613         } else {
614                 releaseMetaLock(t, o, r);
615                 panic("Illegal monitor exception");
616         }
617 }
618
619 static threadobject *wakeupEE(monitorLockRecord *lr)
620 {
621         while (lr->queue && lr->queue->owner->ee.isWaitingForNotify)
622                 lr = lr->queue;
623         return lr->owner;
624 }
625
626 static void monitorExitSlow(threadobject *t, java_objectheader *o, monitorLockRecord *lr)
627 {
628         threadobject *wakeEE = wakeupEE(lr);
629         if (wakeEE) {
630                 pthread_mutex_lock(&wakeEE->ee.monitorLockMutex);
631                 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
632                 pthread_cond_signal(&wakeEE->ee.monitorLockCond);
633                 pthread_mutex_unlock(&wakeEE->ee.monitorLockMutex);
634         } else {
635                 releaseMetaLock(t, o, makeLockBits(lr, WAITERS));
636         }
637 }
638
639 void monitorWait(threadobject *t, java_objectheader *o, s8 millis)
640 {
641         long r = getMetaLock(t, o);
642         monitorLockRecord *ownerLR = lockRecord(r);
643         int state = lockState(r);
644         if (state == LOCKED && ownerLR->owner == t) {
645                 pthread_mutex_lock(&t->ee.monitorLockMutex);
646                 t->ee.isWaitingForNotify = true;
647                 monitorExitSlow(t, o, ownerLR);
648                 if (millis == -1)
649                         pthread_cond_wait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex);
650                 else
651                         timedCondWait(&t->ee.monitorLockCond, &t->ee.monitorLockMutex, millis);
652                 t->ee.isWaitingForNotify = false;
653                 pthread_mutex_unlock(&t->ee.monitorLockMutex);
654                 r = getMetaLock(t, o);
655                 monitorEnterSlow(t, o, r);
656         } else {
657                 releaseMetaLock(t, o, r);
658                 panic("Illegal monitor exception");
659         }
660 }
661
662 static void notifyOneOrAll(threadobject *t, java_objectheader *o, bool one)
663 {
664         long r = getMetaLock(t, o);
665         monitorLockRecord *ownerLR = lockRecord(r);
666         int state = lockState(r);
667         if (state == LOCKED && ownerLR->owner == t) {
668                 monitorLockRecord *q = ownerLR->queue;
669                 while (q) {
670                         if (q->owner->ee.isWaitingForNotify) {
671                                 q->owner->ee.isWaitingForNotify = false;
672                                 if (one)
673                                         break;
674                         }
675                         q = q->queue;
676                 }
677                 releaseMetaLock(t, o, r);
678         } else {
679                 releaseMetaLock(t, o, r);
680                 panic("Illegal monitor exception");
681         }
682 }
683
684 void wait_cond_for_object(java_objectheader *o, s8 time)
685 {
686         threadobject *t = (threadobject*) THREADOBJECT;
687         monitorWait(t, o, time);
688 }
689
690 void signal_cond_for_object(java_objectheader *o)
691 {
692         threadobject *t = (threadobject*) THREADOBJECT;
693         notifyOneOrAll(t, o, true);
694 }
695
696 void broadcast_cond_for_object(java_objectheader *o)
697 {
698         threadobject *t = (threadobject*) THREADOBJECT;
699         notifyOneOrAll(t, o, false);
700 }
701
702 #endif