home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 10: Diskmags / nf_archive_10.iso / MAGS / PURE_B / PBMAG22A.MSA / MINT095S.ZIP / SRC / PROC.C < prev    next >
C/C++ Source or Header  |  1987-04-22  |  13KB  |  598 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /* routines for handling processes */
  6.  
  7. #include "mint.h"
  8. #include "xbra.h"
  9.  
  10. static void do_wakeup_things P_((void));
  11.  
  12. extern short proc_clock;
  13.  
  14. /* global process variables */
  15. PROC *proclist;            /* list of all active processes */
  16. PROC *curproc;            /* current process        */
  17. PROC *rootproc;            /* pid 0 -- MiNT itself        */
  18. PROC *sys_q[NUM_QUEUES];
  19.  
  20. #define TIME_SLICE    1    /* number of 20ms ticks before process is
  21.                    pre-empted */
  22.  
  23.  
  24. /* macro for calculating number of missed time slices, based on a
  25.  * process' priority
  26.  */
  27. #define SLICES(pri)    (((pri) >= 0) ? 0 : -(pri))
  28.  
  29. extern FILESYS bios_filesys;
  30.  
  31. /*
  32.  * get a new process struct
  33.  */
  34. #define NPROC    5    /* get this many PROC structures at a time */
  35.  
  36. PROC *pfreelist = 0;
  37.  
  38. PROC *
  39. new_proc()
  40. {
  41.     PROC *p;
  42. #if 0
  43.     int i;
  44.  
  45.     if (pfreelist == 0) {
  46.         p = (PROC *)kmalloc(NPROC * SIZEOF(PROC));
  47.         if (!p) {
  48.             ALERT("new_proc: couldn't get a PROC structure");
  49.             return 0;
  50.         }
  51.         else {
  52.             for (i = 0; i < NPROC; i++) {
  53.                 p->gl_next = pfreelist;
  54.                 pfreelist = p;
  55.                 p++;
  56.             }
  57.         }
  58.     }
  59.     p = pfreelist;
  60.     pfreelist = p->gl_next;
  61.     p->gl_next = 0;
  62. #else
  63.     p = (PROC *)kmalloc(SIZEOF(PROC));
  64. #endif
  65.     return p;
  66. }
  67.  
  68. /*
  69.  * dispose of an old proc
  70.  */
  71.  
  72. void
  73. dispose_proc(p)
  74.     PROC *p;
  75. {
  76. #if 0
  77.     p->gl_next = pfreelist;
  78.     pfreelist = p;
  79. #else
  80.     kfree(p);
  81. #endif
  82. }
  83.  
  84. /*
  85.  * create a new process that is (practically) a duplicate of the
  86.  * current one
  87.  */
  88.  
  89. PROC *
  90. fork_proc()
  91. {
  92.     PROC *p;
  93.     int i;
  94.     FILEPTR *f;
  95.  
  96.     if (!(p = new_proc())) {
  97. nomem:
  98.         DEBUG("fork_proc: insufficient memory");
  99.         mint_errno = ENSMEM; return 0;
  100.     }
  101.  
  102.     *p = *curproc;    /* child shares most things with parent... */
  103.  
  104. /* ... except for these: */
  105.     p->ppid = curproc->pid;
  106.     p->pid = newpid();
  107.     p->sigpending = 0;
  108.     p->sysstack = (long)(p->stack + STKSIZE - 12);
  109.     p->ctxt[CURRENT].ssp = p->sysstack;
  110.     p->ctxt[SYSCALL].ssp = (long)(p->stack + ISTKSIZE);
  111.     p->alarmtim = 0;
  112.     p->curpri = p->pri;
  113.     p->slices = SLICES(p->pri);
  114.     p->starttime = timestamp;
  115.     p->startdate = datestamp;
  116.  
  117.     ((long *)p->sysstack)[1] = FRAME_MAGIC;
  118.     ((long *)p->sysstack)[2] = 0;
  119.     ((long *)p->sysstack)[3] = 0;
  120.  
  121.     p->usrtime = p->systime = p->chldstime = p->chldutime = 0;
  122.  
  123. /* copy open handles */
  124.     for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  125.         if ((f = p->handle[i]) != 0) {
  126.             if (f->flags & O_NOINHERIT)
  127.         /* oops, we didn't really want to copy this handle */
  128.                 p->handle[i] = 0;
  129.             else
  130.                 f->links++;
  131.         }
  132.     }
  133.  
  134. /* clear directory search info */
  135.     zero((char *)p->srchdta, NUM_SEARCH * SIZEOF(DTABUF *));
  136.  
  137. /* copy memory */
  138.     p->mem = (MEMREGION **) kmalloc(p->num_reg * SIZEOF(MEMREGION *));
  139.     if (!p->mem) {
  140.         dispose_proc(p);
  141.         goto nomem;
  142.     }
  143.     p->addr = (virtaddr *)kmalloc(p->num_reg * SIZEOF(virtaddr));
  144.     if (!p->addr) {
  145.         kfree(p->mem);
  146.         dispose_proc(p);
  147.         goto nomem;
  148.     }
  149.  
  150.     for (i = 0; i < curproc->num_reg; i++) {
  151.         if (p->mem[i] = curproc->mem[i])    /* yes, "=" is right */
  152.             p->mem[i]->links++;
  153.         p->addr[i] = curproc->addr[i];
  154.     }
  155.  
  156.     p->starttime = Tgettime();
  157.     p->startdate = Tgetdate();
  158.  
  159.     p->q_next = 0;
  160.     p->wait_q = 0;
  161.     p->gl_next = proclist;
  162.     proclist = p;            /* hook into the process list */
  163.     return p;
  164. }
  165.  
  166. /*
  167.  * initialize the process table
  168.  */
  169.  
  170. void
  171. init_proc()
  172. {
  173.     int i;
  174.     FILESYS *fs;
  175.     fcookie dir;
  176.     extern BASEPAGE **tosbp;    /* in main.c */
  177.  
  178.     rootproc = curproc = new_proc();
  179.     assert(curproc);
  180.  
  181.     zero((char *)curproc, (long)sizeof(PROC));
  182.  
  183.     curproc->ppid = -1;        /* no parent */
  184.     curproc->domain = DOM_TOS;    /* TOS domain */
  185.     curproc->sysstack = (long) (curproc->stack+STKSIZE-12);
  186.     curproc->magic = CTXT_MAGIC;
  187.     ((long *)curproc->sysstack)[1] = FRAME_MAGIC;
  188.     ((long *)curproc->sysstack)[2] = 0;
  189.     ((long *)curproc->sysstack)[3] = 0;
  190.  
  191.     curproc->base = (BASEPAGE *) *tosbp;
  192.  
  193.     strcpy(curproc->name, "MiNT");
  194.  
  195. /* get some memory */
  196.     curproc->mem = (MEMREGION **)kmalloc(NUM_REGIONS*SIZEOF(MEMREGION *));
  197.     curproc->addr = (virtaddr *)kmalloc(NUM_REGIONS*SIZEOF(virtaddr));
  198.     assert(curproc->mem && curproc->addr);
  199.  
  200. /* make sure it's filled with zeros */
  201.     zero((char *)curproc->addr, NUM_REGIONS * SIZEOF(virtaddr));
  202.     zero((char *)curproc->mem, NUM_REGIONS * SIZEOF(MEMREGION *));
  203.     curproc->num_reg = NUM_REGIONS;
  204.  
  205. /* get root and current directories for all drives */
  206.     for (i = 0; i < NUM_DRIVES; i++) {
  207.         if ((fs = drives[i]) != 0 && (*fs->root)(i, &dir) == E_OK) {
  208.                 curproc->root[i] = curproc->curdir[i] = dir;
  209.         } else {
  210.             curproc->root[i].fs = curproc->curdir[i].fs = 0;
  211.             curproc->root[i].dev = curproc->curdir[i].dev = i;
  212.         }
  213.     }
  214.  
  215. /* Set the correct drive. The current directory we
  216.  * set later, after all file systems have been loaded.
  217.  */
  218.  
  219.     curproc->curdrv = Dgetdrv();
  220.     proclist = curproc;
  221.  
  222.     curproc->umask = 0;
  223.  
  224. /*
  225.  * some more protection against job control; unless these signals are
  226.  * re-activated by a shell that knows about job control, they'll have
  227.  * no effect
  228.  */
  229.     curproc->sighandle[SIGTTIN] = curproc->sighandle[SIGTTOU] =
  230.         curproc->sighandle[SIGTSTP] = SIG_IGN;
  231.  
  232. /* set up some more per-process variables */
  233.     curproc->starttime = Tgettime();
  234.     curproc->startdate = Tgetdate();
  235.     if (has_bconmap)
  236.         curproc->bconmap = curbconmap;
  237.     else
  238.         curproc->bconmap = 1;
  239.  
  240.     curproc->logbase = (void *)Logbase();
  241.     curproc->criticerr = *((long (**) P_((long)))0x404L);
  242. }
  243.  
  244. /*
  245.  * reset all process priorities to their base level
  246.  * called once per second, so that cpu hogs can get _some_ time
  247.  * slices :-).
  248.  */
  249.  
  250. void
  251. reset_priorities()
  252. {
  253.     PROC *p;
  254.  
  255.     for (p = proclist; p; p = p->gl_next) {
  256.         p->curpri = p->pri;
  257.         p->slices = SLICES(p->curpri);
  258.     }
  259. }
  260.  
  261. /*
  262.  * more priority code stuff:
  263.  * run_next(p, slices): schedule process "p" to run next, with "slices"
  264.  *       initial time slices; "p" does not actually start running until
  265.  *       the next context switch
  266.  * fresh_slices(slices): give the current process "slices" more slices in
  267.  *       which to run
  268.  */
  269.  
  270. void
  271. run_next(p, slices)
  272.     PROC *p;
  273.     int slices;    /* BUG: currently ignored */
  274. {
  275.     p->slices = 0;
  276.     p->curpri = MAX_NICE;
  277.     p->wait_q = READY_Q;
  278.     p->q_next = sys_q[READY_Q];
  279.     sys_q[READY_Q] = p;
  280. }
  281.  
  282. void
  283. fresh_slices(slices)
  284.     int slices;
  285. {
  286.     curproc->slices = 0;
  287.     curproc->curpri = MAX_NICE+1;
  288.     proc_clock = slices;
  289. }
  290.  
  291. /*
  292.  * add a process to a wait (or ready) queue.
  293.  *
  294.  * processes go onto a queue in first in-first out order
  295.  */
  296.  
  297. void
  298. add_q(que, proc)
  299.     int que;
  300.     PROC *proc;
  301. {
  302.     PROC *q, **lastq;
  303.  
  304. /* "proc" should not already be on a list */
  305.     assert(proc->wait_q == 0);
  306.     assert(proc->q_next == 0);
  307.  
  308.     lastq = &sys_q[que];
  309.     q = *lastq;
  310.     while(q) {
  311.         lastq = &q->q_next;
  312.         q = *lastq;
  313.     }
  314.     *lastq = proc;
  315.     proc->wait_q = que;
  316.     if (que != READY_Q) {
  317.         proc->curpri = proc->pri;    /* reward the process */
  318.         proc->slices = SLICES(proc->curpri);
  319.     }
  320. }
  321.  
  322. /*
  323.  * remove a process from a queue
  324.  */
  325.  
  326. void
  327. rm_q(que, proc)
  328.     int que;
  329.     PROC *proc;
  330. {
  331.     PROC *q;
  332.     PROC *old = 0;
  333.  
  334.     assert(proc->wait_q == que);
  335.  
  336.     q = sys_q[que];
  337.     while (q && q != proc) {
  338.         old = q;
  339.         q = q->q_next;
  340.     }
  341.     if (q == 0)
  342.         FATAL("rm_q: unable to remove process from queue");
  343.  
  344.     if (old)
  345.         old->q_next = proc->q_next;
  346.     else
  347.         sys_q[que] = proc->q_next;
  348.  
  349.     proc->wait_q = 0;
  350.     proc->q_next = 0;
  351. }
  352.  
  353. /*
  354.  * preempt(): called by the vbl routine and/or the trap handlers when
  355.  * they detect that a process has exceeded its time slice and hasn't
  356.  * yielded gracefully. For now, it just does sleep(READY_Q); later,
  357.  * we might want to keep track of statistics or something.
  358.  */
  359.  
  360. void
  361. preempt()
  362. {
  363.     extern short bconbsiz;    /* in bios.c */
  364.  
  365.     if (bconbsiz)
  366.         (void)bflush();
  367.     else {
  368.         /* punish the pre-empted process */
  369.         if (curproc->curpri >= MIN_NICE)
  370.             curproc->curpri -= 1;
  371.     }
  372.     sleep(READY_Q, curproc->wait_cond);
  373. }
  374.  
  375. /*
  376.  * sleep(que, cond): put the current process on the given queue, then switch
  377.  * contexts. Before a new process runs, give it a fresh time slice. "cond"
  378.  * is the condition for which the process is waiting, and is placed in
  379.  * curproc->wait_cond
  380.  */
  381.  
  382. static void
  383. do_wakeup_things()
  384. {
  385. /*
  386.  * check for stack underflow, just in case
  387.  */
  388.     auto int foo;
  389.  
  390.     if ( curproc->pid != 0 &&
  391.          ((long)&foo) < (long)curproc->stack + ISTKSIZE + 512 ) {
  392.         ALERT("sleep: stack overflow");
  393.         handle_sig(SIGBUS);
  394.     }
  395. /*
  396.  * check processes for alarms
  397.  */
  398.  
  399.     checkalarms();
  400.  
  401.     check_time();        /* check for CPU limit exceeded */
  402.     check_sigs();        /* check for signals */
  403.  
  404.     proc_clock = TIME_SLICE;    /* get a fresh time slice */
  405.     curproc->slices = SLICES(curproc->curpri);
  406. }
  407.  
  408. void
  409. sleep(que, cond)
  410.     int que;
  411.     long cond;
  412. {
  413.     PROC *p;
  414.     short sr;
  415.     extern short kintr;    /* in bios.c */
  416.     extern short bconbsiz;
  417. #ifdef FASTTEXT
  418.     extern int hardscroll;    /* in fasttext.c */
  419. #endif
  420.     assert(bconbsiz == 0);
  421.  
  422. /*
  423.  * if there have been keyboard interrupts since our last sleep, check for
  424.  * special keys like CTRL-ALT-Fx
  425.  */
  426.  
  427.     if (kintr) {
  428.         (void)checkkeys();
  429.         kintr = 0;
  430.     }
  431.  
  432.     if (que == READY_Q && !sys_q[READY_Q]) {
  433. /* we're just going to wake up again right away! */
  434.         do_wakeup_things();
  435.         return;
  436.     }
  437.  
  438.     sr = spl7();
  439.  
  440.     add_q(que, curproc);
  441.     curproc->wait_cond = cond;
  442.  
  443.     if (!sys_q[READY_Q]) {
  444. /* hmm, no-one is ready to run. might be a deadlock, might not.
  445.  * first, try waking up any napping processes; if that doesn't work,
  446.  * run the root process, just so we have someone to charge time
  447.  * to.
  448.  */
  449.         wake(SELECT_Q, (long)&nap);
  450.         if (!sys_q[READY_Q]) {
  451.             p = rootproc;        /* pid 0 */
  452.             rm_q(p->wait_q, p);
  453.             add_q(READY_Q, p);
  454.         }
  455.     }
  456.  
  457. /*
  458.  * Walk through the ready list, to find what process should run next.
  459.  * Lower priority processes don't get to run every time through this
  460.  * loop; if "p->slices" is positive, it's the number of times that they
  461.  * will have to miss a turn before getting to run again
  462.  */
  463.     p = 0;
  464.  
  465.     while (!p) {
  466.         for (p = sys_q[READY_Q]; p; p = p->q_next) {
  467.             if (p->slices > 0)
  468.                 p->slices--;
  469.             else
  470.                 break;
  471.         }
  472.     }
  473.     rm_q(READY_Q, p);
  474.  
  475.     spl(sr);
  476.  
  477.     if (save_context(&(curproc->ctxt[CURRENT]))) {
  478.         if (curproc->q_next) {
  479.             DEBUG("sleep: why is curproc on a queue???");
  480.         }
  481. /*
  482.  * restore per-process variables here
  483.  */
  484. #ifdef FASTTEXT
  485.         if (!hardscroll)
  486. #endif
  487.             *((void **)0x44eL) = curproc->logbase;
  488.         do_wakeup_things();
  489.         return;
  490.     }
  491. /*
  492.  * save per-process variables here
  493.  */
  494. #ifdef FASTTEXT
  495.     if (!hardscroll)
  496. #endif
  497.         curproc->logbase = *((void **)0x44eL);
  498.     curproc->ctxt[CURRENT].regs[0] = 1;
  499.     curproc = p;
  500.     proc_clock = TIME_SLICE;    /* fresh time */
  501.     if ((p->ctxt[CURRENT].sr & 0x2000) == 0) {    /* user mode? */
  502.         leave_kernel();
  503.     }
  504.     assert(p->magic == CTXT_MAGIC);
  505.     restore_context(&(p->ctxt[CURRENT]));
  506. }
  507.  
  508. /*
  509.  * wake(que, cond): wake up all processes on the given queue that are waiting
  510.  * for the indicated condition
  511.  */
  512.  
  513. void
  514. wake(que, cond)
  515.     int que;
  516.     long cond;
  517. {
  518.     PROC *p;
  519.  
  520.     if (que == READY_Q) {
  521.         ALERT("wake: why wake up ready processes??");
  522.         return;
  523.     }
  524. top:
  525.     for(p = sys_q[que]; p; p = p->q_next) {
  526.         if (p->wait_cond == cond) {
  527.             rm_q(que, p);
  528.             add_q(READY_Q, p);
  529.             goto top;
  530.         }
  531.     }
  532. }
  533.  
  534. /*
  535.  * wakeselect(p): wake process p from a select() system call
  536.  * may be called by an interrupt handler or whatever
  537.  */
  538.  
  539. void
  540. wakeselect(param)
  541.     long param;
  542. {
  543.     PROC *p = (PROC *)param;
  544.     short s;
  545.  
  546.     s = spl7();    /* block interrupts */
  547.     if(p->wait_cond == (long)&wakeselect) {
  548.         p->wait_cond = 0;
  549.     }
  550.     if (p->wait_q == SELECT_Q) {
  551.         rm_q(SELECT_Q, p);
  552.         add_q(READY_Q, p);
  553.     }
  554.     spl(s);
  555. }
  556.  
  557. /*
  558.  * check_time(): check to see if process' time limit has been exceeded
  559.  */
  560.  
  561. void
  562. check_time()
  563. {
  564.     if (curproc->maxcpu) {
  565.         if (curproc->maxcpu <= curproc->systime + curproc->usrtime) {
  566.             DEBUG("cpu limit exceeded");
  567.             raise(SIGXCPU);
  568.         }
  569.     }
  570. }
  571.  
  572. /*
  573.  * dump out information about processes
  574.  */
  575.  
  576. /*
  577.  * kludge alert! In order to get the right pid printed by ALERT, we use
  578.  * curproc as the loop variable.
  579.  */
  580.  
  581. void
  582. DUMPPROC()
  583. {
  584.     PROC *p = curproc;
  585.  
  586.     for (curproc = proclist; curproc; curproc = curproc->gl_next) {
  587.         ALERT("queue %d cond %lx PC: %lx USP: %lx SSP: %lx SYSSP: %lx FRAME: %lx",
  588.         curproc->wait_q, curproc->wait_cond,
  589.         curproc->ctxt[SYSCALL].pc,
  590.         curproc->ctxt[SYSCALL].usp,
  591.         curproc->ctxt[SYSCALL].ssp,
  592.         curproc->sysstack,
  593.         ((long *)curproc->sysstack)[2]
  594.         );
  595.     }
  596.     curproc = p;        /* restore the real curproc */
  597. }
  598.