home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / kaffe-0.5p4-src.tgz / tar.out / contrib / kaffe / kaffevm / thread.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  13KB  |  598 lines

  1. /*
  2.  * thread.c
  3.  * Thread support.
  4.  *
  5.  * Copyright (c) 1996 Systems Architecture Research Centre,
  6.  *           City University, 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@sarc.city.ac.uk>, February 1996.
  12.  */
  13.  
  14. #define    DBG(s)
  15. #define    SDBG(s)
  16.  
  17. #include <assert.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #if defined(HAVE_UNISTD_H)
  21. #include <unistd.h>
  22. #endif
  23. #include <signal.h>
  24. #include "gtypes.h"
  25. #include "access.h"
  26. #include "object.h"
  27. #include "constants.h"
  28. #include "classMethod.h"
  29. #include "baseClasses.h"
  30. #include "thread.h"
  31. #include "locks.h"
  32. #include "exception.h"
  33. #include "support.h"
  34. #include "md.h"
  35.  
  36. #if defined(USE_INTERNAL_THREADS)
  37.  
  38. #if defined(INTERPRETER)
  39. #include <setjmp.h>
  40. extern jmp_buf* cjbuf;
  41. #endif
  42.  
  43. thread* currentThread;
  44. thread* threadQhead[MAX_THREAD_PRIO + 1];
  45. thread* threadQtail[MAX_THREAD_PRIO + 1];
  46.  
  47. thread* garbageman;
  48. thread* finalman;
  49.  
  50. thread* liveThreads;
  51. thread* alarmList;
  52. classes* ThreadClass;
  53.  
  54. int blockInts;
  55. bool needReschedule;
  56.  
  57. static int talive;
  58. static int tdaemon;
  59.  
  60. static void firstStartThread(void);
  61. static thread* startDaemon(void*, char*);
  62. static void alarmException(int);
  63.  
  64. void reschedule(void);
  65. void finaliserMan(void);
  66. void gcMan(void);
  67. void checkEvents(bool);
  68.  
  69. /* Setup default thread stack size - this can be overwritten if required */
  70. int threadStackSize = THREADSTACKSIZE;
  71.  
  72. #define    ALLOCTHREADSTACK(_t)                        \
  73.     (_t)->PrivateInfo->stackBase = malloc(threadStackSize);        \
  74.     assert((_t)->PrivateInfo->stackBase != 0);            \
  75.     (_t)->PrivateInfo->stackEnd = (_t)->PrivateInfo->stackBase +     \
  76.         threadStackSize
  77.  
  78. #define    FREETHREADSTACK(_t)                        \
  79.     if (!((_t)->PrivateInfo->flags & THREAD_FLAGS_NOSTACKALLOC)) {    \
  80.         free((_t)->PrivateInfo->stackBase);            \
  81.     }                                \
  82.     (_t)->PrivateInfo->stackBase = 0;                \
  83.     (_t)->PrivateInfo->stackEnd = 0
  84.  
  85.  
  86.  
  87. /*
  88.  * Initialise threads.
  89.  */
  90. void
  91. initThreads(void)
  92. {
  93.     /* Get a handle on the thread class */
  94.     ThreadClass = lookupClass(addString(THREADCLASS));
  95.     assert(ThreadClass != 0);
  96.  
  97.     /* Allocate a thread to be the main thread */
  98.     currentThread = (thread*)alloc_object(ThreadClass, false);
  99.     assert(currentThread != 0);
  100.     currentThread->PrivateInfo = calloc(sizeof(ctx), 1);
  101.     liveThreads = currentThread;
  102.  
  103.     currentThread->name = makeJavaCharArray("main", strlen("main"));
  104.     currentThread->priority = NORM_THREAD_PRIO;
  105.     currentThread->PrivateInfo->priority = (uint8)currentThread->priority;
  106.     currentThread->next = 0;
  107.     currentThread->PrivateInfo->status = THREAD_SUSPENDED;
  108.     assert(currentThread->PrivateInfo != 0);
  109.     THREADINFO(currentThread->PrivateInfo);
  110. DBG(    printf("main thread %x base %x end %x\n", currentThread, currentThread->PrivateInfo->stackBase, currentThread->PrivateInfo->stackEnd); )
  111.     currentThread->PrivateInfo->flags = THREAD_FLAGS_NOSTACKALLOC;
  112.     currentThread->PrivateInfo->nextlive = 0;
  113.     currentThread->single_step = 0;
  114.     currentThread->daemon = 0;
  115.     currentThread->stillborn = 0;
  116.     currentThread->target = 0;
  117.     currentThread->interruptRequested = 0;
  118.     currentThread->group = (threadGroup*)execute_java_constructor(0, "java.lang.ThreadGroup", 0, "()V");
  119.     assert(currentThread->group != 0);
  120.  
  121.     talive++;
  122.  
  123.     /* Add thread into runQ */
  124.     resumeThread(currentThread);
  125.  
  126.     /* Start any daemons we need */
  127.     finalman = startDaemon(&finaliserMan, "finaliser");
  128.     garbageman = startDaemon(&gcMan, "gc");
  129.     resumeThread(finalman);
  130.     resumeThread(garbageman);
  131.  
  132.     /* Plug in the alarm handler */
  133. #if defined(SIGALRM)
  134.     signal(SIGALRM, (SIG_T)alarmException);
  135. #else
  136. #error "No alarm signal support"
  137. #endif
  138. }
  139.  
  140. /*
  141.  * Start a new thread running.
  142.  */
  143. void
  144. startThread(thread* tid)
  145. {
  146.     /* Allocate a stack context */
  147.     assert(tid->PrivateInfo == 0);
  148.     tid->PrivateInfo = calloc(sizeof(ctx), 1);
  149.     assert(tid->PrivateInfo != 0);
  150.     tid->PrivateInfo->nextlive = liveThreads;
  151.     liveThreads = tid;
  152.     ALLOCTHREADSTACK(tid);
  153.     tid->PrivateInfo->flags = THREAD_FLAGS_GENERAL;
  154.     tid->PrivateInfo->status = THREAD_SUSPENDED;
  155.     tid->PrivateInfo->priority = (uint8)tid->priority;
  156.  
  157.     /* Construct the initial restore point. */
  158.     THREADINIT(tid->PrivateInfo, &firstStartThread);
  159. DBG(    printf("new thread %x base %x end %x\n", tid, tid->PrivateInfo->stackBase, tid->PrivateInfo->stackEnd); )
  160.  
  161.     talive++;
  162.     if (tid->daemon) {
  163.         tdaemon++;
  164.     }
  165.  
  166.     /* Add thread into runQ */
  167.     resumeThread(tid);
  168. }
  169.  
  170. /*
  171.  * All threads start here.
  172.  */
  173. static
  174. void
  175. firstStartThread(void)
  176. {
  177. DBG(    printf("firstStartThread %x\n", currentThread);        )
  178.     /* Every thread starts with the interrupts off */
  179.     intsRestore();
  180.  
  181.     /* Find the run()V method and call it */
  182.     do_execute_java_method(0, (object*)currentThread, "run", "()V", 0, 0);
  183.     do_execute_java_method(0, (object*)currentThread, "exit", "()V", 0, 0);
  184.     killThread(0);
  185.     assert("Thread returned from killThread" == 0);
  186. }
  187.  
  188. /*
  189.  * Resume a thread running.
  190.  */
  191. void
  192. resumeThread(thread* tid)
  193. {
  194. DBG(    printf("resumeThread %x\n", tid);            )
  195.  
  196.     intsDisable();
  197.  
  198.     if (tid->PrivateInfo->status != THREAD_RUNNING) {
  199.         tid->PrivateInfo->status = THREAD_RUNNING;
  200.  
  201.         /* Place thread on the end of its queue */
  202.         if (threadQhead[tid->PrivateInfo->priority] == 0) {
  203.             threadQhead[tid->PrivateInfo->priority] = tid;
  204.             threadQtail[tid->PrivateInfo->priority] = tid;
  205.             if (tid->PrivateInfo->priority > currentThread->PrivateInfo->priority) {
  206.                 needReschedule = true;
  207.             }
  208.         }
  209.         else {
  210.             threadQtail[tid->PrivateInfo->priority]->next = tid;
  211.             threadQtail[tid->PrivateInfo->priority] = tid;
  212.         }
  213.         tid->next = 0;
  214.     }
  215. SDBG(    else {
  216.         printf("Re-resuming 0x%x\n", tid);
  217.     }                            )
  218.     intsRestore();
  219. }
  220.  
  221. /*
  222.  * Yield process to another thread of equal priority.
  223.  */
  224. void
  225. yieldThread()
  226. {
  227.     intsDisable();
  228.  
  229.     if (threadQhead[currentThread->PrivateInfo->priority] != threadQtail[currentThread->PrivateInfo->priority]) {
  230.  
  231.         /* Get the next thread and move me to the end */
  232.         threadQhead[currentThread->PrivateInfo->priority] = currentThread->next;
  233.         threadQtail[currentThread->PrivateInfo->priority]->next = currentThread;
  234.         threadQtail[currentThread->PrivateInfo->priority] = currentThread;
  235.         currentThread->next = 0;
  236.         needReschedule = true;
  237.     }
  238.  
  239.     intsRestore();
  240. }
  241.  
  242. /*
  243.  * Suspend a thread.
  244.  */
  245. void
  246. suspendThread(thread* tid)
  247. {
  248.     thread** ntid;
  249.  
  250.     intsDisable();
  251.  
  252.     if (tid->PrivateInfo->status != THREAD_SUSPENDED) {
  253.         tid->PrivateInfo->status = THREAD_SUSPENDED;
  254.  
  255.         for (ntid = &threadQhead[tid->PrivateInfo->priority]; *ntid != 0; ntid = &(*ntid)->next) {
  256.             if (*ntid == tid) {
  257.                 *ntid = tid->next;
  258.                 tid->next = 0;
  259.                 if (tid == currentThread) {
  260.                     reschedule();
  261.                 }
  262.                 break;
  263.             }
  264.         }
  265.     }
  266. SDBG(    else {
  267.         printf("Re-suspending 0x%x\n", tid);
  268.     }                            )
  269.  
  270.     intsRestore();
  271. }
  272.  
  273. /*
  274.  * Suspend a thread on a queue.
  275.  */
  276. void
  277. suspendOnQThread(thread* tid, thread** queue)
  278. {
  279.     thread** ntid;
  280.  
  281. DBG(    printf("suspendOnQThread %x\n", tid);        )
  282.  
  283.     assert(blockInts == 1);
  284.  
  285.     if (tid->PrivateInfo->status != THREAD_SUSPENDED) {
  286.         tid->PrivateInfo->status = THREAD_SUSPENDED;
  287.  
  288.         for (ntid = &threadQhead[tid->PrivateInfo->priority]; *ntid != 0; ntid = &(*ntid)->next) {
  289.             if (*ntid == tid) {
  290.                 *ntid = tid->next;
  291.                 /* Insert onto head of lock wait Q */
  292.                 tid->next = *queue;
  293.                 *queue = tid;
  294.                 if (tid == currentThread) {
  295.                     reschedule();
  296.                 }
  297.                 break;
  298.             }
  299.         }
  300.     }
  301. SDBG(    else {
  302.         printf("Re-suspending 0x%x on %x\n", tid, *queue);
  303.     }                            )
  304. }
  305.  
  306. /*
  307.  * Kill thread.
  308.  */
  309. void
  310. killThread(thread* tid)
  311. {
  312.     thread** ntid;
  313.  
  314.     intsDisable();
  315.  
  316.     /* A null tid means the current thread */
  317.     if (tid == 0) {
  318.         tid = currentThread;
  319.     }
  320.  
  321. DBG(    printf("killThread %x\n", tid);            )
  322.  
  323.     if (tid->PrivateInfo->status != THREAD_DEAD) {
  324.  
  325.         /* Get thread off runq (if it needs it) */
  326.         if (tid->PrivateInfo->status == THREAD_RUNNING) {
  327.             for (ntid = &threadQhead[tid->PrivateInfo->priority]; *ntid != 0; ntid = &(*ntid)->next) {
  328.                 if (*ntid == tid) {
  329.                     *ntid = tid->next;
  330.                     break;
  331.                 }
  332.             }
  333.         }
  334.  
  335.         tid->PrivateInfo->status = THREAD_DEAD;
  336.         talive--;
  337.         if (tid->daemon) {
  338.             tdaemon--;
  339.         }
  340.  
  341.         /* If we only have daemons left, then everyone is dead. */
  342.         if (talive == tdaemon) {
  343.             /* Am I suppose to close things down nicely ?? */
  344.             exit(0);
  345.         }
  346.  
  347.         /* Notify on the object just in case anyone is waiting */
  348.         lockMutex(&tid->obj);
  349.         broadcastCond(&tid->obj); 
  350.         unlockMutex(&tid->obj);
  351.  
  352.         /* Remove thread from live list to it can be garbaged */
  353.         for (ntid = &liveThreads; *ntid != 0; ntid = &(*ntid)->PrivateInfo->nextlive) {
  354.             if (tid == (*ntid)) {
  355.                 (*ntid) = tid->PrivateInfo->nextlive;
  356.                 break;
  357.             }
  358.         }
  359.  
  360.         /* Free stack */
  361.         FREETHREADSTACK(tid);
  362.  
  363.         /* Run something else */
  364.         needReschedule = true;
  365.     }
  366.     intsRestore();
  367. }
  368.  
  369. /*
  370.  * Change thread priority.
  371.  */
  372. void
  373. setPriorityThread(thread* tid, int prio)
  374. {
  375.     thread** ntid;
  376.  
  377.     if (tid->PrivateInfo == 0) {
  378.         tid->priority = prio;
  379.         return;
  380.     }
  381.  
  382.     if (tid->PrivateInfo->status == THREAD_SUSPENDED) {
  383.         tid->PrivateInfo->priority = (uint8)prio;
  384.         return;
  385.     }
  386.  
  387.     intsDisable();
  388.  
  389.     /* Remove from current thread list */
  390.     for (ntid = &threadQhead[tid->PrivateInfo->priority]; *ntid != 0; ntid = &(*ntid)->next) {
  391.         if (*ntid == tid) {
  392.             *ntid = tid->next;
  393.             break;
  394.         }
  395.     }
  396.  
  397.     /* Insert onto a new one */
  398.     tid->priority = prio;
  399.     tid->PrivateInfo->priority = (uint8)tid->priority;
  400.     if (threadQhead[prio] == 0) {
  401.         threadQhead[prio] = tid;
  402.         threadQtail[prio] = tid;
  403.         if (prio > currentThread->PrivateInfo->priority) {
  404.             needReschedule = true;
  405.         }
  406.     }
  407.     else {
  408.         threadQtail[prio]->next = tid;
  409.         threadQtail[prio] = tid;
  410.     }
  411.     tid->next = 0;
  412.  
  413.     intsRestore();
  414. }
  415.  
  416. /*
  417.  * Put a thread to sleep.
  418.  */
  419. void
  420. sleepThread(int64 time)
  421. {
  422.     thread** tidp;
  423.  
  424.     /* Sleep for no time */
  425.     if (time == 0) {
  426.         return;
  427.     }
  428.  
  429.     intsDisable();
  430.  
  431.     /* Get absolute time */
  432.     currentThread->PrivateInfo->time = time + currentTime();
  433.  
  434.     /* Find place in alarm list */
  435.     for (tidp = &alarmList; (*tidp) != 0; tidp = &(*tidp)->next) {
  436.         if ((*tidp)->PrivateInfo->time > currentThread->PrivateInfo->time) {
  437.             break;
  438.         }
  439.     }
  440.  
  441.     /* If I'm head of alarm list, restart alarm */
  442.     if (tidp == &alarmList) {
  443.         alarm((int)((time + 999) / 1000));
  444.     }
  445.  
  446.     /* Suspend thread on it */
  447.     suspendOnQThread(currentThread, tidp);
  448.  
  449.     intsRestore();
  450. }
  451.  
  452. /*
  453.  * Handle alarm.
  454.  */
  455. static
  456. void
  457. alarmException(int sig)
  458. {
  459.     thread* tid;
  460.     int64 time;
  461.  
  462.     /* Re-enable signal - necessary for SysV */
  463.     signal(sig, (SIG_T)alarmException);
  464.  
  465.     intsDisable();
  466.  
  467.     /* Wake all the threads which need waking */
  468.     time = currentTime();
  469.     while (alarmList != 0 && alarmList->PrivateInfo->time <= time) {
  470.         tid = alarmList;
  471.         alarmList = alarmList->next;
  472.         resumeThread(tid);
  473.     }
  474.  
  475.     /* Restart alarm */
  476.     if (alarmList != 0) {
  477.         alarm((int)((alarmList->PrivateInfo->time - time + 999) / 1000));
  478.     }
  479.  
  480.     intsRestore();
  481. }
  482.  
  483. /*
  484.  * Is this thread alive?
  485.  */
  486. bool
  487. aliveThread(thread* tid)
  488. {
  489.     if (tid->PrivateInfo != 0 && tid->PrivateInfo->status != THREAD_DEAD) {
  490.         return (true);
  491.     }
  492.     else {
  493.         return (false);
  494.     }
  495. }
  496.  
  497. /*
  498.  * How many stack frames have I invoked?
  499.  */
  500. long
  501. framesThread(thread* tid)
  502. {
  503.     long count;
  504.     THREADFRAMES(tid, count);
  505.     return (count);
  506. }
  507.  
  508. /*
  509.  * Reschedule the thread.
  510.  * Called whenever a change in the running thread is required.
  511.  */
  512. void
  513. reschedule(void)
  514. {
  515.     int i;
  516.     thread* lastThread;
  517.     int b;
  518.  
  519.     /* Check events - we may release a high priority thread */
  520.     checkEvents(false);
  521.  
  522.     for (;;) {
  523.         for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--) {
  524.             if (threadQhead[i] != 0) {
  525.                 if (threadQhead[i] != currentThread) {
  526.                     b = blockInts;
  527. #if defined(INTERPRETER)
  528.                     currentThread->PrivateInfo->exceptPtr = (void*)cjbuf;
  529.                     cjbuf = 0;
  530. #endif
  531.                     lastThread = currentThread;
  532.                     currentThread = threadQhead[i];
  533. DBG( printf("ctxswitch %x -> %x\n", lastThread, currentThread); )
  534.                     THREADSWITCH(currentThread->PrivateInfo, lastThread->PrivateInfo);
  535. #if defined(INTERPRETER)
  536.                     cjbuf = (jmp_buf*)currentThread->PrivateInfo->exceptPtr;
  537. #endif
  538.                     blockInts = b;
  539.                 }
  540.                 /* Now we kill the schedule and turn ints
  541.                    back on */
  542.                 needReschedule = false;
  543.                 return;
  544.             }
  545.         }
  546.         /* Nothing to run - wait for external event */
  547.         checkEvents(true);
  548.     }
  549. }
  550.  
  551. /*
  552.  * Start a daemon thread.
  553.  */
  554. static
  555. thread*
  556. startDaemon(void* func, char* nm)
  557. {
  558.     thread* tid;
  559.  
  560. DBG(    printf("startDaemon %s\n", nm);                )
  561.  
  562.     /* Keep daemon threads as root objects */
  563.     tid = (thread*)alloc_object(ThreadClass, true);
  564.     assert(tid != 0);
  565.     tid->PrivateInfo = calloc(sizeof(ctx), 1);
  566.  
  567.     tid->name = makeJavaCharArray(nm, strlen(nm));
  568.     tid->priority = MAX_THREAD_PRIO;
  569.     tid->PrivateInfo->priority = (uint8)tid->priority;
  570.     tid->next = 0;
  571.     tid->PrivateInfo->status = THREAD_SUSPENDED;
  572.     assert(tid->PrivateInfo != 0);
  573.  
  574.     /* Insert into live list as long as it's not the finaliser */
  575.     if (func != &finaliserMan) {
  576.         tid->PrivateInfo->nextlive = liveThreads;
  577.         liveThreads = tid;
  578.     }
  579.  
  580.     ALLOCTHREADSTACK(tid);
  581.     tid->single_step = 0;
  582.     tid->daemon = 1;
  583.     tid->stillborn = 0;
  584.     tid->target = 0;
  585.     tid->interruptRequested = 0;
  586.     tid->group = 0;
  587.  
  588.     /* Construct the initial restore point. */
  589.     THREADINIT(tid->PrivateInfo, func);
  590.  
  591.     talive++;
  592.     tdaemon++;
  593.  
  594.     return (tid);
  595. }
  596.  
  597. #endif
  598.