summaryrefslogtreecommitdiffstats
path: root/fs/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/select.c')
-rw-r--r--fs/select.c86
1 files changed, 37 insertions, 49 deletions
diff --git a/fs/select.c b/fs/select.c
index 7ab56a4b8..38742c84e 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -10,25 +10,12 @@
* parameter to reflect time remaining.
*/
-#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/personality.h>
-#include <linux/mm.h>
#include <linux/malloc.h>
-#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/file.h>
#include <asm/uaccess.h>
-#include <asm/system.h>
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
@@ -124,28 +111,25 @@ get_max:
#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
#define POLLEX_SET (POLLPRI)
-int do_select(int n, fd_set_buffer *fds, unsigned long timeout)
+int do_select(int n, fd_set_buffer *fds, long *timeout)
{
poll_table wait_table, *wait;
- int retval;
- int i;
-
- lock_kernel();
+ int retval, i;
+ long __timeout = *timeout;
wait = NULL;
- current->timeout = timeout;
- if (timeout) {
- struct poll_table_entry *entry = (struct poll_table_entry *)
- __get_free_page(GFP_KERNEL);
- if (!entry) {
- retval = -ENOMEM;
- goto out_nowait;
- }
+ if (__timeout) {
+ struct poll_table_entry *entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
wait_table.nr = 0;
wait_table.entry = entry;
wait = &wait_table;
}
+ lock_kernel();
+
retval = max_select_fd(n, fds);
if (retval < 0)
goto out;
@@ -190,18 +174,22 @@ int do_select(int n, fd_set_buffer *fds, unsigned long timeout)
}
}
wait = NULL;
- if (retval || !current->timeout || signal_pending(current))
+ if (retval || !__timeout || signal_pending(current))
break;
- schedule();
+ __timeout = schedule_timeout(__timeout);
}
current->state = TASK_RUNNING;
out:
- if (timeout) {
+ if (*timeout) {
free_wait(&wait_table);
free_page((unsigned long) wait_table.entry);
}
-out_nowait:
+
+ /*
+ * Up-to-date the caller timeout.
+ */
+ *timeout = __timeout;
unlock_kernel();
return retval;
}
@@ -214,14 +202,17 @@ out_nowait:
* Update: ERESTARTSYS breaks at least the xview clock binary, so
* I'm trying ERESTARTNOHAND which restart only when you want to.
*/
+#define MAX_SELECT_SECONDS \
+ ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+
asmlinkage int
sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{
fd_set_buffer *fds;
- unsigned long timeout;
+ long timeout;
int ret;
- timeout = ~0UL;
+ timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) {
time_t sec, usec;
@@ -230,10 +221,10 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
|| (ret = __get_user(usec, &tvp->tv_usec)))
goto out_nofds;
- timeout = ROUND_UP(usec, 1000000/HZ);
- timeout += sec * (unsigned long) HZ;
- if (timeout)
- timeout += jiffies + 1;
+ if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+ timeout = ROUND_UP(usec, 1000000/HZ);
+ timeout += sec * (unsigned long) HZ;
+ }
}
ret = -ENOMEM;
@@ -253,12 +244,11 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
zero_fd_set(n, fds->res_out);
zero_fd_set(n, fds->res_ex);
- ret = do_select(n, fds, timeout);
+ ret = do_select(n, fds, &timeout);
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
- unsigned long timeout = current->timeout - jiffies - 1;
time_t sec = 0, usec = 0;
- if ((long) timeout > 0) {
+ if (timeout) {
sec = timeout / HZ;
usec = timeout % HZ;
usec *= (1000000/HZ);
@@ -266,7 +256,6 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
put_user(sec, &tvp->tv_sec);
put_user(usec, &tvp->tv_usec);
}
- current->timeout = 0;
if (ret < 0)
goto out;
@@ -287,7 +276,8 @@ out_nofds:
return ret;
}
-static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
+static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait,
+ long timeout)
{
int count = 0;
@@ -321,15 +311,15 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
}
wait = NULL;
- if (count || !current->timeout || signal_pending(current))
+ if (count || !timeout || signal_pending(current))
break;
- schedule();
+ timeout = schedule_timeout(timeout);
}
current->state = TASK_RUNNING;
return count;
}
-asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
+asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
{
int i, fdcount, err, size;
struct pollfd * fds, *fds1;
@@ -342,9 +332,9 @@ asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
goto out;
if (timeout < 0)
- timeout = 0x7fffffff;
+ timeout = MAX_SCHEDULE_TIMEOUT;
else if (timeout)
- timeout = ((unsigned long)timeout*HZ+999)/1000+jiffies+1;
+ timeout = (timeout*HZ+999)/1000+1;
err = -ENOMEM;
if (timeout) {
@@ -366,9 +356,7 @@ asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
if (copy_from_user(fds, ufds, size))
goto out_fds;
- current->timeout = timeout;
- fdcount = do_poll(nfds, fds, wait);
- current->timeout = 0;
+ fdcount = do_poll(nfds, fds, wait, timeout);
/* OK, now copy the revents fields back to user space. */
fds1 = fds;