|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.