home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mint104s.zoo / mint.src / proc.c < prev    next >
C/C++ Source or Header  |  1993-03-08  |  14KB  |  649 lines

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