home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_09_11 / 9n11043a < prev    next >
Text File  |  1991-09-25  |  8KB  |  299 lines

  1. /* -- exec.h --
  2.  */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <setjmp.h>
  6.  
  7. #ifndef STRATOM_H
  8. #include "stratom.h"
  9. #endif
  10.  
  11. #ifndef YES
  12. #define YES 1
  13. #define NO  0
  14. typedef int BOOL;
  15. #endif
  16.  
  17. #ifndef BIT
  18. #define BIT(i)  (1 << (i))
  19. #endif
  20.  
  21. /*      different perfixes for EXEC_ID
  22.  */
  23. #define PORT_PREFIX         BIT(15)
  24. #define SEMAPHORE_PREFIX    BIT(14)
  25. #define TIMER_PREFIX        BIT(13)
  26. #define MONOSTABLE_PREFIX   BIT(12)
  27. #define TRIGGER_PREFIX      BIT(11)
  28.  
  29. #define BAD_EXEC_ID 0
  30.  
  31. typedef int                     EXEC_ID;
  32. typedef unsigned char   THREAD_ID;
  33.  
  34. typedef unsigned int    PORT;
  35. typedef unsigned int    SEMAPHORE;
  36.  
  37. /*      process type.  Not used yet
  38.  */
  39. typedef enum
  40.     { NORMAL_PROC = 10, HALTABLE_PROC, INHIBITABLE_PROC } 
  41.                 PROCESS_TYPE;
  42.  
  43. void *ExecAlloc(unsigned int size);
  44. THREAD_ID ExecCreateThread(PROCESS_TYPE procType, 
  45.         void (*pFunction)(void), unsigned int stackSize, 
  46.         unsigned long arg0, unsigned long arg1);
  47. THREAD_ID ExecGetThreadID(void);
  48. void ExecInit(void);
  49. void ExecStart(void);
  50.  
  51. void MsgClearSemaphore(STRING_ATOM semaphoreAtom);
  52. BOOL MsgConnectPorts(STRING_ATOM sourceAtom, 
  53.         STRING_ATOM destinationAtom);
  54. void MsgDeleteTimer(EXEC_ID watchID);
  55. EXEC_ID MsgGetMsg(void);
  56. BOOL MsgInhibitPorts(STRING_ATOM sourceAtom, 
  57.         STRING_ATOM destinationAtom);
  58. void *MsgOpenPort(STRING_ATOM nameAtom, PORT *pPortValue);
  59. PORT MsgPeekPort(STRING_ATOM, PORT *);
  60. void MsgSetSemaphore(STRING_ATOM semaphoreAtom);
  61. BOOL MsgSuppressPorts(STRING_ATOM sourceAtom, 
  62.         STRING_ATOM destinationAtom);
  63. EXEC_ID MsgWatchPort(STRING_ATOM portAtom, PORT *pPortValue);
  64. EXEC_ID MsgWatchSemaphore(STRING_ATOM semaphoreAtom, BOOL detectOn);
  65. EXEC_ID MsgWatchTimer(unsigned int interval);
  66. void MsgWriteToPort(STRING_ATOM portAtom, PORT portValue);
  67.  
  68. #define MsgWatchTrigger(portAtom) MsgWatchPort(portAtom, NULL)
  69.  
  70. void SysLEDs(int i);
  71.  
  72. typedef unsigned
  73. #ifdef HC11
  74. int
  75. #else
  76. long
  77. #endif
  78. EXEC_ARG;
  79.  
  80. extern EXEC_ARG ExecArg0, ExecArg1;
  81.  
  82. /* -- exec.c -- 
  83.  */
  84. #include <stdlib.h>
  85. #include <string.h>
  86. #include "exec.h"
  87. #include "execpriv.h"
  88.  
  89. /*      arguments to threads 
  90.  */
  91. EXEC_ARG                ExecArg0;
  92. EXEC_ARG                ExecArg1;
  93.  
  94. /*      number of possible threads
  95.  */
  96. #ifndef NUMBER_OF_THREADS  
  97. #define NUMBER_OF_THREADS   34
  98. #endif
  99.  
  100. /*      process state
  101.  */
  102. typedef enum 
  103.     { INIT_STATE = 20, RUNNING_STATE, WAIT_STATE } 
  104.                 PROCESS_STATE;
  105.  
  106. /*      context for thread
  107.  */
  108. typedef struct
  109.     {
  110.     THREAD_ID       threadID;
  111.     void            (*pFunction)(void);
  112.     PROCESS_TYPE    procType;
  113.     PROCESS_STATE   procState;
  114.     jmp_buf         exitContext;
  115.     jmp_buf         switchContext;
  116.     char            *stackTop;
  117.     char            *stackBottom;
  118.         EXEC_ARG                arg0;
  119.         EXEC_ARG                arg1;
  120.     } THREAD_CONTEXT;
  121.  
  122. /*      file static variables
  123.  */
  124. static BOOL                                     hasCreatedThreads;
  125. static THREAD_CONTEXT       threadTable[NUMBER_OF_THREADS];
  126. static THREAD_ID            execCurrentThreadID;
  127.  
  128. static void execRunNewThread(void);
  129.  
  130. /*      allocate a block of memory, zeroed out
  131.  */
  132. void *ExecAlloc(unsigned int size)
  133.     {
  134.     void *p;
  135.  
  136.     p = calloc(1, size);
  137.         if (!p)
  138.                 {
  139. #ifndef HC11
  140.                 printf("no memory\n");
  141. #endif
  142.                 exit(1);
  143.                 }
  144.     return (p);
  145.     }
  146.  
  147. /*      thread function returns here, jump to exit context
  148.  */
  149. void ExecCallReturn(void)
  150.     {
  151.  
  152.     longjmp(threadTable[execCurrentThreadID].exitContext, 
  153.                 execCurrentThreadID);
  154.     }
  155.  
  156. /*      create a thread context
  157.  */
  158. THREAD_ID ExecCreateThread(PROCESS_TYPE procType, void (*pFunction)(void), 
  159.     unsigned int stackSize, unsigned long arg0, unsigned long arg1)
  160.     {
  161.         char *stack;
  162.     THREAD_ID i;
  163.  
  164.         /*      find the next free entry in table
  165.          */
  166.     for (i = 0; i < NUMBER_OF_THREADS && threadTable[i].procState; ++i)
  167.         ;
  168.     if (i == NUMBER_OF_THREADS)
  169.         return (BAD_EXEC_ID);
  170.         hasCreatedThreads = YES;
  171.         /*      clear entry and allocate stack
  172.          */
  173.         memset(&threadTable[i], '\0', sizeof (THREAD_CONTEXT));
  174.         /*      stack space used by the executive, i.e. by the functions MsgGetMsg()
  175.          *      and ExecSwitch()
  176.          */
  177.         stackSize &= ~0x3;      /* quad byte aligned */
  178. #define EXEC_STACK_SIZE 40      
  179.         stackSize += EXEC_STACK_SIZE;
  180.         stack = SysGetStack(stackSize);
  181.         threadTable[i].procType = procType;
  182.         threadTable[i].pFunction = pFunction;
  183.         threadTable[i].stackBottom = stack;
  184.         threadTable[i].stackTop = stack + stackSize;
  185.         threadTable[i].procState = INIT_STATE;
  186.         /*      memorize the initail arguments to function
  187.          */
  188.         threadTable[i].arg0 = arg0;
  189.         threadTable[i].arg1 = arg1;
  190.         /*      put this on the runnable queue
  191.          */
  192.         MsgEnQueue(i, i);
  193.         return (i);
  194.     }
  195.  
  196. /*      return a new id
  197.  */
  198. EXEC_ID execExecID(unsigned int prefix)
  199.     {
  200.     static unsigned int i;
  201.     
  202.     return (prefix | (++i));
  203.     }
  204.      
  205. /*      return the current thread id
  206.  */
  207. THREAD_ID ExecGetThreadID(void)
  208.     {
  209.  
  210.     return (execCurrentThreadID);
  211.     }
  212.  
  213. /*      initialize the system
  214.  */
  215. void ExecInit(void)
  216.     {
  217.         SysInit();
  218.     }
  219.  
  220. /*      take the first thread off the runnable queue and give execution to it
  221.  */
  222. static
  223. void execRunNewThread(void)
  224.         {
  225.         EXEC_ID returnID;
  226.         PROCESS_STATE procState;
  227.  
  228.         /*      take the first thread off the queue
  229.          */
  230.         execCurrentThreadID = MsgDeQueue(&returnID);
  231.         SysLEDs(execCurrentThreadID);
  232.         /*      set process state
  233.          */
  234.         procState = threadTable[execCurrentThreadID].procState;
  235.         threadTable[execCurrentThreadID].procState = RUNNING_STATE;
  236.         /*      procState == WAIT_STAT - use longjmp() to switch back to the old
  237.          *      execution context
  238.          */
  239.         if (procState != INIT_STATE)
  240.                 longjmp(threadTable[execCurrentThreadID].switchContext, returnID);
  241.         else
  242.                 {
  243.                 /*      initial call to a thread.  Put thread arguments
  244. in the external
  245.                  *      variables and call an assembly routine to call the thread
  246.                  */
  247.                 if (setjmp(threadTable[execCurrentThreadID].exitContext) == 0)
  248.                         {
  249.                         ExecArg0 = threadTable[execCurrentThreadID].arg0;
  250.                         ExecArg1 = threadTable[execCurrentThreadID].arg1;
  251.                         ExecCall(threadTable[execCurrentThreadID].pFunction, 
  252.                                         threadTable[execCurrentThreadID].stackTop);
  253.                         }
  254.                 /*      thread dies, reclaim thread table entry (but
  255. not stack space)
  256.                  *      and run the next available thread
  257.                  */
  258.                 threadTable[execCurrentThreadID].procState = 0;
  259.                 /*      need to delete from all queues and ports
  260.                  */
  261.                 execRunNewThread();
  262.                 }
  263.         }
  264.  
  265. /*      start the system.
  266.  */
  267. void ExecStart(void)
  268.     {
  269.  
  270.         if (hasCreatedThreads)
  271.                 execRunNewThread();
  272.     }
  273.  
  274. /*      switch to a new thread
  275.  */
  276. EXEC_ID ExecSwitch(void)
  277.     {
  278.     EXEC_ID watchID;
  279.  
  280.         /*      check for stack overflow
  281.          */
  282.         if ((char *)&watchID < threadTable[execCurrentThreadID].stackBottom)
  283.                 {
  284. #ifndef HC11
  285.                 printf("stack overflow\n");
  286. #endif
  287.                 exit(1);
  288.                 }
  289.     /*  set up our return context and switch
  290.      */
  291.     if ((watchID = setjmp(threadTable[execCurrentThreadID].switchContext)) == 0)
  292.         {
  293.                 threadTable[execCurrentThreadID].procState = WAIT_STATE;
  294.                 execRunNewThread();
  295.                 }
  296.     return (watchID);
  297.     }
  298.  
  299.