
/* ************************* */
/* Multi-threading functions */

#include <setjmp.h>
#define  TSTACKSIZE 200   /* Stack space reseved in each thread in words */
#define  MAXTHREAD 20       /* Max No of concurrent threads */
#define  SPINDX  1        /* Index of stack pointer into env */
#define  NULL 0
static struct threaddat {
       int     *env ;        /* Environment pointer */
       int     (*tfp)() ;    /* Thread function pointer */
       int     state ;       /* 0 Waiting 1 running -1 terminated */
               } threaddata[MAXTHREAD] ;
/* Globals for thread() */
static jmp_buf envroot ;          /* root environment */
static int threadnum = -1 ;       /* Number of threads */
static int threadindx ;              /* Thread indexer */
/* Takes a NULL terminated list of function pointers, sets up
   the global parameters above and the root environment and then
   calls threadrun() to define and run the function threads. */
thread(fplist)
int (*fplist)() ;
{
  int  (**fplptr)() ;
  void threadrun() ;
  if (threadnum == -1)
   { fplptr = &fplist ;
     threadnum = 0 ;
     while (*fplptr != NULL)
        threaddata[threadnum++].tfp = *fplptr++ ;
     threadindx = 0 ;
     if (!setjmp(envroot))
       threadrun() ;         /* define thread environments recursivly */
                                   /* then run them to extinction */
   }
}
/* recusivly defines thread environments then runs in round robin */
void threadrun()
{
  jmp_buf envthread ;
  int stackspace[TSTACKSIZE] ;
  if (threadindx < threadnum)
    { if (setjmp(envthread))
       { /* Will arrive here by longjmp  for function dispatch */
         (*threaddata[threadindx].tfp)() ;      /* Start thread */
         threaddata[threadindx].state = -1 ;    /* terminated */
         threadswitch() ;
         printf("Multi-threading error - terminating ) ;
         exit(1) ;
       }
      else
       {
/* Global pointer to thread env */
         threaddata[threadindx].env = envthread ;
/* Thread state to waiting to run */
         threaddata[threadindx].state = 0 ;
/* Modify env value for stack with a little margin for luck */
         envthread[SPINDX] = (int) &stackspace[TSTACKSIZE-5] ;
         threadrun(++threadindx) ;  /* Recusive call for next thread env */
       }
    }
  else                            /* Run threads in round robin */
    {
/* Start the ball rolling with thread 1*/
        threadindx = 0 ;
        longjmp(threaddata[threadindx].env, -1) ;
    }
}
/* Thread switcher : Will switch to next available function thread in list.
   If function threads have all terminated will terminate the threads
   environment and return to the root enviroment */
threadswitch()
{ int i ;
  if (threadnum != -1)
  {
    if (threaddata[threadindx].state != -1)
      threaddata[threadindx].state = 0 ;
    if (!setjmp(threaddata[threadindx].env))
    {
      for (i=1; i <= threadnum; i++)
        { if (++threadindx >= threadnum)
             threadindx = 0 ;
          if (!threaddata[threadindx].state)
            { threaddata[threadindx].state = 1 ;
              longjmp(threaddata[threadindx].env, -1) ;
            }
         }
       threadnum = -1 ;
       longjmp(envroot, -1) ;
     }
  }
}


