/* * Copyright (c) 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * @(#)sys_pipe.c 1.5 (2.11BSD GTE) 1997/2/7 */ #include "param.h" #include "systm.h" #include "user.h" #include "proc.h" #include "inode.h" #include "file.h" #include "fs.h" #include "mount.h" #include "uio.h" extern int ino_ioctl(); int pipe_rw(), pipe_select(), pipe_close(); struct fileops pipeops = { pipe_rw, ino_ioctl, pipe_select, pipe_close }; /* * The sys-pipe entry. * Allocate an inode on the root device. Allocate 2 * file structures. Put it all together with flags. */ pipe() { register struct inode *ip; register struct file *rf, *wf; static struct mount *mp; struct inode itmp; int r; /* * if pipedev not yet found, or not available, get it; if can't * find it, use rootdev. It would be cleaner to wander around * and fix it so that this and getfs() only check m_dev OR * m_inodp, but hopefully the mount table isn't scanned enough * to make it a problem. Besides, 4.3's is just as bad. Basic * fantasy is that if m_inodp is set, m_dev *will* be okay. */ if (!mp || !mp->m_inodp || mp->m_dev != pipedev) { for (mp = &mount[0];;++mp) { if (mp == &mount[NMOUNT]) { mp = &mount[0]; /* use root */ break; } if (mp->m_inodp == NULL || mp->m_dev != pipedev) continue; break; } if (mp->m_filsys.fs_ronly) { u.u_error = EROFS; return; } } itmp.i_fs = &mp->m_filsys; itmp.i_dev = mp->m_dev; ip = ialloc(&itmp); if (ip == NULL) return; rf = falloc(); if (rf == NULL) { iput(ip); return; } r = u.u_r.r_val1; wf = falloc(); if (wf == NULL) { rf->f_count = 0; u.u_ofile[r] = NULL; iput(ip); return; } u.u_r.r_val2 = u.u_r.r_val1; u.u_r.r_val1 = r; wf->f_flag = FWRITE; rf->f_flag = FREAD; rf->f_type = wf->f_type = DTYPE_PIPE; rf->f_data = wf->f_data = (caddr_t)ip; ip->i_count = 2; ip->i_mode = IFREG; ip->i_flag = IACC|IUPD|ICHG|IPIPE; } pipe_rw(fp, uio, flag) register struct file *fp; register struct uio *uio; int flag; { if (uio->uio_rw == UIO_READ) return (readp(fp, uio, flag)); return (writep(fp, uio, flag)); } readp(fp, uio, flag) register struct file *fp; register struct uio *uio; int flag; { register struct inode *ip; int error; ip = (struct inode *)fp->f_data; loop: /* Very conservative locking. */ ILOCK(ip); /* If nothing in the pipe, wait (unless FNONBLOCK is set). */ if (ip->i_size == 0) { /* * If there are not both reader and writer active, * return without satisfying read. */ IUNLOCK(ip); if (ip->i_count != 2) return (0); if (fp->f_flag & FNONBLOCK) return (EWOULDBLOCK); ip->i_mode |= IREAD; sleep((caddr_t)ip+4, PPIPE); goto loop; } uio->uio_offset = fp->f_offset; error = rwip(ip, uio, flag); fp->f_offset = uio->uio_offset; /* * If reader has caught up with writer, reset * offset and size to 0. */ if (fp->f_offset == ip->i_size) { fp->f_offset = 0; ip->i_size = 0; if (ip->i_mode & IWRITE) { ip->i_mode &= ~IWRITE; wakeup((caddr_t)ip+2); } if (ip->i_wsel) { selwakeup(ip->i_wsel, (long)(ip->i_flag & IWCOLL)); ip->i_wsel = 0; ip->i_flag &= ~IWCOLL; } } IUNLOCK(ip); return (error); } writep(fp, uio, flag) struct file *fp; register struct uio *uio; int flag; { register struct inode *ip; register int c; int error = 0; ip = (struct inode *)fp->f_data; c = uio->uio_resid; ILOCK(ip); if ((fp->f_flag & FNONBLOCK) && ip->i_size + c >= MAXPIPSIZ) { error = EWOULDBLOCK; goto done; } loop: /* If all done, return. */ if (c == 0) { uio->uio_resid = 0; goto done; } /* * If there are not both read and write sides of the pipe active, * return error and signal too. */ if (ip->i_count != 2) { psignal(u.u_procp, SIGPIPE); error = EPIPE; done: IUNLOCK(ip); return (error); } /* * If the pipe is full, wait for reads to deplete * and truncate it. */ if (ip->i_size >= MAXPIPSIZ) { ip->i_mode |= IWRITE; IUNLOCK(ip); sleep((caddr_t)ip+2, PPIPE); ILOCK(ip); goto loop; } /* * Write what is possible and loop back. * If writing less than MAXPIPSIZ, it always goes. * One can therefore get a file > MAXPIPSIZ if write * sizes do not divide MAXPIPSIZ. */ uio->uio_offset = ip->i_size; uio->uio_resid = MIN((u_int)c, (u_int)MAXPIPSIZ); c -= uio->uio_resid; error = rwip(ip, uio, flag); if (ip->i_mode&IREAD) { ip->i_mode &= ~IREAD; wakeup((caddr_t)ip+4); } if (ip->i_rsel) { selwakeup(ip->i_rsel, (long)(ip->i_flag & IRCOLL)); ip->i_rsel = 0; ip->i_flag &= ~IRCOLL; } goto loop; } pipe_select(fp, which) struct file *fp; int which; { register struct inode *ip = (struct inode *)fp->f_data; register struct proc *p; register int retval = 0; extern int selwait; ILOCK(ip); if (ip->i_count != 2) retval = 1; else switch (which) { case FREAD: if (ip->i_size) { retval = 1; break; } if ((p = ip->i_rsel) && p->p_wchan == (caddr_t)&selwait) ip->i_flag |= IRCOLL; else ip->i_rsel = u.u_procp; break; case FWRITE: if (ip->i_size < MAXPIPSIZ) { retval = 1; break; } if ((p = ip->i_wsel) && p->p_wchan == (caddr_t)&selwait) ip->i_flag |= IWCOLL; else ip->i_wsel = u.u_procp; break; } IUNLOCK(ip); return(retval); } /* * This routine was pulled out of what used to be called 'ino_close'. Doing * so saved a test of the inode belonging to a pipe. We know this is a pipe * because the inode type was DTYPE_PIPE. The dispatch in closef() can come * directly here instead of the general inode close routine. * * This routine frees the inode by calling 'iput'. The inode must be * unlocked prior to calling this routine because an 'ilock' is done prior * to the select wakeup processing. */ pipe_close(fp) struct file *fp; { register struct inode *ip = (struct inode *)fp->f_data; ilock(ip); #ifdef DIAGNOSTIC if ((ip->i_flag & IPIPE) == 0) panic("pipe_close !IPIPE"); #endif if (ip->i_rsel) { selwakeup(ip->i_rsel, (long)(ip->i_flag & IRCOLL)); ip->i_rsel = 0; ip->i_flag &= ~IRCOLL; } if (ip->i_wsel) { selwakeup(ip->i_wsel, (long)(ip->i_flag & IWCOLL)); ip->i_wsel = 0; ip->i_flag &= ~IWCOLL; } ip->i_mode &= ~(IREAD|IWRITE); wakeup((caddr_t)ip+2); wakeup((caddr_t)ip+4); /* * And finally decrement the reference count and (likely) release the inode. */ iput(ip); return(0); }