make threads work again (means, they don't crash anymore, just block the application...
[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
36 static classinfo *class_java_lang_ThreadDeath;
37
38 thread* currentThread = NULL;
39 thread* mainThread;
40 thread* threadQhead[MAX_THREAD_PRIO + 1];
41 thread* threadQtail[MAX_THREAD_PRIO + 1];
42
43 thread* liveThreads = NULL;
44 thread* sleepThreads = NULL;
45
46 int blockInts;
47 bool needReschedule;
48
49 ctx contexts[MAXTHREADS];
50
51 /* Number of threads alive, also counting daemons */
52 static int talive;
53
54 /* Number of daemon threads alive */
55 static int tdaemon;
56
57 static void firstStartThread(void);
58
59 void reschedule(void);
60
61 /* Setup default thread stack size - this can be overwritten if required */
62 int threadStackSize = THREADSTACKSIZE;
63
64 /* Pointer to the stack of the last killed thread. The free is delayed. */
65 void *stack_to_be_freed = 0;
66
67 static thread* startDaemon(void* func, char* nm, int stackSize);
68
69 /*
70  * Allocate the stack for a thread
71  */
72 void
73 allocThreadStack (thread *tid, int size)
74 {
75     int pageSize = getpagesize();
76     unsigned long pageBegin;
77
78         assert(stack_to_be_freed == 0);
79
80     CONTEXT(tid).stackMem = GCNEW(u1, size + 4 * pageSize);
81     assert(CONTEXT(tid).stackMem != 0);
82     CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
83     
84     pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
85     pageBegin = pageBegin - pageBegin % pageSize;
86
87     CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
88 }
89
90 /*
91  * Mark the stack for a thread to be freed. We cannot free the stack
92  * immediately because it is still in use!
93  */
94 void
95 freeThreadStack (thread *tid)
96 {
97     if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
98     {
99                 int pageSize = getpagesize();
100                 unsigned long pageBegin;
101
102                 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
103                 pageBegin = pageBegin - pageBegin % pageSize;
104
105                 assert(stack_to_be_freed == 0);
106
107                 stack_to_be_freed = CONTEXT(tid).stackMem;
108     }
109     CONTEXT(tid).stackMem = 0;
110     CONTEXT(tid).stackBase = 0;
111     CONTEXT(tid).stackEnd = 0;
112 }
113
114 /*
115  * Initialize threads.
116  */
117 void
118 initThreads(u1 *stackbottom)
119 {
120         thread *the_main_thread;
121     int i;
122         char mainname[] = "main";
123         /*int len = strlen(mainname);*/
124
125         signal(SIGPIPE, SIG_IGN);
126
127     initLocks();
128
129     for (i = 0; i < MAXTHREADS; ++i) {
130                 contexts[i].free = true;
131                 contexts[i].thread = NULL;
132                 heap_addreference((void**)&contexts[i].thread);
133         }
134
135     /* Allocate a thread to be the main thread */
136     liveThreads = the_main_thread = (thread*)builtin_new(loader_load(utf_new_char("java/lang/Thread")));
137     assert(the_main_thread != 0);
138         /* heap_addreference((void **) &liveThreads); */
139     
140     the_main_thread->PrivateInfo = 1;
141     CONTEXT(the_main_thread).free = false;
142
143 #if 0
144     {
145         /* stefan */
146         methodinfo *m;
147         m = class_findmethod(
148                         class_java_lang_String,
149                         utf_new_char ("toCharArray"),
150                         utf_new_char ("()[C")
151                         );
152 printf("DEADCODE LIVES ?????????\n");fflush(stdout);
153         the_main_thread->name = asm_calljavafunction (m, javastring_new(utf_new_char("main")), 0, 0, 0);
154     }
155 #endif
156         the_main_thread->name=javastring_new(utf_new_char(mainname));
157 /*      the_main_thread->name = builtin_newarray_char(len);
158         {   u2 *d = the_main_thread->name->data;
159                 for (i=0; i<len; i++)
160                         d[i] = mainname[i];
161         }*/
162     the_main_thread->priority = NORM_THREAD_PRIO;
163     CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
164     CONTEXT(the_main_thread).exceptionptr = 0;
165     the_main_thread->next = 0;
166     CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
167     CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
168     THREADINFO(&CONTEXT(the_main_thread));
169
170     DBG( printf("main thread %p base %p end %p\n", 
171                                 the_main_thread,
172                                 CONTEXT(the_main_thread).stackBase,
173                                 CONTEXT(the_main_thread).stackEnd); );
174
175         CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
176         CONTEXT(the_main_thread).nextlive = 0;
177         CONTEXT(the_main_thread).thread = the_main_thread;
178         /*the_main_thread->single_step = 0;*/
179         the_main_thread->daemon = 0;
180         /*the_main_thread->stillborn = 0;*/
181         /*the_main_thread->target = 0;*/
182
183         the_main_thread->contextClassLoader = 0;
184         /*the_main_thread->inheritedAccessControlContext = 0;*/
185         /*the_main_thread->values = 0;*/
186
187         /* Allocate and init ThreadGroup */
188         the_main_thread->group = (threadGroup*)native_new_and_init(loader_load(utf_new_char("java/lang/ThreadGroup")));
189         assert(the_main_thread->group != 0);
190
191         talive++;
192
193         /* Load exception classes */
194         class_java_lang_ThreadDeath = loader_load(utf_new_char("java/lang/ThreadDeath"));
195
196         DBG( fprintf(stderr, "finishing initThreads\n"); );
197
198     mainThread = currentThread = the_main_thread;
199
200         /* heap_addreference((void**)&mainThread); */
201
202         /* Add thread into runQ */
203         iresumeThread(mainThread);
204
205         assert(blockInts == 0);
206 }
207
208 /*
209  * Start a new thread running.
210  */
211 void
212 startThread (thread* tid)
213 {
214     int i;
215
216     /* Allocate a stack context */
217     for (i = 0; i < MAXTHREADS; ++i)
218                 if (contexts[i].free)
219                         break;
220
221     if (i == MAXTHREADS)
222                 panic("Too many threads");
223
224         assert(tid->priority >= MIN_THREAD_PRIO && tid->priority <= MAX_THREAD_PRIO);
225
226     tid->PrivateInfo = i + 1;
227     CONTEXT(tid).free = false;
228         CONTEXT(tid).thread = tid;
229     CONTEXT(tid).nextlive = liveThreads;
230     liveThreads = tid;
231     allocThreadStack(tid, threadStackSize);
232     CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
233     CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
234     CONTEXT(tid).status = THREAD_SUSPENDED;
235     CONTEXT(tid).priority = (u1)tid->priority;
236     CONTEXT(tid).exceptionptr = 0;
237
238     /* Construct the initial restore point. */
239     THREADINIT((&CONTEXT(tid)), firstStartThread);
240
241     DBG( printf("new thread %p base %p end %p\n",
242                                 tid, CONTEXT(tid).stackBase,
243                                 CONTEXT(tid).stackEnd); );
244
245         talive++;
246         if (tid->daemon)
247                 tdaemon++;
248
249         /* Add thread into runQ */
250         iresumeThread(tid);
251 }
252
253 /*
254  * Start a daemon thread.
255  */
256 static thread*
257 startDaemon(void* func, char* nm, int stackSize)
258 {
259     thread* tid;
260     int i;
261
262     DBG( printf("startDaemon %s\n", nm); );
263
264         tid = (thread*)builtin_new(loader_load(utf_new_char("java/lang/Thread")));
265         assert(tid != 0);
266
267         for (i = 0; i < MAXTHREADS; ++i)
268                 if (contexts[i].free)
269                         break;
270         if (i == MAXTHREADS)
271                 panic("Too many threads");
272
273         tid->PrivateInfo = i + 1;
274         CONTEXT(tid).free = false;
275         tid->name = 0;          /* for the moment */
276         tid->priority = MAX_THREAD_PRIO;
277         CONTEXT(tid).priority = (u1)tid->priority;
278         tid->next = 0;
279         CONTEXT(tid).status = THREAD_SUSPENDED;
280
281         allocThreadStack(tid, stackSize);
282         /*tid->single_step = 0;*/
283         tid->daemon = 1;
284         /*tid->stillborn = 0;*/
285         /*tid->target = 0;*/
286         tid->group = 0;
287
288         /* Construct the initial restore point. */
289         THREADINIT((&CONTEXT(tid)), func);
290
291         talive++;
292         tdaemon++;
293
294         return tid;
295 }
296
297 /*
298  * All threads start here.
299  */
300 static void
301 firstStartThread(void)
302 {
303     methodinfo *method;
304         java_objectheader *local_exceptionptr = NULL;
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         local_exceptionptr = asm_calljavamethod(method, currentThread, NULL, NULL, NULL);
323
324     if (local_exceptionptr) {
325         utf_display(local_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 }