Get rid of asm_javacallmethod
[cacao.git] / src / threads / green / threads.c
1 /* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */
2 /*
3  * thread.c
4  * Thread support.
5  *
6  * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK.
7  *
8  * See the file "license.terms" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * Written by Tim Wilkinson <tim@tjwassoc.demon.co.uk>, 1996.
12  */
13
14
15 #include <stdlib.h>
16 #include <string.h>
17 #include <assert.h>
18 #include <sys/types.h>
19 #include <sys/mman.h>                   /* for mprotect */
20 #include <unistd.h>
21 #include <signal.h>
22 #include <sys/time.h>
23
24 #include "config.h"
25 #include "thread.h"
26 #include "locks.h"
27 #include "tables.h"
28 #include "native.h"
29 #include "loader.h"
30 #include "builtin.h"
31 #include "asmpart.h"
32 #include "toolbox/loging.h"
33 #include "toolbox/memory.h"
34
35 #if defined(NATIVE_THREADS)
36 pthread_mutex_t cast_mutex = PTHREAD_MUTEX_INITIALIZER;
37 pthread_mutex_t compiler_mutex = PTHREAD_MUTEX_INITIALIZER;
38 #endif
39
40 static classinfo *class_java_lang_ThreadDeath;
41
42 thread* currentThread = NULL;
43 thread* mainThread;
44 thread* threadQhead[MAX_THREAD_PRIO + 1];
45 thread* threadQtail[MAX_THREAD_PRIO + 1];
46
47 thread* liveThreads = NULL;
48 thread* sleepThreads = NULL;
49
50 int blockInts;
51 bool needReschedule;
52
53 ctx contexts[MAXTHREADS];
54
55 /* Number of threads alive, also counting daemons */
56 static int talive;
57
58 /* Number of daemon threads alive */
59 static int tdaemon;
60
61 static void firstStartThread(void);
62
63 void reschedule(void);
64
65 /* Setup default thread stack size - this can be overwritten if required */
66 int threadStackSize = THREADSTACKSIZE;
67
68 /* Pointer to the stack of the last killed thread. The free is delayed. */
69 void *stack_to_be_freed = 0;
70
71 static thread* startDaemon(void* func, char* nm, int stackSize);
72
73 /*
74  * Allocate the stack for a thread
75  */
76 void
77 allocThreadStack (thread *tid, int size)
78 {
79     int pageSize = getpagesize();
80     unsigned long pageBegin;
81
82         assert(stack_to_be_freed == 0);
83
84     CONTEXT(tid).stackMem = GCNEW(u1, size + 4 * pageSize);
85     assert(CONTEXT(tid).stackMem != 0);
86     CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
87     
88     pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
89     pageBegin = pageBegin - pageBegin % pageSize;
90
91     CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
92 }
93
94 /*
95  * Mark the stack for a thread to be freed. We cannot free the stack
96  * immediately because it is still in use!
97  */
98 void
99 freeThreadStack (thread *tid)
100 {
101     if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
102     {
103                 int pageSize = getpagesize();
104                 unsigned long pageBegin;
105
106                 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
107                 pageBegin = pageBegin - pageBegin % pageSize;
108
109                 assert(stack_to_be_freed == 0);
110
111                 stack_to_be_freed = CONTEXT(tid).stackMem;
112     }
113     CONTEXT(tid).stackMem = 0;
114     CONTEXT(tid).stackBase = 0;
115     CONTEXT(tid).stackEnd = 0;
116 }
117
118 /*
119  * Initialize threads.
120  */
121 void
122 initThreads(u1 *stackbottom)
123 {
124         thread *the_main_thread;
125     int i;
126         char mainname[] = "main";
127         /*int len = strlen(mainname);*/
128
129         signal(SIGPIPE, SIG_IGN);
130
131     initLocks();
132
133     for (i = 0; i < MAXTHREADS; ++i) {
134                 contexts[i].free = true;
135                 contexts[i].thread = NULL;
136         }
137
138     /* Allocate a thread to be the main thread */
139     liveThreads = the_main_thread = (thread*)builtin_new(loader_load_sysclass(NULL,utf_new_char("java/lang/Thread")));
140     assert(the_main_thread != 0);
141     
142     the_main_thread->PrivateInfo = 1;
143     CONTEXT(the_main_thread).free = false;
144
145 #if 0
146     {
147         /* stefan */
148         methodinfo *m;
149         m = class_fetchmethod(
150                         class_java_lang_String,
151                         utf_new_char ("toCharArray"),
152                         utf_new_char ("()[C")
153                         );
154 printf("DEADCODE LIVES ?????????\n");fflush(stdout);
155         the_main_thread->name = asm_calljavafunction (m, javastring_new(utf_new_char("main")), 0, 0, 0);
156     }
157 #endif
158         the_main_thread->name=javastring_new(utf_new_char(mainname));
159 /*      the_main_thread->name = builtin_newarray_char(len);
160         {   u2 *d = the_main_thread->name->data;
161                 for (i=0; i<len; i++)
162                         d[i] = mainname[i];
163         }*/
164     the_main_thread->priority = NORM_THREAD_PRIO;
165     CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
166     CONTEXT(the_main_thread).exceptionptr = 0;
167     the_main_thread->next = 0;
168     CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
169     CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
170     THREADINFO(&CONTEXT(the_main_thread));
171
172     DBG( printf("main thread %p base %p end %p\n", 
173                                 the_main_thread,
174                                 CONTEXT(the_main_thread).stackBase,
175                                 CONTEXT(the_main_thread).stackEnd); );
176
177         CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
178         CONTEXT(the_main_thread).nextlive = 0;
179         CONTEXT(the_main_thread).thread = the_main_thread;
180         /*the_main_thread->single_step = 0;*/
181         the_main_thread->daemon = 0;
182         /*the_main_thread->stillborn = 0;*/
183         /*the_main_thread->target = 0;*/
184
185         the_main_thread->contextClassLoader = 0;
186         /*the_main_thread->inheritedAccessControlContext = 0;*/
187         /*the_main_thread->values = 0;*/
188
189         /* Allocate and init ThreadGroup */
190         the_main_thread->group = (threadGroup*)native_new_and_init(loader_load(utf_new_char("java/lang/ThreadGroup")));
191         assert(the_main_thread->group != 0);
192
193         talive++;
194
195         /* Load exception classes */
196     loader_load_sysclass(&class_java_lang_ThreadDeath,
197                          utf_new_char("java/lang/ThreadDeath"));
198
199         DBG( fprintf(stderr, "finishing initThreads\n"); );
200
201     mainThread = currentThread = the_main_thread;
202
203         /* Add thread into runQ */
204         iresumeThread(mainThread);
205
206         assert(blockInts == 0);
207 }
208
209 /*
210  * Start a new thread running.
211  */
212 void
213 startThread (thread* tid)
214 {
215     int i;
216
217     /* Allocate a stack context */
218     for (i = 0; i < MAXTHREADS; ++i)
219                 if (contexts[i].free)
220                         break;
221
222     if (i == MAXTHREADS)
223                 panic("Too many threads");
224
225         assert(tid->priority >= MIN_THREAD_PRIO && tid->priority <= MAX_THREAD_PRIO);
226
227     tid->PrivateInfo = i + 1;
228     CONTEXT(tid).free = false;
229         CONTEXT(tid).thread = tid;
230     CONTEXT(tid).nextlive = liveThreads;
231     liveThreads = tid;
232     allocThreadStack(tid, threadStackSize);
233     CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
234     CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
235     CONTEXT(tid).status = THREAD_SUSPENDED;
236     CONTEXT(tid).priority = (u1)tid->priority;
237     CONTEXT(tid).exceptionptr = 0;
238
239     /* Construct the initial restore point. */
240     THREADINIT((&CONTEXT(tid)), firstStartThread);
241
242     DBG( printf("new thread %p base %p end %p\n",
243                                 tid, CONTEXT(tid).stackBase,
244                                 CONTEXT(tid).stackEnd); );
245
246         talive++;
247         if (tid->daemon)
248                 tdaemon++;
249
250         /* Add thread into runQ */
251         iresumeThread(tid);
252 }
253
254 /*
255  * Start a daemon thread.
256  */
257 static thread*
258 startDaemon(void* func, char* nm, int stackSize)
259 {
260     thread* tid;
261     int i;
262
263     DBG( printf("startDaemon %s\n", nm); );
264
265         tid = (thread*)builtin_new(loader_load_sysclass(NULL,utf_new_char("java/lang/Thread")));
266         assert(tid != 0);
267
268         for (i = 0; i < MAXTHREADS; ++i)
269                 if (contexts[i].free)
270                         break;
271         if (i == MAXTHREADS)
272                 panic("Too many threads");
273
274         tid->PrivateInfo = i + 1;
275         CONTEXT(tid).free = false;
276         tid->name = 0;          /* for the moment */
277         tid->priority = MAX_THREAD_PRIO;
278         CONTEXT(tid).priority = (u1)tid->priority;
279         tid->next = 0;
280         CONTEXT(tid).status = THREAD_SUSPENDED;
281
282         allocThreadStack(tid, stackSize);
283         /*tid->single_step = 0;*/
284         tid->daemon = 1;
285         /*tid->stillborn = 0;*/
286         /*tid->target = 0;*/
287         tid->group = 0;
288
289         /* Construct the initial restore point. */
290         THREADINIT((&CONTEXT(tid)), func);
291
292         talive++;
293         tdaemon++;
294
295         return tid;
296 }
297
298 /*
299  * All threads start here.
300  */
301 static void
302 firstStartThread(void)
303 {
304     methodinfo *method;
305
306     DBG( printf("firstStartThread %p\n", currentThread); );
307
308         if (stack_to_be_freed != 0)     {
309                 stack_to_be_freed = 0;
310         }
311
312         /* Every thread starts with the interrupts off */
313         intsRestore();
314         assert(blockInts == 0);
315
316         /* Find the run()V method and call it */
317         method = class_findmethod(currentThread->header.vftbl->class,
318                                                           utf_new_char("run"), utf_new_char("()V"));
319         if (method == 0)
320                 panic("Cannot find method \'void run ()\'");
321
322         asm_calljavafunction(method, currentThread, NULL, NULL, NULL);
323
324     if (exceptionptr) {
325         utf_display(exceptionptr->vftbl->class->name);
326         printf("\n");
327     }
328
329         killThread(0);
330         assert("Thread returned from killThread" == 0);
331 }
332
333 /*
334  * Resume a thread running.
335  * This routine has to be called only from locations which ensure
336  * run / block queue consistency. There is no check for illegal resume
337  * conditions (like explicitly resuming an IO blocked thread). There also
338  * is no update of any blocking queue. Both has to be done by the caller
339  */
340 void
341 iresumeThread(thread* tid)
342 {
343     DBG( printf("resumeThread %p\n", tid); );
344
345         intsDisable();
346
347         if (CONTEXT(tid).status != THREAD_RUNNING)
348         {
349                 CONTEXT(tid).status = THREAD_RUNNING;
350
351                 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
352
353                 /* Place thread on the end of its queue */
354                 if (threadQhead[CONTEXT(tid).priority] == 0) {
355                         threadQhead[CONTEXT(tid).priority] = tid;
356                         threadQtail[CONTEXT(tid).priority] = tid;
357                         if (CONTEXT(tid).priority
358                                 > CONTEXT(currentThread).priority)
359                                 needReschedule = true;
360                 }
361                 else
362                 {
363                         threadQtail[CONTEXT(tid).priority]->next = tid;
364                         threadQtail[CONTEXT(tid).priority] = tid;
365                 }
366                 tid->next = 0;
367         }
368         SDBG( else { printf("Re-resuming %p\n", tid); } );
369
370         intsRestore();
371 }
372
373 /*
374  * Yield process to another thread of equal priority.
375  */
376 void
377 yieldThread()
378 {
379     intsDisable();
380
381     if (threadQhead[CONTEXT(currentThread).priority]
382                 != threadQtail[CONTEXT(currentThread).priority])
383     {
384                 /* Get the next thread and move me to the end */
385                 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
386                 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
387                 threadQtail[CONTEXT(currentThread).priority] = currentThread;
388                 currentThread->next = 0;
389                 needReschedule = true;
390     }
391
392     intsRestore();
393 }
394
395 /*
396  * Explicit request by user to resume a thread
397  * The definition says that it is just legal to call this after a preceeding
398  * suspend (which got through). If the thread was blocked for some other
399  * reason (either sleep or IO or a muxSem), we simply can't do it
400  * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
401  * (which is set by suspendThread(.))
402  */
403 void
404 resumeThread (thread* tid)
405 {
406     if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
407     {
408                 intsDisable();
409                 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
410                 iresumeThread(tid);
411                 intsRestore();
412     }
413 }
414
415 /*
416  * Suspend a thread.
417  * This is an explicit user request to suspend the thread - the counterpart
418  * for resumeThreadRequest(.). It is JUST called by the java method
419  * Thread.suspend()
420  * What makes it distinct is the fact that the suspended thread is not contained
421  * in any block queue. Without a special flag (indicating the user suspend), we
422  * can't check s suspended thread for this condition afterwards (which is
423  * required by resumeThreadRequest()). The new thread flag
424  * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
425  */
426 void
427 suspendThread(thread* tid)
428 {
429     thread** ntid;
430
431     intsDisable();
432
433     if (CONTEXT(tid).status != THREAD_SUSPENDED)
434     {
435                 CONTEXT(tid).status = THREAD_SUSPENDED;
436                 
437                 /*
438                  * This is used to indicate the explicit suspend condition
439                  * required by resumeThreadRequest()
440                  */
441                 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
442
443                 for (ntid = &threadQhead[CONTEXT(tid).priority];
444                          *ntid != 0;
445                          ntid = &(*ntid)->next)
446                 {
447                         if (*ntid == tid)
448                         {
449                                 *ntid = tid->next;
450                                 tid->next = 0;
451                                 if (tid == currentThread)
452                                 {
453                                         reschedule();
454                                 }
455                                 break;
456                         }
457                 }
458     }
459         SDBG( else { printf("Re-suspending %p\n", tid); } );
460
461         intsRestore();
462 }
463
464 /*
465  * Suspend a thread on a queue.
466  */
467 void
468 suspendOnQThread(thread* tid, thread** queue)
469 {
470     thread** ntid;
471
472         DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
473
474         assert(blockInts > 0);
475
476         if (CONTEXT(tid).status != THREAD_SUSPENDED)
477         {
478                 CONTEXT(tid).status = THREAD_SUSPENDED;
479
480                 for (ntid = &threadQhead[CONTEXT(tid).priority];
481                          *ntid != 0;
482                          ntid = &(*ntid)->next)
483                 {
484                         if (*ntid == tid)
485                         {
486                                 *ntid = tid->next;
487                                 /* Insert onto head of lock wait Q */
488                                 tid->next = *queue;
489                                 *queue = tid;
490                                 if (tid == currentThread)
491                                 {
492                                         DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
493                                                                  tid, currentThread, CONTEXT(tid).priority); );
494                                         reschedule();
495                                 }
496                                 break;
497                         }
498                 }
499         }
500         SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
501 }
502
503 /*
504  * Kill thread.
505  */
506 void
507 killThread(thread* tid)
508 {
509     thread** ntid;
510
511     intsDisable();
512
513     /* A null tid means the current thread */
514     if (tid == 0)
515     {
516                 tid = currentThread;
517     }
518
519         DBG( printf("killThread %p\n", tid); );
520
521         if (CONTEXT(tid).status != THREAD_DEAD)
522         {
523                 /* Get thread off runq (if it needs it) */
524                 if (CONTEXT(tid).status == THREAD_RUNNING)
525                 {
526                         for (ntid = &threadQhead[CONTEXT(tid).priority];
527                                  *ntid != 0;
528                                  ntid = &(*ntid)->next)
529                         {
530                                 if (*ntid == tid)
531                                 {
532                                         *ntid = tid->next;
533                                         break;
534                                 }
535                         }
536                 }
537
538                 CONTEXT(tid).status = THREAD_DEAD;
539                 talive--;
540                 if (tid->daemon) {
541                         tdaemon--;
542                 }
543
544                 /* If we only have daemons left, then everyone is dead. */
545                 if (talive == tdaemon) {
546                         /* atexit functions get called to clean things up */
547                         intsRestore();
548                         exit(0);
549                 }
550
551                 /* Notify on the object just in case anyone is waiting */
552                 internal_lock_mutex_for_object(&tid->header);
553                 internal_broadcast_cond_for_object(&tid->header);
554                 internal_unlock_mutex_for_object(&tid->header);
555
556                 /* Remove thread from live list to it can be garbaged */
557                 for (ntid = &liveThreads;
558                          *ntid != 0;
559                          ntid = &(CONTEXT((*ntid)).nextlive))
560                 {
561                         if (tid == (*ntid))
562                         {
563                                 (*ntid) = CONTEXT(tid).nextlive;
564                                 break;
565                         }
566                 }
567
568                 /* Free stack */
569                 freeThreadStack(tid);
570
571                 /* free context */
572                 if (tid != mainThread) {
573                         CONTEXT(tid).free = true;
574                         CONTEXT(tid).thread = NULL;
575                 }
576
577                 /* Run something else */
578                 needReschedule = true;
579         }
580         intsRestore();
581 }
582
583 /*
584  * Change thread priority.
585  */
586 void
587 setPriorityThread(thread* tid, int prio)
588 {
589     thread** ntid;
590
591         assert(prio >= MIN_THREAD_PRIO && prio <= MAX_THREAD_PRIO);
592
593     if (tid->PrivateInfo == 0) {
594                 tid->priority = prio;
595                 return;
596     }
597
598     if (CONTEXT(tid).status == THREAD_SUSPENDED) {
599                 CONTEXT(tid).priority = (u8)prio;
600                 return;
601     }
602
603     intsDisable();
604
605     /* Remove from current thread list */
606     for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
607                 if (*ntid == tid) {
608                         *ntid = tid->next;
609                         break;
610                 }
611     }
612
613     /* Insert onto a new one */
614     tid->priority = prio;
615     CONTEXT(tid).priority = (u8)tid->priority;
616     if (threadQhead[prio] == 0) {
617                 threadQhead[prio] = tid;
618                 threadQtail[prio] = tid;
619                 if (prio > CONTEXT(currentThread).priority) {
620                         needReschedule = true;
621                 }
622     }
623     else {
624                 threadQtail[prio]->next = tid;
625                 threadQtail[prio] = tid;
626     }
627     tid->next = 0;
628
629     intsRestore();
630 }
631
632 /*
633  * Get the current time in milliseconds since 1970-01-01.
634  */
635 s8
636 currentTime (void)
637 {
638         struct timeval tv;
639         s8 time;
640
641         gettimeofday(&tv, 0);
642
643         time = tv.tv_sec;
644         time *= 1000;
645         time += tv.tv_usec / 1000;
646
647         return time;
648 }
649
650 /*
651  * Put a thread to sleep.
652  */
653 void
654 sleepThread (s8 time)
655 {
656     thread** tidp;
657
658     /* Sleep for no time */
659     if (time <= 0) {
660                 return;
661     }
662     
663     intsDisable();
664
665     /* Get absolute time */
666     CONTEXT(currentThread).time = time + currentTime();
667
668     /* Find place in alarm list */
669     for (tidp = &sleepThreads; (*tidp) != 0; tidp = &(*tidp)->next)
670         {
671                 if (CONTEXT(*tidp).time > CONTEXT(currentThread).time)
672                         break;
673     }
674
675     /* Suspend thread on it */
676     suspendOnQThread(currentThread, tidp);
677     
678     intsRestore();
679 }
680
681 /*
682  * Is this thread alive?
683  */
684 bool
685 aliveThread(thread* tid)
686 {
687     if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
688                 return (true);
689     else
690                 return (false);
691 }
692
693 /*
694  * Reschedule the thread.
695  * Called whenever a change in the running thread is required.
696  */
697 void
698 reschedule(void)
699 {
700     int i;
701     thread* lastThread;
702     int b;
703     /*    sigset_t nsig; */
704
705     /* A reschedule in a non-blocked context is half way to hell */
706     assert(blockInts > 0);
707     b = blockInts;
708     
709     /* Check events - we may release a high priority thread */
710     /* Just check IO, no need for a reschedule call by checkEvents() */
711     needReschedule = false;
712     checkEvents(false);
713
714     for (;;)
715     {
716                 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
717                 {
718                         if (threadQhead[i] != 0)
719                         {
720                                 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
721
722                                 if (threadQhead[i] != currentThread)
723                                 {
724                                         /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
725
726                                         lastThread = currentThread;
727                                         currentThread = threadQhead[i];
728
729                                         CONTEXT(currentThread).exceptionptr = exceptionptr;
730
731                     DBG( fprintf(stderr, "thread switch from: %p to: %p\n", lastThread, currentThread); );
732                                         THREADSWITCH((&CONTEXT(currentThread)),
733                                                                  (&CONTEXT(lastThread)));
734                                         blockInts = b;
735
736                                         exceptionptr = CONTEXT(currentThread).exceptionptr;
737
738                                         if (stack_to_be_freed != 0) {
739                                                 stack_to_be_freed = 0;
740                                         }
741
742                                         /* Alarm signal may be blocked - if so
743                                          * unblock it.
744                                          */
745                                         /*
746                                           if (alarmBlocked == true) {
747                                           alarmBlocked = false;
748                                           sigemptyset(&nsig);
749                                           sigaddset(&nsig, SIGALRM);
750                                           sigprocmask(SIG_UNBLOCK, &nsig, 0);
751                                           }
752                                         */
753
754                                         /* I might be dying */
755                                         if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
756                                                 != 0)
757                                         {
758                                                 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
759                                                 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
760                                         }
761                                 }
762                                 /* Now we kill the schedule and turn ints
763                                    back on */
764                                 needReschedule = false;
765                                 return;
766                         }
767                 }
768                 /* Nothing to run - wait for external event */
769                 DBG( fprintf(stderr, "nothing more to do\n"); );
770                 checkEvents(true);
771     }
772 }