Re: [PATCH] fix __pollwait()

From: Manfred Spraul (manfreds@colorfullife.com)
Date: Sun Apr 16 2000 - 13:15:25 EST


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