Annotation of coherent/b/STREAMS/coh.386/pipe.c, revision 1.1.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.