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