home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / network / src_1218.zip / KERNEL.C < prev    next >
C/C++ Source or Header  |  1991-11-03  |  13KB  |  522 lines

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