home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / mint / mint095s / dosmem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-03  |  23.0 KB  |  991 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /*
  6.  * GEMDOS emulation routines: these are for the GEMDOS system calls
  7.  * concerning allocating/freeing memory, including Pexec() (since
  8.  * this allocates memory) and Pterm() (since this, implicitly, frees
  9.  * it).
  10.  */
  11.  
  12. #include "mint.h"
  13.  
  14. int procdate, proctime;    /* set when any processes are created/destroyed */
  15.  
  16. static long do_vfork P_((int));
  17.  
  18. /*
  19.  * new call for TT TOS, for the user to inform DOS of alternate memory
  20.  * FIXME: we really shouldn't trust the user so completely
  21.  */
  22.  
  23. long
  24. m_addalt(start, size)
  25.     long start, size;
  26. {
  27.     if (!add_region(alt, start, size, M_ALT))
  28.         return EINTRN;
  29.     else
  30.         return 0;
  31. }
  32.  
  33. /*
  34.  * internal routine for doing Malloc on a particular memory map
  35.  */
  36.  
  37. long
  38. _do_malloc(map, size, mode)
  39.     MMAP map;
  40.     long size;
  41.     int mode;
  42. {
  43.     virtaddr v;
  44.     MEMREGION *m;
  45.     long maxsize, mleft;
  46.  
  47.     if (size == -1L) {
  48.         maxsize = max_rsize(map);
  49.         if (curproc->maxmem) {
  50.             mleft = curproc->maxmem - memused(curproc);
  51.             if (maxsize > mleft)
  52.                 maxsize = mleft;
  53.             if (maxsize < 0)
  54.                 maxsize = 0;
  55.         }
  56.     /* make sure to round down */
  57.         return maxsize & ~MASKBITS;
  58.     }
  59.  
  60. /* special case: Malloc(0) should always return 0 */
  61.     if (size == 0)
  62.         return 0;
  63.  
  64.     if (curproc->maxmem) {        /* memory limit? */
  65.         if (size > curproc->maxmem - memused(curproc)) {
  66.             DEBUG("malloc: memory request would exceed limit");
  67.             return 0;
  68.         }
  69.     }
  70.  
  71.     m = get_region(map, size);
  72.     if (!m) {
  73.         DEBUG("malloc: out of memory");
  74.         return 0;
  75.     }
  76.     v = attach_region(curproc, m);
  77.     if (!v) {
  78.         m->links = 0;
  79.         free_region(m);
  80.         return 0;
  81.     }
  82. /* NOTE: get_region returns a region with link count 1; since attach_region
  83.  * increments the link count, we have to remember to decrement the count
  84.  * to correct for this.
  85.  */
  86.     m->links--;
  87.     if ((mode & F_KEEP)) {    /* request for permanent memory */
  88.         m->mflags |= M_KEEP;
  89.     }
  90.     return (long)v;
  91. }
  92.  
  93. long
  94. m_xalloc(size, mode)
  95.     long size;
  96.     int mode;
  97. {
  98.     long r, r1;
  99.  
  100.     TRACE("Mxalloc(%ld,%x)",size,mode);
  101.     if ( (mode & 8) ) {
  102.         DEBUG("Unsupported Mxalloc mode");
  103.         return 0;        /* future expansion */
  104.     }
  105.     if ( (mode&3) == 0)
  106.         return _do_malloc(core, size, mode);
  107.     else if ( (mode&3) == 1)
  108.         return _do_malloc(alt, size, mode);
  109.     else if (size == -1) {
  110.         /* modes 2 and 3 are the same for for size -1 */
  111.         r = _do_malloc(core, -1L, mode);
  112.         r1 = _do_malloc(alt, -1L, mode);
  113.         if (r > r1) return r;
  114.         else return r1;
  115.     }
  116.     else if ( (mode&3) == 2) {
  117.         r = _do_malloc(core, size, mode);
  118.         if (r == 0) return _do_malloc(alt, size, mode);
  119.         else return r;
  120.     }
  121.     else /* if ( (mode&3) == 3) */ {
  122.         r = _do_malloc(alt, size, mode);
  123.         if (r == 0) return _do_malloc(core, size, mode);
  124.         else return r;
  125.     }
  126.  
  127.     DEBUG("Mxalloc: bad request??");
  128.     return 0;
  129. }
  130.  
  131. long
  132. m_alloc(size)
  133.     long size;
  134. {
  135.     long r;
  136.  
  137.     TRACE("Malloc(%lx)", size);
  138.     if (curproc->memflags & F_ALTALLOC)
  139.         r = m_xalloc(size, 3);
  140.     else
  141.         r = m_xalloc(size, 0);
  142.     TRACE("Malloc: returning %lx", r);
  143.     return r;
  144. }
  145.  
  146. long
  147. m_free(block)
  148.     virtaddr block;
  149. {
  150.     MEMREGION *m;
  151.     int i;
  152.  
  153.     TRACE("Mfree(%lx)", block);
  154.     if (!block) {
  155.         DEBUG("Mfree: null pointer");
  156.         return EIMBA;
  157.     }
  158.  
  159. /* search backwards so that most recently allocated incarnations of
  160.    shared memory blocks are freed first (this doesn't matter very often)
  161.  */
  162.  
  163.     for (i = curproc->num_reg - 1; i >= 0; i--) {
  164.         if (curproc->addr[i] == block) {
  165.             m = curproc->mem[i];
  166.             assert(m != NULL);
  167.             assert(m->loc == (long)block);
  168.             curproc->mem[i] = 0;
  169.             curproc->addr[i] = 0;
  170.             m->links--;
  171.             if (m->links == 0) {
  172.                 free_region(m);
  173.             }
  174.             return 0;
  175.         }
  176.     }
  177.  
  178. /* hmmm... if we didn't find the region, perhaps it's a global
  179.  * one (with the M_KEEP flag set) belonging to a process that
  180.  * terminated
  181.  */
  182.     for (i = rootproc->num_reg - 1; i >= 0; i--) {
  183.         if (rootproc->addr[i] == block) {
  184.             m = rootproc->mem[i];
  185.             assert(m != NULL);
  186.             assert(m->loc == (long)block);
  187.             if (!(m->mflags & M_KEEP))
  188.                 continue;
  189.             rootproc->mem[i] = 0;
  190.             rootproc->addr[i] = 0;
  191.             m->links--;
  192.             if (m->links == 0) {
  193.                 free_region(m);
  194.             }
  195.             return 0;
  196.         }
  197.     }
  198.  
  199.  
  200.     DEBUG("Mfree: bad address %lx", block);
  201.     return EIMBA;
  202. }
  203.  
  204. long
  205. m_shrink(dummy, block, size)
  206.     int dummy;
  207.     virtaddr block;
  208.     long size;
  209. {
  210.     MEMREGION *m;
  211.     int i;
  212.  
  213.     TRACE("Mshrink: %lx to %ld", block, size);
  214.     if (!block) {
  215.         DEBUG("Mshrink: null pointer");
  216.         return EIMBA;
  217.     }
  218.  
  219.     for (i = 0; i < curproc->num_reg; i++) {
  220.         if (curproc->addr[i] == block) {
  221.             m = curproc->mem[i];
  222.             assert(m != NULL);
  223.             assert(m->loc == (long)block);
  224.             return shrink_region(m, size);
  225.         }
  226.     }
  227.     DEBUG("Mshrink: bad address (%lx)", block);
  228.     return EIMBA;
  229. }
  230.  
  231. long
  232. p_exec(mode, ptr1, ptr2, ptr3)
  233.     int mode;
  234.     void *ptr1, *ptr2, *ptr3;
  235. {
  236.     MEMREGION *base, *env = 0;   /* assignment suppress spurious warning */
  237.     PROC *p = 0;
  238.     long r, flags = 0;
  239.     int i;
  240.     char mkbase = 0, mkload = 0, mkgo = 0, mkwait = 0, mkfree = 0;
  241.     char overlay = 0;
  242.     char thread = 0;
  243.     char mkname = 0, *newname, *lastslash;
  244.     char localname[PNAMSIZ+1];
  245.     XATTR xattr;
  246.  
  247.     switch(mode) {
  248.     case 0:
  249.         mkwait = 1;        /* fall through */
  250.     case 100:
  251.         mkload = mkgo = mkfree = 1;
  252.         mkname = 1;
  253.         TRACE("Pexec(%d,%s,\"%s\")", mode, ptr1, ptr2);
  254.         break;
  255.     case 200:            /* overlay current process */
  256.         mkload = mkgo = 1;
  257.         overlay = mkname = 1;
  258.         TRACE("Pexec(%d,%s,\"%s\")", mode, ptr1, ptr2);
  259.         break;
  260.     case 3:
  261.         mkload = 1;
  262.         TRACE("Pexec(%d,%s,\"%s\")", mode, ptr1, ptr2);
  263.         break;
  264.     case 6:
  265.         mkfree = 1;
  266.         /* fall through */
  267.     case 4:
  268.         mkwait = mkgo = 1;
  269.         TRACE("Pexec(%d,%lx)", mode, ptr2);
  270.         break;
  271.     case 106:
  272.         mkfree = 1;        /* fall through */
  273.     case 104:
  274.         thread = (mode == 104);
  275.         mkgo = 1;
  276.         mkname = (ptr1 != 0);
  277.         TRACE("Pexec(%d,%s,%lx)", mode, ptr1, ptr2);
  278.         break;
  279.     case 7:
  280.         flags = (long)ptr1;    /* set program flags */
  281.                     /* and fall through */
  282.     case 5:
  283.         mkbase = 1;
  284.         TRACE("Pexec(%d,%lx,\"%s\")", mode, ptr1, ptr2);
  285.         break;
  286.     default:
  287.         DEBUG("Pexec: bad mode %d", mode);
  288.         return EINVFN;
  289.     }
  290.  
  291. /* in most cases, we'll want a process struct to exist,
  292.  * so make sure one is around. Note that we must be
  293.  * careful to free it later!
  294.  */
  295.  
  296.     p = 0;
  297.     if (!overlay) {
  298.         p = new_proc();
  299.         if (!p) {
  300.             DEBUG("Pexec: couldn't get a PROC struct");
  301.             return ENSMEM;
  302.         }
  303.     }
  304.  
  305.  
  306.     if (mkload || mkbase) {
  307.         env = create_env((char *)ptr3);
  308.         if (!env) {
  309.             DEBUG("Pexec: unable to create environment");
  310.             if (p) dispose_proc(p);
  311.             return ENSMEM;
  312.         }
  313.     }
  314.  
  315.     if (mkbase) {
  316.         base = create_base((char *)ptr2, env, flags, 0L);
  317.         if (!base) {
  318.             DEBUG("Pexec: unable to create basepage");
  319.             detach_region(curproc, env);
  320.             if (p) dispose_proc(p);
  321.             return ENSMEM;
  322.         }
  323.     }
  324.     else if (mkload) {
  325.         base = load_region((char *)ptr1, env, (char *)ptr2, &xattr);
  326.         if (!base) {
  327.             DEBUG("Pexec: load_region failed");
  328.             detach_region(curproc, env);
  329.             if (p) dispose_proc(p);
  330.             return mint_errno;
  331.         }
  332.     }
  333.     else {    /* mode == 4 or 6 or 104 or 106 -- just go */
  334.         base = addr2mem((virtaddr)ptr2);
  335.         if (base)
  336.             env = addr2mem(*(void **)(base->loc + 0x2c));
  337.         else
  338.             env = 0;
  339.         if (!env) {
  340.             if (p) dispose_proc(p);
  341.             return EIMBA;
  342.         }
  343.     }
  344.  
  345. /* make a local copy of the name, in case we are overlaying the current
  346.  * process
  347.  */
  348.     if (mkname) {
  349.         lastslash = 0;
  350.         newname = ptr1;
  351.         while (*newname) {
  352.             if (*newname == '\\' || *newname == '/')
  353.                 lastslash = newname;
  354.             ++newname;
  355.         }
  356.         if (!lastslash)
  357.             lastslash = ptr1;
  358.         else
  359.             lastslash++;
  360.  
  361.         i = 0; newname = localname;
  362.         while (i++ < PNAMSIZ) {
  363.             if (*lastslash == '.' || *lastslash == 0) {
  364.                 *newname = 0; break;
  365.             }
  366.             else
  367.                 *newname++ = *lastslash++;
  368.         }
  369.         *newname = 0;
  370.     }
  371.  
  372.     if (p) {
  373.     /* free the PROC struct so fork_proc will succeed */
  374.         dispose_proc(p);
  375.         p = 0;
  376.     }
  377.  
  378.     if (mkgo) {
  379.         BASEPAGE *b;
  380.  
  381.         if (overlay) {
  382.             p = curproc;
  383.         /* make sure that exec_region doesn't free the base and env */
  384.             base->links++;
  385.             env->links++;
  386.         }
  387.         else {
  388.             p = fork_proc();
  389.         }
  390.         if (!p) {
  391.             if (mkbase) {
  392.                 detach_region(curproc, base);
  393.                 detach_region(curproc, env);
  394.             }
  395.             return mint_errno;
  396.         }
  397.  
  398.         if (mkload && mkgo) {        /* setuid/setgid is OK */
  399.             if (xattr.mode & S_ISUID)
  400.                 p->euid = xattr.uid;
  401.             if (xattr.mode & S_ISGID)
  402.                 p->egid = xattr.gid;
  403.         }
  404.         (void)exec_region(p, base, thread);
  405.         attach_region(p, env);
  406.         attach_region(p, base);
  407.  
  408.     /* tell the child who the parent was */
  409.         b = (BASEPAGE *)base->loc;
  410.         if (!overlay)
  411.             b->p_parent = (BASEPAGE *)curproc->base;
  412.  
  413.         if (mkname) {
  414.     /* interesting coincidence -- if a process needs a name, it usually
  415.      * needs to have its domain reset to DOM_TOS. Doing it this way
  416.      * (instead of doing it in exec_region) means that Pexec(4,...)
  417.      * can be used to create new threads of execution which retain
  418.      * the same domain.
  419.      */
  420.             if (!thread)
  421.                 p->domain = DOM_TOS;
  422.  
  423.     /* put in the new process name we saved above */
  424.             strcpy(p->name, localname);
  425.         }
  426.  
  427.     /* set the time/date stamp of u:\proc */
  428.         proctime = timestamp;
  429.         procdate = datestamp;
  430.  
  431.         if (overlay) {
  432.             /* correct for temporary increase in links (see above) */
  433.             base->links--;
  434.             env->links--;
  435.             /* let our parent run, if it Vfork'd() */
  436.             if ( (p = pid2proc(curproc->ppid)) != 0 ) {
  437.                 if (p->wait_q == WAIT_Q && 
  438.                     p->wait_cond == (long)curproc) {
  439.                     rm_q(WAIT_Q, p);
  440.                     add_q(READY_Q, p);
  441.                 }
  442.             }
  443.  
  444.         /* OK, let's run our new code */
  445.         /* we guarantee ourselves at least 2 timeslices to do an Mshrink */
  446.             assert(curproc->magic == CTXT_MAGIC);
  447.             fresh_slices(2);
  448.             leave_kernel();
  449.             restore_context(&(curproc->ctxt[CURRENT]));
  450.         }
  451.         else {
  452.     /* we want this process to run ASAP */
  453.     /* so we temporarily give it high priority and put it first on the
  454.      * run queue
  455.      */
  456.             run_next(p, 2);
  457.         }
  458.     }
  459.  
  460.     if (mkfree) {
  461.         detach_region(curproc, base);
  462.         detach_region(curproc, env);
  463.     }
  464.  
  465.     if (mkwait) {
  466.         long oldsigint, oldsigquit;
  467.  
  468.         oldsigint = curproc->sighandle[SIGINT];
  469.         oldsigquit = curproc->sighandle[SIGQUIT];
  470.         curproc->sighandle[SIGINT] =
  471.              curproc->sighandle[SIGQUIT] = SIG_IGN;
  472.  
  473.         i = p->pid;
  474.         for(;;) {
  475.             r = p_wait3(0, (long *)0);
  476.             if (r < 0) {
  477.                 ALERT("p_exec: wait error");
  478.                 return EINTRN;
  479.             }
  480.             if ( i == ((r&0xffff0000) >> 16) ) {
  481.                 TRACE("leaving Pexec with child return code");
  482.                 r = r & 0x0000ffff;
  483.                 break;
  484.             }
  485.             if (curproc->pid)
  486.                 DEBUG("Pexec: wrong child found");
  487.         }
  488.         curproc->sighandle[SIGINT] = oldsigint;
  489.         curproc->sighandle[SIGQUIT] = oldsigquit;
  490.         return r;
  491.     }
  492.     else if (mkgo) {
  493.         yield();    /* let the new process run */
  494.         return p->pid;
  495.     } else {
  496.         TRACE("leaving Pexec with basepage address %lx", base->loc);
  497.         return base->loc;
  498.     }
  499. }
  500.  
  501. /*
  502.  * terminate a process, with return code "code". If que == ZOMBIE_Q, free
  503.  * all resources attached to the child; if que == TSR_Q, free everything
  504.  * but memory
  505.  */
  506.  
  507. long
  508. terminate(code, que)
  509.     int code, que;
  510. {
  511.     extern PROC *dlockproc[];    /* in dosdir.c */
  512.     PROC *p;
  513.     FILEPTR *fp;
  514.     MEMREGION *m;
  515.     int  i, wakemint = 0;
  516.     extern short bconbsiz;    /* in bios.c */
  517.  
  518.     if (bconbsiz)
  519.         (void) bflush();
  520.  
  521.     assert(que == ZOMBIE_Q || que == TSR_Q);
  522.  
  523.     if (curproc->pid == 0) {
  524.         FATAL("attempt to terminate MiNT");
  525.     }
  526.  
  527. /* cancel all pending timeouts for this process */
  528.     cancelalltimeouts();
  529. /* cancel alarm clock */
  530.     curproc->alarmtim = 0;
  531.  
  532. /* release any drives locked by Dlock */
  533.     for(i = 0; i < NUM_DRIVES; i++) {
  534.         if (dlockproc[i] == curproc) {
  535.             dlockproc[i] = 0;
  536.             changedrv(i);
  537.         }
  538.     }
  539.  
  540. /* release the controlling terminal, if we're a process group leader */
  541.     fp = curproc->handle[-1];
  542.     if (fp && is_terminal(fp) && curproc->pgrp == curproc->pid) {
  543.         struct tty *tty = (struct tty *)fp->devinfo;
  544.         if (curproc->pgrp == tty->pgrp)
  545.             tty->pgrp = 0;
  546.     }
  547.  
  548. /* close all files */
  549.     for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  550.         if ((fp = curproc->handle[i]))
  551.             do_close(fp);
  552.         curproc->handle[i] = 0;
  553.     }
  554.  
  555. /* close any unresolved Fsfirst/Fsnext directory searches */
  556.     for (i = 0; i < NUM_SEARCH; i++) {
  557.         if (curproc->srchdta[i]) {
  558.             DIR *dirh = &curproc->srchdir[i];
  559.             (*dirh->fc.fs->closedir)(dirh);
  560.         }
  561.     }
  562.  
  563. /* release all semaphores owned by this process */
  564.     free_semaphores(curproc->pid);
  565.  
  566. /* free all memory */
  567.     if (que == ZOMBIE_Q) {
  568.         for (i = curproc->num_reg - 1; i >=0; i--) {
  569.             m = curproc->mem[i];
  570.             curproc->mem[i] = 0; curproc->addr[i] = 0;
  571.             if (m) {
  572.         /* don't free specially allocated memory */
  573.                 if (m->mflags & M_KEEP) {
  574.                     if (curproc != rootproc)
  575.                         attach_region(rootproc, m);
  576.                 }
  577.                 m->links--;
  578.                 if (m->links == 0) {
  579.                     free_region(m);
  580.                 }
  581.             }
  582.         }
  583.         kfree(curproc->mem); kfree(curproc->addr);
  584.         curproc->mem = 0;
  585.         curproc->addr = 0;
  586.         curproc->num_reg = 0;
  587.     }
  588. /*    else
  589.          make TSR process non-swappable */
  590.  
  591. /*
  592.  * make sure that any open files that refer to this process are
  593.  * closed
  594.  */
  595.     changedrv(PROC_BASE_DEV | curproc->pid);
  596.  
  597. /* find our parent (if parent not found, then use process 0 as parent
  598.  * since that process is constantly in a wait loop)
  599.  */
  600.  
  601.     p = pid2proc(curproc->ppid);
  602.     if (!p) {
  603.         TRACE("terminate: parent not found");
  604.         p = pid2proc(0);
  605.     }
  606.  
  607. /* NOTE: normally just post_sig is sufficient for sending a signal; but
  608.  * in this particular case, we have to worry about processes that are
  609.  * blocking all signals because they Vfork'd and are waiting for us to
  610.  * finish (which is indicated by a wait_cond matching our PROC
  611.  * structure), and also processes that are ignoring SIGCHLD but are
  612.  * waiting for us.
  613.  */
  614.     if (p->wait_q == WAIT_Q && 
  615.         (p->wait_cond == (long)curproc || p->wait_cond == (long)&p_wait3) ) {
  616.         TRACE("terminate: waking up parent");
  617.         rm_q(WAIT_Q, p);
  618.         add_q(READY_Q, p);
  619.     }
  620.     post_sig(p, SIGCHLD);        /* inform of process termination */
  621.  
  622. /* find our children, and orphan them */
  623.     i = curproc->pid;
  624.     for (p = proclist; p; p = p->gl_next) {
  625.         if (p->ppid == i) {
  626.             p->ppid = 0;    /* have the system adopt it */
  627.             if (p->wait_q == ZOMBIE_Q) 
  628.                 wakemint = 1;    /* we need to wake proc. 0 */
  629.         }
  630.     }
  631.  
  632.     if (wakemint) {
  633.         p = rootproc;        /* pid 0 */
  634.         if (p->wait_q == WAIT_Q) {
  635.             rm_q(WAIT_Q, p);
  636.             add_q(READY_Q, p);
  637.         }
  638.     }
  639.  
  640. /* this makes sure that our children are inherited by the system;
  641.  * plus, it may help avoid problems if somehow a signal gets
  642.  * through to us
  643.  */
  644.     for(i = 0; i < NSIG; i++)
  645.         curproc->sighandle[i] = SIG_IGN;
  646.  
  647. /* finally, reset the time/date stamp for u:\proc */
  648.     proctime = timestamp;
  649.     procdate = datestamp;
  650.  
  651.     for(;;) {
  652.         sleep(que, (long)(unsigned)code);
  653. /* we shouldn't ever get here */
  654.         FATAL("terminate: sleep woke up when it shouldn't have");
  655.     }
  656.     return 0;    /* fake */
  657. }
  658.  
  659. /*
  660.  * TOS process termination entry points:
  661.  * p_term terminates the process with extreme prejuidice
  662.  * p_termres lets the process hang around resident in memory, after
  663.  * shrinking its transient program area to "save" bytes
  664.  */
  665.  
  666. long
  667. p_term(code)
  668.     int code;
  669. {
  670.     CONTEXT *syscall;
  671.  
  672.     TRACE("Pterm(%d)", code);
  673. /* call the process termination vector */
  674.     syscall = &curproc->ctxt[SYSCALL];
  675.  
  676.     if (syscall->term_vec != (long)rts) {
  677.         TRACE("term_vec: user has something to do");
  678. /*
  679.  * we handle the termination vector just like Supexec(), by
  680.  * sending signal 0 to the process. See supexec() in xbios.c for details.
  681.  * Note that we _always_ want to unwind the signal stack, hence the
  682.  * curproc->sigmask setting here.
  683.  */
  684.         curproc->sigmask |= 1L;
  685.         (void)supexec((Func)syscall->term_vec, 0L, 0L, 0L, 0L, 
  686.                 (long)code);
  687. /*
  688.  * if we arrive here, continue with the termination...
  689.  */
  690.     }
  691.     return terminate(code, ZOMBIE_Q);
  692. }
  693.  
  694. long
  695. p_term0()
  696. {
  697.     return p_term(0);
  698. }
  699.  
  700. long
  701. p_termres(save, code)
  702.     long save;
  703.     int code;
  704. {
  705.     MEMREGION *m;
  706.  
  707.     TRACE("Ptermres(%ld, %d)", save, code);
  708.     m = curproc->mem[1];    /* should be the basepage (0 is env.) */
  709.     if (m) {
  710.         (void)shrink_region(m, save);
  711.     }
  712.     return terminate(code, TSR_Q);
  713. }
  714.  
  715. /*
  716.  * routine for waiting for children to die. Return has the pid of the
  717.  * found child in the high word, and the child's exit code in
  718.  * the low word. If no children exist, return "File Not Found".
  719.  * If (nohang & 1) is nonzero, then return a 0 immediately if we have
  720.  * no dead children but some living ones that we still have to wait
  721.  * for. If (nohang & 2) is nonzero, then we return any stopped
  722.  * children; otherwise, only children that have exited or are stopped
  723.  * due to a trace trap are returned.
  724.  * If "rusage" is non-zero and a child is found, put the child's
  725.  * resource usage into it (currently only the user and system time are
  726.  * sent back) 
  727.  */
  728.  
  729. long
  730. p_wait3(nohang, rusage)
  731.     int nohang;
  732.     long *rusage;
  733. {
  734.     long r;
  735.     PROC *p, *q;
  736.     int ourpid;
  737.     int found;
  738.  
  739.     TRACE("Pwait3");
  740.     ourpid = curproc->pid;
  741.  
  742. /* if there are terminated children, clean up and return their info;
  743.  * if there are children, but still running, wait for them;
  744.  * if there are no children, return an error
  745.  */
  746.  
  747.     do {
  748. /* look for any children */
  749.         found = 0;
  750.         for (p = proclist; p; p = p->gl_next) {
  751.             if (p->ppid == ourpid) {
  752.                 found++;
  753.                 if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
  754.                     break;
  755.  
  756. /* p->wait_cond == 0 if a stopped process has already been waited for */
  757.                 if (p->wait_q == STOP_Q && p->wait_cond) {
  758.                     if ((nohang & 2) ||
  759.                     ((p->wait_cond&0x1f00) == SIGTRAP<<8))
  760.                         break;
  761.                 }
  762.             }
  763.         }
  764.         if (!p) {
  765.             if (found) {
  766.                 if (nohang & 1)
  767.                     return 0;
  768.                 if (curproc->pid)
  769.                     TRACE("Pwait3: going to sleep");
  770.                 sleep(WAIT_Q, (long)&p_wait3);
  771.             }
  772.             else {
  773.                 DEBUG("Pwait3: no children found");
  774.                 return EFILNF;
  775.             }
  776.         }
  777.     } while (!p);
  778.  
  779. /* OK, we've found our child */
  780. /* calculate the return code from the child's exit code and pid */
  781.     r = (((unsigned long)p->pid) << 16) | (p->wait_cond & 0x0000ffff);
  782.  
  783. /* check resource usage */
  784.     if (rusage) {
  785.         *rusage++ = p->usrtime;
  786.         *rusage++ = p->systime;
  787.     }
  788.  
  789. /* add child's resource usage to parent's */
  790.     if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q) {
  791.         curproc->chldstime += p->systime;
  792.         curproc->chldutime += p->usrtime;
  793.     }
  794.  
  795. /* if it was a TSR, mark it as having been found and return */
  796.     if (p->wait_q == TSR_Q) {
  797.         p->ppid = -1;
  798.         return r;
  799.     }
  800.  
  801. /* if it was stopped, mark it as having been found and again return */
  802.     if (p->wait_q == STOP_Q) {
  803.         p->wait_cond = 0;
  804.         return r;
  805.     }
  806.  
  807. /* it better have been on the ZOMBIE queue from here on in... */
  808.     assert(p->wait_q == ZOMBIE_Q);
  809.     assert(p != curproc);
  810.  
  811. /* take the child off both the global and ZOMBIE lists */
  812.     rm_q(ZOMBIE_Q, p);
  813.  
  814.     if (proclist == p) {
  815.         proclist = p->gl_next;
  816.         p->gl_next = 0;
  817.     }
  818.     else {
  819.         q = proclist;
  820.         while(q && q->gl_next != p)
  821.             q = q->gl_next;
  822.         assert(q);
  823.         q->gl_next = p->gl_next;
  824.         p->gl_next = 0;
  825.     }
  826.  
  827.     dispose_proc(p);    /* free the PROC structure */
  828.  
  829.     return r;
  830. }
  831.  
  832. /* p_wait: block until a child has exited, and don't worry about
  833.    resource stats. this is provided as a convenience, and to maintain
  834.    compatibility with existing binaries (yes, I'm lazy...). we could
  835.    make do with Pwait3().
  836.  */
  837.  
  838. long
  839. p_wait()
  840. {
  841.     return p_wait3(2, (long *)0);
  842. }
  843.  
  844. /*
  845.  * do_vfork(save): create a duplicate of  the current process. This is
  846.  * essentially a vfork() algorithm, except that if (save == 1) the
  847.  * parent's address space is saved, and then restored when the process
  848.  * is made runnable again. The parent is suspended until either the child
  849.  * process (the duplicate) exits or does a Pexec which overlays its
  850.  * memory space.
  851.  *
  852.  * "txtsize" is the size of the process' TEXT area, if it has a valid one;
  853.  * this is part of the second memory region attached (the basepage one)
  854.  * and need not be saved (we assume processes don't write on their own
  855.  * code segment)
  856.  */
  857.  
  858. static long
  859. do_vfork(save)
  860.     int save;
  861. {
  862.     PROC *p;
  863.     long sigmask;
  864.     MEMREGION *m, *savemem = 0;
  865.     long savesize, txtsize;
  866.     int i;
  867.     char *saveplace;
  868.  
  869.     p = fork_proc();
  870.     if (!p) {
  871.         DEBUG("do_vfork: couldn't get new PROC struct");
  872.         return mint_errno;
  873.     }
  874. /* set u:\proc time+date */
  875.     proctime = timestamp;
  876.     procdate = datestamp;
  877.  
  878. /*
  879.  * maybe save the parent's address space
  880.  */
  881.     txtsize = p->txtsize;
  882.  
  883.     if (save) {
  884.         TRACE("do_vfork: saving parent");
  885.         savesize = memused(curproc) - txtsize;
  886.         assert(savesize >= 0);
  887.  
  888.         saveplace = (char *)alloc_region(alt, savesize);
  889.         if (!saveplace)
  890.             saveplace = (char *)alloc_region(core, savesize);
  891.  
  892.         if (!saveplace) {
  893.             DEBUG("do_vfork: can't save parent's memory");
  894.             p->ppid = 0;        /* abandon the child */
  895.             post_sig(p, SIGKILL);    /* then kill it */
  896.             p->ctxt[CURRENT].pc = (long)check_sigs;
  897.                 /* just to make sure it dies */
  898.             p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  899.             p->pri = MAX_NICE+1;
  900.             run_next(p, 1);
  901.             yield();
  902.             return ENSMEM;
  903.         }
  904.         savemem = addr2mem((virtaddr)saveplace);
  905.         assert(savemem);
  906.         for (i = 0; i < curproc->num_reg; i++) {
  907.             m = curproc->mem[i];
  908.             if (m && m != savemem) {
  909.                 if (i != 1 || txtsize == 0) {
  910.                     quickmove(saveplace, (char *)m->loc, m->len);
  911.                     saveplace += m->len;
  912.                 }
  913.                 else {
  914.                     quickmove(saveplace, (char *)m->loc+txtsize,
  915.                     m->len - txtsize);
  916.                     saveplace += m->len - txtsize;
  917.                 }
  918.             }
  919.         }
  920.     }
  921.                 
  922.     p->ctxt[CURRENT] = p->ctxt[SYSCALL];
  923.     p->ctxt[CURRENT].regs[0] = 0;    /* child returns a 0 from call */
  924.     p->ctxt[CURRENT].sr &= ~(0x2000); /* child must be in user mode */
  925. #if 0        /* set up in fork_proc() */
  926.     p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  927. #endif
  928.  
  929. /* watch out for job control signals, since our parent can never wake
  930.  * up to respond to them. solution: block them; exec_region (in mem.c)
  931.  * clears the signal mask, so an exec() will unblock them.
  932.  */
  933.     p->sigmask |= (1L << SIGTSTP) | (1L << SIGTTIN) | (1L << SIGTTOU);
  934.  
  935.     TRACE("do_vfork: parent going to sleep, wait_cond == %lx",
  936.         (long)p);
  937.  
  938. /* WARNING: This sleep() must absolutely not wake up until the child
  939.  * has released the memory space correctly. That's why we mask off
  940.  * all signals.
  941.  */
  942.     sigmask = curproc->sigmask;
  943.     curproc->sigmask = ~(1L << SIGKILL);
  944.  
  945.     add_q(READY_Q, p);        /* put it on the ready queue */
  946.     sleep(WAIT_Q, (long)p);            /* while we wait for it */
  947.     TRACE("do_vfork: parent waking up");
  948.  
  949.     if (save) {
  950.         TRACE("do_vfork: parent restoring memory");
  951.         saveplace = (char *)savemem->loc;
  952.         for (i = 0; i < curproc->num_reg; i++) {
  953.             m = curproc->mem[i];
  954.             if (m && (m != savemem)) {
  955.                 if (i != 1 || txtsize == 0) {
  956.                     quickmove((char *)m->loc, saveplace, m->len);
  957.                     saveplace += m->len;
  958.                 }
  959.                 else {
  960.                     quickmove((char *)m->loc+txtsize, saveplace,
  961.                     m->len - txtsize);
  962.                     saveplace += m->len - txtsize;
  963.                 }
  964.             }
  965.         }
  966.         detach_region(curproc, savemem);
  967.     }
  968.     curproc->sigmask = sigmask;
  969.     check_sigs();    /* did we get any signals while sleeping? */
  970.     return p->pid;
  971. }
  972.  
  973. /*
  974.  * here are the interfaces that the user sees. Pvfork() doesn't save
  975.  * the child's address space; Pfork() does. Someday Pfork() should
  976.  * allow asynchronous execution of both child and parent, but this
  977.  * will do for now.
  978.  */
  979.  
  980. long
  981. p_vfork()
  982. {
  983.     return do_vfork(0);
  984. }
  985.  
  986. long
  987. p_fork()
  988. {
  989.     return do_vfork(1);
  990. }
  991.