home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / KERNEL.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  13KB  |  527 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  
  5. /****************************************************************************
  6. *    $Id: kernel.c 1.4 93/07/16 11:45:57 ROOT_DOS Exp $
  7. *    13 Jul 93    1.3        GT    Fix warnings.                                    *
  8. ****************************************************************************/
  9.  
  10. #define    SUSPEND_PROC    1
  11.  
  12. #if    defined(PROCLOG) || defined(PROCTRACE)
  13. #include <stdio.h>
  14. #endif
  15. #include <dos.h>
  16. #include <setjmp.h>
  17. #include "global.h"
  18. #include "mbuf.h"
  19. #include "proc.h"
  20. #include "timer.h"
  21. #include "socket.h"
  22. #include "daemon.h"
  23. #include "hardware.h"
  24.  
  25. #ifdef    PROCLOG
  26. FILE *proclog;
  27. FILE *proctrace;
  28. #endif
  29. int Stkchk = 0;
  30. struct proc *Curproc;        /* Currently running process */
  31. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  32. struct proc *Waittab[PHASH];    /* Waiting process list */
  33. struct proc *Susptab;        /* Suspended processes */
  34. static struct mbuf *Killq;
  35.  
  36. static void addproc __ARGS((struct proc *entry));
  37. static void delproc __ARGS((struct proc *entry));
  38.  
  39. /* Create a process descriptor for the main function. Must be actually
  40.  * called from the main function!
  41.  * Note that standard I/O is NOT set up here.
  42.  */
  43. struct proc *
  44. mainproc(name)
  45. char *name;
  46. {
  47.     register struct proc *pp;
  48.  
  49.     /* Create process descriptor */
  50.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  51.  
  52.     /* Create name */
  53.     pp->name = strdup(name);
  54. #ifndef    AMIGA
  55.     pp->stksize = 0;
  56. #else
  57.     init_psetup(pp);
  58. #endif
  59.     /* Make current */
  60.     pp->state = READY;
  61.     Curproc = pp;
  62.  
  63. #ifdef    PROCLOG
  64.     proclog = fopen("proclog",APPEND_TEXT);
  65.     proctrace = fopen("proctrace",APPEND_TEXT);
  66. #endif
  67.     return pp;
  68. }
  69. /* Create a new, ready process and return pointer to descriptor.
  70.  * The general registers are not initialized, but optional args are pushed
  71.  * on the stack so they can be seen by a C function.
  72.  */
  73. struct proc *
  74. newproc(name,stksize,pc,iarg,parg1,parg2,freeargs)
  75. char *name;        /* Arbitrary user-assigned name string */
  76. unsigned int stksize;    /* Stack size in words to allocate */
  77. void (*pc)();        /* Initial execution address */
  78. int iarg;        /* Integer argument (argc) */
  79. void *parg1;        /* Generic pointer argument #1 (argv) */
  80. void *parg2;        /* Generic pointer argument #2 (session ptr) */
  81. int freeargs;        /* If set, free arg list on parg1 at termination */
  82. {
  83.     register struct proc *pp;
  84.     int i;
  85.  
  86.     if(Stkchk)
  87.         chkstk();
  88.  
  89.     /* Create process descriptor */
  90.     pp = (struct proc *)callocw(1,sizeof(struct proc));
  91.  
  92.     /* Create name */
  93.     pp->name = strdup(name);
  94.  
  95.     /* Allocate stack */
  96. #ifdef    AMIGA
  97.     stksize += 2000;    /* DOS overhead */
  98. #endif
  99.     pp->stksize = stksize;
  100.     if((pp->stack = (int16 *)malloc(sizeof(int16)*stksize)) == NULL){
  101.         free(pp->name);
  102.         free((char *)pp);
  103.         return NULLPROC;
  104.     }
  105.     /* Initialize stack for high-water check */
  106.     for(i=0;i<stksize;i++)
  107.         pp->stack[i] = STACKPAT;
  108.  
  109.     /* Do machine-dependent initialization of stack */
  110.     psetup(pp,iarg,parg1,parg2,pc);
  111.  
  112.     pp->freeargs = freeargs;
  113.     pp->iarg = iarg;
  114.     pp->parg1 = parg1;
  115.     pp->parg2 = parg2;
  116.     
  117.     /* Inherit creator's input and output sockets */
  118.     usesock(Curproc->input);
  119.     pp->input = Curproc->input;
  120.     usesock(Curproc->output);
  121.     pp->output = Curproc->output;
  122.  
  123.     /* Add to ready process table */
  124.     pp->state = READY;
  125.     addproc(pp);
  126.     return pp;
  127. }
  128.  
  129. /* Free resources allocated to specified process. If a process wants to kill
  130.  * itself, the reaper is called to do the dirty work. This avoids some
  131.  * messy situations that would otherwise occur, like freeing your own stack.
  132.  */
  133. void
  134. killproc(pp)
  135. register struct proc *pp;
  136. {
  137.     char **argv;
  138.  
  139.     if(pp == NULLPROC)
  140.         return;
  141.     /* Don't check the stack here! Will cause infinite recursion if
  142.      * called from a stack error
  143.      */
  144.  
  145.     if(pp == Curproc)
  146.         killself();    /* Doesn't return */
  147.  
  148.     /* Close any open sockets */
  149.     freesock(pp);
  150.  
  151.     close_s(pp->input);
  152.     close_s(pp->output);
  153.  
  154.     /* Stop alarm clock in case it's running */
  155.     stop_timer(&pp->alarm);
  156.  
  157.     /* Alert everyone waiting for this proc to die */
  158.     psignal(pp,0);
  159.  
  160.     /* Remove from appropriate table */
  161.     delproc(pp);
  162.  
  163. #ifdef    PROCLOG
  164.     fprintf(proclog,"id %lx name %s stack %u/%u\n",ptol(pp),
  165.         pp->name,stkutil(pp),pp->stksize);
  166.     fclose(proclog);
  167.     proclog = fopen("proclog",APPEND_TEXT);
  168.     proctrace = fopen("proctrace",APPEND_TEXT);
  169. #endif
  170.     /* Free allocated memory resources */
  171.     if(pp->freeargs){
  172.         argv = pp->parg1;
  173.         while(pp->iarg-- != 0)
  174.             free(*argv++);
  175.         free(pp->parg1);
  176.     }
  177.     free(pp->name);
  178.     free(pp->stack);
  179.     free(pp->outbuf);
  180.     free((char *)pp);
  181. }
  182. /* Terminate current process by sending a request to the killer process.
  183.  * Automatically called when a process function returns. Does not return.
  184.  */
  185. void
  186. killself()
  187. {
  188.     register struct mbuf *bp;
  189.  
  190.     if(Curproc != NULLPROC){
  191.         bp = pushdown(NULLBUF,sizeof(Curproc));
  192.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  193.         enqueue(&Killq,bp);
  194.     }
  195.     /* "Wait for me; I will be merciful and quick." */
  196.     for(;;)
  197.         pwait(NULL);
  198. }
  199. /* Process used by processes that want to kill themselves */
  200. void
  201. killer(i,v1,v2)
  202. int i;
  203. void *v1;
  204. void *v2;
  205. {
  206.     struct proc *pp;
  207.     struct mbuf *bp;
  208.  
  209.     for(;;){
  210.         while(Killq == NULLBUF)
  211.             pwait(&Killq);
  212.         bp = dequeue(&Killq);
  213.         pullup(&bp,(char *)&pp,sizeof(pp));
  214.         free_p(bp);
  215.         if(pp != Curproc)    /* We're immortal */
  216.             killproc(pp);
  217.     }                        
  218. }
  219.  
  220. #ifdef    SUSPEND_PROC
  221. /* Inhibit a process from running */
  222. void
  223. suspend(pp)
  224. struct proc *pp;
  225. {
  226.     if(pp == NULLPROC)
  227.         return;
  228.     if(pp != Curproc)
  229.         delproc(pp);    /* Running process isn't on any list */
  230.     pp->state |= SUSPEND;
  231.     if(pp != Curproc)
  232.         addproc(pp);    /* pwait will do it for us */
  233.     else
  234.         pwait(NULL);
  235. }
  236. /* Restart suspended process */
  237. void
  238. resume(pp)
  239. struct proc *pp;
  240. {
  241.     if(pp == NULLPROC)
  242.         return;
  243.     delproc(pp);    /* Can't be Curproc! */
  244.     pp->state &= ~SUSPEND;
  245.     addproc(pp);
  246. }
  247. #endif    /* SUSPEND_PROC */
  248.  
  249. /* Wakeup waiting process, regardless of event it's waiting for. The process
  250.  * will see a return value of "val" from its pwait() call.
  251.  */
  252. void
  253. alert(pp,val)
  254. struct proc *pp;
  255. int val;
  256. {
  257.     if(pp == NULLPROC)
  258.         return;
  259. #ifdef    notdef
  260.     if((pp->state & WAITING) == 0)
  261.         return;
  262. #endif
  263. #ifdef    PROCTRACE
  264.     printf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
  265.     fflush(stdout);
  266. #endif
  267.     if(pp != Curproc)
  268.         delproc(pp);
  269.     pp->state &= ~WAITING;
  270.     pp->retval = val;
  271.     pp->event = 0;
  272.     if(pp != Curproc)
  273.         addproc(pp);
  274. }
  275.  
  276. /* Post a wait on a specified event and give up the CPU until it happens. The
  277.  * null event is special: it means "I don't want to block on an event, but let
  278.  * somebody else run for a while". It can also mean that the present process
  279.  * is terminating; in this case the wait never returns.
  280.  *
  281.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  282.  * arg in an alert() call. Pwait must not be called from interrupt level.
  283.  *
  284.  * Note that pwait can run with interrupts enabled even though it examines
  285.  * a few global variables that can be modified by psignal at interrupt time.
  286.  * These *seem* safe.
  287.  */
  288. int
  289. pwait(event)
  290. void *event;
  291. {
  292.     register struct proc *oldproc;
  293.     int tmp;
  294.  
  295.     if(Curproc != NULLPROC){    /* If process isn't terminating */
  296.         if(Stkchk)
  297.             chkstk();
  298.  
  299.         if(event == NULL){
  300.             /* Special case; just give up the processor.
  301.              *
  302.              * Optimization: if nothing else is ready, just return.
  303.              */
  304.             if(Rdytab == NULLPROC){
  305.                 return 0;
  306.             }
  307.         } else {
  308.             /* Post a wait for the specified event */
  309.             Curproc->event = event;
  310.             Curproc->state = WAITING;
  311.         }
  312.         addproc(Curproc);
  313.     }
  314.     /* Look for a ready process and run it. If there are none,
  315.      * loop or halt until an interrupt makes something ready.
  316.      */
  317.     while(Rdytab == NULLPROC){
  318.         /* Give system back to upper-level multitasker, if any.
  319.          * Note that this function enables interrupts internally
  320.          * to prevent deadlock, but it restores our state
  321.          * before returning.
  322.          */
  323.         kbint();    /***/
  324.         giveup();
  325.     }
  326.     /* Remove first entry from ready list */
  327.     oldproc = Curproc;
  328.     Curproc = Rdytab;
  329.     delproc(Curproc);
  330.  
  331.     /* Now do the context switch.
  332.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  333.      *
  334.      * If the old process has gone away, simply load the new process's
  335.      * environment. Otherwise, save the current process's state. Then if
  336.      * this is still the old process, load the new environment. Since the
  337.      * new task will "think" it's returning from the setjmp() with a return
  338.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  339.      * would otherwise cause an infinite loop.
  340.      */
  341. #ifdef    PROCTRACE
  342.     if(strcmp(oldproc->name,Curproc->name) != 0){
  343.           printf("-> %s(%d)\n",Curproc->name,!!Curproc->i_state);
  344.         fflush(stdout);
  345.     }
  346. #endif
  347.     /* Note use of comma operator to save old interrupt state only if
  348.      * oldproc is non-null
  349.      */
  350.     if(oldproc == NULLPROC
  351.      || (oldproc->i_state = istate(), setjmp(oldproc->env) == 0)){
  352.         /* We're still running in the old task; load new task context.
  353.          * The interrupt state is restored here in case longjmp
  354.          * doesn't do it (e.g., systems other than Turbo-C).
  355.          */
  356.         restore(Curproc->i_state);
  357.         longjmp(Curproc->env,1);
  358.     }
  359.     /* At this point, we're running in the newly dispatched task */
  360.     tmp = Curproc->retval;
  361.     Curproc->retval = 0;
  362.  
  363.     /* Also restore the true interrupt state here, in case the longjmp
  364.      * DOES restore the interrupt state saved at the time of the setjmp().
  365.      * This is the case with Turbo-C's setjmp/longjmp.
  366.      */
  367.     restore(Curproc->i_state);
  368.     return tmp;
  369. }
  370.  
  371. /* Make ready the first 'n' processes waiting for a given event. The ready
  372.  * processes will see a return value of 0 from pwait().  Note that they don't
  373.  * actually get control until we explicitly give up the CPU ourselves through
  374.  * a pwait(). Psignal may be called from interrupt level. It returns the
  375.  * number of processes that were woken up.
  376.  */
  377. int
  378. psignal(event,n)
  379. void *event;    /* Event to signal */
  380. int n;        /* Max number of processes to wake up */
  381. {
  382.     register struct proc *pp;
  383.     struct proc *pnext;
  384.     int i_state;
  385.     unsigned int hashval;
  386.     int cnt = 0;
  387.  
  388.     if(Stkchk)
  389.         chkstk();
  390.  
  391.     if(event == NULL)
  392.         return 0;        /* Null events are invalid */
  393.  
  394.     /* n = 0 means "signal everybody waiting for this event" */
  395.     if(n == 0)
  396.         n = (int) 65535L;
  397.  
  398.     hashval = phash(event);
  399.     i_state = dirps();
  400.     for(pp = Waittab[hashval];n != 0 && pp != NULLPROC;pp = pnext){
  401.         pnext = pp->next;
  402.         if(pp->event == event){
  403. #ifdef    PROCTRACE
  404.             if(i_state){
  405.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  406.                  ptol(pp),pp->name);
  407.                 fflush(stdout);
  408.             }
  409. #endif
  410.             delproc(pp);
  411.             pp->state &= ~WAITING;
  412.             pp->retval = 0;
  413.             pp->event = NULL;
  414.             addproc(pp);
  415.             n--;
  416.             cnt++;
  417.         }
  418.     }
  419. #ifdef    SUSPEND_PROC
  420.     for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
  421.         pnext = pp->next;
  422.         if(pp->event == event){
  423. #ifdef    PROCTRACE
  424.             if(i_state){
  425.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  426.                  ptol(pp),pp->name);
  427.                 fflush(stdout);
  428.             }
  429. #endif /* PROCTRACE */
  430.             delproc(pp);
  431.             pp->state &= ~WAITING;
  432.             pp->event = 0;
  433.             pp->retval = 0;
  434.             addproc(pp);
  435.             n--;
  436.             cnt++;
  437.         }
  438.     }
  439. #endif    /* SUSPEND_PROC */
  440.     restore(i_state);
  441.     return cnt;
  442. }
  443.  
  444. /* Rename a process */
  445. void
  446. chname(pp,newname)
  447. struct proc *pp;
  448. char *newname;
  449. {
  450.     free(pp->name);
  451.     pp->name = strdup(newname);
  452. }
  453. /* Remove a process entry from the appropriate table */
  454. static void
  455. delproc(entry)
  456. register struct proc *entry;    /* Pointer to entry */
  457. {
  458.     int i_state;
  459.  
  460.     if(entry == NULLPROC)
  461.         return;
  462.  
  463.     i_state = dirps();
  464.     if(entry->next != NULLPROC)
  465.         entry->next->prev = entry->prev;
  466.     if(entry->prev != NULLPROC){
  467.         entry->prev->next = entry->next;
  468.     } else {
  469.         switch(entry->state){
  470.         case READY:
  471.             Rdytab = entry->next;
  472.             break;
  473.         case WAITING:
  474.             Waittab[phash(entry->event)] = entry->next;
  475.             break;
  476. #ifdef    SUSPEND_PROC
  477.         case SUSPEND:
  478.         case SUSPEND|WAITING:
  479.             Susptab = entry->next;
  480.             break;
  481. #endif
  482.         }
  483.     }
  484.     restore(i_state);
  485. }
  486. /* Append proc entry to end of appropriate list */
  487. static void
  488. addproc(entry)
  489. register struct proc *entry;    /* Pointer to entry */
  490. {
  491.     register struct proc *pp;
  492.     struct proc **head;
  493.     int i_state;
  494.  
  495.     if(entry == NULLPROC)
  496.         return;
  497.  
  498.     switch(entry->state){
  499.     case READY:
  500.         head = &Rdytab;
  501.         break;
  502.     case WAITING:
  503.         head = &Waittab[phash(entry->event)];
  504.         break;
  505. #ifdef    SUSPEND_PROC
  506.     case SUSPEND:
  507.     case SUSPEND|WAITING:
  508.         head = &Susptab;
  509.         break;
  510. #endif
  511.     }
  512.     entry->next = NULLPROC;
  513.     i_state = dirps();
  514.     if(*head == NULLPROC){
  515.         /* Empty list, stick at beginning */
  516.         entry->prev = NULLPROC;
  517.         *head = entry;
  518.     } else {
  519.         /* Find last entry on list */
  520.         for(pp = *head;pp->next != NULLPROC;pp = pp->next)
  521.             ;
  522.         pp->next = entry;
  523.         entry->prev = pp;
  524.     }
  525.     restore(i_state);
  526. }
  527.