select(2) patch.

Richard Gooch (rgooch@atnf.CSIRO.AU)
Tue, 26 Aug 1997 20:06:42 +1000


Hi, Linus. Below is a patch that does the same thing as the poll(2)
patch I sent a few days ago: it prevents wait queue manipulation if
the timeout is 0. This takes the execution time for select from around
4 milliseconds to 2 milliseconds (Pentium 100, 1000 fds).
The patch is against 2.1.51 + pre-patch-2.1.52-2. I'm running a few
machines with this patch now, without any problems.

Regards,

Richard....

--- linux/fs/select.c-orig Tue Aug 26 17:23:52 1997
+++ linux/fs/select.c Tue Aug 26 19:15:13 1997
@@ -141,25 +141,16 @@
#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
#define POLLEX_SET (POLLPRI)

-static int do_select(int n, fd_set_buffer *fds)
+static int do_select(int n, fd_set_buffer *fds, poll_table *wait)
{
int retval;
- poll_table wait_table, *wait;
- struct poll_table_entry *entry;
int i;

retval = max_select_fd(n, fds);
if (retval < 0)
goto out;
n = retval;
- retval = -ENOMEM;
- entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
- if (!entry)
- goto out;
retval = 0;
- wait_table.nr = 0;
- wait_table.entry = entry;
- wait = &wait_table;
for (;;) {
struct file ** fd = current->files->fd;
current->state = TASK_INTERRUPTIBLE;
@@ -197,8 +188,6 @@
break;
schedule();
}
- free_wait(&wait_table);
- free_page((unsigned long) entry);
current->state = TASK_RUNNING;
out:
return retval;
@@ -286,14 +275,22 @@
*/
asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
{
- int error = -EINVAL;
- fd_set_buffer *fds;
+ int error = -ENOMEM;
+ fd_set_buffer *fds = NULL;
unsigned long timeout;
+ poll_table wait_table;
+ struct poll_table_entry *entry = NULL;

lock_kernel();
+ entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL);
+ if (!entry)
+ goto out;
+ wait_table.nr = 0;
+ wait_table.entry = entry;
fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL);
if (!fds)
goto out;
+ error = -EINVAL;
if (n < 0)
goto out;
if (n > KFDS_NR)
@@ -320,9 +317,10 @@
zero_fd_set(n, &fds->res_out);
zero_fd_set(n, &fds->res_ex);
current->timeout = timeout;
- error = do_select(n, fds);
+ error = do_select(n, fds, timeout ? &wait_table : NULL);
timeout = current->timeout - jiffies - 1;
current->timeout = 0;
+ free_wait(&wait_table);
if ((long) timeout < 0)
timeout = 0;
if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
@@ -343,7 +341,10 @@
set_fd_set(n, outp, &fds->res_out);
set_fd_set(n, exp, &fds->res_ex);
out:
- free_page((unsigned long) fds);
+ if (entry)
+ free_page((unsigned long) entry);
+ if (fds)
+ free_page((unsigned long) fds);
unlock_kernel();
return error;
}