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