Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/kern Import FreeBSD sys_pipe.c rev 1.82 for reference (t...
details: https://anonhg.NetBSD.org/src/rev/9a547344782a
branches: trunk
changeset: 511282:9a547344782a
user: jdolecek <jdolecek%NetBSD.org@localhost>
date: Sat Jun 16 09:21:34 2001 +0000
description:
Import FreeBSD sys_pipe.c rev 1.82 for reference (this was used as a base
for the NetBSD port).
diffstat:
sys/kern/sys_pipe.c | 1308 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1308 insertions(+), 0 deletions(-)
diffs (truncated from 1312 to 300 lines):
diff -r c29e73ab8bec -r 9a547344782a sys/kern/sys_pipe.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/kern/sys_pipe.c Sat Jun 16 09:21:34 2001 +0000
@@ -0,0 +1,1308 @@
+/*
+ * Copyright (c) 1996 John S. Dyson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Absolutely no warranty of function or purpose is made by the author
+ * John S. Dyson.
+ * 4. Modifications may be freely made to this file if the above conditions
+ * are met.
+ *
+ * $FreeBSD: src/sys/kern/sys_pipe.c,v 1.82 2001/06/15 20:45:01 jlemon Exp $
+ */
+
+/*
+ * This file contains a high-performance replacement for the socket-based
+ * pipes scheme originally used in FreeBSD/4.4Lite. It does not support
+ * all features of sockets, but does do everything that pipes normally
+ * do.
+ */
+
+/*
+ * This code has two modes of operation, a small write mode and a large
+ * write mode. The small write mode acts like conventional pipes with
+ * a kernel buffer. If the buffer is less than PIPE_MINDIRECT, then the
+ * "normal" pipe buffering is done. If the buffer is between PIPE_MINDIRECT
+ * and PIPE_SIZE in size, it is fully mapped and wired into the kernel, and
+ * the receiving process can copy it directly from the pages in the sending
+ * process.
+ *
+ * If the sending process receives a signal, it is possible that it will
+ * go away, and certainly its address space can change, because control
+ * is returned back to the user-mode side. In that case, the pipe code
+ * arranges to copy the buffer supplied by the user process, to a pageable
+ * kernel buffer, and the receiving process will grab the data from the
+ * pageable kernel buffer. Since signals don't happen all that often,
+ * the copy operation is normally eliminated.
+ *
+ * The constant PIPE_MINDIRECT is chosen to make sure that buffering will
+ * happen for small transfers so that the system will not spend all of
+ * its time context switching. PIPE_SIZE is constrained by the
+ * amount of kernel virtual memory.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/filio.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/ttycom.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
+#include <sys/signalvar.h>
+#include <sys/sysproto.h>
+#include <sys/pipe.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/uio.h>
+#include <sys/event.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/vm_object.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
+#include <vm/vm_page.h>
+#include <vm/vm_zone.h>
+
+/*
+ * Use this define if you want to disable *fancy* VM things. Expect an
+ * approx 30% decrease in transfer rate. This could be useful for
+ * NetBSD or OpenBSD.
+ */
+/* #define PIPE_NODIRECT */
+
+/*
+ * interfaces to the outside world
+ */
+static int pipe_read __P((struct file *fp, struct uio *uio,
+ struct ucred *cred, int flags, struct proc *p));
+static int pipe_write __P((struct file *fp, struct uio *uio,
+ struct ucred *cred, int flags, struct proc *p));
+static int pipe_close __P((struct file *fp, struct proc *p));
+static int pipe_poll __P((struct file *fp, int events, struct ucred *cred,
+ struct proc *p));
+static int pipe_kqfilter __P((struct file *fp, struct knote *kn));
+static int pipe_stat __P((struct file *fp, struct stat *sb, struct proc *p));
+static int pipe_ioctl __P((struct file *fp, u_long cmd, caddr_t data, struct proc *p));
+
+static struct fileops pipeops = {
+ pipe_read, pipe_write, pipe_ioctl, pipe_poll, pipe_kqfilter,
+ pipe_stat, pipe_close
+};
+
+static void filt_pipedetach(struct knote *kn);
+static int filt_piperead(struct knote *kn, long hint);
+static int filt_pipewrite(struct knote *kn, long hint);
+
+static struct filterops pipe_rfiltops =
+ { 1, NULL, filt_pipedetach, filt_piperead };
+static struct filterops pipe_wfiltops =
+ { 1, NULL, filt_pipedetach, filt_pipewrite };
+
+
+/*
+ * Default pipe buffer size(s), this can be kind-of large now because pipe
+ * space is pageable. The pipe code will try to maintain locality of
+ * reference for performance reasons, so small amounts of outstanding I/O
+ * will not wipe the cache.
+ */
+#define MINPIPESIZE (PIPE_SIZE/3)
+#define MAXPIPESIZE (2*PIPE_SIZE/3)
+
+/*
+ * Maximum amount of kva for pipes -- this is kind-of a soft limit, but
+ * is there so that on large systems, we don't exhaust it.
+ */
+#define MAXPIPEKVA (8*1024*1024)
+
+/*
+ * Limit for direct transfers, we cannot, of course limit
+ * the amount of kva for pipes in general though.
+ */
+#define LIMITPIPEKVA (16*1024*1024)
+
+/*
+ * Limit the number of "big" pipes
+ */
+#define LIMITBIGPIPES 32
+static int nbigpipe;
+
+static int amountpipekva;
+
+static void pipeclose __P((struct pipe *cpipe));
+static void pipe_free_kmem __P((struct pipe *cpipe));
+static int pipe_create __P((struct pipe **cpipep));
+static __inline int pipelock __P((struct pipe *cpipe, int catch));
+static __inline void pipeunlock __P((struct pipe *cpipe));
+static __inline void pipeselwakeup __P((struct pipe *cpipe));
+#ifndef PIPE_NODIRECT
+static int pipe_build_write_buffer __P((struct pipe *wpipe, struct uio *uio));
+static void pipe_destroy_write_buffer __P((struct pipe *wpipe));
+static int pipe_direct_write __P((struct pipe *wpipe, struct uio *uio));
+static void pipe_clone_write_buffer __P((struct pipe *wpipe));
+#endif
+static int pipespace __P((struct pipe *cpipe, int size));
+
+static vm_zone_t pipe_zone;
+
+/*
+ * The pipe system call for the DTYPE_PIPE type of pipes
+ */
+
+/* ARGSUSED */
+int
+pipe(p, uap)
+ struct proc *p;
+ struct pipe_args /* {
+ int dummy;
+ } */ *uap;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct file *rf, *wf;
+ struct pipe *rpipe, *wpipe;
+ int fd, error;
+
+ if (pipe_zone == NULL)
+ pipe_zone = zinit("PIPE", sizeof(struct pipe), 0, 0, 4);
+
+ rpipe = wpipe = NULL;
+ if (pipe_create(&rpipe) || pipe_create(&wpipe)) {
+ pipeclose(rpipe);
+ pipeclose(wpipe);
+ return (ENFILE);
+ }
+
+ rpipe->pipe_state |= PIPE_DIRECTOK;
+ wpipe->pipe_state |= PIPE_DIRECTOK;
+
+ error = falloc(p, &rf, &fd);
+ if (error) {
+ pipeclose(rpipe);
+ pipeclose(wpipe);
+ return (error);
+ }
+ fhold(rf);
+ p->p_retval[0] = fd;
+
+ /*
+ * Warning: once we've gotten past allocation of the fd for the
+ * read-side, we can only drop the read side via fdrop() in order
+ * to avoid races against processes which manage to dup() the read
+ * side while we are blocked trying to allocate the write side.
+ */
+ rf->f_flag = FREAD | FWRITE;
+ rf->f_type = DTYPE_PIPE;
+ rf->f_data = (caddr_t)rpipe;
+ rf->f_ops = &pipeops;
+ error = falloc(p, &wf, &fd);
+ if (error) {
+ if (fdp->fd_ofiles[p->p_retval[0]] == rf) {
+ fdp->fd_ofiles[p->p_retval[0]] = NULL;
+ fdrop(rf, p);
+ }
+ fdrop(rf, p);
+ /* rpipe has been closed by fdrop(). */
+ pipeclose(wpipe);
+ return (error);
+ }
+ wf->f_flag = FREAD | FWRITE;
+ wf->f_type = DTYPE_PIPE;
+ wf->f_data = (caddr_t)wpipe;
+ wf->f_ops = &pipeops;
+ p->p_retval[1] = fd;
+
+ rpipe->pipe_peer = wpipe;
+ wpipe->pipe_peer = rpipe;
+ fdrop(rf, p);
+
+ return (0);
+}
+
+/*
+ * Allocate kva for pipe circular buffer, the space is pageable
+ * This routine will 'realloc' the size of a pipe safely, if it fails
+ * it will retain the old buffer.
+ * If it fails it will return ENOMEM.
+ */
+static int
+pipespace(cpipe, size)
+ struct pipe *cpipe;
+ int size;
+{
+ struct vm_object *object;
+ caddr_t buffer;
+ int npages, error;
+
+ npages = round_page(size)/PAGE_SIZE;
+ /*
+ * Create an object, I don't like the idea of paging to/from
+ * kernel_object.
+ * XXX -- minor change needed here for NetBSD/OpenBSD VM systems.
+ */
+ mtx_lock(&vm_mtx);
+ object = vm_object_allocate(OBJT_DEFAULT, npages);
+ buffer = (caddr_t) vm_map_min(kernel_map);
+
+ /*
+ * Insert the object into the kernel map, and allocate kva for it.
+ * The map entry is, by default, pageable.
+ * XXX -- minor change needed here for NetBSD/OpenBSD VM systems.
+ */
+ error = vm_map_find(kernel_map, object, 0,
+ (vm_offset_t *) &buffer, size, 1,
+ VM_PROT_ALL, VM_PROT_ALL, 0);
+
+ if (error != KERN_SUCCESS) {
+ vm_object_deallocate(object);
+ mtx_unlock(&vm_mtx);
+ return (ENOMEM);
+ }
+
+ /* free old resources if we're resizing */
+ pipe_free_kmem(cpipe);
+ mtx_unlock(&vm_mtx);
+ cpipe->pipe_buffer.object = object;
+ cpipe->pipe_buffer.buffer = buffer;
+ cpipe->pipe_buffer.size = size;
+ cpipe->pipe_buffer.in = 0;
+ cpipe->pipe_buffer.out = 0;
+ cpipe->pipe_buffer.cnt = 0;
+ amountpipekva += cpipe->pipe_buffer.size;
+ return (0);
+}
+
+/*
+ * initialize and allocate VM and memory for pipe
+ */
+static int
+pipe_create(cpipep)
+ struct pipe **cpipep;
+{
+ struct pipe *cpipe;
Home |
Main Index |
Thread Index |
Old Index