home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / UZI / UZI.ARK / PROCESS.C < prev    next >
C/C++ Source or Header  |  1988-11-29  |  12KB  |  590 lines

  1. /**************************************************
  2. UZI (Unix Z80 Implementation) Kernel:  process.c
  3. ***************************************************/
  4.  
  5.  
  6. #include "unix.h"
  7. #include "extern.h"
  8.  
  9. init2()
  10. {
  11.     register char *j;
  12.     static char bootchar;
  13.     static char *arg[2] = { "init", NULL };
  14.     inoptr i_open(), n_open();
  15.     ptptr ptab_alloc();
  16.  
  17.     bufinit();
  18.  
  19.     /* Create the context for the first process */
  20.     newproc(udata.u_ptab = initproc = ptab_alloc());
  21.     initproc->p_status = P_RUNNING;
  22.  
  23.     /* User's file table */
  24.     for (j=udata.u_files; j < (udata.u_files+UFTSIZE); ++j)
  25.     *j = -1;
  26.  
  27.     /* Turn on the clock */
  28.     out(02,0xf1);
  29.     ei();
  30.  
  31.     /* Wait until the clock has interrupted, to set tod
  32.     while (!tod.t_date) ;  /* Loop */
  33.     /*
  34.  
  35.     /* Open the console tty device */
  36.     if (d_open(TTYDEV) != 0)
  37.     panic("no tty");
  38.  
  39.     kprintf("boot: ");
  40.     udata.u_base = &bootchar;
  41.     udata.u_count = 1;
  42.     cdread(TTYDEV);
  43.     ROOTDEV = bootchar - '0';
  44.  
  45.     /* Mount the root device */
  46.     if (fmount(ROOTDEV,NULLINODE))
  47.     panic("no filesys");
  48.  
  49.     ifnot (root = i_open(ROOTDEV,ROOTINODE))
  50.     panic("no root");
  51.  
  52.     i_ref(udata.u_cwd = root);
  53.     rdtime(&udata.u_time);
  54.  
  55.     udata.u_argn2 = (int16)("/init");
  56.     udata.u_argn1 = (int16)(&arg[0]);
  57.     udata.u_argn = (int16)(&arg[1]);
  58.     _execve();
  59. /*
  60.     _execve("/init",&arg[0],&arg[1]);
  61. */
  62.     panic("no /init");
  63.  
  64. }
  65.  
  66.  
  67. /* psleep() puts a process to sleep on the given event.
  68. If another process is runnable, it swaps out the current one
  69. and starts the new one.
  70. Normally when psleep is called, the interrupts have already been
  71. disabled.   An event of 0 means a pause(), while an event equal
  72. to the process's own ptab address is a wait().   */
  73.  
  74. psleep(event)
  75. char *event;
  76. {
  77.     register dummy;  /* Force saving of registers */
  78.  
  79.     di();
  80.     if (udata.u_ptab->p_status != P_RUNNING)
  81.     panic("psleep: voodoo");
  82.     if (!event)
  83.     udata.u_ptab->p_status = P_PAUSE;
  84.     else if (event == (char *)udata.u_ptab)
  85.     udata.u_ptab->p_status = P_WAIT;
  86.     else
  87.     udata.u_ptab->p_status = P_SLEEP;
  88.  
  89.     udata.u_ptab->p_wait = event;
  90.  
  91.     ei();
  92.  
  93.     swapout();          /* Swap us out, and start another process */
  94.  
  95.     /* Swapout doesn't return until we have been swapped back in */
  96. }
  97.  
  98.  
  99. /* wakeup() looks for any process waiting on the event,
  100. and make them runnable */
  101.  
  102. wakeup(event)
  103. char *event;
  104. {
  105.     register ptptr p;
  106.  
  107.     di();
  108.     for(p=ptab;p < ptab+PTABSIZE; ++p)
  109.     {
  110.     if (p->p_status > P_RUNNING && p->p_wait == event)
  111.     {
  112.         p->p_status = P_READY;
  113.         p->p_wait = (char *)NULL;
  114.     }
  115.     }
  116.     ei();
  117. }
  118.  
  119.  
  120. /* Getproc returns the process table pointer of a runnable process.
  121. It is actually the scheduler.
  122. If there are none, it loops.  This is the only time-wasting loop in the
  123. system. */
  124.  
  125. ptptr
  126. getproc()
  127. {
  128.     register status;
  129.     static ptptr pp = ptab;    /* Pointer for round-robin scheduling */
  130.  
  131.     for (;;)
  132.     {
  133.     if (++pp >= ptab + PTABSIZE)
  134.         pp = ptab;
  135.  
  136.     di();
  137.     status = pp->p_status;
  138.     ei();
  139.  
  140.     if (status == P_RUNNING)
  141.         panic("getproc: extra running");
  142.     if (status == P_READY)
  143.         return(pp);
  144.     }
  145. }
  146.  
  147. /* Temp storage for swapout() */
  148. char *stkptr;
  149.  
  150.  
  151. /* Swapout swaps out the current process, finds another that is READY,
  152. possibly the same process, and swaps it in.
  153. When a process is restarted after calling swapout,
  154. it thinks it has just returned from swapout(). */
  155.  
  156. /* This function can have no arguments or auto variables */
  157. swapout()
  158. {
  159.     static ptptr newp;
  160.     ptptr getproc();
  161.  
  162.  
  163.     /* See if any signals are pending */
  164.     chksigs();
  165.  
  166.     /* Get a new process */
  167.     newp = getproc();
  168.  
  169.     /* If there is nothing else to run, just return */
  170.     if (newp == udata.u_ptab)
  171.     {
  172.     udata.u_ptab->p_status = P_RUNNING;
  173.     return (runticks = 0);
  174.     }
  175.  
  176.     ;
  177.     /* Save the stack pointer and critical registers */
  178. #asm
  179.     LD      HL,01   ;this will return 1 if swapped.
  180.     PUSH    HL      ;will be return value
  181.     PUSH    BC
  182.     PUSH    IX
  183.     LD      HL,0
  184.     ADD     HL,SP   ;get sp into hl
  185.     LD      (stkptr?),HL
  186. #endasm
  187.     udata.u_sp = stkptr;
  188.  
  189.     swrite();
  190.     /* Read the new process in, and return into its context. */
  191.     swapin(newp);
  192.  
  193.     /* We should never get here. */
  194.     panic("swapin failed");
  195. }
  196.  
  197.  
  198. /* This actually writes out the image */
  199. swrite()
  200. {
  201.     blkno_t blk;
  202.     blk = udata.u_ptab->p_swap;
  203.  
  204.     /* Start by writing out the user data. */
  205.  
  206.     /* The user data is written so that it is packed to the top of one block */
  207.     swapwrite(SWAPDEV, blk, 512, ((char *)(&udata+1))-512 );
  208.  
  209.     /* The user address space is written in two i/o operations,
  210.        one from 0x100 to the break, and then from the stack up. */
  211.     /* Notice that this might also include part or all of the user data,
  212.        but never anything above it. */
  213.  
  214.     swapwrite(SWAPDEV,
  215.             blk+1,
  216.             (((char *)(&udata+1))-PROGBASE) & ~511,
  217.             PROGBASE);
  218.  
  219. }
  220.  
  221. /* No automatics can be used past tempstack(); */
  222. swapin(pp)
  223. ptptr pp;
  224. {
  225.     static blkno_t blk;
  226.     static ptptr newp;
  227.  
  228.     di();
  229.     newp = pp;
  230.     blk = newp->p_swap;
  231.     ei();
  232.  
  233.     tempstack();
  234.  
  235.     swapread(SWAPDEV, blk, 512, ((char *)(&udata+1))-512 );
  236.  
  237.     /* The user address space is read in two i/o operations,
  238.        one from 0x100 to the break, and then from the stack up. */
  239.     /* Notice that this might also include part or all of the user data,
  240.        but never anything above it. */
  241.  
  242.     swapread(SWAPDEV,
  243.             blk+1,
  244.             (((char *)(&udata+1))-PROGBASE) & ~511,
  245.             PROGBASE);
  246.  
  247.     if (newp != udata.u_ptab)
  248.     panic("mangled swapin");
  249.     di();
  250.     newp->p_status = P_RUNNING;
  251.     runticks = 0;
  252.     ei();
  253.     /* Restore the registers */
  254.  
  255.     stkptr = udata.u_sp;
  256. #asm
  257.     LD      HL,(stkptr?)
  258.     LD      SP,HL
  259.     POP     IX
  260.     POP     BC
  261.     POP     HL
  262.     LD      A,H
  263.     OR      L
  264.     RET             ;return into the context of the swapped-in process
  265. #endasm
  266.  
  267. }
  268.  
  269.  
  270. /* Temp storage for dofork */
  271. int16 newid;
  272.  
  273. /* dofork implements forking.  */
  274. /* This function can have no arguments or auto variables */
  275.  
  276. dofork()
  277. {
  278.     static ptptr p;
  279.     ptptr ptab_alloc();
  280.  
  281.     ifnot (p = ptab_alloc())
  282.     {
  283.     udata.u_error = EAGAIN;
  284.     return(-1);
  285.     }
  286.     di();
  287.     udata.u_ptab->p_status = P_READY; /* Parent is READY */
  288.     newid = p->p_pid;
  289.     ei();
  290.  
  291.     /* Save the stack pointer and critical registers */
  292.     /* When the process is swapped back in, it will be as if
  293.     it returns with the value of the childs pid. */
  294.  
  295. #asm
  296.     LD      HL,(newid?)
  297.     PUSH    HL
  298.     PUSH    BC
  299.     PUSH    IX
  300.     LD      HL,0
  301.     ADD     HL,SP   ;get sp into hl
  302.     LD      (stkptr?),HL
  303. #endasm
  304.  
  305.     udata.u_sp = stkptr;
  306.     swrite();
  307.  
  308. #asm
  309.     POP     HL              ;repair stack pointer
  310.     POP     HL
  311.     POP     HL
  312. #endasm
  313.  
  314.     /* Make a new process table entry, etc. */
  315.     newproc(p);
  316.  
  317.     di();
  318.     runticks = 0;
  319.     p->p_status = P_RUNNING;
  320.     ei();
  321.     return (0);  /* Return to child */
  322. }
  323.  
  324.  
  325. /* Newproc fixes up the tables for the child of a fork */
  326.  
  327. newproc(p)
  328. ptptr p;    /* New process table entry */
  329. {
  330.     register char *j;
  331.  
  332.     /* Note that ptab_alloc clears most of the entry */
  333.     di();
  334.     p->p_swap = (p - ptab) * 65  + 1;  /* Allow 65 blocks per process */
  335.     p->p_status = P_RUNNING;
  336.  
  337.     p->p_pptr = udata.u_ptab;
  338.     p->p_ignored = udata.u_ptab->p_ignored;
  339.     p->p_uid = udata.u_ptab->p_uid;
  340.     udata.u_ptab = p;
  341.     bzero(&udata.u_utime,4*sizeof(time_t)); /* Clear tick counters */
  342.     ei();
  343.  
  344.     rdtime(&udata.u_time);
  345.     i_ref(udata.u_cwd);
  346.     udata.u_cursig = udata.u_error = 0;
  347.  
  348.     for (j=udata.u_files; j < (udata.u_files+UFTSIZE); ++j)
  349.     if (*j >= 0)
  350.        ++of_tab[*j].o_refs;
  351. }
  352.  
  353.  
  354.  
  355. /* This allocates a new process table slot, and fills
  356. in its p_pid field with a unique number.  */
  357.  
  358. ptptr
  359. ptab_alloc()
  360. {
  361.     register ptptr p;
  362.     register ptptr pp;
  363.     static int nextpid = 0;
  364.  
  365.     di();
  366.     for(p=ptab;p < ptab+PTABSIZE; ++p)
  367.     {
  368.     if (p->p_status == P_EMPTY)
  369.         goto found;
  370.     }
  371.     ei();
  372.     return(NULL);
  373.  
  374. found:
  375.  
  376.     /* See if next pid number is unique */
  377. nogood:
  378.     if (nextpid++ > 32000)
  379.     nextpid = 1;
  380.     for (pp=ptab; pp < ptab+PTABSIZE; ++pp)
  381.     {
  382.     if (pp->p_status != P_EMPTY && pp->p_pid == nextpid)
  383.         goto nogood;
  384.     }
  385.  
  386.     bzero(p,sizeof(struct p_tab));
  387.     p->p_pid = nextpid;
  388.     p->p_status = P_FORKING;
  389.     ei();
  390.     return (p);
  391. }
  392.  
  393.  
  394.  
  395. /* This is the clock interrupt routine.   Its job is to
  396. increment the clock counters, increment the tick count of the
  397. running process, and either swap it out if it has been in long enough
  398. and is in user space or mark it to be swapped out if in system space.
  399. Also it decrements the alarm clock of processes.
  400. This must have no automatic or register variables */
  401.  
  402. clk_int()
  403. {
  404.     static ptptr p;
  405.  
  406.     ifnot (in(0xf0))    /* See if clock actually interrupted, and turn it off */
  407.     return(0);
  408.  
  409.     /* Increment processes and global tick counters */
  410.     if (udata.u_ptab->p_status == P_RUNNING)
  411.     incrtick(udata.u_insys ? &udata.u_stime : &udata.u_utime);
  412.  
  413.     incrtick(&ticks);
  414.  
  415.     /* Do once-per-second things */
  416.  
  417.     if (++sec == TICKSPERSEC)
  418.     {
  419.     /* Update global time counters */
  420.     sec = 0;
  421.  
  422.     rdtod();  /* Update time-of-day */
  423.  
  424.     /* Update process alarm clocks */
  425.     for (p=ptab; p < ptab+PTABSIZE; ++p)
  426.     {
  427.         if (p->p_alarm)
  428.             ifnot(--p->p_alarm)
  429.                 sendsig(p,SIGALRM);
  430.     }
  431.     }
  432.  
  433.  
  434.     /* Check run time of current process */
  435.     if (++runticks >= MAXTICKS && !udata.u_insys)    /* Time to swap out */
  436.     {
  437.     udata.u_insys = 1;
  438.     inint = 0;
  439.     udata.u_ptab->p_status = P_READY;
  440.     swapout();
  441.     di();
  442.     udata.u_insys = 0;      /* We have swapped back in */
  443.     }
  444.  
  445.     return(1);
  446. }
  447.  
  448.  
  449.  
  450. extern int (*disp_tab[])();
  451.  
  452. static int j;
  453.  
  454. /* No auto vars here, so carry flag will be preserved */
  455. unix(argn3, argn2, argn1, argn, uret, callno)
  456. int16 argn3, argn2, argn1, argn;
  457. char *uret;
  458. int callno;
  459. {
  460.     udata.u_argn3 = argn3;
  461.     udata.u_argn2 = argn2;
  462.     udata.u_argn1 = argn1;
  463.     udata.u_argn = argn;
  464.     udata.u_retloc = uret;
  465.     udata.u_callno = callno;
  466.  
  467.     udata.u_insys = 1;
  468.     udata.u_error = 0;
  469.     ei();
  470.  
  471. #ifdef DEBUG
  472.     kprintf ("\t\t\t\t\tcall %d (%x, %x, %x)\n",callno,argn2,argn1,argn);
  473. #endif
  474.  
  475.     /* Branch to correct routine */
  476.  
  477.     udata.u_retval = (*disp_tab[udata.u_callno])();
  478.  
  479. #ifdef DEBUG
  480.     kprintf("\t\t\t\t\t\tcall %d ret %x err %d\n",
  481.     udata.u_callno,udata.u_retval, udata.u_error);
  482. #endif
  483.  
  484.  
  485.     chksigs();
  486.     di();
  487.     if (runticks >= MAXTICKS)
  488.     {
  489.     udata.u_ptab->p_status = P_READY;
  490.     swapout();
  491.     }
  492.     ei();
  493.  
  494.     udata.u_insys = 0;
  495.     calltrap();         /* Call trap routine if necessary */
  496.  
  497.     /* If an error, return errno with carry set */
  498.  
  499.     if (udata.u_error)
  500.     {
  501.     ;
  502. #asm
  503.     LD      HL, (udata? + ?OERR)
  504.     POP     BC              ;restore frame pointer
  505.     PUSH    BC
  506.     POP     IX
  507.     SCF
  508.     RET
  509. #endasm
  510.     ;
  511.     }
  512.  
  513.     return(udata.u_retval);
  514. }
  515.  
  516.  
  517.  
  518. /* This sees if the current process has any signals set, and deals with them */
  519. chksigs()
  520. {
  521.     register j;
  522.  
  523.     di();
  524.     ifnot (udata.u_ptab->p_pending)
  525.     {
  526.     ei();
  527.     return;
  528.     }
  529.  
  530.     for (j=1; j < NSIGS; ++j)
  531.     {
  532.     ifnot (sigmask(j) & udata.u_ptab->p_pending)
  533.         continue;
  534.     if (udata.u_sigvec[j] == SIG_DFL)
  535.     {
  536.         ei();
  537.         doexit(0,j);
  538.     }
  539.  
  540.     if (udata.u_sigvec[j] != SIG_IGN)
  541.     {
  542.         /* Arrange to call the user routine at return */
  543.         udata.u_ptab->p_pending &= !sigmask(j);
  544.         udata.u_cursig = j;
  545.     }
  546.     }
  547.     ei();
  548. }
  549.  
  550.  
  551. sendsig(proc,sig)
  552. ptptr proc;
  553. int16 sig;
  554. {
  555.     register ptptr p;
  556.  
  557.     if (proc)
  558.     ssig(proc,sig);
  559.     else
  560.     for (p=ptab; p < ptab+PTABSIZE; ++p)
  561.         if (p->p_status)
  562.             ssig(p,sig);
  563.     
  564. }
  565.  
  566. ssig(proc,sig)
  567. register ptptr proc;
  568. int16 sig;
  569. {
  570.     register stat;
  571.  
  572.     di();
  573.     ifnot(proc->p_status)
  574.     goto done;              /* Presumably was killed just now */
  575.  
  576.     if (proc->p_ignored & sigmask(sig))
  577.     goto done;
  578.  
  579.     stat = proc->p_status;
  580.     if (stat == P_PAUSE || stat == P_WAIT || stat == P_SLEEP)
  581.     proc->p_status = P_READY;
  582.  
  583.     proc->p_wait = (char *)NULL;
  584.     proc->p_pending |= sigmask(sig);
  585. done:
  586.     ei();
  587. }
  588.  
  589.  
  590.