home *** CD-ROM | disk | FTP | other *** search
- /*
- * linux/fs/pipe.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
- #include <asm/segment.h>
-
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/signal.h>
- #include <linux/fcntl.h>
- #include <linux/termios.h>
-
-
- /* We don't use the head/tail construction any more. Now we use the start/len*/
- /* contruction providing full use of PIPE_BUF (multiple of PAGE_SIZE) */
- /* Florian Coosmann (FGC) ^ current = 1 */
- /* Additionally, we now use locking technique. This prevents race condition */
- /* in case of paging and multiple read/write on the same pipe. (FGC) */
-
-
- static int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)
- {
- int chars = 0, size = 0, read = 0;
- char *pipebuf;
-
- if (filp->f_flags & O_NONBLOCK) {
- if (PIPE_LOCK(*inode))
- return -EAGAIN;
- if (PIPE_EMPTY(*inode))
- if (PIPE_WRITERS(*inode))
- return -EAGAIN;
- else
- return 0;
- } else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) {
- if (PIPE_EMPTY(*inode)) {
- if (!PIPE_WRITERS(*inode))
- return 0;
- }
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- interruptible_sleep_on(&PIPE_WAIT(*inode));
- }
- PIPE_LOCK(*inode)++;
- while (count>0 && (size = PIPE_SIZE(*inode))) {
- chars = PIPE_MAX_RCHUNK(*inode);
- if (chars > count)
- chars = count;
- if (chars > size)
- chars = size;
- read += chars;
- pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode);
- PIPE_START(*inode) += chars;
- PIPE_START(*inode) &= (PIPE_BUF-1);
- PIPE_LEN(*inode) -= chars;
- count -= chars;
- memcpy_tofs(buf, pipebuf, chars );
- buf += chars;
- }
- PIPE_LOCK(*inode)--;
- wake_up_interruptible(&PIPE_WAIT(*inode));
- if (read)
- return read;
- if (PIPE_WRITERS(*inode))
- return -EAGAIN;
- return 0;
- }
-
- static int pipe_write(struct inode * inode, struct file * filp, char * buf, int count)
- {
- int chars = 0, free = 0, written = 0;
- char *pipebuf;
-
- if (!PIPE_READERS(*inode)) { /* no readers */
- send_sig(SIGPIPE,current,0);
- return -EPIPE;
- }
- /* if count <= PIPE_BUF, we have to make it atomic */
- if (count <= PIPE_BUF)
- free = count;
- else
- free = 1; /* can't do it atomically, wait for any free space */
- while (count>0) {
- while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) {
- if (!PIPE_READERS(*inode)) { /* no readers */
- send_sig(SIGPIPE,current,0);
- return written? :-EPIPE;
- }
- if (current->signal & ~current->blocked)
- return written? :-ERESTARTSYS;
- if (filp->f_flags & O_NONBLOCK)
- return written? :-EAGAIN;
- interruptible_sleep_on(&PIPE_WAIT(*inode));
- }
- PIPE_LOCK(*inode)++;
- while (count>0 && (free = PIPE_FREE(*inode))) {
- chars = PIPE_MAX_WCHUNK(*inode);
- if (chars > count)
- chars = count;
- if (chars > free)
- chars = free;
- pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode);
- written += chars;
- PIPE_LEN(*inode) += chars;
- count -= chars;
- memcpy_fromfs(pipebuf, buf, chars );
- buf += chars;
- }
- PIPE_LOCK(*inode)--;
- wake_up_interruptible(&PIPE_WAIT(*inode));
- free = 1;
- }
- return written;
- }
-
- static int pipe_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
- {
- return -ESPIPE;
- }
-
- static int pipe_readdir(struct inode * inode, struct file * file, struct dirent * de, int count)
- {
- return -ENOTDIR;
- }
-
- static int bad_pipe_rw(struct inode * inode, struct file * filp, char * buf, int count)
- {
- return -EBADF;
- }
-
- static int pipe_ioctl(struct inode *pino, struct file * filp,
- unsigned int cmd, unsigned long arg)
- {
- int error;
-
- switch (cmd) {
- case FIONREAD:
- error = verify_area(VERIFY_WRITE, (void *) arg,4);
- if (!error)
- put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg);
- return error;
- default:
- return -EINVAL;
- }
- }
-
- static int pipe_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
- {
- switch (sel_type) {
- case SEL_IN:
- if (!PIPE_EMPTY(*inode) || !PIPE_WRITERS(*inode))
- return 1;
- select_wait(&PIPE_WAIT(*inode), wait);
- return 0;
- case SEL_OUT:
- if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode))
- return 1;
- select_wait(&PIPE_WAIT(*inode), wait);
- return 0;
- case SEL_EX:
- if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
- return 1;
- select_wait(&inode->i_wait,wait);
- return 0;
- }
- return 0;
- }
-
- /*
- * Arggh. Why does SunOS have to have different select() behaviour
- * for pipes and fifos? Hate-Hate-Hate. See difference in SEL_IN..
- */
- static int fifo_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
- {
- switch (sel_type) {
- case SEL_IN:
- if (!PIPE_EMPTY(*inode))
- return 1;
- select_wait(&PIPE_WAIT(*inode), wait);
- return 0;
- case SEL_OUT:
- if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode))
- return 1;
- select_wait(&PIPE_WAIT(*inode), wait);
- return 0;
- case SEL_EX:
- if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
- return 1;
- select_wait(&inode->i_wait,wait);
- return 0;
- }
- return 0;
- }
-
- /*
- * The 'connect_xxx()' functions are needed for named pipes when
- * the open() code hasn't guaranteed a connection (O_NONBLOCK),
- * and we need to act differently until we do get a writer..
- */
- static int connect_read(struct inode * inode, struct file * filp, char * buf, int count)
- {
- while (!PIPE_SIZE(*inode)) {
- if (PIPE_WRITERS(*inode))
- break;
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- wake_up_interruptible(& PIPE_WAIT(*inode));
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- interruptible_sleep_on(& PIPE_WAIT(*inode));
- }
- filp->f_op = &read_fifo_fops;
- return pipe_read(inode,filp,buf,count);
- }
-
- static int connect_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
- {
- switch (sel_type) {
- case SEL_IN:
- if (!PIPE_EMPTY(*inode)) {
- filp->f_op = &read_fifo_fops;
- return 1;
- }
- select_wait(&PIPE_WAIT(*inode), wait);
- return 0;
- case SEL_OUT:
- if (!PIPE_FULL(*inode))
- return 1;
- select_wait(&PIPE_WAIT(*inode), wait);
- return 0;
- case SEL_EX:
- if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
- return 1;
- select_wait(&inode->i_wait,wait);
- return 0;
- }
- return 0;
- }
-
- /*
- * Ok, these three routines NOW keep track of readers/writers,
- * Linus previously did it with inode->i_count checking.
- */
- static void pipe_read_release(struct inode * inode, struct file * filp)
- {
- PIPE_READERS(*inode)--;
- wake_up_interruptible(&PIPE_WAIT(*inode));
- }
-
- static void pipe_write_release(struct inode * inode, struct file * filp)
- {
- PIPE_WRITERS(*inode)--;
- wake_up_interruptible(&PIPE_WAIT(*inode));
- }
-
- static void pipe_rdwr_release(struct inode * inode, struct file * filp)
- {
- PIPE_READERS(*inode)--;
- PIPE_WRITERS(*inode)--;
- wake_up_interruptible(&PIPE_WAIT(*inode));
- }
-
- /*
- * The file_operations structs are not static because they
- * are also used in linux/fs/fifo.c to do operations on fifo's.
- */
- struct file_operations connecting_fifo_fops = {
- pipe_lseek,
- connect_read,
- bad_pipe_rw,
- pipe_readdir,
- connect_select,
- pipe_ioctl,
- NULL, /* no mmap on pipes.. surprise */
- NULL, /* no special open code */
- pipe_read_release,
- NULL
- };
-
- struct file_operations read_fifo_fops = {
- pipe_lseek,
- pipe_read,
- bad_pipe_rw,
- pipe_readdir,
- fifo_select,
- pipe_ioctl,
- NULL, /* no mmap on pipes.. surprise */
- NULL, /* no special open code */
- pipe_read_release,
- NULL
- };
-
- struct file_operations write_fifo_fops = {
- pipe_lseek,
- bad_pipe_rw,
- pipe_write,
- pipe_readdir,
- fifo_select,
- pipe_ioctl,
- NULL, /* mmap */
- NULL, /* no special open code */
- pipe_write_release,
- NULL
- };
-
- struct file_operations rdwr_fifo_fops = {
- pipe_lseek,
- pipe_read,
- pipe_write,
- pipe_readdir,
- fifo_select,
- pipe_ioctl,
- NULL, /* mmap */
- NULL, /* no special open code */
- pipe_rdwr_release,
- NULL
- };
-
- struct file_operations read_pipe_fops = {
- pipe_lseek,
- pipe_read,
- bad_pipe_rw,
- pipe_readdir,
- pipe_select,
- pipe_ioctl,
- NULL, /* no mmap on pipes.. surprise */
- NULL, /* no special open code */
- pipe_read_release,
- NULL
- };
-
- struct file_operations write_pipe_fops = {
- pipe_lseek,
- bad_pipe_rw,
- pipe_write,
- pipe_readdir,
- pipe_select,
- pipe_ioctl,
- NULL, /* mmap */
- NULL, /* no special open code */
- pipe_write_release,
- NULL
- };
-
- struct file_operations rdwr_pipe_fops = {
- pipe_lseek,
- pipe_read,
- pipe_write,
- pipe_readdir,
- pipe_select,
- pipe_ioctl,
- NULL, /* mmap */
- NULL, /* no special open code */
- pipe_rdwr_release,
- NULL
- };
-
- struct inode_operations pipe_inode_operations = {
- &rdwr_pipe_fops,
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL /* permission */
- };
-
- asmlinkage int sys_pipe(unsigned long * fildes)
- {
- struct inode * inode;
- struct file * f[2];
- int fd[2];
- int i,j;
-
- j = verify_area(VERIFY_WRITE,fildes,8);
- if (j)
- return j;
- for(j=0 ; j<2 ; j++)
- if (!(f[j] = get_empty_filp()))
- break;
- if (j==1)
- f[0]->f_count--;
- if (j<2)
- return -ENFILE;
- j=0;
- for(i=0;j<2 && i<NR_OPEN;i++)
- if (!current->filp[i]) {
- current->filp[ fd[j]=i ] = f[j];
- j++;
- }
- if (j==1)
- current->filp[fd[0]]=NULL;
- if (j<2) {
- f[0]->f_count--;
- f[1]->f_count--;
- return -EMFILE;
- }
- if (!(inode=get_pipe_inode())) {
- current->filp[fd[0]] = NULL;
- current->filp[fd[1]] = NULL;
- f[0]->f_count--;
- f[1]->f_count--;
- return -ENFILE;
- }
- f[0]->f_inode = f[1]->f_inode = inode;
- f[0]->f_pos = f[1]->f_pos = 0;
- f[0]->f_flags = O_RDONLY;
- f[0]->f_op = &read_pipe_fops;
- f[0]->f_mode = 1; /* read */
- f[1]->f_flags = O_WRONLY;
- f[1]->f_op = &write_pipe_fops;
- f[1]->f_mode = 2; /* write */
- put_fs_long(fd[0],0+fildes);
- put_fs_long(fd[1],1+fildes);
- return 0;
- }
-