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