sys_pipe.c revision 13688
113675Sdyson/* 213675Sdyson * Copyright (c) 1996 John S. Dyson 313675Sdyson * All rights reserved. 413675Sdyson * 513675Sdyson * Redistribution and use in source and binary forms, with or without 613675Sdyson * modification, are permitted provided that the following conditions 713675Sdyson * are met: 813675Sdyson * 1. Redistributions of source code must retain the above copyright 913675Sdyson * notice immediately at the beginning of the file, without modification, 1013675Sdyson * this list of conditions, and the following disclaimer. 1113675Sdyson * 2. Redistributions in binary form must reproduce the above copyright 1213675Sdyson * notice, this list of conditions and the following disclaimer in the 1313675Sdyson * documentation and/or other materials provided with the distribution. 1413675Sdyson * 3. Absolutely no warranty of function or purpose is made by the author 1513675Sdyson * John S. Dyson. 1613675Sdyson * 4. This work was done expressly for inclusion into FreeBSD. Other use 1713675Sdyson * is allowed if this notation is included. 1813675Sdyson * 5. Modifications may be freely made to this file if the above conditions 1913675Sdyson * are met. 2013675Sdyson * 2113688Sdyson * $Id: sys_pipe.c,v 1.1 1996/01/28 23:38:26 dyson Exp $ 2213675Sdyson */ 2313675Sdyson 2413675Sdyson#ifndef OLD_PIPE 2513675Sdyson 2613675Sdyson/* 2713675Sdyson * This file contains a high-performance replacement for the socket-based 2813675Sdyson * pipes scheme originally used in FreeBSD/4.4Lite. It does not support 2913675Sdyson * all features of sockets, but does do everything that pipes normally 3013675Sdyson * do. 3113675Sdyson */ 3213675Sdyson 3313675Sdyson#include <sys/param.h> 3413675Sdyson#include <sys/systm.h> 3513675Sdyson#include <sys/proc.h> 3613675Sdyson#include <sys/file.h> 3713675Sdyson#include <sys/protosw.h> 3813675Sdyson#include <sys/stat.h> 3913675Sdyson#include <sys/filedesc.h> 4013675Sdyson#include <sys/malloc.h> 4113675Sdyson#include <sys/ioctl.h> 4213675Sdyson#include <sys/stat.h> 4313675Sdyson#include <sys/select.h> 4413675Sdyson#include <sys/signalvar.h> 4513675Sdyson#include <sys/errno.h> 4613675Sdyson#include <sys/queue.h> 4713675Sdyson#include <sys/vmmeter.h> 4813675Sdyson#include <sys/kernel.h> 4913675Sdyson#include <sys/sysproto.h> 5013675Sdyson#include <sys/pipe.h> 5113675Sdyson 5213675Sdyson#include <vm/vm.h> 5313675Sdyson#include <vm/vm_prot.h> 5413675Sdyson#include <vm/vm_param.h> 5513675Sdyson#include <vm/lock.h> 5613675Sdyson#include <vm/vm_object.h> 5713675Sdyson#include <vm/vm_kern.h> 5813675Sdyson#include <vm/vm_extern.h> 5913675Sdyson#include <vm/pmap.h> 6013675Sdyson#include <vm/vm_map.h> 6113675Sdyson 6213675Sdysonstatic int pipe_read __P((struct file *fp, struct uio *uio, 6313675Sdyson struct ucred *cred)); 6413675Sdysonstatic int pipe_write __P((struct file *fp, struct uio *uio, 6513675Sdyson struct ucred *cred)); 6613675Sdysonstatic int pipe_close __P((struct file *fp, struct proc *p)); 6713675Sdysonstatic int pipe_select __P((struct file *fp, int which, struct proc *p)); 6813675Sdysonstatic int pipe_ioctl __P((struct file *fp, int cmd, caddr_t data, struct proc *p)); 6913675Sdyson 7013675Sdysonstatic struct fileops pipeops = 7113675Sdyson { pipe_read, pipe_write, pipe_ioctl, pipe_select, pipe_close }; 7213675Sdyson 7313675Sdyson/* 7413675Sdyson * Default pipe buffer size(s), this can be kind-of large now because pipe 7513675Sdyson * space is pageable. The pipe code will try to maintain locality of 7613675Sdyson * reference for performance reasons, so small amounts of outstanding I/O 7713675Sdyson * will not wipe the cache. 7813675Sdyson */ 7913675Sdyson#define PIPESIZE (16384) 8013675Sdyson#define MINPIPESIZE (PIPESIZE/3) 8113675Sdyson#define MAXPIPESIZE (2*PIPESIZE/3) 8213675Sdyson 8313675Sdysonstatic void pipeclose __P((struct pipe *cpipe)); 8413675Sdysonstatic void pipebufferinit __P((struct pipe *cpipe)); 8513675Sdysonstatic void pipeinit __P((struct pipe *cpipe)); 8613675Sdysonstatic __inline int pipelock __P((struct pipe *cpipe)); 8713675Sdysonstatic __inline void pipeunlock __P((struct pipe *cpipe)); 8813675Sdyson 8913675Sdyson/* 9013675Sdyson * The pipe system call for the DTYPE_PIPE type of pipes 9113675Sdyson */ 9213675Sdyson 9313675Sdyson/* ARGSUSED */ 9413675Sdysonint 9513675Sdysonpipe(p, uap, retval) 9613675Sdyson struct proc *p; 9713675Sdyson struct pipe_args /* { 9813675Sdyson int dummy; 9913675Sdyson } */ *uap; 10013675Sdyson int retval[]; 10113675Sdyson{ 10213675Sdyson register struct filedesc *fdp = p->p_fd; 10313675Sdyson struct file *rf, *wf; 10413675Sdyson struct pipe *rpipe, *wpipe; 10513675Sdyson int fd, error; 10613675Sdyson 10713675Sdyson rpipe = malloc( sizeof (*rpipe), M_TEMP, M_WAITOK); 10813675Sdyson pipeinit(rpipe); 10913675Sdyson wpipe = malloc( sizeof (*wpipe), M_TEMP, M_WAITOK); 11013675Sdyson pipeinit(wpipe); 11113675Sdyson 11213675Sdyson error = falloc(p, &rf, &fd); 11313675Sdyson if (error) 11413675Sdyson goto free2; 11513675Sdyson retval[0] = fd; 11613675Sdyson rf->f_flag = FREAD | FWRITE; 11713675Sdyson rf->f_type = DTYPE_PIPE; 11813675Sdyson rf->f_ops = &pipeops; 11913675Sdyson rf->f_data = (caddr_t)rpipe; 12013675Sdyson error = falloc(p, &wf, &fd); 12113675Sdyson if (error) 12213675Sdyson goto free3; 12313675Sdyson wf->f_flag = FREAD | FWRITE; 12413675Sdyson wf->f_type = DTYPE_PIPE; 12513675Sdyson wf->f_ops = &pipeops; 12613675Sdyson wf->f_data = (caddr_t)wpipe; 12713675Sdyson retval[1] = fd; 12813675Sdyson 12913675Sdyson rpipe->pipe_peer = wpipe; 13013675Sdyson wpipe->pipe_peer = rpipe; 13113675Sdyson 13213675Sdyson return (0); 13313675Sdysonfree3: 13413675Sdyson ffree(rf); 13513675Sdyson fdp->fd_ofiles[retval[0]] = 0; 13613675Sdysonfree2: 13713675Sdyson (void)pipeclose(wpipe); 13813675Sdysonfree1: 13913675Sdyson (void)pipeclose(rpipe); 14013675Sdyson return (error); 14113675Sdyson} 14213675Sdyson 14313675Sdyson/* 14413675Sdyson * initialize and allocate VM and memory for pipe 14513675Sdyson */ 14613675Sdysonstatic void 14713675Sdysonpipeinit(cpipe) 14813675Sdyson struct pipe *cpipe; 14913675Sdyson{ 15013688Sdyson int npages, error; 15113675Sdyson 15213675Sdyson npages = round_page(PIPESIZE)/PAGE_SIZE; 15313675Sdyson 15413675Sdyson /* 15513675Sdyson * Create an object, I don't like the idea of paging to/from 15613675Sdyson * kernel_object. 15713675Sdyson */ 15813675Sdyson cpipe->pipe_buffer.object = vm_object_allocate(OBJT_DEFAULT, npages); 15913688Sdyson cpipe->pipe_buffer.buffer = (caddr_t) vm_map_min(kernel_map); 16013675Sdyson 16113675Sdyson /* 16213675Sdyson * Insert the object into the kernel map, and allocate kva for it. 16313675Sdyson * The map entry is, by default, pageable. 16413675Sdyson */ 16513688Sdyson error = vm_map_find(kernel_map, cpipe->pipe_buffer.object, 0, 16613675Sdyson (vm_offset_t *) &cpipe->pipe_buffer.buffer, PIPESIZE, 1, 16713688Sdyson VM_PROT_ALL, VM_PROT_ALL, 0); 16813675Sdyson 16913688Sdyson if (error != KERN_SUCCESS) 17013688Sdyson panic("pipeinit: cannot allocate pipe -- out of kvm -- code = %d", error); 17113688Sdyson 17213675Sdyson cpipe->pipe_buffer.in = 0; 17313675Sdyson cpipe->pipe_buffer.out = 0; 17413675Sdyson cpipe->pipe_buffer.cnt = 0; 17513675Sdyson cpipe->pipe_buffer.size = PIPESIZE; 17613675Sdyson 17713675Sdyson cpipe->pipe_state = 0; 17813675Sdyson cpipe->pipe_peer = NULL; 17913675Sdyson cpipe->pipe_busy = 0; 18013675Sdyson cpipe->pipe_ctime = time; 18113675Sdyson cpipe->pipe_atime = time; 18213675Sdyson cpipe->pipe_mtime = time; 18313675Sdyson bzero(&cpipe->pipe_sel, sizeof cpipe->pipe_sel); 18413675Sdyson} 18513675Sdyson 18613675Sdyson 18713675Sdyson/* 18813675Sdyson * lock a pipe for I/O, blocking other access 18913675Sdyson */ 19013675Sdysonstatic __inline int 19113675Sdysonpipelock(cpipe) 19213675Sdyson struct pipe *cpipe; 19313675Sdyson{ 19413675Sdyson while (cpipe->pipe_state & PIPE_LOCK) { 19513675Sdyson cpipe->pipe_state |= PIPE_LWANT; 19613675Sdyson if (tsleep( &cpipe->pipe_state, PRIBIO|PCATCH, "pipelk", 0)) { 19713675Sdyson return ERESTART; 19813675Sdyson } 19913675Sdyson } 20013675Sdyson cpipe->pipe_state |= PIPE_LOCK; 20113675Sdyson return 0; 20213675Sdyson} 20313675Sdyson 20413675Sdyson/* 20513675Sdyson * unlock a pipe I/O lock 20613675Sdyson */ 20713675Sdysonstatic __inline void 20813675Sdysonpipeunlock(cpipe) 20913675Sdyson struct pipe *cpipe; 21013675Sdyson{ 21113675Sdyson cpipe->pipe_state &= ~PIPE_LOCK; 21213675Sdyson if (cpipe->pipe_state & PIPE_LWANT) { 21313675Sdyson cpipe->pipe_state &= ~PIPE_LWANT; 21413675Sdyson wakeup(&cpipe->pipe_state); 21513675Sdyson } 21613675Sdyson return; 21713675Sdyson} 21813675Sdyson 21913675Sdyson/* ARGSUSED */ 22013675Sdysonstatic int 22113675Sdysonpipe_read(fp, uio, cred) 22213675Sdyson struct file *fp; 22313675Sdyson struct uio *uio; 22413675Sdyson struct ucred *cred; 22513675Sdyson{ 22613675Sdyson 22713675Sdyson struct pipe *rpipe = (struct pipe *) fp->f_data; 22813675Sdyson int error = 0; 22913675Sdyson int nread = 0; 23013675Sdyson 23113675Sdyson ++rpipe->pipe_busy; 23213675Sdyson while (uio->uio_resid) { 23313675Sdyson if (rpipe->pipe_buffer.cnt > 0) { 23413675Sdyson int size = rpipe->pipe_buffer.size - rpipe->pipe_buffer.out; 23513675Sdyson if (size > rpipe->pipe_buffer.cnt) 23613675Sdyson size = rpipe->pipe_buffer.cnt; 23713675Sdyson if (size > uio->uio_resid) 23813675Sdyson size = uio->uio_resid; 23913675Sdyson if ((error = pipelock(rpipe)) == 0) { 24013675Sdyson error = uiomove( &rpipe->pipe_buffer.buffer[rpipe->pipe_buffer.out], 24113675Sdyson size, uio); 24213675Sdyson pipeunlock(rpipe); 24313675Sdyson } 24413675Sdyson if (error) { 24513675Sdyson break; 24613675Sdyson } 24713675Sdyson rpipe->pipe_buffer.out += size; 24813675Sdyson if (rpipe->pipe_buffer.out >= rpipe->pipe_buffer.size) 24913675Sdyson rpipe->pipe_buffer.out = 0; 25013675Sdyson 25113675Sdyson rpipe->pipe_buffer.cnt -= size; 25213675Sdyson nread += size; 25313675Sdyson rpipe->pipe_atime = time; 25413675Sdyson } else { 25513675Sdyson /* 25613675Sdyson * detect EOF condition 25713675Sdyson */ 25813675Sdyson if (rpipe->pipe_state & PIPE_EOF) { 25913675Sdyson break; 26013675Sdyson } 26113675Sdyson /* 26213675Sdyson * If the "write-side" has been blocked, wake it up now. 26313675Sdyson */ 26413675Sdyson if (rpipe->pipe_state & PIPE_WANTW) { 26513675Sdyson rpipe->pipe_state &= ~PIPE_WANTW; 26613675Sdyson wakeup(rpipe); 26713675Sdyson } 26813675Sdyson if ((nread > 0) || (rpipe->pipe_state & PIPE_NBIO)) 26913675Sdyson break; 27013675Sdyson if (rpipe->pipe_peer == NULL) 27113675Sdyson break; 27213675Sdyson 27313675Sdyson /* 27413675Sdyson * If there is no more to read in the pipe, reset 27513675Sdyson * it's pointers to the beginning. This improves 27613675Sdyson * cache hit stats. 27713675Sdyson */ 27813675Sdyson 27913675Sdyson if ((error = pipelock(rpipe)) == 0) { 28013675Sdyson if (rpipe->pipe_buffer.cnt == 0) { 28113675Sdyson rpipe->pipe_buffer.in = 0; 28213675Sdyson rpipe->pipe_buffer.out = 0; 28313675Sdyson } 28413675Sdyson pipeunlock(rpipe); 28513675Sdyson } else { 28613675Sdyson break; 28713675Sdyson } 28813675Sdyson rpipe->pipe_state |= PIPE_WANTR; 28913675Sdyson if (tsleep(rpipe, PRIBIO|PCATCH, "piperd", 0)) { 29013675Sdyson error = ERESTART; 29113675Sdyson break; 29213675Sdyson } 29313675Sdyson } 29413675Sdyson } 29513675Sdyson 29613675Sdyson --rpipe->pipe_busy; 29713675Sdyson if ((rpipe->pipe_busy == 0) && (rpipe->pipe_state & PIPE_WANT)) { 29813675Sdyson rpipe->pipe_state &= ~(PIPE_WANT|PIPE_WANTW); 29913675Sdyson wakeup(rpipe); 30013675Sdyson } else if (rpipe->pipe_buffer.cnt < MINPIPESIZE) { 30113675Sdyson /* 30213675Sdyson * If there is no more to read in the pipe, reset 30313675Sdyson * it's pointers to the beginning. This improves 30413675Sdyson * cache hit stats. 30513675Sdyson */ 30613675Sdyson if ((error == 0) && (error = pipelock(rpipe)) == 0) { 30713675Sdyson if (rpipe->pipe_buffer.cnt == 0) { 30813675Sdyson rpipe->pipe_buffer.in = 0; 30913675Sdyson rpipe->pipe_buffer.out = 0; 31013675Sdyson } 31113675Sdyson pipeunlock(rpipe); 31213675Sdyson } 31313675Sdyson 31413675Sdyson /* 31513675Sdyson * If the "write-side" has been blocked, wake it up now. 31613675Sdyson */ 31713675Sdyson if (rpipe->pipe_state & PIPE_WANTW) { 31813675Sdyson rpipe->pipe_state &= ~PIPE_WANTW; 31913675Sdyson wakeup(rpipe); 32013675Sdyson } 32113675Sdyson } 32213675Sdyson if (rpipe->pipe_state & PIPE_SEL) { 32313675Sdyson rpipe->pipe_state &= ~PIPE_SEL; 32413675Sdyson selwakeup(&rpipe->pipe_sel); 32513675Sdyson } 32613675Sdyson return error; 32713675Sdyson} 32813675Sdyson 32913675Sdyson/* ARGSUSED */ 33013675Sdysonstatic int 33113675Sdysonpipe_write(fp, uio, cred) 33213675Sdyson struct file *fp; 33313675Sdyson struct uio *uio; 33413675Sdyson struct ucred *cred; 33513675Sdyson{ 33613675Sdyson struct pipe *rpipe = (struct pipe *) fp->f_data; 33713675Sdyson struct pipe *wpipe = rpipe->pipe_peer; 33813675Sdyson int error = 0; 33913675Sdyson 34013675Sdyson /* 34113675Sdyson * detect loss of pipe read side, issue SIGPIPE if lost. 34213675Sdyson */ 34313675Sdyson if (wpipe == NULL || (wpipe->pipe_state & PIPE_EOF)) { 34413675Sdyson psignal(curproc, SIGPIPE); 34513675Sdyson return 0; 34613675Sdyson } 34713675Sdyson 34813675Sdyson ++wpipe->pipe_busy; 34913675Sdyson while (uio->uio_resid) { 35013675Sdyson int space = wpipe->pipe_buffer.size - wpipe->pipe_buffer.cnt; 35113675Sdyson if (space > 0) { 35213675Sdyson int size = wpipe->pipe_buffer.size - wpipe->pipe_buffer.in; 35313675Sdyson if (size > space) 35413675Sdyson size = space; 35513675Sdyson if (size > uio->uio_resid) 35613675Sdyson size = uio->uio_resid; 35713675Sdyson if ((error = pipelock(wpipe)) == 0) { 35813675Sdyson error = uiomove( &wpipe->pipe_buffer.buffer[wpipe->pipe_buffer.in], 35913675Sdyson size, uio); 36013675Sdyson pipeunlock(wpipe); 36113675Sdyson } 36213675Sdyson if (error) 36313675Sdyson break; 36413675Sdyson 36513675Sdyson wpipe->pipe_buffer.in += size; 36613675Sdyson if (wpipe->pipe_buffer.in >= wpipe->pipe_buffer.size) 36713675Sdyson wpipe->pipe_buffer.in = 0; 36813675Sdyson 36913675Sdyson wpipe->pipe_buffer.cnt += size; 37013675Sdyson wpipe->pipe_mtime = time; 37113675Sdyson } else { 37213675Sdyson /* 37313675Sdyson * If the "read-side" has been blocked, wake it up now. 37413675Sdyson */ 37513675Sdyson if (wpipe->pipe_state & PIPE_WANTR) { 37613675Sdyson wpipe->pipe_state &= ~PIPE_WANTR; 37713675Sdyson wakeup(wpipe); 37813675Sdyson } 37913675Sdyson /* 38013675Sdyson * don't block on non-blocking I/O 38113675Sdyson */ 38213675Sdyson if (wpipe->pipe_state & PIPE_NBIO) { 38313675Sdyson break; 38413675Sdyson } 38513675Sdyson wpipe->pipe_state |= PIPE_WANTW; 38613675Sdyson if (tsleep(wpipe, (PRIBIO+1)|PCATCH, "pipewr", 0)) { 38713675Sdyson error = ERESTART; 38813675Sdyson break; 38913675Sdyson } 39013675Sdyson /* 39113675Sdyson * If read side wants to go away, we just issue a signal 39213675Sdyson * to ourselves. 39313675Sdyson */ 39413675Sdyson if (wpipe->pipe_state & PIPE_EOF) { 39513675Sdyson psignal(curproc, SIGPIPE); 39613675Sdyson break; 39713675Sdyson } 39813675Sdyson } 39913675Sdyson } 40013675Sdyson 40113675Sdyson --wpipe->pipe_busy; 40213675Sdyson if ((wpipe->pipe_busy == 0) && 40313675Sdyson (wpipe->pipe_state & PIPE_WANT)) { 40413675Sdyson wpipe->pipe_state &= ~(PIPE_WANT|PIPE_WANTR); 40513675Sdyson wakeup(wpipe); 40613675Sdyson } else if (wpipe->pipe_buffer.cnt > 0) { 40713675Sdyson /* 40813675Sdyson * If we have put any characters in the buffer, we wake up 40913675Sdyson * the reader. 41013675Sdyson */ 41113675Sdyson if (wpipe->pipe_state & PIPE_WANTR) { 41213675Sdyson wpipe->pipe_state &= ~PIPE_WANTR; 41313675Sdyson wakeup(wpipe); 41413675Sdyson } 41513675Sdyson } 41613675Sdyson if (wpipe->pipe_state & PIPE_SEL) { 41713675Sdyson wpipe->pipe_state &= ~PIPE_SEL; 41813675Sdyson selwakeup(&wpipe->pipe_sel); 41913675Sdyson } 42013675Sdyson return error; 42113675Sdyson} 42213675Sdyson 42313675Sdyson/* 42413675Sdyson * we implement a very minimal set of ioctls for compatibility with sockets. 42513675Sdyson */ 42613675Sdysonint 42713675Sdysonpipe_ioctl(fp, cmd, data, p) 42813675Sdyson struct file *fp; 42913675Sdyson int cmd; 43013675Sdyson register caddr_t data; 43113675Sdyson struct proc *p; 43213675Sdyson{ 43313675Sdyson register struct pipe *mpipe = (struct pipe *)fp->f_data; 43413675Sdyson 43513675Sdyson switch (cmd) { 43613675Sdyson 43713675Sdyson case FIONBIO: 43813675Sdyson if (*(int *)data) 43913675Sdyson mpipe->pipe_state |= PIPE_NBIO; 44013675Sdyson else 44113675Sdyson mpipe->pipe_state &= ~PIPE_NBIO; 44213675Sdyson return (0); 44313675Sdyson 44413675Sdyson case FIOASYNC: 44513675Sdyson if (*(int *)data) { 44613675Sdyson mpipe->pipe_state |= PIPE_ASYNC; 44713675Sdyson } else { 44813675Sdyson mpipe->pipe_state &= ~PIPE_ASYNC; 44913675Sdyson } 45013675Sdyson return (0); 45113675Sdyson 45213675Sdyson case FIONREAD: 45313675Sdyson *(int *)data = mpipe->pipe_buffer.cnt; 45413675Sdyson return (0); 45513675Sdyson 45613675Sdyson case SIOCSPGRP: 45713675Sdyson mpipe->pipe_pgid = *(int *)data; 45813675Sdyson return (0); 45913675Sdyson 46013675Sdyson case SIOCGPGRP: 46113675Sdyson *(int *)data = mpipe->pipe_pgid; 46213675Sdyson return (0); 46313675Sdyson 46413675Sdyson } 46513675Sdyson return ENOSYS; 46613675Sdyson} 46713675Sdyson 46813675Sdysonint 46913675Sdysonpipe_select(fp, which, p) 47013675Sdyson struct file *fp; 47113675Sdyson int which; 47213675Sdyson struct proc *p; 47313675Sdyson{ 47413675Sdyson register struct pipe *rpipe = (struct pipe *)fp->f_data; 47513675Sdyson struct pipe *wpipe; 47613675Sdyson register int s = splnet(); 47713675Sdyson 47813675Sdyson wpipe = rpipe->pipe_peer; 47913675Sdyson switch (which) { 48013675Sdyson 48113675Sdyson case FREAD: 48213675Sdyson if (rpipe->pipe_buffer.cnt > 0) { 48313675Sdyson splx(s); 48413675Sdyson return (1); 48513675Sdyson } 48613675Sdyson selrecord(p, &rpipe->pipe_sel); 48713675Sdyson rpipe->pipe_state |= PIPE_SEL; 48813675Sdyson break; 48913675Sdyson 49013675Sdyson case FWRITE: 49113675Sdyson if (wpipe == 0) { 49213675Sdyson splx(s); 49313675Sdyson return (1); 49413675Sdyson } 49513675Sdyson if (wpipe->pipe_buffer.cnt < wpipe->pipe_buffer.size) { 49613675Sdyson splx(s); 49713675Sdyson return (1); 49813675Sdyson } 49913675Sdyson selrecord(p, &wpipe->pipe_sel); 50013675Sdyson wpipe->pipe_state |= PIPE_SEL; 50113675Sdyson break; 50213675Sdyson 50313675Sdyson case 0: 50413675Sdyson selrecord(p, &rpipe->pipe_sel); 50513675Sdyson rpipe->pipe_state |= PIPE_SEL; 50613675Sdyson break; 50713675Sdyson } 50813675Sdyson splx(s); 50913675Sdyson return (0); 51013675Sdyson} 51113675Sdyson 51213675Sdysonint 51313675Sdysonpipe_stat(pipe, ub) 51413675Sdyson register struct pipe *pipe; 51513675Sdyson register struct stat *ub; 51613675Sdyson{ 51713675Sdyson bzero((caddr_t)ub, sizeof (*ub)); 51813675Sdyson ub->st_mode = S_IFSOCK; 51913675Sdyson ub->st_blksize = pipe->pipe_buffer.size / 2; 52013675Sdyson ub->st_size = pipe->pipe_buffer.cnt; 52113675Sdyson ub->st_blocks = (ub->st_size + ub->st_blksize - 1) / ub->st_blksize; 52213675Sdyson TIMEVAL_TO_TIMESPEC(&pipe->pipe_atime, &ub->st_atimespec); 52313675Sdyson TIMEVAL_TO_TIMESPEC(&pipe->pipe_mtime, &ub->st_mtimespec); 52413675Sdyson TIMEVAL_TO_TIMESPEC(&pipe->pipe_ctime, &ub->st_ctimespec); 52513675Sdyson return 0; 52613675Sdyson} 52713675Sdyson 52813675Sdyson/* ARGSUSED */ 52913675Sdysonstatic int 53013675Sdysonpipe_close(fp, p) 53113675Sdyson struct file *fp; 53213675Sdyson struct proc *p; 53313675Sdyson{ 53413675Sdyson int error = 0; 53513675Sdyson struct pipe *cpipe = (struct pipe *)fp->f_data; 53613675Sdyson pipeclose(cpipe); 53713675Sdyson fp->f_data = NULL; 53813675Sdyson return 0; 53913675Sdyson} 54013675Sdyson 54113675Sdyson/* 54213675Sdyson * shutdown the pipe 54313675Sdyson */ 54413675Sdysonstatic void 54513675Sdysonpipeclose(cpipe) 54613675Sdyson struct pipe *cpipe; 54713675Sdyson{ 54813675Sdyson if (cpipe) { 54913675Sdyson /* 55013675Sdyson * If the other side is blocked, wake it up saying that 55113675Sdyson * we want to close it down. 55213675Sdyson */ 55313675Sdyson while (cpipe->pipe_busy) { 55413675Sdyson wakeup(cpipe); 55513675Sdyson cpipe->pipe_state |= PIPE_WANT|PIPE_EOF; 55613675Sdyson tsleep(cpipe, PRIBIO, "pipecl", 0); 55713675Sdyson } 55813675Sdyson 55913675Sdyson /* 56013675Sdyson * Disconnect from peer 56113675Sdyson */ 56213675Sdyson if (cpipe->pipe_peer) { 56313675Sdyson cpipe->pipe_peer->pipe_state |= PIPE_EOF; 56413675Sdyson wakeup(cpipe->pipe_peer); 56513675Sdyson cpipe->pipe_peer->pipe_peer = NULL; 56613675Sdyson } 56713675Sdyson 56813675Sdyson /* 56913675Sdyson * free resources 57013675Sdyson */ 57113675Sdyson kmem_free(kernel_map, (vm_offset_t)cpipe->pipe_buffer.buffer, 57213675Sdyson cpipe->pipe_buffer.size); 57313675Sdyson free(cpipe, M_TEMP); 57413675Sdyson } 57513675Sdyson} 57613675Sdyson#endif 577