Annotation of coherent/b/STREAMS/coh.386/pipe.c, revision 1.1

1.1     ! root        1: /* $Header: /ker/coh.386/RCS/pipe.c,v 2.2 93/07/26 14:28:58 nigel Exp $ */
        !             2: /* (lgl-
        !             3:  *     The information contained herein is a trade secret of Mark Williams
        !             4:  *     Company, and  is confidential information.  It is provided  under a
        !             5:  *     license agreement,  and may be  copied or disclosed  only under the
        !             6:  *     terms of  that agreement.  Any  reproduction or disclosure  of this
        !             7:  *     material without the express written authorization of Mark Williams
        !             8:  *     Company or persuant to the license agreement is unlawful.
        !             9:  *
        !            10:  *     COHERENT Version 2.3.37
        !            11:  *     Copyright (c) 1982, 1983, 1984.
        !            12:  *     An unpublished work by Mark Williams Company, Chicago.
        !            13:  *     All rights reserved.
        !            14:  -lgl) */
        !            15: /*
        !            16:  * Coherent.
        !            17:  * Pipes.
        !            18:  *
        !            19:  * $Log:       pipe.c,v $
        !            20:  * Revision 2.2  93/07/26  14:28:58  nigel
        !            21:  * Nigel's R80
        !            22:  * 
        !            23:  * Revision 1.7  93/04/14  10:06:40  root
        !            24:  * r75
        !            25:  * 
        !            26:  * Revision 1.2  92/01/06  11:59:52  hal
        !            27:  * Compile with cc.mwc.
        !            28:  * 
        !            29:  * Revision 1.1        88/03/24  16:14:07      src
        !            30:  * Initial revision
        !            31:  * 
        !            32:  * 86/11/19    Allan Cornish           /usr/src/sys/coh/pipe.c
        !            33:  * Added check for non-blocking read and write if (io_flag & IPNDLY) set.
        !            34:  * Eliminated use of i_a inode field since now included in inode macros.
        !            35:  */
        !            36: 
        !            37: #include <kernel/_sleep.h>
        !            38: #include <sys/coherent.h>
        !            39: #include <sys/errno.h>
        !            40: #include <sys/filsys.h>
        !            41: #include <sys/ino.h>
        !            42: #include <sys/inode.h>
        !            43: #include <sys/io.h>
        !            44: #include <sys/proc.h>
        !            45: #include <sys/sched.h>
        !            46: #include <sys/file.h>
        !            47: #include <signal.h>
        !            48: 
        !            49: /*
        !            50:  *  These are nothing more than random different values at this point!
        !            51:  *  Historically, these were bit's or'ed into ip->i_flag, no more!
        !            52:  */
        !            53: 
        !            54: #define        IFWFR   1                       /* Sleeping Waiting for a Reader */
        !            55: #define        IFWFW   2                       /* Sleeping Waiting for a Writer */
        !            56: 
        !            57: 
        !            58: /*
        !            59:  *  pmake(mode)  --  called from the upipe() system call in sys3.c
        !            60:  *
        !            61:  *  Creates and returns a locked pipe inode with the given mode on
        !            62:  *  the pipedev.
        !            63:  */
        !            64: 
        !            65: INODE *
        !            66: pmake(mode)
        !            67: {
        !            68:        register INODE *ip;
        !            69: 
        !            70:        if ((ip = ialloc (pipedev, IFPIPE | mode)) != NULL)
        !            71:                pclear (ip);
        !            72:        pdump ("M", ip, mode);
        !            73:        return ip;
        !            74: }
        !            75: 
        !            76: pclear(ip)
        !            77: register INODE *ip;
        !            78: {
        !            79:        ip->i_pnc =
        !            80:        ip->i_prx =
        !            81:        ip->i_pwx =
        !            82:        ip->i_par =
        !            83:        ip->i_paw =
        !            84:        ip->i_psr =
        !            85:        ip->i_psw = 0;
        !            86:        ip->i_iev.e_pnext =
        !            87:        ip->i_iev.e_dnext =
        !            88:        ip->i_iev.e_dlast =
        !            89:        ip->i_iev.e_procp =
        !            90:        ip->i_oev.e_pnext =
        !            91:        ip->i_oev.e_dnext =
        !            92:        ip->i_oev.e_dlast =
        !            93:        ip->i_oev.e_procp = NULL;
        !            94: }
        !            95: 
        !            96: /*
        !            97:  *  popen(ip, mode)  --  Opens a pipe inode, with the given mode.
        !            98:  *                      Note:  The inode is locked upon entry.
        !            99:  *
        !           100:  *  This routine follows the requirements concerning opening pipes.
        !           101:  *  Specifically, if opening readonly without O_NDELAY, then block
        !           102:  *  until we have a writer.  If opening readonly with O_NDELAY, then
        !           103:  *  return opened, no blocking.  If opening writeonly without O_NDELAY,
        !           104:  *  then block until we have a reader.  If opening writeonly with
        !           105:  *  O_NDELAY, then return an error, and set u.u_errno to ENXIO.
        !           106:  *  Beware of subtle race conditions!  Also notice, I followed hal's
        !           107:  *  style of no internal returns in a function.
        !           108:  *
        !           109:  *  Note: these pipe routines maintain the pipe counter variables:
        !           110:  *       ip->i_par:  Number of Awake readers
        !           111:  *       ip->i_paw:  Number of Awake writers
        !           112:  *       ip->i_psr:  Number of Sleeping readers
        !           113:  *       ip->i_psw:  Number of Sleeping writers
        !           114:  */
        !           115: 
        !           116: popen(ip, mode)
        !           117: register INODE *ip;
        !           118: {
        !           119:        pdump ("OA", ip, mode);
        !           120:        switch (mode & (IPR | IPW)) {
        !           121:        case IPR:
        !           122:                ++ip->i_par;
        !           123:                while (! ip->i_paw && ! ip->i_psw) {
        !           124:                        if (mode & (IPNDLY | IPNONBLOCK))
        !           125:                                break;
        !           126:                        else {
        !           127:                                if (psleep (ip, IFWFW) < 0) {
        !           128:                                        -- ip->i_par;
        !           129:                                        goto popen_done;
        !           130:                                }
        !           131:                                if (ip->i_pnc != 0)
        !           132:                                        break;
        !           133:                        }
        !           134:                }
        !           135:                pwake (ip, IFWFR);
        !           136:                break;
        !           137: 
        !           138:        case IPW:
        !           139:                ++ ip->i_paw;
        !           140:                if (! ip->i_par && ! ip->i_psr) {
        !           141:                        if (mode & (IPNDLY | IPNONBLOCK)) {
        !           142:                                u.u_error = ENXIO;
        !           143:                                -- ip->i_paw;
        !           144:                                goto popen_done;
        !           145:                        } else {
        !           146:                                if (psleep (ip, IFWFR) < 0) {
        !           147:                                        -- ip->i_paw;
        !           148:                                        goto popen_done;
        !           149:                                }
        !           150:                        }
        !           151:                }
        !           152:                pwake (ip, IFWFW);
        !           153:                break;
        !           154: 
        !           155:        case IPR | IPW:
        !           156:                ++ ip->i_par;
        !           157:                ++ ip->i_paw;
        !           158:                pwake (ip, IFWFW);
        !           159:                pwake (ip, IFWFR);
        !           160:                break;
        !           161:        }
        !           162: 
        !           163: popen_done:
        !           164:        pdump ("OZ", ip, mode);
        !           165:        return;
        !           166: }
        !           167: 
        !           168: 
        !           169: /*
        !           170:  *  pclose(ip, mode)  --  Opens a pipe inode, with the given mode.
        !           171:  *                       Note:  The inode is locked upon entry.
        !           172:  *
        !           173:  *  This routine closes the given INODE with the given mode.  We
        !           174:  *  must have the mode correct to maintain counters properly.
        !           175:  *  Good thing that mode cannot be changed by fcntl()!
        !           176:  */
        !           177: 
        !           178: pclose(ip, mode)
        !           179: register INODE *ip;
        !           180: {
        !           181:        pdump ("CA", ip, mode);
        !           182:        pwake (ip, IFWFR);
        !           183:        pwake (ip, IFWFW);
        !           184:        if (mode & IPR)
        !           185:                if (-- ip->i_par < 0)
        !           186:                        panic ("Out of sync IPR in pclose");
        !           187:        if (mode & IPW)
        !           188:                if (-- ip->i_paw < 0)
        !           189:                        panic ("Out of sync IPW in pclose");
        !           190: 
        !           191:        if (! ip->i_paw && ! ip->i_psw && ! ip->i_par && ! ip->i_psr)
        !           192:                pclear (ip);
        !           193:        pdump ("CZ", ip, mode);
        !           194: }
        !           195: 
        !           196: 
        !           197: /*
        !           198:  *  pread(ip, iop)  --  Reads from a pipe inode, accoring to the IO info.
        !           199:  *                     Note:  The inode is locked upon entry.
        !           200:  *
        !           201:  *  This routine follows the requirements concerning reading from pipes.
        !           202:  *  Specifically, if there is no data in the pipe, then the read will
        !           203:  *  block waiting for data, unless you have IONDLY set in which case
        !           204:  *  it will simply return zero.  Notice, the traditional value returned
        !           205:  *  from uread() is the number of characters actually read.  This is
        !           206:  *  nothing more that iop->io_ioc on entry minus iop->io_ioc on exit.
        !           207:  *  This routine also works with the ring buffer in the inode maintained
        !           208:  *  by the variables ip->i_pnc:  Number of Characters in pipe.
        !           209:  *                  ip->i_prx:  Offset in pipe to begin reading.
        !           210:  *                  ip->i_pwx:  Offset in pipe to begin writing.
        !           211:  *  Notice: we do not unlock the inode when we call fread(), this is to
        !           212:  *  guarantee that we read all that is available even if we go to sleep.
        !           213:  *  Subtle race condition?  I don't think so, since if we go to sleep
        !           214:  *  in fread(), it's wrt a resource unrelated to this particular INODE.
        !           215:  */
        !           216: 
        !           217: pread(ip, iop)
        !           218: register INODE *ip;
        !           219: register IO *iop;
        !           220: {
        !           221:        register unsigned n;
        !           222:        register unsigned ioc;
        !           223: 
        !           224:        pdump ("R", ip, 0);
        !           225:        while (ip->i_pnc == 0) {
        !           226:                /*
        !           227:                 * If we are in O_NDELAY mode, just return and uread () will
        !           228:                 * see nothing read, returning 0 to the user.
        !           229:                 */
        !           230:                if ((iop->io_flag & IONDLY) != 0)
        !           231:                        goto pread_done;
        !           232:                /*
        !           233:                 * If we are in O_NONBLOCK mode, set u.u_error so that upon
        !           234:                 * returning to user level the return value of uread () gets
        !           235:                 * forced to -1. Layering? What layering?
        !           236:                 */
        !           237:                if ((iop->io_flag & IONONBLOCK) != 0) {
        !           238:                        u.u_error = EAGAIN;
        !           239:                        goto pread_done;
        !           240:                }
        !           241:                if (! ip->i_paw && ! ip->i_psw)
        !           242:                        goto pread_done;
        !           243:                if (psleep (ip, IFWFW) < 0)
        !           244:                        goto pread_done;
        !           245:        }
        !           246: 
        !           247:        ioc = iop->io_ioc;
        !           248:        while (! u.u_error && ioc > 0 && ip->i_pnc > 0) {
        !           249:                if ((n = (PIPSIZE - ip->i_prx)) > ioc)
        !           250:                        n = ioc;
        !           251:                if (n > ip->i_pnc)
        !           252:                        n = ip->i_pnc;
        !           253:                iop->io_ioc = n;
        !           254:                iop->io_seek = ip->i_prx;
        !           255:                fread (ip, iop);
        !           256:                n -= iop->io_ioc;
        !           257:                if ((ip->i_prx += n) == PIPSIZE)
        !           258:                        ip->i_prx = 0;
        !           259:                if ((ip->i_pnc -= n) == 0) {
        !           260:                        ip->i_prx =
        !           261:                        ip->i_pwx = 0;
        !           262:                }
        !           263:                ioc -= n;
        !           264:        }
        !           265:        iop->io_ioc = ioc;
        !           266: 
        !           267:        if (ip->i_pnc < PIPSIZE)
        !           268:                pwake (ip, IFWFR);
        !           269: 
        !           270: pread_done:
        !           271:        return;
        !           272: }
        !           273: 
        !           274: 
        !           275: /*
        !           276:  *  pwrite(ip, iop)  --  Writes to a pipe inode, according to the IO info.
        !           277:  *                      Note:  The inode is locked upon entry.
        !           278:  *
        !           279:  *  This routine follows the requirements concerning writing to pipes.
        !           280:  *  Specifically, if the pipe is full, then the write will block waiting
        !           281:  *  for data to be consumed, unless you have IONDLY set in which case
        !           282:  *  it will simply return zero.  Notice, the traditional value returned
        !           283:  *  from uwrite() is the number of characters actually written.  This is
        !           284:  *  nothing more that iop->io_ioc on entry minus iop->io_ioc on exit.
        !           285:  *  In other words, iop->io_ioc had better be zero on exit.  The possibility
        !           286:  *  does exist if the number of characters to be written is larger than
        !           287:  *  PIPSIZE, and thus we do not guarantee atomic writes, that while the
        !           288:  *  process is sleeping waiting for a reader to consume data, that the
        !           289:  *  process will be woken from sleeping by a SIGNAL, thus causing a partial
        !           290:  *  write.  The return value will be the actual number of character written.
        !           291:  *  This routine also works with the ring buffer in the inode maintained
        !           292:  *  by the variables ip->i_pnc:  Number of Characters in pipe.
        !           293:  *                  ip->i_prx:  Offset in pipe to begin reading.
        !           294:  *                  ip->i_pwx:  Offset in pipe to begin writing.
        !           295:  *  Notice: we do not unlock the inode when we call fwrite(), this is to
        !           296:  *  guarantee that we have an atomic write for all writes of size less
        !           297:  *  than PIPSIZE, even if we go to sleep in the fwrite().  Subtle race
        !           298:  *  condition?  I don't think so, since if we go to sleep in fwrite(),
        !           299:  *  it's wrt a resource unrelated to this particular INODE.
        !           300:  */
        !           301: 
        !           302: pwrite(ip, iop)
        !           303: register INODE *ip;
        !           304: register IO *iop;
        !           305: {
        !           306:        register unsigned n;
        !           307:        register unsigned ioc;
        !           308: 
        !           309:        pdump ("W", ip, 0);
        !           310:        ioc = iop->io_ioc;
        !           311:        while (! u.u_error && (ioc > 0)) {
        !           312:                if (! ip->i_par && ! ip->i_psr) {
        !           313:                        u.u_error = EPIPE;
        !           314:                        sendsig (SIGPIPE, SELF);
        !           315:                        goto pwrite_done;
        !           316:                }
        !           317:                if ((n = PIPSIZE - ip->i_pwx) > ioc)
        !           318:                        n = ioc;
        !           319:                if (n > PIPSIZE - ip->i_pnc)
        !           320:                        n = PIPSIZE - ip->i_pnc;
        !           321:                if (n == 0 || (ioc <= PIPSIZE && n != ioc)) {
        !           322:                        /*
        !           323:                         * If we are in O_NDELAY mode, just return and all
        !           324:                         * uwrite () will see is 0 bytes written.
        !           325:                         */
        !           326:                        if ((iop->io_flag & IONDLY) != 0)
        !           327:                                goto pwrite_done;
        !           328:                        /*
        !           329:                         * If we are in O_NONBLOCK mode, set u.u_error so that
        !           330:                         * the return from system-call code will force the
        !           331:                         * return value of uwrite () to -1.
        !           332:                         */
        !           333:                        if ((iop->io_flag & IONONBLOCK) != 0) {
        !           334:                                u.u_error = EAGAIN;
        !           335:                                goto pwrite_done;
        !           336:                        }
        !           337:                        if (psleep (ip, IFWFR) < 0)
        !           338:                                goto pwrite_done;
        !           339:                        continue;
        !           340:                }
        !           341:                iop->io_ioc = n;
        !           342:                iop->io_seek = ip->i_pwx;
        !           343:                fwrite (ip, iop);
        !           344:                n -= iop->io_ioc;
        !           345:                if ((ip->i_pwx += n) == PIPSIZE)
        !           346:                        ip->i_pwx = 0;
        !           347:                ip->i_pnc += n;
        !           348:                ioc -= n;
        !           349: 
        !           350:                if (ip->i_pnc > 0)
        !           351:                        pwake (ip, IFWFW);
        !           352:        }
        !           353: pwrite_done:
        !           354:        iop->io_ioc = ioc;
        !           355: }
        !           356: 
        !           357: 
        !           358: /*
        !           359:  *  psleep(ip, who)  --  go to sleep either waiting for a reader if (who==IFWFR)
        !           360:  *                      or waiting for a writer if (who==IFWFW).
        !           361:  *  Returns:  0  if woke up ok
        !           362:  *          -1  if woke up by signal (e.g. SIGALRM, SIGKILL, etc.)
        !           363:  */
        !           364: 
        !           365: psleep(ip, who)
        !           366: register INODE *ip;
        !           367: {
        !           368:        __sleep_t       sleep;
        !           369: 
        !           370:        pdump ("SA", ip, 0);
        !           371:        iunlock (ip);
        !           372:        switch (who) {
        !           373:        case IFWFW:
        !           374:                -- ip->i_par;  ++ ip->i_psr;
        !           375:                sleep = x_sleep ((char *) & ip->i_psw, primed, slpriSigCatch,
        !           376:                                 "pipe wx");
        !           377:                ++ ip->i_par;  -- ip->i_psr;
        !           378:                break;
        !           379: 
        !           380:        case IFWFR:
        !           381:                -- ip->i_paw;  ++ ip->i_psw;
        !           382:                sleep = x_sleep ((char *) & ip->i_psr, primed, slpriSigCatch,
        !           383:                                 "pipe rx");
        !           384:                ++ ip->i_paw;  -- ip->i_psw;
        !           385:                break;
        !           386: 
        !           387:        default:
        !           388:                panic ("psleep() internal error");
        !           389:        }
        !           390:        ilock (ip);
        !           391:        pdump ("SZ", ip, 0);
        !           392: 
        !           393:        if (sleep == PROCESS_SIGNALLED) {
        !           394:                u.u_error = EINTR;
        !           395:                return -1;
        !           396:        }
        !           397:        return 0;
        !           398: }
        !           399: 
        !           400: 
        !           401: /*
        !           402:  *  pwake(ip, who)  --  wake up processes which are waiting for a reader if
        !           403:  *                     (who==IFWFR) or waiting for a writer if (who==IFWFW).
        !           404:  */
        !           405: 
        !           406: pwake(ip, who)
        !           407: register INODE *ip;
        !           408: {
        !           409:        pdump ("KA", ip, 0);
        !           410:        switch (who) {
        !           411:        case IFWFW:
        !           412:                if (ip->i_psr)
        !           413:                        wakeup ((char *) & ip->i_psw);
        !           414:                if (ip->i_pnc > 0)
        !           415:                        pollwake (& ip->i_iev);
        !           416:                break;
        !           417: 
        !           418:        case IFWFR:
        !           419:                if (ip->i_psw)
        !           420:                        wakeup ((char *) & ip->i_psr);
        !           421:                if (ip->i_pnc < PIPSIZE && (ip->i_par || ip->i_psr) )
        !           422:                        pollwake (& ip->i_oev);
        !           423:                break;
        !           424: 
        !           425:        default:
        !           426:                panic ("pwake() internal error");
        !           427:        }
        !           428:        pdump ("KZ", ip, 0);
        !           429: }
        !           430: 
        !           431: 
        !           432: /*
        !           433:  *  ppoll(ip, ev)  --  Poll the given pipe inode.
        !           434:  *  INODE *ip  --  The inode in question.
        !           435:  *  int ev     --  The event bit field.
        !           436:  *  int msec   --  Number of msecs to wait.
        !           437:  *  Returns or'ed bits according to the following rules:
        !           438:  *  POLLIN:  indicates input is available for reading, notice it is possible
        !           439:  *          to read even if there are no more writers anywhere!
        !           440:  *  POLLOUT: indicates room in pipe for new output, notice it is not possible
        !           441:  *          to write unless there is a reader attached!
        !           442:  *
        !           443:  *  No priority polls are supported.
        !           444:  */
        !           445: 
        !           446: ppoll(ip, ev, msec)
        !           447: register INODE *ip;
        !           448: int ev, msec;
        !           449: {
        !           450:        register int rval = 0;
        !           451: 
        !           452:        if (ev & POLLIN) {
        !           453:                if (ip->i_pnc > 0)
        !           454:                        rval |= POLLIN;
        !           455:                else if (msec != 0)
        !           456:                        pollopen (& ip->i_iev);
        !           457:        }
        !           458:        if (ev & POLLOUT) {
        !           459:                if (ip->i_pnc < PIPSIZE && (ip->i_par || ip->i_psr))
        !           460:                        rval |= POLLOUT;
        !           461:                else if (msec != 0)
        !           462:                        pollopen (& ip->i_oev);
        !           463:        }
        !           464:        return rval;
        !           465: }
        !           466: 
        !           467: /*
        !           468:  *  pdump(loc, ip, mode)  --  A kernel debugging output line.
        !           469:  *  char *loc  --  prefix of line (two characters indicating where we are)
        !           470:  *  INODE *ip  --  The inode information to dump
        !           471:  *  int mode   --  The mode of the IO call, i.e. IPW, IPR, IPNDLY, ...
        !           472:  */
        !           473: 
        !           474: #if 1
        !           475: pdump()
        !           476: {}
        !           477: #else
        !           478: pdump(loc, ip, mode)
        !           479: char *loc;
        !           480: register INODE *ip;
        !           481: int mode;
        !           482: {
        !           483:        printf("%s ip=%x mde=%x nlk=%x rf=%x nc=%x rx=%x wx=%x",
        !           484:                loc, ip, mode, ip->i_nlink, ip->i_refc,
        !           485:                ip->i_pnc, ip->i_prx, ip->i_pwx);
        !           486: 
        !           487:        printf(" ar=%x aw=%x sr=%x sw=%x f=%x\n",
        !           488:                ip->i_par, ip->i_paw, ip->i_psr, ip->i_psw, ip->i_flag);
        !           489: }
        !           490: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.