home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1992 / 06 / 386bsd.692 next >
Text File  |  1992-05-18  |  31KB  |  876 lines

  1. _PORTING UNIX TO THE 386: THE MISSING PIECES, PART II_
  2. by William Jolitz and Lynne Greer Jolitz
  3.  
  4. [LISTING ONE]
  5.  
  6. /* Copyright (c) 1989, 1990, 1991, 1992 William F. Jolitz, TeleMuse
  7.  * All rights reserved.
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *  This software is a component of "386BSD" developed by 
  19.  *  William F. Jolitz, TeleMuse.
  20.  * 4. Neither the name of the developer nor the name "386BSD" may be used to 
  21.  *    endorse or promote products derived from this software without specific 
  22.  *    prior written permission.
  23.  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 
  24.  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 
  25.  * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 
  26.  * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 
  27.  * NOT MAKE USE OF THIS WORK. THIS SOFTWARE IS PROVIDED BY THE DEVELOPER 
  28.  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  29.  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  30.  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE FOR ANY 
  31.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
  32.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  33.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  34.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  35.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
  36.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37.  *
  38.  * This procedure implements a minimal program execution facility for
  39.  * 386BSD. It interfaces to the BSD kernel as the execve system call.
  40.  * Significant limitations and lack of compatiblity with POSIX are
  41.  * present with this version, to make its basic operation more clear.
  42.  */
  43.  
  44. #include "param.h"
  45. #include "systm.h"
  46. #include "proc.h"
  47. #include "mount.h"
  48. #include "namei.h"
  49. #include "vnode.h"
  50. #include "file.h"
  51. #include "exec.h"
  52. #include "stat.h"
  53. #include "wait.h"
  54. #include "signalvar.h"
  55. #include "mman.h"
  56. #include "malloc.h"
  57.  
  58. #include "vm/vm.h"
  59. #include "vm/vm_param.h"
  60. #include "vm/vm_map.h"
  61. #include "vm/vm_kern.h"
  62.  
  63. #include "machine/reg.h"
  64. extern int dostacklimits;
  65.  
  66. /* execve() system call. */
  67. /* ARGSUSED */
  68. execve(p, uap, retval)
  69.     struct proc *p;
  70.     register struct args {
  71.         char    *fname;
  72.         char    **argp;
  73.         char    **envp;
  74.     } *uap;
  75.     int *retval;
  76. {
  77.     register struct nameidata *ndp;
  78.     struct nameidata nd;
  79.     struct exec hdr;
  80.     char **argbuf, **argbufp, *stringbuf, *stringbufp;
  81.     char **vectp, *ep;
  82.     int needsenv, limitonargs, stringlen, addr, size, len,
  83.         rv, amt, argc, tsize, dsize, bsize, cnt, foff;
  84.     struct vattr attr;
  85.     struct vmspace *vs;
  86.     caddr_t newframe;
  87.     /* Step 1. Lookup filename to see if we have something to execute. */
  88.     ndp = &nd;
  89.     ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
  90.     ndp->ni_segflg = UIO_USERSPACE;
  91.     ndp->ni_dirp = uap->fname;
  92.     /* is it there? */
  93.     if (rv = namei(ndp, p))
  94.         return (rv);
  95.     /* is it a regular file? */
  96.     if (ndp->ni_vp->v_type != VREG) {
  97.         vput(ndp->ni_vp);
  98.         return(ENOEXEC);
  99.     }
  100.     /* is it executable? */
  101.     rv = VOP_ACCESS(ndp->ni_vp, VEXEC, p->p_ucred, p);
  102.     if (rv)
  103.         goto exec_fail;
  104.     /* does it have any attributes? */
  105.     rv = VOP_GETATTR(ndp->ni_vp, &attr, p->p_ucred, p);
  106.     if (rv)
  107.         goto exec_fail;
  108.     /* Step 2. Does file contain a format we can understand and execute */
  109.     rv = vn_rdwr(UIO_READ, ndp->ni_vp, (caddr_t)&hdr, sizeof(hdr),
  110.         0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &amt, p);
  111.     /* big enough to hold a header? */
  112.     if (rv)
  113.         goto exec_fail;
  114.     /* ... that we recognize? */
  115.     rv = ENOEXEC;
  116.     if (hdr.a_magic != ZMAGIC)
  117.         goto exec_fail;
  118.     /* sanity check  "ain't not such thing as a sanity clause" -groucho */
  119.     if (hdr.a_text > MAXTSIZ
  120.         || hdr.a_text % NBPG || hdr.a_text > attr.va_size)
  121.         goto exec_fail;
  122.     if (hdr.a_data == 0 || hdr.a_data > DFLDSIZ
  123.         || hdr.a_data > attr.va_size
  124.         || hdr.a_data + hdr.a_text > attr.va_size)
  125.         goto exec_fail;
  126.     if (hdr.a_bss > MAXDSIZ)
  127.         goto exec_fail;
  128.     if (hdr.a_text + hdr.a_data + hdr.a_bss > MAXTSIZ + MAXDSIZ)
  129.         goto exec_fail;
  130.     /* Step 3.  File and header are valid. Now, dig out the strings
  131.      * out of the old process image. */
  132.     /* We implement a single-pass algorithm that builds a new stack
  133.      * frame within the address space of the "old" process image,
  134.      * avoiding the second pass entirely. Thus, the new frame is
  135.      * in position to be run. This consumes much virtual address space,
  136.      * and two pages more of 'real' memory, such are the costs.
  137.      * [Also, note the cache wipe that's avoided!] */
  138.     /* create anonymous memory region for new stack */
  139.     vs = p->p_vmspace;
  140.     if ((unsigned)vs->vm_maxsaddr + MAXSSIZ < USRSTACK)
  141.         newframe = (caddr_t) USRSTACK - MAXSSIZ;
  142.     else
  143.         vs->vm_maxsaddr = newframe = (caddr_t) USRSTACK - 2*MAXSSIZ;
  144.     /* don't do stack limit checking on traps temporarily XXX*/
  145.     dostacklimits = 0;
  146.     rv = vm_allocate(&vs->vm_map, &newframe, MAXSSIZ, FALSE);
  147.     if (rv) goto exec_fail;
  148.     /* allocate string buffer and arg buffer */
  149.     argbuf = (char **) (newframe + MAXSSIZ - 3*ARG_MAX);
  150.     stringbuf = stringbufp = ((char *)argbuf) + 2*ARG_MAX;
  151.     argbufp = argbuf;
  152.     /* first, do args */
  153.     vectp = uap->argp;
  154.     needsenv = 1;
  155.     limitonargs = ARG_MAX;
  156.     cnt = 0;
  157. do_env_as_well:
  158.     if(vectp == 0) goto dont_bother;
  159.     /* for each envp, copy in string */
  160.     do {
  161.         /* did we outgrow initial argbuf, if so, die */
  162.         if (argbufp == (char **)stringbuf) {
  163.             rv = E2BIG;
  164.             goto exec_dealloc;
  165.         }
  166.         /* get an string pointer */
  167.         ep = (char *)fuword(vectp++);
  168.         if (ep == (char *)-1) {
  169.             rv = EFAULT;
  170.             goto exec_dealloc;
  171.         }
  172.         /* if not a null pointer, copy string */
  173.         if (ep) {
  174.             if (rv = copyinoutstr(ep, stringbufp,
  175.                 (u_int)limitonargs, (u_int *) &stringlen)) {
  176.                 if (rv == ENAMETOOLONG)
  177.                     rv = E2BIG;
  178.                 goto exec_dealloc;
  179.             }
  180.             suword(argbufp++, (int)stringbufp);
  181.             cnt++;
  182.             stringbufp += stringlen;
  183.             limitonargs -= stringlen;
  184.         } else {
  185.             suword(argbufp++, 0);
  186.             break;
  187.         }
  188.     } while (limitonargs > 0);
  189. dont_bother:
  190.     if (limitonargs <= 0) {
  191.         rv = E2BIG;
  192.         goto exec_dealloc;
  193.     }
  194.     /* have we done the environment yet ? */
  195.     if (needsenv) {
  196.         /* remember the arg count for later */
  197.         argc = cnt;
  198.         vectp = uap->envp;
  199.         needsenv = 0;
  200.         goto do_env_as_well;
  201.     }
  202.     /* At this point, one could optionally implement a second pass to 
  203.          * condense strings, arguement vectors, and stack to fit fewest pages.
  204.      * One might selectively do this when copying was cheaper
  205.      * than leaving allocated two more pages per process. */
  206.     /* stuff arg count on top of "new" stack */
  207.     argbuf[-1] = (char *)argc;
  208.     /* Step 4. Build the new processes image. At this point, we are 
  209.          * committed -- destroy old executable! */
  210.     /* blow away all address space, except the stack */
  211.     rv = vm_deallocate(&vs->vm_map, 0, USRSTACK - 2*MAXSSIZ, FALSE);
  212.     if (rv)
  213.         goto exec_abort;
  214.     /* destroy "old" stack */
  215.     if ((unsigned)newframe < USRSTACK - MAXSSIZ) {
  216.         rv = vm_deallocate(&vs->vm_map, USRSTACK - MAXSSIZ, MAXSSIZ,
  217.             FALSE);
  218.         if (rv)
  219.             goto exec_abort;
  220.     } else {
  221.         rv = vm_deallocate(&vs->vm_map, USRSTACK - 2*MAXSSIZ, MAXSSIZ,
  222.             FALSE);
  223.         if (rv)
  224.             goto exec_abort;
  225.     }
  226.     /* build a new address space */
  227.     addr = 0;
  228.     /* screwball mode -- special case of 413 to save space for floppy */
  229.     if (hdr.a_text == 0) {
  230.         foff = tsize = 0;
  231.         hdr.a_data += hdr.a_text;
  232.     } else {
  233.         tsize = roundup(hdr.a_text, NBPG);
  234.         foff = NBPG;
  235.     }
  236.     /* treat text and data in terms of integral page size */
  237.     dsize = roundup(hdr.a_data, NBPG);
  238.     bsize = roundup(hdr.a_bss + dsize, NBPG);
  239.     bsize -= dsize;
  240.     /* map text & data in file, as being "paged in" on demand */
  241.     rv = vm_mmap(&vs->vm_map, &addr, tsize+dsize, VM_PROT_ALL,
  242.         MAP_FILE|MAP_COPY|MAP_FIXED, (caddr_t)ndp->ni_vp, foff);
  243.     if (rv)
  244.         goto exec_abort;
  245.     /* mark pages r/w data, r/o text */
  246.     if (tsize) {
  247.         addr = 0;
  248.         rv = vm_protect(&vs->vm_map, addr, tsize, FALSE,
  249.             VM_PROT_READ|VM_PROT_EXECUTE);
  250.         if (rv)
  251.             goto exec_abort;
  252.     }
  253.     /* create anonymous memory region for bss */
  254.     addr = dsize + tsize;
  255.     rv = vm_allocate(&vs->vm_map, &addr, bsize, FALSE);
  256.     if (rv)
  257.         goto exec_abort;
  258.     /* Step 5. Prepare process for execution. */
  259.     /* touchup process information -- vm system is unfinished! */
  260.     vs->vm_tsize = tsize/NBPG;      /* text size (pages) XXX */
  261.     vs->vm_dsize = (dsize+bsize)/NBPG;  /* data size (pages) XXX */
  262.     vs->vm_taddr = 0;       /* user virtual address of text XXX */
  263.     vs->vm_daddr = (caddr_t)tsize;  /* user virtual address of data XXX */
  264.     vs->vm_maxsaddr = newframe; /* user VA at max stack growth XXX */
  265.     vs->vm_ssize =  ((unsigned)vs->vm_maxsaddr + MAXSSIZ
  266.         - (unsigned)argbuf)/ NBPG + 1; /* stack size (pages) */
  267.     dostacklimits = 1;  /* allow stack limits to be enforced XXX */
  268.     /* close files on exec, fixup signals */
  269.     fdcloseexec(p);
  270.     execsigs(p);
  271.     /* setup initial register state */
  272.     p->p_regs[SP] = (unsigned) (argbuf - 1);
  273.     setregs(p, hdr.a_entry);
  274.     vput(ndp->ni_vp);
  275.     return (0);
  276. exec_dealloc:
  277.     /* remove interim "new" stack frame we were building */
  278.     vm_deallocate(&vs->vm_map, newframe, MAXSSIZ, FALSE);
  279. exec_fail:
  280.     dostacklimits = 1;
  281.     vput(ndp->ni_vp);
  282.     return(rv);
  283. exec_abort:
  284.     /* sorry, no more process anymore. exit gracefully */
  285.     vm_deallocate(&vs->vm_map, newframe, MAXSSIZ, FALSE);
  286.     vput(ndp->ni_vp);
  287.     exit(p, W_EXITCODE(0, SIGABRT));
  288.     /* NOTREACHED */
  289.     return(0);
  290. }
  291.  
  292.  
  293. [LISTING TWO]
  294.  
  295. /* Copyright (c) 1992 William Jolitz. All rights reserved.
  296.  * Written by William Jolitz 1/92
  297.  * Redistribution and use in source and binary forms, with or without
  298.  * modification, are permitted provided that the following conditions
  299.  * are met:
  300.  * 1. Redistributions of source code must retain the above copyright
  301.  *    notice, this list of conditions and the following disclaimer.
  302.  * 2. Redistributions in binary form must reproduce the above copyright
  303.  *    notice, this list of conditions and the following disclaimer in the
  304.  *    documentation and/or other materials provided with the distribution.
  305.  * 3. All advertising materials mentioning features or use of this software
  306.  *    must display the following acknowledgement:
  307.  *  This software is a component of "386BSD" developed by 
  308.     William F. Jolitz, TeleMuse.
  309.  * 4. Neither the name of the developer nor the name "386BSD"
  310.  *    may be used to endorse or promote products derived from this software
  311.  *    without specific prior written permission.
  312.  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 
  313.  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS SOFTWARE 
  314.  * SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. THE DEVELOPER URGES 
  315.  * THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT NOT MAKE USE OF THIS WORK. THIS
  316.  * SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  317.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
  318.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 
  319.  * EVENT SHALL THE DEVELOPER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  320.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  321.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  322.  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  323.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
  324.  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
  325.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  326.  *
  327.  * Block I/O Cache mechanism, ala malloc(). */
  328. #include "param.h"
  329. #include "proc.h"
  330. #include "vnode.h"
  331. #include "buf.h"
  332. #include "specdev.h"
  333. #include "mount.h"
  334. #include "malloc.h"
  335. #include "resourcevar.h"
  336.  
  337. /* Initialize buffer headers and related structures.  */
  338. void bufinit()
  339. {
  340.     struct bufhd *bh;
  341.     struct buf *bp;
  342.  
  343.     /* first, make a null hash table */
  344.     for(bh = bufhash; bh < bufhash + BUFHSZ; bh++) {
  345.         bh->b_flags = 0;
  346.         bh->b_forw = (struct buf *)bh;
  347.         bh->b_back = (struct buf *)bh;
  348.     }
  349.     /* next, make a null set of free lists */
  350.     for(bp = bfreelist; bp < bfreelist + BQUEUES; bp++) {
  351.         bp->b_flags = 0;
  352.         bp->av_forw = bp;
  353.         bp->av_back = bp;
  354.         bp->b_forw = bp;
  355.         bp->b_back = bp;
  356.     }
  357.     /* finally, initialize each buffer header and stick on empty q */
  358.     for(bp = buf; bp < buf + nbuf ; bp++) {
  359.         bp->b_flags = B_HEAD | B_INVAL; /* we're just an empty header */
  360.         bp->b_dev = NODEV;
  361.         bp->b_vp = 0;
  362.         binstailfree(bp, bfreelist + BQ_EMPTY);
  363.         binshash(bp, bfreelist + BQ_EMPTY);
  364.     }
  365. }
  366. /* Find the block in the buffer pool. If buffer is not present, allocate a new
  367.  * buffer and load its contents according to the filesystem fill routine.  */
  368. bread(vp, blkno, size, cred, bpp)
  369.     struct vnode *vp;
  370.     daddr_t blkno;
  371.     int size;
  372.     struct ucred *cred;
  373.     struct buf **bpp;
  374. {
  375.     struct buf *bp;
  376.     int rv = 0;
  377.     bp = getblk (vp, blkno, size);
  378.     /* if not found in cache, do some I/O */
  379.     if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) {
  380.         bp->b_flags |= B_READ;
  381.         bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL);
  382.         VOP_STRATEGY(bp);
  383.         rv = biowait (bp);
  384.     }
  385.     *bpp = bp;
  386.     return (rv);
  387. }
  388. /* Operates like bread, but also starts I/O on the specified read-ahead block.
  389.  * [See page 55 of Bach's Book] */
  390. breada(vp, blkno, size, rablkno, rabsize, cred, bpp)
  391.     struct vnode *vp;
  392.     daddr_t blkno; int size;
  393.     daddr_t rablkno; int rabsize;
  394.     struct ucred *cred;
  395.     struct buf **bpp;
  396. {
  397.     struct buf *bp, *rabp;
  398.     int rv = 0, needwait = 0;
  399.     bp = getblk (vp, blkno, size);
  400.     /* if not found in cache, do some I/O */
  401.     if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) {
  402.         bp->b_flags |= B_READ;
  403.         bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL);
  404.         VOP_STRATEGY(bp);
  405.         needwait++;
  406.     }
  407.     rabp = getblk (vp, rablkno, rabsize);
  408.     /* if not found in cache, do some I/O (overlapped with first) */
  409.     if ((rabp->b_flags & B_CACHE) == 0 || (rabp->b_flags & B_INVAL) != 0) {
  410.         rabp->b_flags |= B_READ | B_ASYNC;
  411.         rabp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL);
  412.         VOP_STRATEGY(rabp);
  413.     } else
  414.         brelse(rabp);
  415.     /* wait for original I/O */
  416.     if (needwait)
  417.         rv = biowait (bp);
  418.     *bpp = bp;
  419.     return (rv);
  420. }
  421. /* Synchronous write. Release buffer on completion. */
  422. bwrite(bp)
  423.     register struct buf *bp;
  424. {
  425.     int rv;
  426.     if(bp->b_flags & B_INVAL) {
  427.         brelse(bp);
  428.         return (0);
  429.     } else {
  430.         int wasdelayed;
  431.         wasdelayed = bp->b_flags & B_DELWRI;
  432.         bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_ASYNC|B_DELWRI);
  433.         if(wasdelayed) reassignbuf(bp, bp->b_vp);
  434.         bp->b_flags |= B_DIRTY;
  435.         VOP_STRATEGY(bp);
  436.         rv = biowait(bp);
  437.         if (!rv)
  438.             bp->b_flags &= ~B_DIRTY;
  439.         brelse(bp);
  440.         return (rv);
  441.     }
  442. }
  443. /* Delayed write. The buffer is marked dirty, but is not queued for I/O. This 
  444.  * routine should be used when the buffer is expected to be modified again 
  445.  * soon, typically a small write that partially fills a buffer. NB: magnetic 
  446.  * tapes can't be delayed; must be written in order writes are requested. */
  447. void bdwrite(bp)
  448.     register struct buf *bp;
  449. {
  450.     if(bp->b_flags & B_INVAL)
  451.         brelse(bp);
  452.     if(bp->b_flags & B_TAPE) {
  453.         bwrite(bp);
  454.         return;
  455.     }
  456.     bp->b_flags &= ~(B_READ|B_DONE);
  457.     bp->b_flags |= B_DIRTY|B_DELWRI;
  458.     reassignbuf(bp, bp->b_vp);
  459.     brelse(bp);
  460.     return;
  461. }
  462. /* Asynchronous write. Start I/O on a buffer, but do not wait for it to 
  463.  * complete. The buffer is released when the I/O completes. */
  464. bawrite(bp)
  465.     register struct buf *bp;
  466. {
  467.     if(!(bp->b_flags & B_BUSY))panic("bawrite: not busy");
  468.     if(bp->b_flags & B_INVAL)
  469.         brelse(bp);
  470.     else {
  471.         int wasdelayed;
  472.         wasdelayed = bp->b_flags & B_DELWRI;
  473.         bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
  474.         if(wasdelayed) reassignbuf(bp, bp->b_vp);
  475.         bp->b_flags |= B_DIRTY | B_ASYNC;
  476.         VOP_STRATEGY(bp);
  477.     }
  478. }
  479. /* Release a buffer. Even if the buffer is dirty, no I/O is started. */
  480. brelse(bp)
  481.     register struct buf *bp;
  482. {
  483.     int x;
  484.     /* anyone need a "free" block? */
  485.     x=splbio();
  486.     if ((bfreelist + BQ_AGE)->b_flags & B_WANTED) {
  487.         (bfreelist + BQ_AGE) ->b_flags &= ~B_WANTED;
  488.         wakeup(bfreelist);
  489.     }
  490.     /* anyone need this very block? */
  491.     if (bp->b_flags & B_WANTED) {
  492.         bp->b_flags &= ~B_WANTED;
  493.         wakeup(bp);
  494.     }
  495.     if (bp->b_flags & (B_INVAL|B_ERROR)) {
  496.         bp->b_flags |= B_INVAL;
  497.         bp->b_flags &= ~(B_DELWRI|B_CACHE);
  498.         if(bp->b_vp)
  499.             brelvp(bp);
  500.     }
  501.     /* enqueue */
  502.     /* buffers with junk contents */
  503.     if(bp->b_flags & (B_ERROR|B_INVAL|B_NOCACHE))
  504.         binsheadfree(bp, bfreelist + BQ_AGE)
  505.     /* buffers with stale but valid contents */
  506.     else if(bp->b_flags & B_AGE)
  507.         binstailfree(bp, bfreelist + BQ_AGE)
  508.     /* buffers with valid and quite potentially reuseable contents */
  509.     else
  510.         binstailfree(bp, bfreelist + BQ_LRU)
  511.     /* unlock */
  512.     bp->b_flags &= ~B_BUSY;
  513.     splx(x);
  514.     return;
  515. }
  516. int freebufspace = 20*NBPG;
  517. int allocbufspace;
  518. /* Find a buffer which is available for use. If free memory for buffer space 
  519.  * and an empty header from the empty list, use that. Otherwise, select 
  520.  * something from a free list. Preference is to AGE list, then LRU list. */
  521. struct buf *
  522. getnewbuf(sz)
  523. {
  524.     struct buf *bp;
  525.     int x;
  526.     x = splbio();
  527. start:
  528.     /* can we constitute a new buffer? */
  529.     if (freebufspace > sz
  530.       && bfreelist[BQ_EMPTY].av_forw != (struct buf *)bfreelist+BQ_EMPTY) {
  531.       caddr_t addr;
  532.         if ((addr = malloc (sz, M_TEMP, M_NOWAIT)) == 0) goto tryfree;
  533.         freebufspace -= sz;
  534.         allocbufspace += sz;
  535.         bp = bfreelist[BQ_EMPTY].av_forw;
  536.         bp->b_flags = B_BUSY | B_INVAL;
  537.         bremfree(bp);
  538.         bp->b_un.b_addr = (caddr_t) addr;
  539.         goto fillin;
  540.     }
  541. tryfree:
  542.     if (bfreelist[BQ_AGE].av_forw != (struct buf *)bfreelist+BQ_AGE) {
  543.         bp = bfreelist[BQ_AGE].av_forw;
  544.         bremfree(bp);
  545.     } else if (bfreelist[BQ_LRU].av_forw != (struct buf *)bfreelist+BQ_LRU) {
  546.         bp = bfreelist[BQ_LRU].av_forw;
  547.         bremfree(bp);
  548.     } else  {
  549.         /* wait for a free buffer of any kind */
  550.         (bfreelist + BQ_AGE)->b_flags |= B_WANTED;
  551.         sleep(bfreelist, PRIBIO);
  552.         splx(x);
  553.         return (0);
  554.     }
  555.     /* if we are a delayed write, convert to an async write! */
  556.     if (bp->b_flags & B_DELWRI) {
  557.         bp->b_flags |= B_BUSY;
  558.         bawrite (bp);
  559.         goto start;
  560.     }
  561.     if(bp->b_vp)
  562.         brelvp(bp);
  563.     /* we are not free, nor do we contain interesting data */
  564.     bp->b_flags = B_BUSY;
  565. fillin:
  566.     bremhash(bp);
  567.     splx(x);
  568.     bp->b_dev = NODEV;
  569.     bp->b_vp = NULL;
  570.     bp->b_blkno = bp->b_lblkno = 0;
  571.     bp->b_iodone = 0;
  572.     bp->b_error = 0;
  573.     bp->b_wcred = bp->b_rcred = NOCRED;
  574.     if (bp->b_bufsize != sz) allocbuf(bp, sz);
  575.     bp->b_bcount = bp->b_bufsize = sz;
  576.     bp->b_dirtyoff = bp->b_dirtyend = 0;
  577.     return (bp);
  578. }
  579. /* Check to see if a block is currently memory resident. */
  580. struct buf *incore(vp, blkno)
  581.     struct vnode *vp;
  582.     daddr_t blkno;
  583. {
  584.     struct buf *bh;
  585.     struct buf *bp;
  586.     bh = BUFHASH(vp, blkno);
  587.     /* Search hash chain */
  588.     bp = bh->b_forw;
  589.     while (bp != (struct buf *) bh) {
  590.         /* hit */
  591.         if (bp->b_lblkno == blkno && bp->b_vp == vp
  592.             && (bp->b_flags & B_INVAL) == 0)
  593.             return (bp);
  594.         bp = bp->b_forw;
  595.     }
  596.     return(0);
  597. }
  598. /* Get a block of requested size that is associated with a given vnode and 
  599.  * block offset. If it is found in block cache, mark it as found, make it busy
  600.  * and return it. Otherwise, return empty block of the correct size. It is up 
  601.  * to caller to insure that the cached blocks be of the correct size. */
  602. struct buf *
  603. getblk(vp, blkno, size)
  604.     register struct vnode *vp;
  605.     daddr_t blkno;
  606.     int size;
  607. {
  608.     struct buf *bp, *bh;
  609.     int x;
  610.     for (;;) {
  611.         if (bp = incore(vp, blkno)) {
  612.             x = splbio();
  613.             if (bp->b_flags & B_BUSY) {
  614.                 bp->b_flags |= B_WANTED;
  615.                 sleep (bp, PRIBIO);
  616.                 continue;
  617.             }
  618.             bp->b_flags |= B_BUSY | B_CACHE;
  619.             bremfree(bp);
  620.             if (size > bp->b_bufsize)
  621.                 panic("now what do we do?");
  622.         } else {
  623.             if((bp = getnewbuf(size)) == 0) continue;
  624.             bp->b_blkno = bp->b_lblkno = blkno;
  625.             bgetvp(vp, bp);
  626.             x = splbio();
  627.             bh = BUFHASH(vp, blkno);
  628.             binshash(bp, bh);
  629.             bp->b_flags = B_BUSY;
  630.         }
  631.         splx(x);
  632.         return (bp);
  633.     }
  634. }
  635. /* Get an empty, disassociated buffer of given size. */
  636. struct buf *
  637. geteblk(size)
  638.     int size;
  639. {
  640.     struct buf *bp;
  641.     int x;
  642.     while ((bp = getnewbuf(size)) == 0)
  643.         ;
  644.     x = splbio();
  645.     binshash(bp, bfreelist + BQ_AGE);
  646.     splx(x);
  647.     return (bp);
  648. }
  649. /* Exchange a buffer's underlying buffer storage for one of different size, 
  650.  * taking care to maintain contents appropriately. When buffer increases in 
  651.  * size, caller is responsible for filling out additional contents. When buffer
  652.  * shrinks in size, data is lost, so caller must first return it to backing 
  653.  * store before shrinking the buffer, as no implied I/O will be done.
  654.  * Expanded buffer is returned as value. */
  655. struct buf *
  656. allocbuf(bp, size)
  657.     register struct buf *bp;
  658.     int size;
  659. {
  660.     caddr_t newcontents;
  661.     /* get new memory buffer */
  662.     newcontents = (caddr_t) malloc (size, M_TEMP, M_WAITOK);
  663.     /* copy the old into the new, up to the maximum that will fit */
  664.     bcopy (bp->b_un.b_addr, newcontents, min(bp->b_bufsize, size));
  665.     /* return old contents to free heap */
  666.     free (bp->b_un.b_addr, M_TEMP);
  667.     /* adjust buffer cache's idea of memory allocated to buffer contents */
  668.     freebufspace -= size - bp->b_bufsize;
  669.     allocbufspace += size - bp->b_bufsize;
  670.     /* update buffer header */
  671.     bp->b_un.b_addr = newcontents;
  672.     bp->b_bcount = bp->b_bufsize = size;
  673.     return(bp);
  674. }
  675. /* Patiently await operations to complete on this buffer. When they do, 
  676.  * extract error value and return it. Extract and return any errors associated
  677.  * with the I/O. If an invalid block, force it off the lookup hash chains. */
  678. biowait(bp)
  679.     register struct buf *bp;
  680. {
  681.     int x;
  682.     x = splbio();
  683.     while ((bp->b_flags & B_DONE) == 0)
  684.         sleep((caddr_t)bp, PRIBIO);
  685.     if((bp->b_flags & B_ERROR) || bp->b_error) {
  686.         if ((bp->b_flags & B_INVAL) == 0) {
  687.             bp->b_flags |= B_INVAL;
  688.             bremhash(bp);
  689.             binshash(bp, bfreelist + BQ_AGE);
  690.         }
  691.         if (!bp->b_error)
  692.             bp->b_error = EIO;
  693.         else
  694.             bp->b_flags |= B_ERROR;
  695.         splx(x);
  696.         return (bp->b_error);
  697.     } else {
  698.         splx(x);
  699.         return (0);
  700.     }
  701. }
  702. /* Finish up operations on a buffer, calling an optional function (if 
  703.  * requested), and releasing the buffer if marked asynchronous. Then mark this 
  704.  * buffer done so that others biowait()'ing for it will notice when they are
  705.  * woken up from sleep(). */
  706. biodone(bp)
  707.     register struct buf *bp;
  708. {
  709.     int x;
  710.     x = splbio();
  711.     if (bp->b_flags & B_CALL) (*bp->b_iodone)(bp);
  712.     bp->b_flags &=  ~B_CALL;
  713.     if (bp->b_flags & B_ASYNC) brelse(bp);
  714.     bp->b_flags &=  ~B_ASYNC;
  715.     bp->b_flags |= B_DONE;
  716.     wakeup(bp);
  717.     splx(x);
  718. }
  719.  
  720.  
  721. [LISTING THREE]
  722.  
  723. /* Copyright (c) 1992 William F. Jolitz. All rights reserved.
  724.  * Written by William Jolitz 1/92
  725.  * Redistribution and use in source and binary forms, with or without
  726.  * modification, are permitted provided that the following conditions
  727.  * are met: 1. Redistributions of source code must retain the above copyright
  728.  *    notice, this list of conditions and the following disclaimer.
  729.  * 2. Redistributions in binary form must reproduce the above copyright
  730.  *    notice, this list of conditions and the following disclaimer in the
  731.  *    documentation and/or other materials provided with the distribution.
  732.  * 3. All advertising materials mentioning features or use of this software
  733.  *    must display the following acknowledgement:
  734.  *  This software is a component of "386BSD" developed by 
  735.     William F. Jolitz, TeleMuse.
  736.  * 4. Neither the name of the developer nor the name "386BSD"
  737.  *    may be used to endorse or promote products derived from this software
  738.  *    without specific prior written permission.
  739.  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 
  740.  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS SOFTWARE 
  741.  * SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. THE DEVELOPER URGES 
  742.  * THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT NOT MAKE USE OF THIS WORK. THIS 
  743.  * SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND ANY EXPRESS OR IMPLIED 
  744.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
  745.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  746.  * EVENT SHALL THE DEVELOPER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  747.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  748.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  749.  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  750.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
  751.  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
  752.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  753.  *
  754.  * Ring Buffer code for 386BSD. */
  755. #include "param.h"
  756. #include "systm.h"
  757. #include "buf.h"
  758. #include "ioctl.h"
  759. #include "tty.h"
  760.  
  761. putc(c, rbp) struct ringb *rbp;
  762. {
  763.     char *nxtp;
  764.     /* ring buffer full? */
  765.     if ( (nxtp = RB_SUCC(rbp, rbp->rb_tl)) == rbp->rb_hd) return (-1);
  766.     /* stuff character */
  767.     *rbp->rb_tl = c;
  768.     rbp->rb_tl = nxtp;
  769.     return(0);
  770. }
  771. getc(rbp) struct ringb *rbp;
  772. {
  773.     u_char c;
  774.     /* ring buffer empty? */
  775.     if (rbp->rb_hd == rbp->rb_tl) return(-1);
  776.     /* fetch character, locate next character */
  777.     c = *(u_char *) rbp->rb_hd;
  778.     rbp->rb_hd = RB_SUCC(rbp, rbp->rb_hd);
  779.     return (c);
  780. }
  781. nextc(cpp, rbp) struct ringb *rbp; char **cpp; {
  782.     if (*cpp == rbp->rb_tl) return (0);
  783.     else {  char *cp;
  784.         cp = *cpp;
  785.         *cpp = RB_SUCC(rbp, cp);
  786.         return(*cp);
  787.     }
  788. }
  789. ungetc(c, rbp) struct ringb *rbp;
  790. {
  791.     char    *backp;
  792.     /* ring buffer full? */
  793.     if ( (backp = RB_PRED(rbp, rbp->rb_hd)) == rbp->rb_tl) return (-1);
  794.     rbp->rb_hd = backp;
  795.     /* stuff character */
  796.     *rbp->rb_hd = c;
  797.     return(0);
  798. }
  799. unputc(rbp) struct ringb *rbp;
  800. {
  801.     char    *backp;
  802.     int c;
  803.     /* ring buffer empty? */
  804.     if (rbp->rb_hd == rbp->rb_tl) return(-1);
  805.     /* backup buffer and dig out previous character */
  806.     backp = RB_PRED(rbp, rbp->rb_tl);
  807.     c = *(u_char *)backp;
  808.     rbp->rb_tl = backp;
  809.     return(c);
  810. }
  811. #define peekc(rbp)  (*(rbp)->rb_hd)
  812. initrb(rbp) struct ringb *rbp; {
  813.     rbp->rb_hd = rbp->rb_tl = rbp->rb_buf;
  814. }
  815. /* Example code for contiguous operations: 
  816.     ...
  817.     nc = RB_CONTIGPUT(&rb);
  818.     if (nc) {
  819.     if (nc > 9) nc = 9;
  820.         bcopy("ABCDEFGHI", rb.rb_tl, nc);
  821.         rb.rb_tl += nc;
  822.         rb.rb_tl = RB_ROLLOVER(&rb, rb.rb_tl);
  823.     }
  824.     ...
  825.     ...
  826.     nc = RB_CONTIGGET(&rb);
  827.     if (nc) {
  828.         if (nc > 79) nc = 79;
  829.         bcopy(rb.rb_hd, stringbuf, nc);
  830.         rb.rb_hd += nc;
  831.         rb.rb_hd = RB_ROLLOVER(&rb, rb.rb_hd);
  832.         stringbuf[nc] = 0;
  833.         printf("%s|", stringbuf);
  834.     }
  835.     ...
  836.  */
  837. /* Concatinate ring buffers. */
  838. catb(from, to)
  839.     struct ringb *from, *to;
  840. {
  841.     char c;
  842.     while ((c = getc(from)) >= 0)
  843.         putc(c, to);
  844. }
  845.  
  846.  
  847. [LISTING FOUR]
  848.  
  849. /* [Excerpted from tty.h, 386BSD Release 0.0 - wfj] */
  850. /* Ring buffers provide a contiguous, dense storage for character data used 
  851.  * by the tty driver. */
  852. #define RBSZ 1024
  853. struct ringb {
  854.     char    *rb_hd;   /* head of buffer segment to be read */
  855.     char    *rb_tl;   /* tail of buffer segment to be written */
  856.     char    rb_buf[RBSZ];   /* segment contents */
  857. };
  858. #define RB_SUCC(rbp, p) \
  859.         ((p) >= (rbp)->rb_buf + RBSZ - 1 ? (rbp)->rb_buf : (p) + 1)
  860. #define RB_ROLLOVER(rbp, p) \
  861.         ((p) > (rbp)->rb_buf + RBSZ - 1 ? (rbp)->rb_buf : (p))
  862. #define RB_PRED(rbp, p) \
  863.         ((p) <= (rbp)->rb_buf ? (rbp)->rb_buf + RBSZ - 1 : (p) - 1)
  864. #define RB_LEN(rp) \
  865.         ((rp)->rb_hd <= (rp)->rb_tl ? (rp)->rb_tl - (rp)->rb_hd : \
  866.         RBSZ - ((rp)->rb_hd - (rp)->rb_tl))
  867. #define RB_CONTIGPUT(rp) \
  868.         (RB_PRED(rp, (rp)->rb_hd) < (rp)->rb_tl ?  \
  869.             (rp)->rb_buf + RBSZ - (rp)->rb_tl : \
  870.             RB_PRED(rp, (rp)->rb_hd) - (rp)->rb_tl)
  871. #define RB_CONTIGGET(rp) \
  872.         ((rp)->rb_hd <= (rp)->rb_tl ? (rp)->rb_tl - (rp)->rb_hd : \
  873.         (rp)->rb_buf + RBSZ - (rp)->rb_hd)
  874.  
  875.  
  876.