Annotation of sys/kern/sys_pipe.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: sys_pipe.c,v 1.52 2007/08/07 11:30:53 millert Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1996 John S. Dyson
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice immediately at the beginning of the file, without modification,
! 12: * this list of conditions, and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Absolutely no warranty of function or purpose is made by the author
! 17: * John S. Dyson.
! 18: * 4. Modifications may be freely made to this file if the above conditions
! 19: * are met.
! 20: */
! 21:
! 22: /*
! 23: * This file contains a high-performance replacement for the socket-based
! 24: * pipes scheme originally used in FreeBSD/4.4Lite. It does not support
! 25: * all features of sockets, but does do everything that pipes normally
! 26: * do.
! 27: */
! 28:
! 29: #include <sys/param.h>
! 30: #include <sys/systm.h>
! 31: #include <sys/proc.h>
! 32: #include <sys/file.h>
! 33: #include <sys/filedesc.h>
! 34: #include <sys/pool.h>
! 35: #include <sys/ioctl.h>
! 36: #include <sys/stat.h>
! 37: #include <sys/signalvar.h>
! 38: #include <sys/mount.h>
! 39: #include <sys/syscallargs.h>
! 40: #include <sys/event.h>
! 41: #include <sys/lock.h>
! 42: #include <sys/poll.h>
! 43:
! 44: #include <uvm/uvm_extern.h>
! 45:
! 46: #include <sys/pipe.h>
! 47:
! 48: /*
! 49: * interfaces to the outside world
! 50: */
! 51: int pipe_read(struct file *, off_t *, struct uio *, struct ucred *);
! 52: int pipe_write(struct file *, off_t *, struct uio *, struct ucred *);
! 53: int pipe_close(struct file *, struct proc *);
! 54: int pipe_poll(struct file *, int events, struct proc *);
! 55: int pipe_kqfilter(struct file *fp, struct knote *kn);
! 56: int pipe_ioctl(struct file *, u_long, caddr_t, struct proc *);
! 57: int pipe_stat(struct file *fp, struct stat *ub, struct proc *p);
! 58:
! 59: static struct fileops pipeops = {
! 60: pipe_read, pipe_write, pipe_ioctl, pipe_poll, pipe_kqfilter,
! 61: pipe_stat, pipe_close
! 62: };
! 63:
! 64: void filt_pipedetach(struct knote *kn);
! 65: int filt_piperead(struct knote *kn, long hint);
! 66: int filt_pipewrite(struct knote *kn, long hint);
! 67:
! 68: struct filterops pipe_rfiltops =
! 69: { 1, NULL, filt_pipedetach, filt_piperead };
! 70: struct filterops pipe_wfiltops =
! 71: { 1, NULL, filt_pipedetach, filt_pipewrite };
! 72:
! 73: /*
! 74: * Default pipe buffer size(s), this can be kind-of large now because pipe
! 75: * space is pageable. The pipe code will try to maintain locality of
! 76: * reference for performance reasons, so small amounts of outstanding I/O
! 77: * will not wipe the cache.
! 78: */
! 79: #define MINPIPESIZE (PIPE_SIZE/3)
! 80:
! 81: /*
! 82: * Limit the number of "big" pipes
! 83: */
! 84: #define LIMITBIGPIPES 32
! 85: int nbigpipe;
! 86: static int amountpipekva;
! 87:
! 88: struct pool pipe_pool;
! 89:
! 90: void pipeclose(struct pipe *);
! 91: void pipe_free_kmem(struct pipe *);
! 92: int pipe_create(struct pipe *);
! 93: static __inline int pipelock(struct pipe *);
! 94: static __inline void pipeunlock(struct pipe *);
! 95: static __inline void pipeselwakeup(struct pipe *);
! 96: int pipespace(struct pipe *, u_int);
! 97:
! 98: /*
! 99: * The pipe system call for the DTYPE_PIPE type of pipes
! 100: */
! 101:
! 102: /* ARGSUSED */
! 103: int
! 104: sys_opipe(struct proc *p, void *v, register_t *retval)
! 105: {
! 106: struct filedesc *fdp = p->p_fd;
! 107: struct file *rf, *wf;
! 108: struct pipe *rpipe, *wpipe;
! 109: int fd, error;
! 110:
! 111: fdplock(fdp);
! 112:
! 113: rpipe = pool_get(&pipe_pool, PR_WAITOK);
! 114: error = pipe_create(rpipe);
! 115: if (error != 0)
! 116: goto free1;
! 117: wpipe = pool_get(&pipe_pool, PR_WAITOK);
! 118: error = pipe_create(wpipe);
! 119: if (error != 0)
! 120: goto free2;
! 121:
! 122: error = falloc(p, &rf, &fd);
! 123: if (error != 0)
! 124: goto free2;
! 125: rf->f_flag = FREAD | FWRITE;
! 126: rf->f_type = DTYPE_PIPE;
! 127: rf->f_data = rpipe;
! 128: rf->f_ops = &pipeops;
! 129: retval[0] = fd;
! 130:
! 131: error = falloc(p, &wf, &fd);
! 132: if (error != 0)
! 133: goto free3;
! 134: wf->f_flag = FREAD | FWRITE;
! 135: wf->f_type = DTYPE_PIPE;
! 136: wf->f_data = wpipe;
! 137: wf->f_ops = &pipeops;
! 138: retval[1] = fd;
! 139:
! 140: rpipe->pipe_peer = wpipe;
! 141: wpipe->pipe_peer = rpipe;
! 142:
! 143: FILE_SET_MATURE(rf);
! 144: FILE_SET_MATURE(wf);
! 145:
! 146: fdpunlock(fdp);
! 147: return (0);
! 148:
! 149: free3:
! 150: fdremove(fdp, retval[0]);
! 151: closef(rf, p);
! 152: rpipe = NULL;
! 153: free2:
! 154: (void)pipeclose(wpipe);
! 155: free1:
! 156: if (rpipe != NULL)
! 157: (void)pipeclose(rpipe);
! 158: fdpunlock(fdp);
! 159: return (error);
! 160: }
! 161:
! 162: /*
! 163: * Allocate kva for pipe circular buffer, the space is pageable.
! 164: * This routine will 'realloc' the size of a pipe safely, if it fails
! 165: * it will retain the old buffer.
! 166: * If it fails it will return ENOMEM.
! 167: */
! 168: int
! 169: pipespace(struct pipe *cpipe, u_int size)
! 170: {
! 171: caddr_t buffer;
! 172:
! 173: buffer = (caddr_t)uvm_km_valloc(kernel_map, size);
! 174: if (buffer == NULL) {
! 175: return (ENOMEM);
! 176: }
! 177:
! 178: /* free old resources if we are resizing */
! 179: pipe_free_kmem(cpipe);
! 180: cpipe->pipe_buffer.buffer = buffer;
! 181: cpipe->pipe_buffer.size = size;
! 182: cpipe->pipe_buffer.in = 0;
! 183: cpipe->pipe_buffer.out = 0;
! 184: cpipe->pipe_buffer.cnt = 0;
! 185:
! 186: amountpipekva += cpipe->pipe_buffer.size;
! 187:
! 188: return (0);
! 189: }
! 190:
! 191: /*
! 192: * initialize and allocate VM and memory for pipe
! 193: */
! 194: int
! 195: pipe_create(struct pipe *cpipe)
! 196: {
! 197: int error;
! 198:
! 199: /* so pipe_free_kmem() doesn't follow junk pointer */
! 200: cpipe->pipe_buffer.buffer = NULL;
! 201: /*
! 202: * protect so pipeclose() doesn't follow a junk pointer
! 203: * if pipespace() fails.
! 204: */
! 205: bzero(&cpipe->pipe_sel, sizeof cpipe->pipe_sel);
! 206: cpipe->pipe_state = 0;
! 207: cpipe->pipe_peer = NULL;
! 208: cpipe->pipe_busy = 0;
! 209:
! 210: error = pipespace(cpipe, PIPE_SIZE);
! 211: if (error != 0)
! 212: return (error);
! 213:
! 214: nanotime(&cpipe->pipe_ctime);
! 215: cpipe->pipe_atime = cpipe->pipe_ctime;
! 216: cpipe->pipe_mtime = cpipe->pipe_ctime;
! 217: cpipe->pipe_pgid = NO_PID;
! 218:
! 219: return (0);
! 220: }
! 221:
! 222:
! 223: /*
! 224: * lock a pipe for I/O, blocking other access
! 225: */
! 226: static __inline int
! 227: pipelock(struct pipe *cpipe)
! 228: {
! 229: int error;
! 230: while (cpipe->pipe_state & PIPE_LOCK) {
! 231: cpipe->pipe_state |= PIPE_LWANT;
! 232: if ((error = tsleep(cpipe, PRIBIO|PCATCH, "pipelk", 0)))
! 233: return error;
! 234: }
! 235: cpipe->pipe_state |= PIPE_LOCK;
! 236: return 0;
! 237: }
! 238:
! 239: /*
! 240: * unlock a pipe I/O lock
! 241: */
! 242: static __inline void
! 243: pipeunlock(struct pipe *cpipe)
! 244: {
! 245: cpipe->pipe_state &= ~PIPE_LOCK;
! 246: if (cpipe->pipe_state & PIPE_LWANT) {
! 247: cpipe->pipe_state &= ~PIPE_LWANT;
! 248: wakeup(cpipe);
! 249: }
! 250: }
! 251:
! 252: static __inline void
! 253: pipeselwakeup(struct pipe *cpipe)
! 254: {
! 255: if (cpipe->pipe_state & PIPE_SEL) {
! 256: cpipe->pipe_state &= ~PIPE_SEL;
! 257: selwakeup(&cpipe->pipe_sel);
! 258: }
! 259: if ((cpipe->pipe_state & PIPE_ASYNC) && cpipe->pipe_pgid != NO_PID)
! 260: gsignal(cpipe->pipe_pgid, SIGIO);
! 261: KNOTE(&cpipe->pipe_sel.si_note, 0);
! 262: }
! 263:
! 264: /* ARGSUSED */
! 265: int
! 266: pipe_read(struct file *fp, off_t *poff, struct uio *uio, struct ucred *cred)
! 267: {
! 268: struct pipe *rpipe = (struct pipe *) fp->f_data;
! 269: int error;
! 270: int nread = 0;
! 271: int size;
! 272:
! 273: error = pipelock(rpipe);
! 274: if (error)
! 275: return (error);
! 276:
! 277: ++rpipe->pipe_busy;
! 278:
! 279: while (uio->uio_resid) {
! 280: /*
! 281: * normal pipe buffer receive
! 282: */
! 283: if (rpipe->pipe_buffer.cnt > 0) {
! 284: size = rpipe->pipe_buffer.size - rpipe->pipe_buffer.out;
! 285: if (size > rpipe->pipe_buffer.cnt)
! 286: size = rpipe->pipe_buffer.cnt;
! 287: if (size > uio->uio_resid)
! 288: size = uio->uio_resid;
! 289: error = uiomove(&rpipe->pipe_buffer.buffer[rpipe->pipe_buffer.out],
! 290: size, uio);
! 291: if (error) {
! 292: break;
! 293: }
! 294: rpipe->pipe_buffer.out += size;
! 295: if (rpipe->pipe_buffer.out >= rpipe->pipe_buffer.size)
! 296: rpipe->pipe_buffer.out = 0;
! 297:
! 298: rpipe->pipe_buffer.cnt -= size;
! 299: /*
! 300: * If there is no more to read in the pipe, reset
! 301: * its pointers to the beginning. This improves
! 302: * cache hit stats.
! 303: */
! 304: if (rpipe->pipe_buffer.cnt == 0) {
! 305: rpipe->pipe_buffer.in = 0;
! 306: rpipe->pipe_buffer.out = 0;
! 307: }
! 308: nread += size;
! 309: } else {
! 310: /*
! 311: * detect EOF condition
! 312: * read returns 0 on EOF, no need to set error
! 313: */
! 314: if (rpipe->pipe_state & PIPE_EOF)
! 315: break;
! 316:
! 317: /*
! 318: * If the "write-side" has been blocked, wake it up now.
! 319: */
! 320: if (rpipe->pipe_state & PIPE_WANTW) {
! 321: rpipe->pipe_state &= ~PIPE_WANTW;
! 322: wakeup(rpipe);
! 323: }
! 324:
! 325: /*
! 326: * Break if some data was read.
! 327: */
! 328: if (nread > 0)
! 329: break;
! 330:
! 331: /*
! 332: * Unlock the pipe buffer for our remaining processing.
! 333: * We will either break out with an error or we will
! 334: * sleep and relock to loop.
! 335: */
! 336: pipeunlock(rpipe);
! 337:
! 338: /*
! 339: * Handle non-blocking mode operation or
! 340: * wait for more data.
! 341: */
! 342: if (fp->f_flag & FNONBLOCK) {
! 343: error = EAGAIN;
! 344: } else {
! 345: rpipe->pipe_state |= PIPE_WANTR;
! 346: if ((error = tsleep(rpipe, PRIBIO|PCATCH, "piperd", 0)) == 0)
! 347: error = pipelock(rpipe);
! 348: }
! 349: if (error)
! 350: goto unlocked_error;
! 351: }
! 352: }
! 353: pipeunlock(rpipe);
! 354:
! 355: if (error == 0)
! 356: nanotime(&rpipe->pipe_atime);
! 357: unlocked_error:
! 358: --rpipe->pipe_busy;
! 359:
! 360: /*
! 361: * PIPE_WANT processing only makes sense if pipe_busy is 0.
! 362: */
! 363: if ((rpipe->pipe_busy == 0) && (rpipe->pipe_state & PIPE_WANT)) {
! 364: rpipe->pipe_state &= ~(PIPE_WANT|PIPE_WANTW);
! 365: wakeup(rpipe);
! 366: } else if (rpipe->pipe_buffer.cnt < MINPIPESIZE) {
! 367: /*
! 368: * Handle write blocking hysteresis.
! 369: */
! 370: if (rpipe->pipe_state & PIPE_WANTW) {
! 371: rpipe->pipe_state &= ~PIPE_WANTW;
! 372: wakeup(rpipe);
! 373: }
! 374: }
! 375:
! 376: if ((rpipe->pipe_buffer.size - rpipe->pipe_buffer.cnt) >= PIPE_BUF)
! 377: pipeselwakeup(rpipe);
! 378:
! 379: return (error);
! 380: }
! 381:
! 382: int
! 383: pipe_write(struct file *fp, off_t *poff, struct uio *uio, struct ucred *cred)
! 384: {
! 385: int error = 0;
! 386: int orig_resid;
! 387:
! 388: struct pipe *wpipe, *rpipe;
! 389:
! 390: rpipe = (struct pipe *) fp->f_data;
! 391: wpipe = rpipe->pipe_peer;
! 392:
! 393: /*
! 394: * detect loss of pipe read side, issue SIGPIPE if lost.
! 395: */
! 396: if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
! 397: return (EPIPE);
! 398: }
! 399: ++wpipe->pipe_busy;
! 400:
! 401: /*
! 402: * If it is advantageous to resize the pipe buffer, do
! 403: * so.
! 404: */
! 405: if ((uio->uio_resid > PIPE_SIZE) &&
! 406: (nbigpipe < LIMITBIGPIPES) &&
! 407: (wpipe->pipe_buffer.size <= PIPE_SIZE) &&
! 408: (wpipe->pipe_buffer.cnt == 0)) {
! 409:
! 410: if ((error = pipelock(wpipe)) == 0) {
! 411: if (pipespace(wpipe, BIG_PIPE_SIZE) == 0)
! 412: nbigpipe++;
! 413: pipeunlock(wpipe);
! 414: }
! 415: }
! 416:
! 417: /*
! 418: * If an early error occured unbusy and return, waking up any pending
! 419: * readers.
! 420: */
! 421: if (error) {
! 422: --wpipe->pipe_busy;
! 423: if ((wpipe->pipe_busy == 0) &&
! 424: (wpipe->pipe_state & PIPE_WANT)) {
! 425: wpipe->pipe_state &= ~(PIPE_WANT | PIPE_WANTR);
! 426: wakeup(wpipe);
! 427: }
! 428: return (error);
! 429: }
! 430:
! 431: orig_resid = uio->uio_resid;
! 432:
! 433: while (uio->uio_resid) {
! 434: int space;
! 435:
! 436: retrywrite:
! 437: if (wpipe->pipe_state & PIPE_EOF) {
! 438: error = EPIPE;
! 439: break;
! 440: }
! 441:
! 442: space = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt;
! 443:
! 444: /* Writes of size <= PIPE_BUF must be atomic. */
! 445: if ((space < uio->uio_resid) && (orig_resid <= PIPE_BUF))
! 446: space = 0;
! 447:
! 448: if (space > 0) {
! 449: if ((error = pipelock(wpipe)) == 0) {
! 450: int size; /* Transfer size */
! 451: int segsize; /* first segment to transfer */
! 452:
! 453: /*
! 454: * If a process blocked in uiomove, our
! 455: * value for space might be bad.
! 456: *
! 457: * XXX will we be ok if the reader has gone
! 458: * away here?
! 459: */
! 460: if (space > wpipe->pipe_buffer.size -
! 461: wpipe->pipe_buffer.cnt) {
! 462: pipeunlock(wpipe);
! 463: goto retrywrite;
! 464: }
! 465:
! 466: /*
! 467: * Transfer size is minimum of uio transfer
! 468: * and free space in pipe buffer.
! 469: */
! 470: if (space > uio->uio_resid)
! 471: size = uio->uio_resid;
! 472: else
! 473: size = space;
! 474: /*
! 475: * First segment to transfer is minimum of
! 476: * transfer size and contiguous space in
! 477: * pipe buffer. If first segment to transfer
! 478: * is less than the transfer size, we've got
! 479: * a wraparound in the buffer.
! 480: */
! 481: segsize = wpipe->pipe_buffer.size -
! 482: wpipe->pipe_buffer.in;
! 483: if (segsize > size)
! 484: segsize = size;
! 485:
! 486: /* Transfer first segment */
! 487:
! 488: error = uiomove(&wpipe->pipe_buffer.buffer[wpipe->pipe_buffer.in],
! 489: segsize, uio);
! 490:
! 491: if (error == 0 && segsize < size) {
! 492: /*
! 493: * Transfer remaining part now, to
! 494: * support atomic writes. Wraparound
! 495: * happened.
! 496: */
! 497: #ifdef DIAGNOSTIC
! 498: if (wpipe->pipe_buffer.in + segsize !=
! 499: wpipe->pipe_buffer.size)
! 500: panic("Expected pipe buffer wraparound disappeared");
! 501: #endif
! 502:
! 503: error = uiomove(&wpipe->pipe_buffer.buffer[0],
! 504: size - segsize, uio);
! 505: }
! 506: if (error == 0) {
! 507: wpipe->pipe_buffer.in += size;
! 508: if (wpipe->pipe_buffer.in >=
! 509: wpipe->pipe_buffer.size) {
! 510: #ifdef DIAGNOSTIC
! 511: if (wpipe->pipe_buffer.in != size - segsize + wpipe->pipe_buffer.size)
! 512: panic("Expected wraparound bad");
! 513: #endif
! 514: wpipe->pipe_buffer.in = size - segsize;
! 515: }
! 516:
! 517: wpipe->pipe_buffer.cnt += size;
! 518: #ifdef DIAGNOSTIC
! 519: if (wpipe->pipe_buffer.cnt > wpipe->pipe_buffer.size)
! 520: panic("Pipe buffer overflow");
! 521: #endif
! 522: }
! 523: pipeunlock(wpipe);
! 524: }
! 525: if (error)
! 526: break;
! 527: } else {
! 528: /*
! 529: * If the "read-side" has been blocked, wake it up now.
! 530: */
! 531: if (wpipe->pipe_state & PIPE_WANTR) {
! 532: wpipe->pipe_state &= ~PIPE_WANTR;
! 533: wakeup(wpipe);
! 534: }
! 535:
! 536: /*
! 537: * don't block on non-blocking I/O
! 538: */
! 539: if (fp->f_flag & FNONBLOCK) {
! 540: error = EAGAIN;
! 541: break;
! 542: }
! 543:
! 544: /*
! 545: * We have no more space and have something to offer,
! 546: * wake up select/poll.
! 547: */
! 548: pipeselwakeup(wpipe);
! 549:
! 550: wpipe->pipe_state |= PIPE_WANTW;
! 551: error = tsleep(wpipe, (PRIBIO + 1)|PCATCH,
! 552: "pipewr", 0);
! 553: if (error)
! 554: break;
! 555: /*
! 556: * If read side wants to go away, we just issue a
! 557: * signal to ourselves.
! 558: */
! 559: if (wpipe->pipe_state & PIPE_EOF) {
! 560: error = EPIPE;
! 561: break;
! 562: }
! 563: }
! 564: }
! 565:
! 566: --wpipe->pipe_busy;
! 567:
! 568: if ((wpipe->pipe_busy == 0) && (wpipe->pipe_state & PIPE_WANT)) {
! 569: wpipe->pipe_state &= ~(PIPE_WANT | PIPE_WANTR);
! 570: wakeup(wpipe);
! 571: } else if (wpipe->pipe_buffer.cnt > 0) {
! 572: /*
! 573: * If we have put any characters in the buffer, we wake up
! 574: * the reader.
! 575: */
! 576: if (wpipe->pipe_state & PIPE_WANTR) {
! 577: wpipe->pipe_state &= ~PIPE_WANTR;
! 578: wakeup(wpipe);
! 579: }
! 580: }
! 581:
! 582: /*
! 583: * Don't return EPIPE if I/O was successful
! 584: */
! 585: if ((wpipe->pipe_buffer.cnt == 0) &&
! 586: (uio->uio_resid == 0) &&
! 587: (error == EPIPE)) {
! 588: error = 0;
! 589: }
! 590:
! 591: if (error == 0)
! 592: nanotime(&wpipe->pipe_mtime);
! 593: /*
! 594: * We have something to offer, wake up select/poll.
! 595: */
! 596: if (wpipe->pipe_buffer.cnt)
! 597: pipeselwakeup(wpipe);
! 598:
! 599: return (error);
! 600: }
! 601:
! 602: /*
! 603: * we implement a very minimal set of ioctls for compatibility with sockets.
! 604: */
! 605: int
! 606: pipe_ioctl(struct file *fp, u_long cmd, caddr_t data, struct proc *p)
! 607: {
! 608: struct pipe *mpipe = (struct pipe *)fp->f_data;
! 609:
! 610: switch (cmd) {
! 611:
! 612: case FIONBIO:
! 613: return (0);
! 614:
! 615: case FIOASYNC:
! 616: if (*(int *)data) {
! 617: mpipe->pipe_state |= PIPE_ASYNC;
! 618: } else {
! 619: mpipe->pipe_state &= ~PIPE_ASYNC;
! 620: }
! 621: return (0);
! 622:
! 623: case FIONREAD:
! 624: *(int *)data = mpipe->pipe_buffer.cnt;
! 625: return (0);
! 626:
! 627: case SIOCSPGRP:
! 628: mpipe->pipe_pgid = *(int *)data;
! 629: return (0);
! 630:
! 631: case SIOCGPGRP:
! 632: *(int *)data = mpipe->pipe_pgid;
! 633: return (0);
! 634:
! 635: }
! 636: return (ENOTTY);
! 637: }
! 638:
! 639: int
! 640: pipe_poll(struct file *fp, int events, struct proc *p)
! 641: {
! 642: struct pipe *rpipe = (struct pipe *)fp->f_data;
! 643: struct pipe *wpipe;
! 644: int revents = 0;
! 645:
! 646: wpipe = rpipe->pipe_peer;
! 647: if (events & (POLLIN | POLLRDNORM)) {
! 648: if ((rpipe->pipe_buffer.cnt > 0) ||
! 649: (rpipe->pipe_state & PIPE_EOF))
! 650: revents |= events & (POLLIN | POLLRDNORM);
! 651: }
! 652:
! 653: /* NOTE: POLLHUP and POLLOUT/POLLWRNORM are mutually exclusive */
! 654: if ((rpipe->pipe_state & PIPE_EOF) ||
! 655: (wpipe == NULL) ||
! 656: (wpipe->pipe_state & PIPE_EOF))
! 657: revents |= POLLHUP;
! 658: else if (events & (POLLOUT | POLLWRNORM)) {
! 659: if ((wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt) >= PIPE_BUF)
! 660: revents |= events & (POLLOUT | POLLWRNORM);
! 661: }
! 662:
! 663: if (revents == 0) {
! 664: if (events & (POLLIN | POLLRDNORM)) {
! 665: selrecord(p, &rpipe->pipe_sel);
! 666: rpipe->pipe_state |= PIPE_SEL;
! 667: }
! 668: if (events & (POLLOUT | POLLWRNORM)) {
! 669: selrecord(p, &wpipe->pipe_sel);
! 670: wpipe->pipe_state |= PIPE_SEL;
! 671: }
! 672: }
! 673: return (revents);
! 674: }
! 675:
! 676: int
! 677: pipe_stat(struct file *fp, struct stat *ub, struct proc *p)
! 678: {
! 679: struct pipe *pipe = (struct pipe *)fp->f_data;
! 680:
! 681: bzero(ub, sizeof(*ub));
! 682: ub->st_mode = S_IFIFO;
! 683: ub->st_blksize = pipe->pipe_buffer.size;
! 684: ub->st_size = pipe->pipe_buffer.cnt;
! 685: ub->st_blocks = (ub->st_size + ub->st_blksize - 1) / ub->st_blksize;
! 686: ub->st_atimespec = pipe->pipe_atime;
! 687: ub->st_mtimespec = pipe->pipe_mtime;
! 688: ub->st_ctimespec = pipe->pipe_ctime;
! 689: ub->st_uid = fp->f_cred->cr_uid;
! 690: ub->st_gid = fp->f_cred->cr_gid;
! 691: /*
! 692: * Left as 0: st_dev, st_ino, st_nlink, st_rdev, st_flags, st_gen.
! 693: * XXX (st_dev, st_ino) should be unique.
! 694: */
! 695: return (0);
! 696: }
! 697:
! 698: /* ARGSUSED */
! 699: int
! 700: pipe_close(struct file *fp, struct proc *p)
! 701: {
! 702: struct pipe *cpipe = (struct pipe *)fp->f_data;
! 703:
! 704: fp->f_ops = NULL;
! 705: fp->f_data = NULL;
! 706: pipeclose(cpipe);
! 707: return (0);
! 708: }
! 709:
! 710: void
! 711: pipe_free_kmem(struct pipe *cpipe)
! 712: {
! 713: if (cpipe->pipe_buffer.buffer != NULL) {
! 714: if (cpipe->pipe_buffer.size > PIPE_SIZE)
! 715: --nbigpipe;
! 716: amountpipekva -= cpipe->pipe_buffer.size;
! 717: uvm_km_free(kernel_map, (vaddr_t)cpipe->pipe_buffer.buffer,
! 718: cpipe->pipe_buffer.size);
! 719: cpipe->pipe_buffer.buffer = NULL;
! 720: }
! 721: }
! 722:
! 723: /*
! 724: * shutdown the pipe
! 725: */
! 726: void
! 727: pipeclose(struct pipe *cpipe)
! 728: {
! 729: struct pipe *ppipe;
! 730: if (cpipe) {
! 731:
! 732: pipeselwakeup(cpipe);
! 733:
! 734: /*
! 735: * If the other side is blocked, wake it up saying that
! 736: * we want to close it down.
! 737: */
! 738: cpipe->pipe_state |= PIPE_EOF;
! 739: while (cpipe->pipe_busy) {
! 740: wakeup(cpipe);
! 741: cpipe->pipe_state |= PIPE_WANT;
! 742: tsleep(cpipe, PRIBIO, "pipecl", 0);
! 743: }
! 744:
! 745: /*
! 746: * Disconnect from peer
! 747: */
! 748: if ((ppipe = cpipe->pipe_peer) != NULL) {
! 749: pipeselwakeup(ppipe);
! 750:
! 751: ppipe->pipe_state |= PIPE_EOF;
! 752: wakeup(ppipe);
! 753: KNOTE(&ppipe->pipe_sel.si_note, 0);
! 754: ppipe->pipe_peer = NULL;
! 755: }
! 756:
! 757: /*
! 758: * free resources
! 759: */
! 760: pipe_free_kmem(cpipe);
! 761: pool_put(&pipe_pool, cpipe);
! 762: }
! 763: }
! 764:
! 765: int
! 766: pipe_kqfilter(struct file *fp, struct knote *kn)
! 767: {
! 768: struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
! 769: struct pipe *wpipe = rpipe->pipe_peer;
! 770:
! 771: switch (kn->kn_filter) {
! 772: case EVFILT_READ:
! 773: kn->kn_fop = &pipe_rfiltops;
! 774: SLIST_INSERT_HEAD(&rpipe->pipe_sel.si_note, kn, kn_selnext);
! 775: break;
! 776: case EVFILT_WRITE:
! 777: if (wpipe == NULL)
! 778: /* other end of pipe has been closed */
! 779: return (1);
! 780: kn->kn_fop = &pipe_wfiltops;
! 781: SLIST_INSERT_HEAD(&wpipe->pipe_sel.si_note, kn, kn_selnext);
! 782: break;
! 783: default:
! 784: return (1);
! 785: }
! 786:
! 787: return (0);
! 788: }
! 789:
! 790: void
! 791: filt_pipedetach(struct knote *kn)
! 792: {
! 793: struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
! 794: struct pipe *wpipe = rpipe->pipe_peer;
! 795:
! 796: switch (kn->kn_filter) {
! 797: case EVFILT_READ:
! 798: SLIST_REMOVE(&rpipe->pipe_sel.si_note, kn, knote, kn_selnext);
! 799: break;
! 800: case EVFILT_WRITE:
! 801: if (wpipe == NULL)
! 802: return;
! 803: SLIST_REMOVE(&wpipe->pipe_sel.si_note, kn, knote, kn_selnext);
! 804: break;
! 805: }
! 806: }
! 807:
! 808: /*ARGSUSED*/
! 809: int
! 810: filt_piperead(struct knote *kn, long hint)
! 811: {
! 812: struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
! 813: struct pipe *wpipe = rpipe->pipe_peer;
! 814:
! 815: kn->kn_data = rpipe->pipe_buffer.cnt;
! 816:
! 817: if ((rpipe->pipe_state & PIPE_EOF) ||
! 818: (wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
! 819: kn->kn_flags |= EV_EOF;
! 820: return (1);
! 821: }
! 822: return (kn->kn_data > 0);
! 823: }
! 824:
! 825: /*ARGSUSED*/
! 826: int
! 827: filt_pipewrite(struct knote *kn, long hint)
! 828: {
! 829: struct pipe *rpipe = (struct pipe *)kn->kn_fp->f_data;
! 830: struct pipe *wpipe = rpipe->pipe_peer;
! 831:
! 832: if ((wpipe == NULL) || (wpipe->pipe_state & PIPE_EOF)) {
! 833: kn->kn_data = 0;
! 834: kn->kn_flags |= EV_EOF;
! 835: return (1);
! 836: }
! 837: kn->kn_data = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt;
! 838:
! 839: return (kn->kn_data >= PIPE_BUF);
! 840: }
! 841:
! 842: void
! 843: pipe_init(void)
! 844: {
! 845: pool_init(&pipe_pool, sizeof(struct pipe), 0, 0, 0, "pipepl",
! 846: &pool_allocator_nointr);
! 847: }
! 848:
CVSweb