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