home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / KERNEL.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  16KB  |  567 lines

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