--- linux/fs/pipe.c.orig2 Wed Sep 29 11:50:27 1999 +++ linux/fs/pipe.c Wed Sep 29 12:33:11 1999 @@ -2,6 +2,8 @@ * linux/fs/pipe.c * * Copyright (C) 1991, 1992, 1999 Linus Torvalds + * + * wake-one pipe handling by Ingo Molnar */ #include @@ -32,17 +34,27 @@ */ /* Drop the inode semaphore and wait for a pipe event, atomically */ -static void pipe_wait(struct inode * inode) +static inline void __pipe_wait (wait_queue_head_t *wq, struct inode * inode) { DECLARE_WAITQUEUE(wait, current); - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(PIPE_WAIT(*inode), &wait); + current->state = TASK_EXCLUSIVE | TASK_INTERRUPTIBLE; + add_wait_queue(wq, &wait); up(PIPE_SEM(*inode)); schedule(); - remove_wait_queue(PIPE_WAIT(*inode), &wait); + remove_wait_queue(wq, &wait); current->state = TASK_RUNNING; } +static void pipe_wait_readqueue (struct inode * inode) +{ + __pipe_wait(PIPE_WAIT_READ(*inode), inode); +} + +static void pipe_wait_writequeue (struct inode * inode) +{ + __pipe_wait(PIPE_WAIT_WRITE(*inode), inode); +} + static ssize_t pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { @@ -74,7 +86,7 @@ goto out; for (;;) { - pipe_wait(inode); + pipe_wait_readqueue(inode); ret = -ERESTARTSYS; if (signal_pending(current)) goto out_nolock; @@ -115,8 +127,8 @@ if (!PIPE_LEN(*inode)) PIPE_START(*inode) = 0; - /* Signal writers there is more room. */ - wake_up_interruptible(PIPE_WAIT(*inode)); + /* Signal writers (and pollers) there is more room. */ + wake_up_pipe(inode, PIPE_WAIT_WRITE(*inode)); if (read) UPDATE_ATIME(inode); @@ -163,7 +175,7 @@ goto out; } else { while (PIPE_FREE(*inode) < free) { - pipe_wait(inode); + pipe_wait_writequeue(inode); ret = -ERESTARTSYS; if (signal_pending(current)) goto out_nolock; @@ -205,8 +217,8 @@ do { /* This should be a synchronous wake-up: don't do idle reschedules! */ - wake_up_interruptible(PIPE_WAIT(*inode)); - pipe_wait(inode); + wake_up_pipe(inode, PIPE_WAIT_READ(*inode)); + pipe_wait_writequeue(inode); if (signal_pending(current)) goto out_nolock; if (down_interruptible(PIPE_SEM(*inode))) @@ -218,7 +230,7 @@ } /* Signal readers there is more data. */ - wake_up_interruptible(PIPE_WAIT(*inode)); + wake_up_pipe(inode, PIPE_WAIT_READ(*inode)); ret = (written ? written : -EAGAIN); inode->i_ctime = inode->i_mtime = CURRENT_TIME; @@ -271,7 +283,7 @@ unsigned int mask; struct inode *inode = filp->f_dentry->d_inode; - poll_wait(filp, PIPE_WAIT(*inode), wait); + poll_wait(filp, PIPE_WAIT_POLL(*inode), wait); /* Reading only -- no need for aquiring the semaphore. */ mask = POLLIN | POLLRDNORM; @@ -296,7 +308,7 @@ unsigned int mask; struct inode *inode = filp->f_dentry->d_inode; - poll_wait(filp, PIPE_WAIT(*inode), wait); + poll_wait(filp, PIPE_WAIT_POLL(*inode), wait); /* Reading only -- no need for aquiring the semaphore. */ mask = POLLIN | POLLRDNORM; @@ -337,7 +349,7 @@ struct inode *inode = filp->f_dentry->d_inode; unsigned int mask = 0; - poll_wait(filp, PIPE_WAIT(*inode), wait); + poll_wait(filp, PIPE_WAIT_POLL(*inode), wait); /* Reading only -- no need for aquiring the semaphore. */ if (!PIPE_EMPTY(*inode)) { @@ -363,7 +375,9 @@ free_page((unsigned long) info->base); kfree(info); } else { - wake_up_interruptible(PIPE_WAIT(*inode)); + wake_up_interruptible(PIPE_WAIT_READ(*inode)); + wake_up_interruptible(PIPE_WAIT_WRITE(*inode)); + wake_up_interruptible(PIPE_WAIT_POLL(*inode)); } up(PIPE_SEM(*inode)); @@ -548,7 +562,9 @@ inode->i_op = &pipe_inode_operations; - init_waitqueue_head(PIPE_WAIT(*inode)); + init_waitqueue_head(PIPE_WAIT_READ(*inode)); + init_waitqueue_head(PIPE_WAIT_WRITE(*inode)); + init_waitqueue_head(PIPE_WAIT_POLL(*inode)); PIPE_BASE(*inode) = (char *) page; PIPE_START(*inode) = PIPE_LEN(*inode) = 0; PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1; --- linux/fs/fifo.c.orig2 Wed Sep 29 12:10:13 1999 +++ linux/fs/fifo.c Wed Sep 29 12:20:06 1999 @@ -37,7 +37,9 @@ inode->i_pipe = info; - init_waitqueue_head(PIPE_WAIT(*inode)); + init_waitqueue_head(PIPE_WAIT_READ(*inode)); + init_waitqueue_head(PIPE_WAIT_WRITE(*inode)); + init_waitqueue_head(PIPE_WAIT_POLL(*inode)); PIPE_BASE(*inode) = (char *) page; PIPE_START(*inode) = PIPE_LEN(*inode) = 0; PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; @@ -51,15 +53,15 @@ * opened, even when there is no process writing the FIFO. */ filp->f_op = &connecting_fifo_fops; - if (PIPE_READERS(*inode)++ == 0) - wake_up_interruptible(PIPE_WAIT(*inode)); + if (!PIPE_READERS(*inode)++) + wake_up_pipe(inode, PIPE_WAIT_WRITE(*inode)); if (!(filp->f_flags & O_NONBLOCK)) { while (!PIPE_WRITERS(*inode)) { if (signal_pending(current)) goto err_rd; up(PIPE_SEM(*inode)); - interruptible_sleep_on(PIPE_WAIT(*inode)); + interruptible_sleep_on(PIPE_WAIT_READ(*inode)); /* Note that using down_interruptible here and similar places below is pointless, @@ -85,13 +87,13 @@ filp->f_op = &write_fifo_fops; if (!PIPE_WRITERS(*inode)++) - wake_up_interruptible(PIPE_WAIT(*inode)); + wake_up_pipe(inode, PIPE_WAIT_READ(*inode)); while (!PIPE_READERS(*inode)) { if (signal_pending(current)) goto err_wr; up(PIPE_SEM(*inode)); - interruptible_sleep_on(PIPE_WAIT(*inode)); + interruptible_sleep_on(PIPE_WAIT_WRITE(*inode)); down(PIPE_SEM(*inode)); } break; @@ -107,8 +109,11 @@ PIPE_READERS(*inode)++; PIPE_WRITERS(*inode)++; - if (PIPE_READERS(*inode) == 1 || PIPE_WRITERS(*inode) == 1) - wake_up_interruptible(PIPE_WAIT(*inode)); + if (PIPE_READERS(*inode) == 1 || PIPE_WRITERS(*inode) == 1) { + wake_up_interruptible(PIPE_WAIT_READ(*inode)); + wake_up_interruptible(PIPE_WAIT_WRITE(*inode)); + wake_up_interruptible(PIPE_WAIT_POLL(*inode)); + } break; default: @@ -122,13 +127,13 @@ err_rd: if (!--PIPE_READERS(*inode)) - wake_up_interruptible(PIPE_WAIT(*inode)); + wake_up_pipe(inode, PIPE_WAIT_WRITE(*inode)); ret = -ERESTARTSYS; goto err; err_wr: if (!--PIPE_WRITERS(*inode)) - wake_up_interruptible(PIPE_WAIT(*inode)); + wake_up_pipe(inode, PIPE_WAIT_READ(*inode)); ret = -ERESTARTSYS; goto err; --- linux/include/linux/wait.h.orig2 Wed Sep 29 12:07:24 1999 +++ linux/include/linux/wait.h Wed Sep 29 12:23:41 1999 @@ -20,7 +20,7 @@ * Temporary debugging help until all code is converted to the new * waitqueue usage. */ -#define WAITQUEUE_DEBUG 0 +#define WAITQUEUE_DEBUG 1 #if WAITQUEUE_DEBUG extern int printk(const char *fmt, ...); --- linux/include/linux/pipe_fs_i.h.orig2 Wed Sep 29 11:52:00 1999 +++ linux/include/linux/pipe_fs_i.h Wed Sep 29 12:12:38 1999 @@ -2,7 +2,9 @@ #define _LINUX_PIPE_FS_I_H struct pipe_inode_info { - wait_queue_head_t wait; + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; + wait_queue_head_t poll_wait; char *base; unsigned int start; unsigned int readers; @@ -14,7 +16,9 @@ #define PIPE_SIZE PAGE_SIZE #define PIPE_SEM(inode) (&(inode).i_sem) -#define PIPE_WAIT(inode) (&(inode).i_pipe->wait) +#define PIPE_WAIT_READ(inode) (&(inode).i_pipe->read_wait) +#define PIPE_WAIT_WRITE(inode) (&(inode).i_pipe->write_wait) +#define PIPE_WAIT_POLL(inode) (&(inode).i_pipe->poll_wait) #define PIPE_BASE(inode) ((inode).i_pipe->base) #define PIPE_START(inode) ((inode).i_pipe->start) #define PIPE_LEN(inode) ((inode).i_size) @@ -27,5 +31,12 @@ #define PIPE_END(inode) ((PIPE_START(inode) + PIPE_LEN(inode)) & (PIPE_SIZE-1)) #define PIPE_MAX_RCHUNK(inode) (PIPE_SIZE - PIPE_START(inode)) #define PIPE_MAX_WCHUNK(inode) (PIPE_SIZE - PIPE_END(inode)) + +#define wake_up_pipe(inode,wq) \ +do { \ + wake_up_interruptible(wq); \ + if (waitqueue_active(PIPE_WAIT_POLL(*(inode)))) \ + wake_up_interruptible(PIPE_WAIT_POLL(*(inode))); \ +} while (0) #endif