Annotation of coherent/b/kernel/coh.386/pipe.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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