home *** CD-ROM | disk | FTP | other *** search
- /**/
- /*
- /* coproc.c
- /*
- /* (C) Copyright by Serge Babkin, 1993
- /*
- /* Any part of this code may be freely distributed for
- /* the non-commertial use when it contains this copyright
- /* notice only.
- /*
- /* My FIDO address is: 2:5010/4
- /*
- /**/
-
- #include <setjmp.h>
- #include <stdio.h>
- #include <malloc.h>
-
- /************************ Configuring ********************************/
-
- /* Uncomment the following line when compiling under MS DOS */
- /* #define DOS */
-
- /************************ Types **************************************/
-
- typedef unsigned short ushort;
-
- /* define the coprocess structure */
-
- typedef struct coproc
- {
- struct coproc *nxt; /* next process in a queue */
- struct coproc *prv; /* previous process in a queue */
- struct sframe *frm; /* stack frame */
- jmp_buf setjmp; /* entry point to this coprocess */
- char *event; /* which event this process is sleeping on */
- ushort pri; /* priority */
- ushort pid; /* coprocess id */
- } coproc_t;
-
- /* define the stack frame */
-
- typedef struct sframe
- {
- struct sframe *nxt; /* next frame in a queue */
- struct sframe *prv; /* previous frame in a queue */
- struct coproc *proc; /* coprocess in this frame */
- jmp_buf setjmp; /* jump to header */
- int maxfrm; /* maximal number of function frames */
- int varsz; /* maximal size of variables */
- int ( *func ) ( ); /* main function of the current coprocess */
- } sframe_t;
-
- /*************************** Global variables **********************/
-
- /* global queues */
-
- static coproc_t runq = {&runq, &runq}; /* runnable processes */
- static coproc_t slepq = {&slepq, &slepq}; /* sleeping processes */
- static sframe_t freefq = {&freefq, &freefq}; /* free frames */
-
- /* current context */
-
- static coproc_t *curproc; /* current process */
- static sframe_t *lastframe; /* last frame */
- static ushort nextpid = 0; /* next pid */
-
- /* temporary variables used for allocation of stack frame */
- static int glb_maxfrm,
- glb_varsz;
- static jmp_buf get_jmpbuf;
-
- int lbolt; /* special address for sleeping, used for
- * sleep on no event */
-
- /**************************** Constants ********************************/
-
- /* messages for longjmp() */
-
- #define WAKEUP 1 /* wake up process */
- #define ADDFRAME 2 /* add new frame to stack */
- #define RMPROC 3 /* remove process */
-
- /****************** Predefinitions of functions *************************/
-
- static sframe_t *getnewframe( );
- static framehead( );
- static allocspace( );
- static allocframe( );
- static rmcoproc( );
-
- /************************* cosleep ***********************************/
- /* cosleep(event,pri) - sleep on event with priority pri */
- /*********************************************************************/
-
- cosleep( event, pri )
- char *event;
- {
-
- curproc->event = event;
- curproc->pri = ( ushort ) pri;
-
- if ( event == ( char * ) &lbolt )
- { /* when simply pass the control */
- coproc_t *pr;
-
- /* found appropriate place in the runnable queue */
- for ( pr = runq.nxt; pr != &runq && pr->pri <= pri; pr = pr->nxt );
-
- /* and insert current process before process found */
-
- curproc->nxt = pr;
- curproc->prv = pr->prv;
- pr->prv->nxt = curproc;
- pr->prv = curproc;
- }
- else
- {
- /* insert it to the begin of sleeping queue */
-
- curproc->nxt = slepq.nxt;
- curproc->prv = &slepq;
- slepq.nxt->prv = curproc;
- slepq.nxt = curproc;
- }
- /* and sleep until woken up */
-
- if ( setjmp( curproc->setjmp ) == WAKEUP )
- return;
-
- /* reschedule some new coprocess */
-
- if ( runq.nxt == &runq && slepq.nxt == &slepq )
- {
- exit( 0 );
- }
-
- while ( runq.nxt == &runq )
- { /* sleep while no coprocesses to run */
- /* i.e. until the waking up signal in UNIX */
- /* or interrupt in DOS */
-
- # ifndef DOS
- sleep( 100 );
- # endif
- }
-
- curproc = runq.nxt;
- runq.nxt = curproc->nxt;
- curproc->nxt->prv = &runq;
-
- longjmp( curproc->setjmp, WAKEUP );
- }
-
- /***************************** cofork ***********************************/
- /* cofork(func,maxfrm,varsz) - create the new coprocess with the main */
- /* function func, stack frame for maximal maxfrm function calls and */
- /* maximal size of local variables varsz. */
- /************************************************************************/
-
- cofork( func, maxfrm, varsz )
- int ( *func ) ( );
- {
- coproc_t *pr;
- sframe_t *fr;
-
- /* try to get a coprocess table entry */
-
- if ( ( pr = ( coproc_t * ) malloc( sizeof( coproc_t ) ) ) == 0 )
- return -1;
-
- glb_maxfrm = maxfrm;
- glb_varsz = varsz;
-
- /* try to use some free frame from the list of free frames */
-
- for ( fr = freefq.nxt; fr != &freefq; fr = fr->nxt )
- {
- if ( fr->maxfrm >= maxfrm && fr->varsz >= varsz )
- break;
- }
-
- if ( fr == &freefq )
- { /* if no free frame, allocate new one */
- if ( ( fr = getnewframe( ) ) == 0 )
- {
- free( pr );
- return -1;
- }
- }
- else
- { /* remove it from the queue */
- fr->nxt->prv = fr->prv;
- fr->prv->nxt = fr->nxt;
- }
-
- /* set up frame */
-
- fr->proc = pr;
- fr->func = func;
-
- /* set up coprocess and add it to begin of the runnable queue */
-
- pr->pid = nextpid++;
- pr->frm = fr;
- memcpy( pr->setjmp, fr->setjmp, sizeof( jmp_buf ) );
-
- pr->prv = &runq;
- pr->nxt = runq.nxt;
- runq.nxt->prv = pr;
- runq.nxt = pr;
-
- pr->pri = 0;
-
- return 0;
- }
-
- /************************* getnewframe *********************************/
- /* getnewframe() - gets new stack frame */
- /***********************************************************************/
-
- static sframe_t *getnewframe( )
- {
- sframe_t *nfrm;
-
- if ( ( nfrm = lastframe ) == 0 )
- return 0;
-
- nfrm->maxfrm = glb_maxfrm;
- nfrm->varsz = glb_varsz;
-
- if ( setjmp( get_jmpbuf ) == WAKEUP )
- return nfrm;
- longjmp( nfrm->setjmp, ADDFRAME );
- }
-
- /*********************** framehead ************************************/
- /* framehead() - header of stack frame, used to create the new frame */
- /**********************************************************************/
-
- static framehead( )
- {
- sframe_t *frm;
-
- if ( ( lastframe = ( sframe_t * ) malloc( sizeof( sframe_t ) ) ) == 0 )
- {
- /* if unable to create the new frame */
-
- longjmp( get_jmpbuf, WAKEUP );
- }
-
- lastframe->func = 0;
- frm = lastframe;
-
- switch ( setjmp( frm->setjmp ) )
- {
- case WAKEUP:
- frm->func( );
- rmcoproc( frm );
- case ADDFRAME:
- allocspace( );
- case RMPROC:
- rmcoproc( frm );
- }
- longjmp( get_jmpbuf, WAKEUP );
- }
-
- /*************************** allocspace ********************************/
- /* allocspace() - allocate one function frame and 1K of space for */
- /* local variables in the stack */
- /***********************************************************************/
-
- static allocspace( )
- {
- char v[1024];
-
- glb_maxfrm--;
- glb_varsz--;
-
- if ( glb_varsz <= 0 )
- if ( glb_maxfrm <= 0 )
- framehead( );
- else
- allocframe( );
- allocspace( );
- }
-
- /************************* allocframe ***********************************/
- /* allocframe() - allocate one function frame in the stack */
- /************************************************************************/
-
- static allocframe( )
- {
- if ( glb_maxfrm-- <= 0 )
- framehead( );
- allocframe( );
- }
-
- /************************ rmcoproc ****************************************/
- /* rmcoproc(frm) - remove coprocess in frame frm */
- /**************************************************************************/
-
- static rmcoproc( frm )
- sframe_t *frm;
- {
- coproc_t *p;
-
- p = frm->proc;
-
- /* free process structure */
- free( frm->proc );
-
- /* insert frame to end of free frames queue */
-
- frm->nxt = &freefq;
- frm->prv = freefq.prv;
- freefq.prv->nxt = frm;
- freefq.prv = frm;
-
- /* reschedule some new coprocess */
-
- if ( runq.nxt == &runq && slepq.nxt == &slepq )
- {
- exit( 0 );
- }
-
- while ( runq.nxt == &runq )
- { /* sleep while no coprocesses to run */
- # ifndef DOS
- sleep( 100 );
- # endif
- }
-
- curproc = runq.nxt;
- runq.nxt = curproc->nxt;
- curproc->nxt->prv = &runq;
-
- longjmp( curproc->setjmp, WAKEUP );
- }
-
- /****************************** run1coproc **********************************/
- /* run1coproc(func,maxfrm,varsz) - create the first coprocess with the main */
- /* function func, stack frame for maximal maxfrm function calls and */
- /* maximal size of local variables varsz. */
- /****************************************************************************/
-
- run1coproc( func, maxfrm, varsz )
- int ( *func ) ( );
- {
- sframe_t *frm;
- coproc_t *pr;
-
- if ( ( pr = ( coproc_t * ) malloc( sizeof( coproc_t ) ) ) == 0 )
- return -1;
-
- lastframe = frm = ( sframe_t * ) malloc( sizeof( sframe_t ) );
-
- if ( frm == 0 )
- {
- free( pr );
- return -1;
- }
-
- frm->maxfrm = glb_maxfrm = maxfrm;
- frm->varsz = glb_varsz = varsz;
- frm->proc = pr;
- frm->func = func;
- pr->pid = nextpid++;
- pr->frm = frm;
-
- /* runq.nxt=runq.prv=pr; pr->nxt=pr->prv=&runq; */
- curproc = pr;
-
- switch ( setjmp( frm->setjmp ) )
- {
- case WAKEUP:
- frm->func( );
- rmcoproc( frm );
- case RMPROC:
- rmcoproc( frm );
- }
-
- memcpy( frm->proc->setjmp, frm->setjmp, sizeof( jmp_buf ) );
- memcpy( get_jmpbuf, frm->setjmp, sizeof( jmp_buf ) );
-
- allocspace( );
- }
-
- /************************* cowakeup ************************************/
- /* cowakeup(event) - wake up all processes sleeping on event */
- /***********************************************************************/
-
- cowakeup( event )
- char *event;
- {
- coproc_t *cpr,
- *pr,
- *tpr;
-
- for ( cpr = slepq.nxt; cpr != &slepq; cpr = tpr )
- {
- tpr = cpr->nxt;
-
- if ( cpr->event == event )
- {
- /* remove this process from the sleeping queue */
- cpr->nxt->prv = cpr->prv;
- cpr->prv->nxt = cpr->nxt;
-
- /* found appropriate place in the runnable queue */
- for ( pr = runq.nxt; pr != &runq && pr->pri <= cpr->pri; pr = pr->nxt );
-
- /* and insert current process before process found */
-
- cpr->nxt = pr;
- cpr->prv = pr->prv;
- pr->prv->nxt = cpr;
- pr->prv = cpr;
- }
- }
- }
-
- /*********************** coexit *****************************************/
- /* coexit() - terminate current process */
- /************************************************************************/
-
- coexit( )
- {
- longjmp( curproc->frm->setjmp, RMPROC );
- }
-
- /*************************** cogetpid ***********************************/
- /* cogetpid() - returns the PID of current coprocess */
- /************************************************************************/
-
- cogetpid( )
- {
- return curproc->pid;
- }
-