patch-2.4.0-test4 linux/fs/select.c
Next file: linux/fs/smbfs/file.c
Previous file: linux/fs/pipe.c
Back to the patch index
Back to the overall index
- Lines: 220
- Date:
Wed Jul 12 12:41:07 2000
- Orig file:
v2.4.0-test3/linux/fs/select.c
- Orig date:
Wed Apr 26 16:34:09 2000
diff -u --recursive --new-file v2.4.0-test3/linux/fs/select.c linux/fs/select.c
@@ -31,57 +31,19 @@
* 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.
*/
-/*
- * I rewrote this again to make the poll_table size variable, take some
- * more shortcuts, improve responsiveness, and remove another race that
- * Linus noticed. -- jrs
- */
-
-static poll_table* alloc_wait(int nfds)
-{
- poll_table* out;
- poll_table* walk;
-
- out = (poll_table *) __get_free_page(GFP_KERNEL);
- if(out==NULL)
- return NULL;
- out->nr = 0;
- out->entry = (struct poll_table_entry *)(out + 1);
- out->next = NULL;
- nfds -=__MAX_POLL_TABLE_ENTRIES;
- walk = out;
- while(nfds > 0) {
- poll_table *tmp = (poll_table *) __get_free_page(GFP_KERNEL);
- if (!tmp) {
- while(out != NULL) {
- tmp = out->next;
- free_page((unsigned long)out);
- out = tmp;
- }
- return NULL;
- }
- tmp->nr = 0;
- tmp->entry = (struct poll_table_entry *)(tmp + 1);
- tmp->next = NULL;
- walk->next = tmp;
- walk = tmp;
- nfds -=__MAX_POLL_TABLE_ENTRIES;
- }
- return out;
-}
-
-static void free_wait(poll_table * p)
+void poll_freewait(poll_table* pt)
{
- struct poll_table_entry * entry;
- poll_table *old;
-
+ struct poll_table_page * p = pt->table;
while (p) {
+ struct poll_table_entry * entry;
+ struct poll_table_page *old;
+
entry = p->entry + p->nr;
while (p->nr > 0) {
p->nr--;
@@ -97,19 +59,34 @@
void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
{
- for (;;) {
- if (p->nr < __MAX_POLL_TABLE_ENTRIES) {
- struct poll_table_entry * entry;
- entry = p->entry + p->nr;
- get_file(filp);
- entry->filp = filp;
- entry->wait_address = wait_address;
- init_waitqueue_entry(&entry->wait, current);
- add_wait_queue(wait_address,&entry->wait);
- p->nr++;
+ struct poll_table_page *table = p->table;
+
+ if (!table || table->nr >= __MAX_POLL_TABLE_ENTRIES) {
+ struct poll_table_page *new_table;
+
+ new_table = (struct poll_table_page *) __get_free_page(GFP_KERNEL);
+ if (!new_table) {
+ p->error = -ENOMEM;
+ __set_current_state(TASK_RUNNING);
return;
}
- p = p->next;
+ new_table->nr = 0;
+ new_table->entry = (struct poll_table_entry *)(new_table + 1);
+ new_table->next = table;
+ p->table = new_table;
+ table = new_table;
+ }
+
+ /* Add a new entry */
+ {
+ struct poll_table_entry * entry;
+ entry = table->entry + table->nr;
+ table->nr++;
+ get_file(filp);
+ entry->filp = filp;
+ entry->wait_address = wait_address;
+ init_waitqueue_entry(&entry->wait, current);
+ add_wait_queue(wait_address,&entry->wait);
}
}
@@ -173,12 +150,10 @@
int do_select(int n, fd_set_bits *fds, long *timeout)
{
- poll_table *wait, *orig_wait;
+ poll_table table, *wait;
int retval, i, off;
long __timeout = *timeout;
- orig_wait = wait = NULL;
-
read_lock(¤t->files->file_lock);
retval = max_select_fd(n, fds);
read_unlock(¤t->files->file_lock);
@@ -186,11 +161,11 @@
if (retval < 0)
return retval;
n = retval;
- if (__timeout) {
- orig_wait = wait = alloc_wait(n);
- if (!wait)
- return -ENOMEM;
- }
+
+ poll_initwait(&table);
+ wait = &table;
+ if (!__timeout)
+ wait = NULL;
retval = 0;
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
@@ -229,11 +204,15 @@
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(orig_wait);
+ poll_freewait(&table);
/*
* Up-to-date the caller timeout.
@@ -382,18 +361,22 @@
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;
@@ -404,7 +387,7 @@
{
int i, j, fdcount, err;
struct pollfd **fds;
- poll_table *wait = NULL;
+ poll_table table, *wait;
int nchunks, nleft;
/* Do a sanity check on nfds ... */
@@ -419,13 +402,12 @@
timeout = MAX_SCHEDULE_TIMEOUT;
}
- if (timeout) {
- wait = alloc_wait(nfds);
- if (!wait)
- return -ENOMEM;
- }
- err = -ENOMEM;
+ poll_initwait(&table);
+ wait = &table;
+ if (!timeout)
+ wait = NULL;
+ err = -ENOMEM;
fds = NULL;
if (nfds != 0) {
fds = (struct pollfd **)kmalloc(
@@ -483,6 +465,6 @@
if (nfds != 0)
kfree(fds);
out:
- free_wait(wait);
+ poll_freewait(&table);
return err;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)