Manfred Spraul wrote:
>
>
> Perhaps we should really allocate twice the number of fds?
>
I found a better fix:
the old code had 2 problems:
* it called kmalloc() with current->state != TASK_RUNNING, but if
kmalloc() changes current->state to TASK_RUNNING, then there won't be a
real problem, just a slow-down.
* there was no OOM handling.
I've attached an _untested_ patch for 2.3:
* kmalloc() if we run out of table space. I also set current->state to
TASK_RUNNING, I don't know if this is required.
* add an error field to the poll table. poll_wait() has no return value,
and I won't change all callers.
// $Header$
// Kernel Version:
// VERSION = 2
// PATCHLEVEL = 3
// SUBLEVEL = 99
// EXTRAVERSION = -pre5
--- 2.3/fs/select.c Thu Feb 10 22:39:09 2000
+++ build-2.3/fs/select.c Sun Apr 16 20:06:58 2000
@@ -67,6 +67,7 @@
return NULL;
}
tmp->nr = 0;
+ tmp->err = 0;
tmp->entry = (struct poll_table_entry *)(tmp + 1);
tmp->next = NULL;
walk->next = tmp;
@@ -100,6 +101,7 @@
for (;;) {
if (p->nr < __MAX_POLL_TABLE_ENTRIES) {
struct poll_table_entry * entry;
+ok_table:
entry = p->entry + p->nr;
get_file(filp);
entry->filp = filp;
@@ -109,6 +111,22 @@
p->nr++;
return;
}
+ if (p->next == NULL) {
+ poll_table *tmp;
+ current->state=TASK_RUNNING;
+ tmp = (poll_table *) __get_free_page(GFP_KERNEL);
+ if (!tmp) {
+ p->err=-ENOMEM;
+ return;
+ }
+ tmp->nr = 0;
+ tmp->err = 0;
+ tmp->entry = (struct poll_table_entry *)(tmp + 1);
+ tmp->next = NULL;
+ p->next = tmp;
+ p = tmp;
+ goto ok_table;
+ }
p = p->next;
}
}
@@ -228,11 +246,19 @@
}
}
unlock_kernel();
- wait = NULL;
if (retval || !__timeout || signal_pending(current))
break;
+ wait=orig_wait;
+ while(wait!=NULL) {
+ if(wait->err) {
+ retval=wait->err;
+ goto out;
+ }
+ wait=wait->next;
+ }
__timeout = schedule_timeout(__timeout);
}
+out:
current->state = TASK_RUNNING;
free_wait(orig_wait);
@@ -384,6 +410,7 @@
struct pollfd *fds[], poll_table *wait, long timeout)
{
int count = 0;
+ poll_table* orig_wait = wait;
for (;;) {
unsigned int i;
@@ -393,11 +420,19 @@
do_pollfd(POLLFD_PER_PAGE, fds[i], &wait, &count);
if (nleft)
do_pollfd(nleft, fds[nchunks], &wait, &count);
- wait = NULL;
if (count || !timeout || signal_pending(current))
break;
+ wait=orig_wait;
+ while(wait!=NULL) {
+ if(wait->err) {
+ count=wait->err;
+ goto out;
+ }
+ wait=wait->next;
+ }
timeout = schedule_timeout(timeout);
}
+out:
current->state = TASK_RUNNING;
return count;
}
--- 2.3/include/linux/poll.h Tue Jun 1 16:29:17 1999
+++ build-2.3/include/linux/poll.h Sun Apr 16 20:02:52 2000
@@ -20,6 +20,7 @@
typedef struct poll_table_struct {
struct poll_table_struct * next;
unsigned int nr;
+ int err;
struct poll_table_entry * entry;
} poll_table;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Sun Apr 23 2000 - 21:00:09 EST