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