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

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * GEMDOS emulation routines: these are for the GEMDOS system calls
  9.  * concerning allocating/freeing memory, including Pexec() (since
  10.  * this allocates memory) and Pterm() (since this, implicitly, frees
  11.  * it).
  12.  */
  13.  
  14. #include "mint.h"
  15.  
  16. int procdate, proctime;    /* set when any processes are created/destroyed */
  17.  
  18. static long do_vfork P_((int));
  19.  
  20. /*
  21.  * new call for TT TOS, for the user to inform DOS of alternate memory
  22.  * FIXME: we really shouldn't trust the user so completely
  23.  * FIXME: doesn't work if memory protection is on
  24.  */
  25.  
  26. long ARGS_ON_STACK
  27. m_addalt(start, size)
  28.     long start, size;
  29. {
  30.     extern int no_mem_prot;        /* see main.c and memprot.c */
  31.  
  32.     if (!no_mem_prot) return 0;    /* pretend to succeed */
  33.     if (!add_region(alt, start, size, M_ALT))
  34.         return EINTRN;
  35.     else
  36.         return 0;
  37. }
  38.  
  39. /*
  40.  * internal routine for doing Malloc on a particular memory map
  41.  */
  42.  
  43. long
  44. _do_malloc(map, size, mode)
  45.     MMAP map;
  46.     long size;
  47.     int mode;
  48. {
  49.     virtaddr v;
  50.     MEMREGION *m;
  51.     long maxsize, mleft;
  52.  
  53.     if (size == -1L) {
  54.         maxsize = max_rsize(map);
  55.         if (curproc->maxmem) {
  56.             mleft = curproc->maxmem - memused(curproc);
  57.             if (maxsize > mleft)
  58.                 maxsize = mleft;
  59.             if (maxsize < 0)
  60.                 maxsize = 0;
  61.         }
  62.     /* make sure to round down */
  63.         return maxsize & ~MASKBITS;
  64.     }
  65.  
  66. /* special case: Malloc(0) should always return 0 */
  67.     if (size == 0)
  68.         return 0;
  69.  
  70.     if (curproc->maxmem) {        /* memory limit? */
  71.         if (size > curproc->maxmem - memused(curproc)) {
  72.             DEBUG(("malloc: memory request would exceed limit"));
  73.             return 0;
  74.         }
  75.     }
  76.  
  77.     m = get_region(map, size, mode);
  78.     if (!m) {
  79.         return 0;
  80.     }
  81.     v = attach_region(curproc, m);
  82.     if (!v) {
  83.         m->links = 0;
  84.         free_region(m);
  85.         return 0;
  86.     }
  87. /* NOTE: get_region returns a region with link count 1; since attach_region
  88.  * increments the link count, we have to remember to decrement the count
  89.  * to correct for this.
  90.  */
  91.     m->links--;
  92.     if ((mode & F_KEEP)) {    /* request for permanent memory */
  93.         m->mflags |= M_KEEP;
  94.     }
  95.     return (long)v;
  96. }
  97.  
  98. long ARGS_ON_STACK
  99. m_xalloc(size, mode)
  100.     long size;
  101.     int mode;
  102. {
  103.     long r, r1;
  104.     int protmode;
  105. #ifndef NO_DEBUG_INFO
  106.     int origmode = mode;
  107. #endif
  108.  
  109.     TRACE(("Mxalloc(%ld,%x)",size,mode));
  110.  
  111. /*
  112.  * AKP: Hack here: if the calling process' PC is in ROM, then this is a
  113.  * Malloc call made by VDI's v_opnvwk routine.  So we change mode to
  114.  * include "super accessible."  This is temporary, until VDI catches up
  115.  * with multitasking TOS.
  116.  */
  117.  
  118.     if (((mode & F_PROTMODE) == 0) &&
  119.         (curproc->ctxt[SYSCALL].pc > 0x00e00000L) &&
  120.         (curproc->ctxt[SYSCALL].pc < 0x00efffffL)) {
  121.         mode |= (F_PROT_S + 0x10) | F_KEEP;
  122.         TRACE(("m_xalloc: VDI special (call from ROM)"));
  123.     }
  124. /*
  125.  * If the mode argument comes in a zero, then set it to the default
  126.  * value from prgflags.  Otherwise subtract one from it to bring it
  127.  * into line with the actual argument to alloc_region.
  128.  */
  129.     protmode = (mode & F_PROTMODE) >> F_PROTSHIFT;
  130.  
  131.     if (protmode == 0) {
  132.         protmode = (curproc->memflags & F_PROTMODE) >> F_PROTSHIFT;
  133.     }
  134.     else --protmode;
  135.  
  136. #if 0
  137. /* I'm very suspicious of the 0x08 flag; I can't see how it could
  138.  * work as the comment below seems to indicate -- ERS
  139.  */
  140.  
  141. /*
  142.  * if the mode argument has the 0x08 bit set then you're trying to change
  143.  * the protection mode of a block you already own. "size" is really its
  144.  * base address. (new as of 2/6/92)
  145.  */
  146.     if (mode & 0x08) change_prot_status(curproc,size,protmode);
  147. #endif
  148.  
  149.     /*
  150.      * Copy the F_KEEP attribute into protmode.  We didn't do that
  151.      * before now because change_prot_status don't want to see no
  152.      * steenking nofree attributes.
  153.      */
  154.  
  155.     protmode |= (mode & F_KEEP);
  156.  
  157.     /* mask off all but the ST/alternative RAM bits before further use */
  158.     mode &= 3;
  159.  
  160.     if (mode == 0) {
  161.         r = _do_malloc(core, size, protmode);
  162.         goto ret;
  163.     }
  164.     else if (mode == 1) {
  165.         r = _do_malloc(alt, size, protmode);
  166.         goto ret;
  167.     }
  168.     else if (size == -1) {
  169.         /* modes 2 and 3 are the same for for size -1 */
  170.         r = _do_malloc(core, -1L, PROT_P);
  171.         r1 = _do_malloc(alt, -1L, PROT_P);
  172.         if (r1 > r) r = r1;
  173.         goto ret;
  174.     }
  175.     else if (mode == 2) {
  176.         r = _do_malloc(core, size, protmode);
  177.         if (r == 0) r = _do_malloc(alt, size, protmode);
  178.         goto ret;
  179.     }
  180.     else /* if (mode == 3) */ {
  181.         r = _do_malloc(alt, size, protmode);
  182.         if (r == 0) r = _do_malloc(core, size, protmode);
  183.         goto ret;
  184.     }
  185. ret:
  186.     if (r == 0) {
  187.         DEBUG(("m_xalloc(%lx,%x) returns 0",size,origmode));
  188.     } else {
  189.         TRACE(("m_xalloc(%lx,%x) returns %lx",size,origmode,r));
  190.     }
  191.     return r;
  192. }
  193.  
  194. long ARGS_ON_STACK
  195. m_alloc(size)
  196.     long size;
  197. {
  198.     long r;
  199.  
  200.     TRACE(("Malloc(%lx)", size));
  201.     if (curproc->memflags & F_ALTALLOC)
  202.         r = m_xalloc(size, 3);
  203.     else
  204.         r = m_xalloc(size, 0);
  205.     TRACE(("Malloc: returning %lx", r));
  206.     return r;
  207. }
  208.  
  209. long ARGS_ON_STACK
  210. m_free(block)
  211.     virtaddr block;
  212. {
  213.     MEMREGION *m;
  214.     int i;
  215.  
  216.     TRACE(("Mfree(%lx)", block));
  217.     if (!block) {
  218.         DEBUG(("Mfree: null pointer"));
  219.         return EIMBA;
  220.     }
  221.  
  222. /* search backwards so that most recently allocated incarnations of
  223.    shared memory blocks are freed first (this doesn't matter very often)
  224.  */
  225.  
  226.     for (i = curproc->num_reg - 1; i >= 0; i--) {
  227.         if (curproc->addr[i] == block) {
  228.             m = curproc->mem[i];
  229.             assert(m != NULL);
  230.             assert(m->loc == (long)block);
  231.             curproc->mem[i] = 0;
  232.             curproc->addr[i] = 0;
  233.             m->links--;
  234.             if (m->links == 0) {
  235.                 free_region(m);
  236.             }
  237.             return 0;
  238.         }
  239.     }
  240.  
  241. /* hmmm... if we didn't find the region, perhaps it's a global
  242.  * one (with the M_KEEP flag set) belonging to a process that
  243.  * terminated
  244.  */
  245.     for (i = rootproc->num_reg - 1; i >= 0; i--) {
  246.         if (rootproc->addr[i] == block) {
  247.             m = rootproc->mem[i];
  248.             assert(m != NULL);
  249.             assert(m->loc == (long)block);
  250.             if (!(m->mflags & M_KEEP))
  251.                 continue;
  252.             TRACE(("Freeing M_KEPT memory"));
  253.             rootproc->mem[i] = 0;
  254.             rootproc->addr[i] = 0;
  255.             m->links--;
  256.             if (m->links == 0) {
  257.                 free_region(m);
  258.             }
  259.             return 0;
  260.         }
  261.     }
  262.  
  263.  
  264.     DEBUG(("Mfree: bad address %lx", block));
  265.     return EIMBA;
  266. }
  267.  
  268. long ARGS_ON_STACK
  269. m_shrink(dummy, block, size)
  270.     int dummy;
  271.     virtaddr block;
  272.     long size;
  273. {
  274.     MEMREGION *m;
  275.     int i;
  276.  
  277.     UNUSED(dummy);
  278.     TRACE(("Mshrink: %lx to %ld", block, size));
  279.     if (!block) {
  280.         DEBUG(("Mshrink: null pointer"));
  281.         return EIMBA;
  282.     }
  283.  
  284.     for (i = 0; i < curproc->num_reg; i++) {
  285.         if (curproc->addr[i] == block) {
  286.             m = curproc->mem[i];
  287.             assert(m != NULL);
  288.             assert(m->loc == (long)block);
  289.             return shrink_region(m, size);
  290.         }
  291.     }
  292.     DEBUG(("Mshrink: bad address (%lx)", block));
  293.     return EIMBA;
  294. }
  295.  
  296. long ARGS_ON_STACK
  297. p_exec(mode, ptr1, ptr2, ptr3)
  298.     int mode;
  299.     void *ptr1, *ptr2, *ptr3;
  300. {
  301.     MEMREGION *base,
  302.         *env = 0;    /* assignment suppresses spurious warning */
  303.     MEMREGION *text = 0;    /* for shared text regions */
  304.     PROC *p;
  305.     long r, flags = 0;
  306.     int i;
  307.     char mkbase = 0, mkload = 0, mkgo = 0, mkwait = 0, mkfree = 0;
  308.     char overlay = 0;
  309.     char thread = 0;
  310.     char ptrace;
  311.     char mkname = 0, *newname, *lastslash;
  312.     char localname[PNAMSIZ+1];
  313.     XATTR xattr;
  314.     int newpid;
  315.  
  316. /* tfmt and tail_offs are used for debugging only */
  317.     const char *tfmt = "Pexec(%d,%s,\"%s\",%lx)";
  318.     int tail_offs = 1;
  319.  
  320. /* the high bit of mode controls process tracing */
  321.     switch(mode & 0x7fff) {
  322.     case 0:
  323.         mkwait = 1;        /* fall through */
  324.     case 100:
  325.         mkload = mkgo = mkfree = 1;
  326.         mkname = 1;
  327.         break;
  328.     case 200:            /* overlay current process */
  329.         mkload = mkgo = 1;
  330.         overlay = mkname = 1;
  331.         break;
  332.     case 3:
  333.         mkload = 1;
  334.         break;
  335.     case 6:
  336.         mkfree = 1;
  337.         /* fall through */
  338.     case 4:
  339.         mkwait = mkgo = 1;
  340.         tfmt = "Pexec(%d,%lx,BP:%lx,%lx)";
  341.         tail_offs = 0;
  342.         break;
  343.     case 106:
  344.         mkfree = 1;        /* fall through */
  345.     case 104:
  346.         thread = (mode == 104);
  347.         mkgo = 1;
  348.         mkname = (ptr1 != 0);
  349.         tfmt = "Pexec(%d,%s,BP:%lx,%lx)";
  350.         tail_offs = 0;
  351.         break;
  352.     case 206:
  353. #if 0
  354.     /* mkfree has no effect when overlay is set, since
  355.      * in this case the "parent" and "child" are the same
  356.      * process; since the "child" will run in memory that the
  357.      * "parent" allocated, we don't want that memory freed!
  358.      */
  359.         mkfree = 1;
  360. #endif
  361.         /* fall through */
  362.     case 204:
  363.         mkgo = overlay = 1;
  364.         mkname = (ptr1 != 0);
  365.         tfmt = "Pexec(%d,%s,BP:%lx,%lx)";
  366.         tail_offs = 0;
  367.         break;
  368.     case 7:
  369.         flags = (long)ptr1;    /* set program flags */
  370.                     /* and fall through */
  371.     case 5:
  372.         mkbase = 1;
  373.         tfmt = "Pexec(%d,%lx,%s,%lx)";
  374.         tail_offs = 0;
  375.         break;
  376.     default:
  377.         DEBUG(("Pexec(%d,%lx,%lx,%lx): bad mode",mode,ptr1,ptr2,ptr3));
  378.         return EINVFN;
  379.     }
  380.  
  381.     TRACE((tfmt,mode,ptr1,(char *)ptr2+tail_offs,ptr3));
  382.  
  383. /* Pexec with mode 0x8000 indicates tracing should be active */
  384.     ptrace = (!mkwait && (mode & 0x8000));
  385.  
  386. /* in most cases, we'll want a process struct to exist,
  387.  * so make sure one is around. Note that we must be
  388.  * careful to free it later!
  389.  */
  390.  
  391. TRACE(("Checking for memory for new PROC structure"));
  392.     p = 0;
  393.     if (!overlay) {
  394.         p = new_proc();
  395.         if (!p) {
  396.             DEBUG(("Pexec: couldn't get a PROC struct"));
  397.             return ENSMEM;
  398.         }
  399.     }
  400.  
  401. TRACE(("creating environment"));
  402.  
  403.     if (mkload || mkbase) {
  404.         env = create_env((char *)ptr3);
  405.         if (!env) {
  406.             DEBUG(("Pexec: unable to create environment"));
  407.             if (p) dispose_proc(p);
  408.             return ENSMEM;
  409.         }
  410.     }
  411.  
  412. TRACE(("creating base page"));
  413.  
  414.     if (mkbase) {
  415.         base = create_base((char *)ptr2, env, flags, 0L);
  416.         if (!base) {
  417.             DEBUG(("Pexec: unable to create basepage"));
  418.             detach_region(curproc, env);
  419.             if (p) dispose_proc(p);
  420.             return ENSMEM;
  421.         }
  422. TRACELOW(("Pexec: basepage region(%lx) is %ld bytes at %lx", base, base->len, base->loc));
  423.     }
  424.     else if (mkload) {
  425.         base = load_region((char *)ptr1, env, (char *)ptr2,
  426.             &xattr, &text, &flags);
  427.         if (!base) {
  428.             DEBUG(("Pexec: load_region failed"));
  429.             detach_region(curproc, env);
  430.             if (p) dispose_proc(p);
  431.             return mint_errno;
  432.         }
  433. TRACE(("Pexec: basepage region(%lx) is %ld bytes at %lx", base, base->len, base->loc));
  434.     }
  435.     else {    /* mode == 4,6,104,106,204, or 206 -- just go */
  436.         base = addr2mem((virtaddr)ptr2);
  437.         if (base)
  438.             env = addr2mem(*(void **)(base->loc + 0x2c));
  439.         else
  440.             env = 0;
  441.         if (!env) {
  442.             if (p) dispose_proc(p);
  443.             return EIMBA;
  444.         }
  445.     }
  446.  
  447. /* make a local copy of the name, in case we are overlaying the current
  448.  * process
  449.  */
  450.     if (mkname) {
  451.         lastslash = 0;
  452.         newname = ptr1;
  453.         while (*newname) {
  454.             if (*newname == '\\' || *newname == '/')
  455.                 lastslash = newname;
  456.             ++newname;
  457.         }
  458.         if (!lastslash)
  459.             lastslash = ptr1;
  460.         else
  461.             lastslash++;
  462.  
  463.         i = 0; newname = localname;
  464.         while (i++ < PNAMSIZ) {
  465.             if (*lastslash == '.' || *lastslash == 0) {
  466.                 *newname = 0; break;
  467.             }
  468.             else
  469.                 *newname++ = *lastslash++;
  470.         }
  471.         *newname = 0;
  472.     }
  473.  
  474.     if (mkload || mkbase) {
  475.         /*
  476.          * Now that the file's loaded, flags is set to the prgflags
  477.          * for the file.  In the case of mkbase it's been right all along.
  478.          * Here's where we change the protection on the environment to
  479.          * match those flags.
  480.          */
  481.         mark_region(env,(short)((flags & F_PROTMODE) >> F_PROTSHIFT));
  482.     }
  483.  
  484.     if (p) {
  485.     /* free the PROC struct so fork_proc will succeed */
  486.     /* FIXME: it would be much better to pass the PROC as a parameter
  487.      * to fork_proc!!
  488.      */
  489.         dispose_proc(p);
  490.         p = 0;
  491.     }
  492.  
  493.     if (mkgo) {
  494.         BASEPAGE *b;
  495.  
  496.     /* tell the child who the parent was */
  497.         b = (BASEPAGE *)base->loc;
  498.  
  499.         if (overlay) {
  500.             b->p_parent = curproc->base->p_parent;
  501.             p = curproc;
  502.         /* make sure that exec_region doesn't free the base and env */
  503.             base->links++;
  504.             env->links++;
  505.             if (text) text->links++;
  506.         }
  507.         else {
  508.             b->p_parent = curproc->base;
  509.             p = fork_proc();
  510.         }
  511.         if (!p) {
  512.             if (mkbase) {
  513.                 detach_region(curproc, base);
  514.                 detach_region(curproc, env);
  515.                 if (text) detach_region(curproc, text);
  516.             }
  517.             return mint_errno;
  518.         }
  519.         if (ptrace)
  520.             p->ptracer = pid2proc(p->ppid);
  521.  
  522.     /* Even though the file system won't allow unauthorized access
  523.      * to setuid/setgid programs, it's better to err on the side of
  524.      * caution and forbid them to be traced (since the parent can arrange
  525.      * to share the child's address space, not all accesses need to
  526.      * go through the file system.)
  527.      */
  528.         if (mkload && mkgo && !p->ptracer) {    /* setuid/setgid is OK */
  529.             if (xattr.mode & S_ISUID)
  530.                 p->euid = xattr.uid;
  531.             if (xattr.mode & S_ISGID)
  532.                 p->egid = xattr.gid;
  533.         }
  534.     /* exec_region frees the memory attached to p; that's always what
  535.      * we want, since fork_proc duplicates the memory, and since
  536.      * if we didn't call fork_proc then we're overlaying.
  537.      * NOTE: after this call, we may not be able to access the
  538.      * original address space that the Pexec was taking place in
  539.      * (if this is an overlaid Pexec, we just freed that memory).
  540.      */
  541.         (void)exec_region(p, base, thread);
  542.         attach_region(p, env);
  543.         attach_region(p, base);
  544.         if (text) attach_region(p, text);
  545.  
  546.         if (mkname) {
  547.     /* interesting coincidence -- if a process needs a name, it usually
  548.      * needs to have its domain reset to DOM_TOS. Doing it this way
  549.      * (instead of doing it in exec_region) means that Pexec(4,...)
  550.      * can be used to create new threads of execution which retain
  551.      * the same domain.
  552.      */
  553.             if (!thread)
  554.                 p->domain = DOM_TOS;
  555.  
  556.     /* put in the new process name we saved above */
  557.             strcpy(p->name, localname);
  558.         }
  559.  
  560.     /* turn on tracing for the new process */
  561.         if (p->ptracer)
  562.             p->ctxt[CURRENT].ptrace = 1;
  563.  
  564.     /* set the time/date stamp of u:\proc */
  565.         proctime = timestamp;
  566.         procdate = datestamp;
  567.  
  568.         if (overlay) {
  569.             /* correct for temporary increase in links (see above) */
  570.             base->links--;
  571.             env->links--;
  572.             if (text) text->links--;
  573.             /* let our parent run, if it Vfork'd() */
  574.             if ( (p = pid2proc(curproc->ppid)) != 0 ) {
  575.                 if (p->wait_q == WAIT_Q && 
  576.                     p->wait_cond == (long)curproc) {
  577.                     short sr = spl7();
  578.                     rm_q(WAIT_Q, p);
  579.                     add_q(READY_Q, p);
  580.                     spl(sr);
  581.                 }
  582.             }
  583.  
  584.         /* OK, let's run our new code */
  585.         /* we guarantee ourselves at least 2 timeslices to do an Mshrink */
  586.             assert(curproc->magic == CTXT_MAGIC);
  587.             fresh_slices(2);
  588.             leave_kernel();
  589.             change_context(&(curproc->ctxt[CURRENT]));
  590.         }
  591.         else {
  592.     /* we want this process to run ASAP */
  593.     /* so we temporarily give it high priority and put it first on the
  594.      * run queue
  595.      */
  596.             run_next(p, 2);
  597.         }
  598.     }
  599.  
  600.     if (mkfree) {
  601.         detach_region(curproc, base);
  602.         detach_region(curproc, env);
  603.         if (text) detach_region(curproc, text);
  604.     }
  605.  
  606.     if (mkwait) {
  607.         long oldsigint, oldsigquit;
  608.  
  609.         oldsigint = curproc->sighandle[SIGINT];
  610.         oldsigquit = curproc->sighandle[SIGQUIT];
  611.         curproc->sighandle[SIGINT] =
  612.              curproc->sighandle[SIGQUIT] = SIG_IGN;
  613.  
  614.         newpid = p->pid;
  615.         for(;;) {
  616.             r = p_wait3(0, (long *)0);
  617.             if (r < 0) {
  618.                 ALERT("p_exec: wait error");
  619.                 return EINTRN;
  620.             }
  621.             if ( newpid == ((r&0xffff0000L) >> 16) ) {
  622.                 TRACE(("leaving Pexec; child return code %ld", r));
  623.                 r = r & 0x0000ffffL;
  624.                 break;
  625.             }
  626.             if (curproc->pid)
  627.                 DEBUG(("Pexec: wrong child found"));
  628.         }
  629.         curproc->sighandle[SIGINT] = oldsigint;
  630.         curproc->sighandle[SIGQUIT] = oldsigquit;
  631.         return r;
  632.     }
  633.     else if (mkgo) {
  634.     /* warning: after the yield() the "p" structure may not exist any more
  635.      * (if the child exits right away)
  636.      */
  637.         newpid = p->pid;
  638.         yield();    /* let the new process run */
  639.         return newpid;
  640.     } else {
  641.         TRACE(("leaving Pexec with basepage address %lx", base->loc));
  642.         return base->loc;
  643.     }
  644. }
  645.  
  646. /*
  647.  * terminate a process, with return code "code". If que == ZOMBIE_Q, free
  648.  * all resources attached to the child; if que == TSR_Q, free everything
  649.  * but memory.
  650.  * NOTE: terminate() should be called only when the process is to be
  651.  * "terminated with extreme prejuidice". Most times, p_term or p_termres
  652.  * are the functions to use, since they allow the user to do some cleaning
  653.  * up, etc.
  654.  */
  655.  
  656. long
  657. terminate(code, que)
  658.     int code, que;
  659. {
  660.     extern PROC *dlockproc[];    /* in dosdir.c */
  661.     PROC *p;
  662.     FILEPTR *fp;
  663.     MEMREGION *m;
  664.     MEMREGION **hold_mem;
  665.     virtaddr *hold_addr;
  666.     int  i, wakemint = 0;
  667.     DIR *dirh, *nexth;
  668.     extern short bconbsiz;    /* in bios.c */
  669.  
  670.     if (bconbsiz)
  671.         (void) bflush();
  672.  
  673.     assert(que == ZOMBIE_Q || que == TSR_Q);
  674.  
  675.     if (curproc->pid == 0) {
  676.         FATAL("attempt to terminate MiNT");
  677.     }
  678.  
  679. /* cancel all pending timeouts for this process */
  680.     cancelalltimeouts();
  681. /* cancel alarm clock */
  682.     curproc->alarmtim = 0;
  683.  
  684. /* release any drives locked by Dlock */
  685.     for(i = 0; i < NUM_DRIVES; i++) {
  686.         if (dlockproc[i] == curproc) {
  687.             dlockproc[i] = 0;
  688.             changedrv(i);
  689.         }
  690.     }
  691.  
  692. /* release the controlling terminal, if we're a process group leader */
  693.     fp = curproc->handle[-1];
  694.     if (fp && is_terminal(fp) && curproc->pgrp == curproc->pid) {
  695.         struct tty *tty = (struct tty *)fp->devinfo;
  696.         if (curproc->pgrp == tty->pgrp)
  697.             tty->pgrp = 0;
  698.     }
  699.  
  700. /* close all files */
  701.     for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  702.         if ((fp = curproc->handle[i]) != 0)
  703.             do_close(fp);
  704.         curproc->handle[i] = 0;
  705.     }
  706.  
  707. /* close any unresolved Fsfirst/Fsnext directory searches */
  708.     for (i = 0; i < NUM_SEARCH; i++) {
  709.         if (curproc->srchdta[i]) {
  710.             DIR *dirh = &curproc->srchdir[i];
  711.             (*dirh->fc.fs->closedir)(dirh);
  712.             release_cookie(&dirh->fc);
  713.             dirh->fc.fs = 0;
  714.         }
  715.     }
  716.  
  717. /* close pending opendir/readdir searches */
  718.     for (dirh = curproc->searches; dirh; ) {
  719.         if (!dirh->fc.fs) continue;
  720.         (*dirh->fc.fs->closedir)(dirh);
  721.         release_cookie(&dirh->fc);
  722.         nexth = dirh->next;
  723.         kfree(dirh);
  724.         dirh = nexth;
  725.     }
  726.  
  727. /* release the directory cookies held by the process */
  728.     for (i = 0; i < NUM_DRIVES; i++) {
  729.         release_cookie(&curproc->curdir[i]);
  730.         curproc->curdir[i].fs = 0;
  731.         release_cookie(&curproc->root[i]);
  732.         curproc->root[i].fs = 0;
  733.     }
  734.  
  735. /* release all semaphores owned by this process */
  736.     free_semaphores(curproc->pid);
  737.  
  738. /* free all memory */
  739. /* if mflags & M_KEEP then attach it to process 0 */
  740.     if (que == ZOMBIE_Q) {
  741.         for (i = curproc->num_reg - 1; i >=0; i--) {
  742.             m = curproc->mem[i];
  743.             curproc->mem[i] = 0; curproc->addr[i] = 0;
  744.             if (m) {
  745.         /* don't free specially allocated memory */
  746.                 if (m->mflags & M_KEEP) {
  747.                     if (curproc != rootproc)
  748.                         attach_region(rootproc, m);
  749.                 }
  750.                 m->links--;
  751.                 if (m->links == 0) {
  752.                     free_region(m);
  753.                 }
  754.             }
  755.         }
  756.  
  757.         /*
  758.          * mark the mem & addr arrays as void so the memory
  759.          * protection code won't try to walk them. Do this before
  760.          * freeing them so we don't try to walk them when marking
  761.          * those pages themselves as free!
  762.          *
  763.          * Note: when a process terminates, the MMU root pointer
  764.          * still points to that process' page table, until the next
  765.          * process is dispatched.  This is OK, since the process'
  766.          * page table is in system memory, and it isn't going to be
  767.          * freed.  It is going to wind up on the free process list,
  768.          * though, after dispose_proc. This might be Not A Good
  769.          * Thing.
  770.          */
  771.  
  772.         hold_addr = curproc->addr;
  773.         hold_mem = curproc->mem;
  774.  
  775.         curproc->mem = NULL;
  776.         curproc->addr = NULL;
  777.         curproc->num_reg = 0;
  778.  
  779.         kfree(hold_addr);
  780.         kfree(hold_mem);
  781.     }
  782. /*    else
  783.          make TSR process non-swappable */
  784.  
  785. /*
  786.  * make sure that any open files that refer to this process are
  787.  * closed
  788.  */
  789.     changedrv(PROC_BASE_DEV | curproc->pid);
  790.  
  791. /* find our parent (if parent not found, then use process 0 as parent
  792.  * since that process is constantly in a wait loop)
  793.  */
  794.  
  795.     p = pid2proc(curproc->ppid);
  796.     if (!p) {
  797.         TRACE(("terminate: parent not found"));
  798.         p = pid2proc(0);
  799.     }
  800.  
  801. /* NOTE: normally just post_sig is sufficient for sending a signal; but
  802.  * in this particular case, we have to worry about processes that are
  803.  * blocking all signals because they Vfork'd and are waiting for us to
  804.  * finish (which is indicated by a wait_cond matching our PROC
  805.  * structure), and also processes that are ignoring SIGCHLD but are
  806.  * waiting for us.
  807.  */
  808.     if (p->wait_q == WAIT_Q && 
  809.         (p->wait_cond == (long)curproc || p->wait_cond == (long)p_waitpid) ) {
  810.         short sr = spl7();
  811.         TRACE(("terminate: waking up parent"));
  812.         rm_q(WAIT_Q, p);
  813.         add_q(READY_Q, p);
  814.         spl(sr);
  815.     }
  816.     if (curproc->ptracer && curproc->ptracer != p) {
  817.         /* BUG: should we ensure curproc->ptracer is awake ? */
  818.         post_sig(curproc->ptracer, SIGCHLD);    /* tell tracing process */
  819.     }
  820.     post_sig(p, SIGCHLD);        /* inform of process termination */
  821.  
  822. /* find our children, and orphan them
  823.  * also, check for processes we were tracing, and
  824.  * cancel the trace
  825.  */
  826.     i = curproc->pid;
  827.     for (p = proclist; p; p = p->gl_next) {
  828.         if (p->ppid == i) {
  829.             p->ppid = 0;    /* have the system adopt it */
  830.             if (p->wait_q == ZOMBIE_Q) 
  831.                 wakemint = 1;    /* we need to wake proc. 0 */
  832.         }
  833.         if (p->ptracer == curproc) {
  834.             p->ptracer = 0;
  835. /*
  836.  * `FEATURE': we terminate traced processes when the tracer terminates.
  837.  * It might plausibly be argued that it would be better to let them
  838.  * continue, to let some (new) tracer take them over. On the other hand,
  839.  * if the tracer terminated normally, it should have used Fcntl(PTRACESFLAGS)
  840.  * to reset the trace nicely, so something must be wrong for us to have
  841.  * reached here.
  842.  */
  843.             post_sig(p, SIGTERM);    /* arrange for termination */
  844.         }
  845.     }
  846.  
  847.     if (wakemint) {
  848.         p = rootproc;        /* pid 0 */
  849.         if (p->wait_q == WAIT_Q) {
  850.             short sr = spl7();
  851.             rm_q(WAIT_Q, p);
  852.             add_q(READY_Q, p);
  853.             spl(sr);
  854.         }
  855.     }
  856.  
  857. /* this makes sure that our children are inherited by the system;
  858.  * plus, it may help avoid problems if somehow a signal gets
  859.  * through to us
  860.  */
  861.     for(i = 0; i < NSIG; i++)
  862.         curproc->sighandle[i] = SIG_IGN;
  863.  
  864. /* finally, reset the time/date stamp for u:\proc */
  865.     proctime = timestamp;
  866.     procdate = datestamp;
  867.  
  868.     sleep(que, (long)(unsigned)code);
  869.  
  870. /* we shouldn't ever get here */
  871.     FATAL("terminate: sleep woke up when it shouldn't have");
  872.     return 0;
  873. }
  874.  
  875. /*
  876.  * TOS process termination entry points:
  877.  * p_term terminates the process, freeing its memory
  878.  * p_termres lets the process hang around resident in memory, after
  879.  * shrinking its transient program area to "save" bytes
  880.  */
  881.  
  882. long ARGS_ON_STACK
  883. p_term(code)
  884.     int code;
  885. {
  886.     CONTEXT *syscall;
  887.  
  888.     TRACE(("Pterm(%d)", code));
  889. /* call the process termination vector */
  890.     syscall = &curproc->ctxt[SYSCALL];
  891.  
  892.     if (syscall->term_vec != (long)rts) {
  893.         TRACE(("term_vec: user has something to do"));
  894. /*
  895.  * we handle the termination vector just like Supexec(), by
  896.  * sending signal 0 to the process. See supexec() in xbios.c for details.
  897.  * Note that we _always_ want to unwind the signal stack, and setting
  898.  * bit 1 of curproc->sigmask tells handle_sig to do that -- see signal.c.
  899.  */
  900.         curproc->sigmask |= 1L;
  901.         (void)supexec((Func)syscall->term_vec, 0L, 0L, 0L, 0L, 
  902.                 (long)code);
  903. /*
  904.  * if we arrive here, continue with the termination...
  905.  */
  906.     }
  907.     return terminate(code, ZOMBIE_Q);
  908. }
  909.  
  910. long ARGS_ON_STACK
  911. p_term0()
  912. {
  913.     return p_term(0);
  914. }
  915.  
  916. long ARGS_ON_STACK
  917. p_termres(save, code)
  918.     long save;
  919.     int code;
  920. {
  921.     MEMREGION *m;
  922.     int i;
  923.  
  924.     TRACE(("Ptermres(%ld, %d)", save, code));
  925.     m = curproc->mem[1];    /* should be the basepage (0 is env.) */
  926.     if (m) {
  927.         (void)shrink_region(m, save);
  928.     }
  929. /*
  930.  * make all of the TSR's private memory globally accessible;
  931.  * this means that more TSR's will "do the right thing"
  932.  * without having to have prgflags set.
  933.  */
  934.     for (i = 0; i < curproc->num_reg; i++) {
  935.         m = curproc->mem[i];
  936.         if (m && m->links == 1) {    /* only the TSR is owner */
  937.             if (get_prot_mode(m) == PROT_P) {
  938.                 mark_region(m, PROT_G);
  939.             }
  940.         }
  941.     }
  942.     return terminate(code, TSR_Q);
  943. }
  944.  
  945. /*
  946.  * routine for waiting for children to die. Return has the pid of the
  947.  * found child in the high word, and the child's exit code in
  948.  * the low word. If no children exist, return "File Not Found".
  949.  * If (nohang & 1) is nonzero, then return a 0 immediately if we have
  950.  * no dead children but some living ones that we still have to wait
  951.  * for. If (nohang & 2) is nonzero, then we return any stopped
  952.  * children; otherwise, only children that have exited or are stopped
  953.  * due to a trace trap are returned.
  954.  * If "rusage" is non-zero and a child is found, put the child's
  955.  * resource usage into it (currently only the user and system time are
  956.  * sent back).
  957.  * The pid argument specifies a set of child processes for which status
  958.  * is requested:
  959.  *     If pid is equal to -1, status is requested for any child process.
  960.  *
  961.  *    If pid is greater than zero, it specifies the process ID of a
  962.  *    single child process for which status is requested.
  963.  *
  964.  *    If pid is equal to zero, status is requested for any child
  965.  *    process whose process group ID is equal to that of the calling
  966.  *    process.
  967.  *
  968.  *    If pid is less than -1, status is requested for any child process
  969.  *    whose process group ID is equal to the absolute value of pid.
  970.  *
  971.  * Note this call is a real standard crosser... POSIX.1 doesn't have the
  972.  * rusage stuff, BSD doesn't have the pid stuff; both are useful, so why
  973.  * not have it all!
  974.  */
  975.  
  976. long ARGS_ON_STACK
  977. p_waitpid(pid, nohang, rusage)
  978.     int pid;
  979.     int nohang;
  980.     long *rusage;
  981. {
  982.     long r;
  983.     PROC *p, *q;
  984.     int ourpid;
  985.     int found;
  986.  
  987.     TRACE(("Pwaitpid(%d, %d, %lx)", pid, nohang, rusage));
  988.     ourpid = curproc->pid;
  989.  
  990. /* if there are terminated children, clean up and return their info;
  991.  * if there are children, but still running, wait for them;
  992.  * if there are no children, return an error
  993.  */
  994.  
  995.     do {
  996. /* look for any children */
  997.         found = 0;
  998.         for (p = proclist; p; p = p->gl_next) {
  999.             if ((p->ppid == ourpid || p->ptracer == curproc) &&
  1000.                 (pid == -1 ||
  1001.                 (pid > 0 && pid == p->pid) ||
  1002.                 (pid == 0 && p->pgrp == ourpid) ||
  1003.                 (pid < -1 && p->pgrp == -pid))) {
  1004.                 found++;
  1005.                 if (p->wait_q == ZOMBIE_Q || p->wait_q == TSR_Q)
  1006.                     break;
  1007.  
  1008. /* p->wait_cond == 0 if a stopped process has already been waited for */
  1009.                 if (p->wait_q == STOP_Q && p->wait_cond) {
  1010.                     if ((nohang & 2) ||
  1011.                     ((p->wait_cond&0x1f00) == (SIGTRAP<<8)))
  1012.                         break;
  1013.                 }
  1014.             }
  1015.         }
  1016.         if (!p) {
  1017.             if (found) {
  1018.                 if (nohang & 1)
  1019.                     return 0;
  1020.                 if (curproc->pid)
  1021.                     TRACE(("Pwaitpid: going to sleep"));
  1022.                 sleep(WAIT_Q, (long)p_waitpid);
  1023.             }
  1024.             else {
  1025.                 DEBUG(("Pwaitpid: no children found"));
  1026.                 return EFILNF;
  1027.             }
  1028.         }
  1029.     } while (!p);
  1030.  
  1031. /* OK, we've found our child */
  1032. /* calculate the return code from the child's exit code and pid */
  1033.     r = (((unsigned long)p->pid) << 16) | (p->wait_cond & 0x0000ffff);
  1034.  
  1035. /* check resource usage */
  1036.     if (rusage) {
  1037.         *rusage++ = p->usrtime;
  1038.         *rusage = p->systime;
  1039.     }
  1040.  
  1041. /* avoid adding adopted trace processes usage to the foster parent */
  1042.     if (curproc->pid == p->ppid) {
  1043.     /* add child's resource usage to parent's */
  1044.         if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q) {
  1045.             curproc->chldstime += p->systime;
  1046.             curproc->chldutime += p->usrtime;
  1047.         }
  1048.     }
  1049.  
  1050. /* if it was stopped, mark it as having been found and again return */
  1051.     if (p->wait_q == STOP_Q) {
  1052.         p->wait_cond = 0;
  1053.         return r;
  1054.     }
  1055.  
  1056. /* We have to worry about processes which attach themselves to running
  1057.  * processes which they want to trace. We fix things up so that the
  1058.  * second time the signal gets delivered we will go all the way to the
  1059.  * end of this function.
  1060.  */
  1061.      if (p->ptracer && p->ptracer->pid != p->ppid) {
  1062.         if (curproc == p->ptracer) {
  1063.         /* deliver the signal to the tracing process first */
  1064.             TRACE(("Pwaitpid(ptracer): returning status to tracing process"));
  1065.             p->ptracer = NULL;
  1066.             return r;
  1067.         }
  1068.         else {
  1069.         /* Hmmm, the real parent got here first */
  1070.             TRACE(("Pwaitpid(ptracer): returning status to parent process"));
  1071.             p->ppid = -1;
  1072.             return r;
  1073.         }
  1074.     }
  1075.     
  1076. /* if it was a TSR, mark it as having been found and return */
  1077.     if (p->wait_q == TSR_Q) {
  1078.         p->ppid = -1;
  1079.         return r;
  1080.     }
  1081.  
  1082. /* it better have been on the ZOMBIE queue from here on in... */
  1083.     assert(p->wait_q == ZOMBIE_Q);
  1084.     assert(p != curproc);
  1085.  
  1086. /* take the child off both the global and ZOMBIE lists */
  1087.     rm_q(ZOMBIE_Q, p);
  1088.  
  1089.     if (proclist == p) {
  1090.         proclist = p->gl_next;
  1091.         p->gl_next = 0;
  1092.     }
  1093.     else {
  1094.         q = proclist;
  1095.         while(q && q->gl_next != p)
  1096.             q = q->gl_next;
  1097.         assert(q);
  1098.         q->gl_next = p->gl_next;
  1099.         p->gl_next = 0;
  1100.     }
  1101.  
  1102.     dispose_proc(p);    /* free the PROC structure */
  1103.  
  1104.     return r;
  1105. }
  1106.  
  1107. /* p_wait3: BSD process termination primitive, here to maintain
  1108.  * compatibility with existing binaries.
  1109.  */
  1110. long ARGS_ON_STACK
  1111. p_wait3(nohang, rusage)
  1112.     int nohang;
  1113.     long *rusage;
  1114. {
  1115.     return p_waitpid(-1, nohang, rusage);
  1116. }
  1117.  
  1118. /* p_wait: block until a child has exited, and don't worry about
  1119.    resource stats. this is provided as a convenience, and to maintain
  1120.    compatibility with existing binaries (yes, I'm lazy...). we could
  1121.    make do with Pwaitpid().
  1122.  */
  1123.  
  1124. long ARGS_ON_STACK
  1125. p_wait()
  1126. {
  1127. /*
  1128.  * BEWARE:
  1129.  * POSIX says that wait() should be implemented as
  1130.  * Pwaitpid(-1, 0, (long *)0). Pwait is really not
  1131.  * useful for much at all, but we'll keep it around
  1132.  * for a while (with it's old, crufty semantics)
  1133.  * for backwards compatibility. People implementing
  1134.  * POSIX style libraries should use Pwaitpid even
  1135.  * to implement wait().
  1136.  */
  1137.     return p_wait3(2, (long *)0);
  1138. }
  1139.  
  1140. /*
  1141.  * do_vfork(save): create a duplicate of  the current process. This is
  1142.  * essentially a vfork() algorithm, except that if (save == 1) the
  1143.  * parent's address space is saved, and then restored when the process
  1144.  * is made runnable again. The parent is suspended until either the child
  1145.  * process (the duplicate) exits or does a Pexec which overlays its
  1146.  * memory space.
  1147.  *
  1148.  * "txtsize" is the size of the process' TEXT area, if it has a valid one;
  1149.  * this is part of the second memory region attached (the basepage one)
  1150.  * and need not be saved (we assume processes don't write on their own
  1151.  * code segment)
  1152.  */
  1153.  
  1154. static long
  1155. do_vfork(save)
  1156.     int save;
  1157. {
  1158.     PROC *p;
  1159.     long sigmask;
  1160.     MEMREGION *m, *savemem = 0;
  1161.     long savesize, txtsize;
  1162.     int i;
  1163.     char *saveplace;
  1164.  
  1165.     p = fork_proc();
  1166.     if (!p) {
  1167.         DEBUG(("do_vfork: couldn't get new PROC struct"));
  1168.         return mint_errno;
  1169.     }
  1170. /* set u:\proc time+date */
  1171.     proctime = timestamp;
  1172.     procdate = datestamp;
  1173.  
  1174. /*
  1175.  * maybe save the parent's address space
  1176.  */
  1177.     txtsize = p->txtsize;
  1178.  
  1179.     if (save) {
  1180.         TRACE(("do_vfork: saving parent"));
  1181.         savesize = memused(curproc) - txtsize;
  1182.         assert(savesize >= 0);
  1183.  
  1184.         saveplace = (char *)alloc_region(alt, savesize, PROT_P);
  1185.         if (!saveplace)
  1186.             saveplace = (char *)alloc_region(core, savesize, PROT_P);
  1187.  
  1188.         if (!saveplace) {
  1189.             DEBUG(("do_vfork: can't save parent's memory"));
  1190.             p->ppid = 0;        /* abandon the child */
  1191.             post_sig(p, SIGKILL);    /* then kill it */
  1192.             p->ctxt[CURRENT].pc = (long)check_sigs;
  1193.                 /* just to make sure it dies */
  1194.             p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  1195.             p->pri = MAX_NICE+1;
  1196.             run_next(p, 1);
  1197.             yield();
  1198.             return ENSMEM;
  1199.         }
  1200.         savemem = addr2mem((virtaddr)saveplace);
  1201.         assert(savemem);
  1202.         for (i = 0; i < curproc->num_reg; i++) {
  1203.             m = curproc->mem[i];
  1204.             if (m && m != savemem && !(m->mflags & M_SHTEXT)) {
  1205.                 if (i != 1 || txtsize == 0) {
  1206.                     quickmove(saveplace, (char *)m->loc, m->len);
  1207.                     saveplace += m->len;
  1208.                 }
  1209.                 else {
  1210.                     quickmove(saveplace, (char *)m->loc+txtsize,
  1211.                     m->len - txtsize);
  1212.                     saveplace += m->len - txtsize;
  1213.                 }
  1214.             }
  1215.         }
  1216.     }
  1217.                 
  1218.     p->ctxt[CURRENT] = p->ctxt[SYSCALL];
  1219.     p->ctxt[CURRENT].regs[0] = 0;    /* child returns a 0 from call */
  1220.     p->ctxt[CURRENT].sr &= ~(0x2000); /* child must be in user mode */
  1221. #if 0        /* set up in fork_proc() */
  1222.     p->ctxt[CURRENT].ssp = (long)(p->stack + ISTKSIZE);
  1223. #endif
  1224.  
  1225. /* watch out for job control signals, since our parent can never wake
  1226.  * up to respond to them. solution: block them; exec_region (in mem.c)
  1227.  * clears the signal mask, so an exec() will unblock them.
  1228.  */
  1229.     p->sigmask |= (1L << SIGTSTP) | (1L << SIGTTIN) | (1L << SIGTTOU);
  1230.  
  1231.     TRACE(("do_vfork: parent going to sleep, wait_cond == %lx",
  1232.         (long)p));
  1233.  
  1234. /* WARNING: This sleep() must absolutely not wake up until the child
  1235.  * has released the memory space correctly. That's why we mask off
  1236.  * all signals.
  1237.  */
  1238.     sigmask = curproc->sigmask;
  1239.     curproc->sigmask = ~((unsigned long)1 << SIGKILL);
  1240.  
  1241.     add_q(READY_Q, p);        /* put it on the ready queue */
  1242.     sleep(WAIT_Q, (long)p);            /* while we wait for it */
  1243.     TRACE(("do_vfork: parent waking up"));
  1244.  
  1245.     if (save) {
  1246.         TRACE(("do_vfork: parent restoring memory"));
  1247.         saveplace = (char *)savemem->loc;
  1248.         for (i = 0; i < curproc->num_reg; i++) {
  1249.             m = curproc->mem[i];
  1250.             if (m && (m != savemem) && !(m->mflags & M_SHTEXT)) {
  1251.                 if (i != 1 || txtsize == 0) {
  1252.                     quickmove((char *)m->loc, saveplace, m->len);
  1253.                     saveplace += m->len;
  1254.                 }
  1255.                 else {
  1256.                     quickmove((char *)m->loc+txtsize, saveplace,
  1257.                     m->len - txtsize);
  1258.                     saveplace += m->len - txtsize;
  1259.                 }
  1260.             }
  1261.         }
  1262.         detach_region(curproc, savemem);
  1263.     }
  1264.     curproc->sigmask = sigmask;
  1265.     check_sigs();    /* did we get any signals while sleeping? */
  1266.     return p->pid;
  1267. }
  1268.  
  1269. /*
  1270.  * here are the interfaces that the user sees. Pvfork() doesn't save
  1271.  * the child's address space; Pfork() does. Someday Pfork() should
  1272.  * allow asynchronous execution of both child and parent, but this
  1273.  * will do for now.
  1274.  */
  1275.  
  1276. long ARGS_ON_STACK
  1277. p_vfork()
  1278. {
  1279.     return do_vfork(0);
  1280. }
  1281.  
  1282. long ARGS_ON_STACK
  1283. p_fork()
  1284. {
  1285.     return do_vfork(1);
  1286. }
  1287.