home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / COPROC.ARJ / COPROC.C next >
Encoding:
C/C++ Source or Header  |  1993-07-29  |  10.8 KB  |  440 lines

  1. /**/
  2. /*
  3. /*      coproc.c
  4. /*
  5. /*      (C) Copyright by Serge Babkin, 1993
  6. /*
  7. /*      Any part of this code may be freely distributed for
  8. /*      the non-commertial use when it contains this copyright
  9. /*      notice only.
  10. /*
  11. /*      My FIDO address is: 2:5010/4
  12. /*
  13. /**/
  14.  
  15. #include <setjmp.h>
  16. #include <stdio.h>
  17. #include <malloc.h>
  18.  
  19. /************************ Configuring ********************************/
  20.  
  21. /* Uncomment the following line when compiling under MS DOS */
  22. /* #define DOS */
  23.  
  24. /************************ Types **************************************/
  25.  
  26. typedef unsigned short ushort;
  27.  
  28. /* define the coprocess structure */
  29.  
  30. typedef struct coproc
  31. {
  32.     struct coproc *nxt;    /* next process in a queue */
  33.     struct coproc *prv;    /* previous process in a queue */
  34.     struct sframe *frm;    /* stack frame */
  35.     jmp_buf setjmp;        /* entry point to this coprocess */
  36.     char   *event;        /* which event this process is sleeping on */
  37.     ushort  pri;        /* priority */
  38.     ushort  pid;        /* coprocess id */
  39. }       coproc_t;
  40.  
  41. /* define the stack frame */
  42.  
  43. typedef struct sframe
  44. {
  45.     struct sframe *nxt;    /* next frame in a queue */
  46.     struct sframe *prv;    /* previous frame in a queue */
  47.     struct coproc *proc;    /* coprocess in this frame */
  48.     jmp_buf setjmp;        /* jump to header */
  49.     int     maxfrm;        /* maximal number of function frames */
  50.     int     varsz;        /* maximal size of variables */
  51.     int     ( *func ) (  );    /* main function of the current coprocess */
  52. }       sframe_t;
  53.  
  54. /*************************** Global variables **********************/
  55.  
  56. /* global queues */
  57.  
  58. static coproc_t runq = {&runq, &runq};    /* runnable processes */
  59. static coproc_t slepq = {&slepq, &slepq};    /* sleeping processes */
  60. static sframe_t freefq = {&freefq, &freefq};    /* free frames */
  61.  
  62. /* current context */
  63.  
  64. static coproc_t *curproc;    /* current process */
  65. static sframe_t *lastframe;    /* last frame */
  66. static ushort nextpid = 0;    /* next pid */
  67.  
  68. /* temporary variables used for allocation of stack frame */
  69. static int glb_maxfrm,
  70.         glb_varsz;
  71. static jmp_buf get_jmpbuf;
  72.  
  73. int     lbolt;            /* special address for sleeping, used for
  74.                  * sleep on no event */
  75.  
  76. /**************************** Constants ********************************/
  77.  
  78. /* messages for longjmp() */
  79.  
  80. #define WAKEUP          1    /* wake up process */
  81. #define ADDFRAME        2    /* add new frame to stack */
  82. #define RMPROC          3    /* remove process */
  83.  
  84. /****************** Predefinitions of functions *************************/
  85.  
  86. static sframe_t *getnewframe(  );
  87. static  framehead(  );
  88. static  allocspace(  );
  89. static  allocframe(  );
  90. static  rmcoproc(  );
  91.  
  92. /************************* cosleep ***********************************/
  93. /* cosleep(event,pri) - sleep on event with priority pri             */
  94. /*********************************************************************/
  95.  
  96. cosleep( event, pri )
  97.     char   *event;
  98. {
  99.  
  100.     curproc->event = event;
  101.     curproc->pri = ( ushort ) pri;
  102.  
  103.     if ( event == ( char * ) &lbolt )
  104.     {            /* when simply pass the control */
  105.         coproc_t *pr;
  106.  
  107.         /* found appropriate place in the runnable queue */
  108.         for ( pr = runq.nxt; pr != &runq && pr->pri <= pri; pr = pr->nxt );
  109.  
  110.         /* and insert current process before process found */
  111.  
  112.         curproc->nxt = pr;
  113.         curproc->prv = pr->prv;
  114.         pr->prv->nxt = curproc;
  115.         pr->prv = curproc;
  116.     }
  117.     else
  118.     {
  119.         /* insert it to the begin of sleeping queue */
  120.  
  121.         curproc->nxt = slepq.nxt;
  122.         curproc->prv = &slepq;
  123.         slepq.nxt->prv = curproc;
  124.         slepq.nxt = curproc;
  125.     }
  126. /* and sleep until woken up */
  127.  
  128.     if ( setjmp( curproc->setjmp ) == WAKEUP )
  129.         return;
  130.  
  131. /* reschedule some new coprocess */
  132.  
  133.     if ( runq.nxt == &runq && slepq.nxt == &slepq )
  134.     {
  135.         exit( 0 );
  136.     }
  137.  
  138.     while ( runq.nxt == &runq )
  139.     {            /* sleep while no coprocesses to run */
  140.         /* i.e. until the waking up signal in UNIX */
  141.         /* or interrupt in DOS                     */
  142.  
  143. #       ifndef DOS
  144.         sleep( 100 );
  145. #       endif
  146.     }
  147.  
  148.     curproc = runq.nxt;
  149.     runq.nxt = curproc->nxt;
  150.     curproc->nxt->prv = &runq;
  151.  
  152.     longjmp( curproc->setjmp, WAKEUP );
  153. }
  154.  
  155. /***************************** cofork ***********************************/
  156. /* cofork(func,maxfrm,varsz) - create the new coprocess with the main   */
  157. /*   function func, stack frame for maximal maxfrm function calls and   */
  158. /*   maximal size of local variables varsz.                             */
  159. /************************************************************************/
  160.  
  161. cofork( func, maxfrm, varsz )
  162.     int     ( *func ) (  );
  163. {
  164.     coproc_t *pr;
  165.     sframe_t *fr;
  166.  
  167. /* try to get a coprocess table entry */
  168.  
  169.     if ( ( pr = ( coproc_t * ) malloc( sizeof( coproc_t ) ) ) == 0 )
  170.         return -1;
  171.  
  172.     glb_maxfrm = maxfrm;
  173.     glb_varsz = varsz;
  174.  
  175. /* try to use some free frame from the list of free frames */
  176.  
  177.     for ( fr = freefq.nxt; fr != &freefq; fr = fr->nxt )
  178.     {
  179.         if ( fr->maxfrm >= maxfrm && fr->varsz >= varsz )
  180.             break;
  181.     }
  182.  
  183.     if ( fr == &freefq )
  184.     {            /* if no free frame, allocate new one */
  185.         if ( ( fr = getnewframe(  ) ) == 0 )
  186.         {
  187.             free( pr );
  188.             return -1;
  189.         }
  190.     }
  191.     else
  192.     {            /* remove it from the queue */
  193.         fr->nxt->prv = fr->prv;
  194.         fr->prv->nxt = fr->nxt;
  195.     }
  196.  
  197. /* set up frame */
  198.  
  199.     fr->proc = pr;
  200.     fr->func = func;
  201.  
  202. /* set up coprocess and add it to begin of the runnable queue */
  203.  
  204.     pr->pid = nextpid++;
  205.     pr->frm = fr;
  206.     memcpy( pr->setjmp, fr->setjmp, sizeof( jmp_buf ) );
  207.  
  208.     pr->prv = &runq;
  209.     pr->nxt = runq.nxt;
  210.     runq.nxt->prv = pr;
  211.     runq.nxt = pr;
  212.  
  213.     pr->pri = 0;
  214.  
  215.     return 0;
  216. }
  217.  
  218. /************************* getnewframe *********************************/
  219. /* getnewframe() - gets new stack frame                                */
  220. /***********************************************************************/
  221.  
  222. static sframe_t *getnewframe(  )
  223. {
  224.     sframe_t *nfrm;
  225.  
  226.     if ( ( nfrm = lastframe ) == 0 )
  227.         return 0;
  228.  
  229.     nfrm->maxfrm = glb_maxfrm;
  230.     nfrm->varsz = glb_varsz;
  231.  
  232.     if ( setjmp( get_jmpbuf ) == WAKEUP )
  233.         return nfrm;
  234.     longjmp( nfrm->setjmp, ADDFRAME );
  235. }
  236.  
  237. /*********************** framehead ************************************/
  238. /* framehead() - header of stack frame, used to create the new frame  */
  239. /**********************************************************************/
  240.  
  241. static  framehead(  )
  242. {
  243.     sframe_t *frm;
  244.  
  245.     if ( ( lastframe = ( sframe_t * ) malloc( sizeof( sframe_t ) ) ) == 0 )
  246.     {
  247.         /* if unable to create the new frame */
  248.  
  249.         longjmp( get_jmpbuf, WAKEUP );
  250.     }
  251.  
  252.     lastframe->func = 0;
  253.     frm = lastframe;
  254.  
  255.     switch ( setjmp( frm->setjmp ) )
  256.     {
  257.         case WAKEUP:
  258.             frm->func(  );
  259.             rmcoproc( frm );
  260.         case ADDFRAME:
  261.             allocspace(  );
  262.         case RMPROC:
  263.             rmcoproc( frm );
  264.     }
  265.     longjmp( get_jmpbuf, WAKEUP );
  266. }
  267.  
  268. /*************************** allocspace ********************************/
  269. /* allocspace() - allocate one function frame and 1K of space for      */
  270. /*   local variables in the stack                                      */
  271. /***********************************************************************/
  272.  
  273. static  allocspace(  )
  274. {
  275.     char    v[1024];
  276.  
  277.     glb_maxfrm--;
  278.     glb_varsz--;
  279.  
  280.     if ( glb_varsz <= 0 )
  281.         if ( glb_maxfrm <= 0 )
  282.             framehead(  );
  283.         else
  284.             allocframe(  );
  285.     allocspace(  );
  286. }
  287.  
  288. /************************* allocframe ***********************************/
  289. /* allocframe() - allocate one function frame in the stack              */
  290. /************************************************************************/
  291.  
  292. static  allocframe(  )
  293. {
  294.     if ( glb_maxfrm-- <= 0 )
  295.         framehead(  );
  296.     allocframe(  );
  297. }
  298.  
  299. /************************ rmcoproc ****************************************/
  300. /* rmcoproc(frm) - remove coprocess in frame frm                          */
  301. /**************************************************************************/
  302.  
  303. static  rmcoproc( frm )
  304.     sframe_t *frm;
  305. {
  306.     coproc_t *p;
  307.  
  308.     p = frm->proc;
  309.  
  310. /* free process structure */
  311.     free( frm->proc );
  312.  
  313. /* insert frame to end of free frames queue */
  314.  
  315.     frm->nxt = &freefq;
  316.     frm->prv = freefq.prv;
  317.     freefq.prv->nxt = frm;
  318.     freefq.prv = frm;
  319.  
  320. /* reschedule some new coprocess */
  321.  
  322.     if ( runq.nxt == &runq && slepq.nxt == &slepq )
  323.     {
  324.         exit( 0 );
  325.     }
  326.  
  327.     while ( runq.nxt == &runq )
  328.     {            /* sleep while no coprocesses to run */
  329. #    ifndef DOS
  330.         sleep( 100 );
  331. #    endif
  332.     }
  333.  
  334.     curproc = runq.nxt;
  335.     runq.nxt = curproc->nxt;
  336.     curproc->nxt->prv = &runq;
  337.  
  338.     longjmp( curproc->setjmp, WAKEUP );
  339. }
  340.  
  341. /****************************** run1coproc **********************************/
  342. /* run1coproc(func,maxfrm,varsz) - create the first coprocess with the main */
  343. /*   function func, stack frame for maximal maxfrm function calls and       */
  344. /*   maximal size of local variables varsz.                                 */
  345. /****************************************************************************/
  346.  
  347. run1coproc( func, maxfrm, varsz )
  348.     int     ( *func ) (  );
  349. {
  350.     sframe_t *frm;
  351.     coproc_t *pr;
  352.  
  353.     if ( ( pr = ( coproc_t * ) malloc( sizeof( coproc_t ) ) ) == 0 )
  354.         return -1;
  355.  
  356.     lastframe = frm = ( sframe_t * ) malloc( sizeof( sframe_t ) );
  357.  
  358.     if ( frm == 0 )
  359.     {
  360.         free( pr );
  361.         return -1;
  362.     }
  363.  
  364.     frm->maxfrm = glb_maxfrm = maxfrm;
  365.     frm->varsz = glb_varsz = varsz;
  366.     frm->proc = pr;
  367.     frm->func = func;
  368.     pr->pid = nextpid++;
  369.     pr->frm = frm;
  370.  
  371. /* runq.nxt=runq.prv=pr; pr->nxt=pr->prv=&runq; */
  372.     curproc = pr;
  373.  
  374.     switch ( setjmp( frm->setjmp ) )
  375.     {
  376.         case WAKEUP:
  377.             frm->func(  );
  378.             rmcoproc( frm );
  379.         case RMPROC:
  380.             rmcoproc( frm );
  381.     }
  382.  
  383.     memcpy( frm->proc->setjmp, frm->setjmp, sizeof( jmp_buf ) );
  384.     memcpy( get_jmpbuf, frm->setjmp, sizeof( jmp_buf ) );
  385.  
  386.     allocspace(  );
  387. }
  388.  
  389. /************************* cowakeup ************************************/
  390. /* cowakeup(event) - wake up all processes sleeping on event           */
  391. /***********************************************************************/
  392.  
  393. cowakeup( event )
  394.     char   *event;
  395. {
  396.     coproc_t *cpr,
  397.            *pr,
  398.            *tpr;
  399.  
  400.     for ( cpr = slepq.nxt; cpr != &slepq; cpr = tpr )
  401.     {
  402.         tpr = cpr->nxt;
  403.  
  404.         if ( cpr->event == event )
  405.         {
  406.             /* remove this process from the sleeping queue */
  407.             cpr->nxt->prv = cpr->prv;
  408.             cpr->prv->nxt = cpr->nxt;
  409.  
  410.             /* found appropriate place in the runnable queue */
  411.             for ( pr = runq.nxt; pr != &runq && pr->pri <= cpr->pri; pr = pr->nxt );
  412.  
  413.             /* and insert current process before process found */
  414.  
  415.             cpr->nxt = pr;
  416.             cpr->prv = pr->prv;
  417.             pr->prv->nxt = cpr;
  418.             pr->prv = cpr;
  419.         }
  420.     }
  421. }
  422.  
  423. /*********************** coexit *****************************************/
  424. /* coexit() - terminate current process                                 */
  425. /************************************************************************/
  426.  
  427. coexit(  )
  428. {
  429.     longjmp( curproc->frm->setjmp, RMPROC );
  430. }
  431.  
  432. /*************************** cogetpid ***********************************/
  433. /* cogetpid() - returns the PID of current coprocess                    */
  434. /************************************************************************/
  435.  
  436. cogetpid(  )
  437. {
  438.     return curproc->pid;
  439. }
  440.