Removed heap_addreference.
[cacao.git] / threads / thread.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         java_objectheader *local_exceptionptr = NULL;
306
307     DBG( printf("firstStartThread %p\n", currentThread); );
308
309         if (stack_to_be_freed != 0)     {
310                 stack_to_be_freed = 0;
311         }
312
313         /* Every thread starts with the interrupts off */
314         intsRestore();
315         assert(blockInts == 0);
316
317         /* Find the run()V method and call it */
318         method = class_findmethod(currentThread->header.vftbl->class,
319                                                           utf_new_char("run"), utf_new_char("()V"));
320         if (method == 0)
321                 panic("Cannot find method \'void run ()\'");
322
323         local_exceptionptr = asm_calljavamethod(method, currentThread, NULL, NULL, NULL);
324
325     if (local_exceptionptr) {
326         utf_display(local_exceptionptr->vftbl->class->name);
327         printf("\n");
328     }
329
330         killThread(0);
331         assert("Thread returned from killThread" == 0);
332 }
333
334 /*
335  * Resume a thread running.
336  * This routine has to be called only from locations which ensure
337  * run / block queue consistency. There is no check for illegal resume
338  * conditions (like explicitly resuming an IO blocked thread). There also
339  * is no update of any blocking queue. Both has to be done by the caller
340  */
341 void
342 iresumeThread(thread* tid)
343 {
344     DBG( printf("resumeThread %p\n", tid); );
345
346         intsDisable();
347
348         if (CONTEXT(tid).status != THREAD_RUNNING)
349         {
350                 CONTEXT(tid).status = THREAD_RUNNING;
351
352                 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
353
354                 /* Place thread on the end of its queue */
355                 if (threadQhead[CONTEXT(tid).priority] == 0) {
356                         threadQhead[CONTEXT(tid).priority] = tid;
357                         threadQtail[CONTEXT(tid).priority] = tid;
358                         if (CONTEXT(tid).priority
359                                 > CONTEXT(currentThread).priority)
360                                 needReschedule = true;
361                 }
362                 else
363                 {
364                         threadQtail[CONTEXT(tid).priority]->next = tid;
365                         threadQtail[CONTEXT(tid).priority] = tid;
366                 }
367                 tid->next = 0;
368         }
369         SDBG( else { printf("Re-resuming %p\n", tid); } );
370
371         intsRestore();
372 }
373
374 /*
375  * Yield process to another thread of equal priority.
376  */
377 void
378 yieldThread()
379 {
380     intsDisable();
381
382     if (threadQhead[CONTEXT(currentThread).priority]
383                 != threadQtail[CONTEXT(currentThread).priority])
384     {
385                 /* Get the next thread and move me to the end */
386                 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
387                 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
388                 threadQtail[CONTEXT(currentThread).priority] = currentThread;
389                 currentThread->next = 0;
390                 needReschedule = true;
391     }
392
393     intsRestore();
394 }
395
396 /*
397  * Explicit request by user to resume a thread
398  * The definition says that it is just legal to call this after a preceeding
399  * suspend (which got through). If the thread was blocked for some other
400  * reason (either sleep or IO or a muxSem), we simply can't do it
401  * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
402  * (which is set by suspendThread(.))
403  */
404 void
405 resumeThread (thread* tid)
406 {
407     if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
408     {
409                 intsDisable();
410                 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
411                 iresumeThread(tid);
412                 intsRestore();
413     }
414 }
415
416 /*
417  * Suspend a thread.
418  * This is an explicit user request to suspend the thread - the counterpart
419  * for resumeThreadRequest(.). It is JUST called by the java method
420  * Thread.suspend()
421  * What makes it distinct is the fact that the suspended thread is not contained
422  * in any block queue. Without a special flag (indicating the user suspend), we
423  * can't check s suspended thread for this condition afterwards (which is
424  * required by resumeThreadRequest()). The new thread flag
425  * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
426  */
427 void
428 suspendThread(thread* tid)
429 {
430     thread** ntid;
431
432     intsDisable();
433
434     if (CONTEXT(tid).status != THREAD_SUSPENDED)
435     {
436                 CONTEXT(tid).status = THREAD_SUSPENDED;
437                 
438                 /*
439                  * This is used to indicate the explicit suspend condition
440                  * required by resumeThreadRequest()
441                  */
442                 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
443
444                 for (ntid = &threadQhead[CONTEXT(tid).priority];
445                          *ntid != 0;
446                          ntid = &(*ntid)->next)
447                 {
448                         if (*ntid == tid)
449                         {
450                                 *ntid = tid->next;
451                                 tid->next = 0;
452                                 if (tid == currentThread)
453                                 {
454                                         reschedule();
455                                 }
456                                 break;
457                         }
458                 }
459     }
460         SDBG( else { printf("Re-suspending %p\n", tid); } );
461
462         intsRestore();
463 }
464
465 /*
466  * Suspend a thread on a queue.
467  */
468 void
469 suspendOnQThread(thread* tid, thread** queue)
470 {
471     thread** ntid;
472
473         DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
474
475         assert(blockInts > 0);
476
477         if (CONTEXT(tid).status != THREAD_SUSPENDED)
478         {
479                 CONTEXT(tid).status = THREAD_SUSPENDED;
480
481                 for (ntid = &threadQhead[CONTEXT(tid).priority];
482                          *ntid != 0;
483                          ntid = &(*ntid)->next)
484                 {
485                         if (*ntid == tid)
486                         {
487                                 *ntid = tid->next;
488                                 /* Insert onto head of lock wait Q */
489                                 tid->next = *queue;
490                                 *queue = tid;
491                                 if (tid == currentThread)
492                                 {
493                                         DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
494                                                                  tid, currentThread, CONTEXT(tid).priority); );
495                                         reschedule();
496                                 }
497                                 break;
498                         }
499                 }
500         }
501         SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
502 }
503
504 /*
505  * Kill thread.
506  */
507 void
508 killThread(thread* tid)
509 {
510     thread** ntid;
511
512     intsDisable();
513
514     /* A null tid means the current thread */
515     if (tid == 0)
516     {
517                 tid = currentThread;
518     }
519
520         DBG( printf("killThread %p\n", tid); );
521
522         if (CONTEXT(tid).status != THREAD_DEAD)
523         {
524                 /* Get thread off runq (if it needs it) */
525                 if (CONTEXT(tid).status == THREAD_RUNNING)
526                 {
527                         for (ntid = &threadQhead[CONTEXT(tid).priority];
528                                  *ntid != 0;
529                                  ntid = &(*ntid)->next)
530                         {
531                                 if (*ntid == tid)
532                                 {
533                                         *ntid = tid->next;
534                                         break;
535                                 }
536                         }
537                 }
538
539                 CONTEXT(tid).status = THREAD_DEAD;
540                 talive--;
541                 if (tid->daemon) {
542                         tdaemon--;
543                 }
544
545                 /* If we only have daemons left, then everyone is dead. */
546                 if (talive == tdaemon) {
547                         /* atexit functions get called to clean things up */
548                         intsRestore();
549                         exit(0);
550                 }
551
552                 /* Notify on the object just in case anyone is waiting */
553                 internal_lock_mutex_for_object(&tid->header);
554                 internal_broadcast_cond_for_object(&tid->header);
555                 internal_unlock_mutex_for_object(&tid->header);
556
557                 /* Remove thread from live list to it can be garbaged */
558                 for (ntid = &liveThreads;
559                          *ntid != 0;
560                          ntid = &(CONTEXT((*ntid)).nextlive))
561                 {
562                         if (tid == (*ntid))
563                         {
564                                 (*ntid) = CONTEXT(tid).nextlive;
565                                 break;
566                         }
567                 }
568
569                 /* Free stack */
570                 freeThreadStack(tid);
571
572                 /* free context */
573                 if (tid != mainThread) {
574                         CONTEXT(tid).free = true;
575                         CONTEXT(tid).thread = NULL;
576                 }
577
578                 /* Run something else */
579                 needReschedule = true;
580         }
581         intsRestore();
582 }
583
584 /*
585  * Change thread priority.
586  */
587 void
588 setPriorityThread(thread* tid, int prio)
589 {
590     thread** ntid;
591
592         assert(prio >= MIN_THREAD_PRIO && prio <= MAX_THREAD_PRIO);
593
594     if (tid->PrivateInfo == 0) {
595                 tid->priority = prio;
596                 return;
597     }
598
599     if (CONTEXT(tid).status == THREAD_SUSPENDED) {
600                 CONTEXT(tid).priority = (u8)prio;
601                 return;
602     }
603
604     intsDisable();
605
606     /* Remove from current thread list */
607     for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
608                 if (*ntid == tid) {
609                         *ntid = tid->next;
610                         break;
611                 }
612     }
613
614     /* Insert onto a new one */
615     tid->priority = prio;
616     CONTEXT(tid).priority = (u8)tid->priority;
617     if (threadQhead[prio] == 0) {
618                 threadQhead[prio] = tid;
619                 threadQtail[prio] = tid;
620                 if (prio > CONTEXT(currentThread).priority) {
621                         needReschedule = true;
622                 }
623     }
624     else {
625                 threadQtail[prio]->next = tid;
626                 threadQtail[prio] = tid;
627     }
628     tid->next = 0;
629
630     intsRestore();
631 }
632
633 /*
634  * Get the current time in milliseconds since 1970-01-01.
635  */
636 s8
637 currentTime (void)
638 {
639         struct timeval tv;
640         s8 time;
641
642         gettimeofday(&tv, 0);
643
644         time = tv.tv_sec;
645         time *= 1000;
646         time += tv.tv_usec / 1000;
647
648         return time;
649 }
650
651 /*
652  * Put a thread to sleep.
653  */
654 void
655 sleepThread (s8 time)
656 {
657     thread** tidp;
658
659     /* Sleep for no time */
660     if (time <= 0) {
661                 return;
662     }
663     
664     intsDisable();
665
666     /* Get absolute time */
667     CONTEXT(currentThread).time = time + currentTime();
668
669     /* Find place in alarm list */
670     for (tidp = &sleepThreads; (*tidp) != 0; tidp = &(*tidp)->next)
671         {
672                 if (CONTEXT(*tidp).time > CONTEXT(currentThread).time)
673                         break;
674     }
675
676     /* Suspend thread on it */
677     suspendOnQThread(currentThread, tidp);
678     
679     intsRestore();
680 }
681
682 /*
683  * Is this thread alive?
684  */
685 bool
686 aliveThread(thread* tid)
687 {
688     if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
689                 return (true);
690     else
691                 return (false);
692 }
693
694 /*
695  * Reschedule the thread.
696  * Called whenever a change in the running thread is required.
697  */
698 void
699 reschedule(void)
700 {
701     int i;
702     thread* lastThread;
703     int b;
704     /*    sigset_t nsig; */
705
706     /* A reschedule in a non-blocked context is half way to hell */
707     assert(blockInts > 0);
708     b = blockInts;
709     
710     /* Check events - we may release a high priority thread */
711     /* Just check IO, no need for a reschedule call by checkEvents() */
712     needReschedule = false;
713     checkEvents(false);
714
715     for (;;)
716     {
717                 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
718                 {
719                         if (threadQhead[i] != 0)
720                         {
721                                 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
722
723                                 if (threadQhead[i] != currentThread)
724                                 {
725                                         /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
726
727                                         lastThread = currentThread;
728                                         currentThread = threadQhead[i];
729
730                                         CONTEXT(currentThread).exceptionptr = exceptionptr;
731
732                     DBG( fprintf(stderr, "thread switch from: %p to: %p\n", lastThread, currentThread); );
733                                         THREADSWITCH((&CONTEXT(currentThread)),
734                                                                  (&CONTEXT(lastThread)));
735                                         blockInts = b;
736
737                                         exceptionptr = CONTEXT(currentThread).exceptionptr;
738
739                                         if (stack_to_be_freed != 0) {
740                                                 stack_to_be_freed = 0;
741                                         }
742
743                                         /* Alarm signal may be blocked - if so
744                                          * unblock it.
745                                          */
746                                         /*
747                                           if (alarmBlocked == true) {
748                                           alarmBlocked = false;
749                                           sigemptyset(&nsig);
750                                           sigaddset(&nsig, SIGALRM);
751                                           sigprocmask(SIG_UNBLOCK, &nsig, 0);
752                                           }
753                                         */
754
755                                         /* I might be dying */
756                                         if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
757                                                 != 0)
758                                         {
759                                                 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
760                                                 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
761                                         }
762                                 }
763                                 /* Now we kill the schedule and turn ints
764                                    back on */
765                                 needReschedule = false;
766                                 return;
767                         }
768                 }
769                 /* Nothing to run - wait for external event */
770                 DBG( fprintf(stderr, "nothing more to do\n"); );
771                 checkEvents(true);
772     }
773 }