summaryrefslogtreecommitdiffstats
path: root/fs/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/select.c')
-rw-r--r--fs/select.c41
1 files changed, 27 insertions, 14 deletions
diff --git a/fs/select.c b/fs/select.c
index a9fd61953..be09afdd7 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -31,14 +31,15 @@
* understand what I'm doing here, then you understand how the linux
* sleep/wakeup mechanism works.
*
- * Two very simple procedures, poll_wait() and free_wait() make all the
+ * Two very simple procedures, poll_wait() and poll_freewait() make all the
* work. poll_wait() is an inline-function defined in <linux/poll.h>,
* as all select/poll functions have to call it to add an entry to the
* poll table.
*/
-static void free_wait(struct poll_table_page * p)
+void poll_freewait(poll_table* pt)
{
+ struct poll_table_page * p = pt->table;
while (p) {
struct poll_table_entry * entry;
struct poll_table_page *old;
@@ -66,6 +67,7 @@ void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table
new_table = (struct poll_table_page *) __get_free_page(GFP_KERNEL);
if (!new_table) {
p->error = -ENOMEM;
+ __set_current_state(TASK_RUNNING);
return;
}
new_table->nr = 0;
@@ -160,9 +162,10 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
return retval;
n = retval;
- table.error = 0;
- table.table = NULL;
+ poll_initwait(&table);
wait = &table;
+ if (!__timeout)
+ wait = NULL;
retval = 0;
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -201,11 +204,15 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
wait = NULL;
if (retval || !__timeout || signal_pending(current))
break;
+ if(table.error) {
+ retval = table.error;
+ break;
+ }
__timeout = schedule_timeout(__timeout);
}
current->state = TASK_RUNNING;
- free_wait(table.table);
+ poll_freewait(&table);
/*
* Up-to-date the caller timeout.
@@ -354,18 +361,22 @@ static int do_poll(unsigned int nfds, unsigned int nchunks, unsigned int nleft,
struct pollfd *fds[], poll_table *wait, long timeout)
{
int count = 0;
+ poll_table* pt = wait;
for (;;) {
unsigned int i;
set_current_state(TASK_INTERRUPTIBLE);
for (i=0; i < nchunks; i++)
- do_pollfd(POLLFD_PER_PAGE, fds[i], &wait, &count);
+ do_pollfd(POLLFD_PER_PAGE, fds[i], &pt, &count);
if (nleft)
- do_pollfd(nleft, fds[nchunks], &wait, &count);
- wait = NULL;
+ do_pollfd(nleft, fds[nchunks], &pt, &count);
+ pt = NULL;
if (count || !timeout || signal_pending(current))
break;
+ if(wait->error) {
+ return wait->error;
+ }
timeout = schedule_timeout(timeout);
}
current->state = TASK_RUNNING;
@@ -376,7 +387,7 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
{
int i, j, fdcount, err;
struct pollfd **fds;
- poll_table table;
+ poll_table table, *wait;
int nchunks, nleft;
/* Do a sanity check on nfds ... */
@@ -391,10 +402,12 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
}
- table.error = 0;
- table.table = NULL;
- err = -ENOMEM;
+ poll_initwait(&table);
+ wait = &table;
+ if (!timeout)
+ wait = NULL;
+ err = -ENOMEM;
fds = NULL;
if (nfds != 0) {
fds = (struct pollfd **)kmalloc(
@@ -429,7 +442,7 @@ asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
goto out_fds1;
}
- fdcount = do_poll(nfds, nchunks, nleft, fds, &table, timeout);
+ fdcount = do_poll(nfds, nchunks, nleft, fds, wait, timeout);
/* OK, now copy the revents fields back to user space. */
for(i=0; i < nchunks; i++)
@@ -452,6 +465,6 @@ out_fds:
if (nfds != 0)
kfree(fds);
out:
- free_wait(table.table);
+ poll_freewait(&table);
return err;
}