Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.24 /fs/select.c

Filename:/fs/select.c
Lines Added:71
Lines Deleted:67
Also changed in: (Previous) 2.6.24-rc8  2.6.24-rc7  2.6.24-rc6  2.6.24-rc5  2.6.24-rc4  2.6.24-rc3 
(Following) 2.6.24-git16  2.6.24-git17  2.6.24-git18  2.6.24-git19  2.6.24-git20  2.6.24-git21 

Location
[  2.6.24
  [  fs
     o  select.c

Patch

diff --git a/fs/select.c b/fs/select.c
index 46dca31..47f4792 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -177,11 +177,6 @@ get_max:
    return max;
 }
 
-#define BIT(i)      (1UL << ((i)&(__NFDBITS-1)))
-#define MEM(i,m)   ((m)+(unsigned)(i)/__NFDBITS)
-#define ISSET(i,m)   (((i)&*(m)) != 0)
-#define SET(i,m)   (*(m) |= (i))
-
 #define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR)
 #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
 #define POLLEX_SET (POLLPRI)
@@ -586,7 +581,7 @@ static int do_poll(unsigned int nfds,  struct poll_list *list,
    /* Optimise the no-wait case */
    if (!(*timeout))
       pt = NULL;
- 
+
    for (;;) {
       struct poll_list *walk;
       long __timeout;
@@ -616,10 +611,12 @@ static int do_poll(unsigned int nfds,  struct poll_list *list,
        * a poll_table to them on the next loop iteration.
        */
       pt = NULL;
-      if (count || !*timeout || signal_pending(current))
-         break;
-      count = wait->error;
-      if (count)
+      if (!count) {
+         count = wait->error;
+         if (signal_pending(current))
+            count = -EINTR;
+      }
+      if (count || !*timeout)
          break;
 
       if (*timeout < 0) {
@@ -651,93 +648,89 @@ static int do_poll(unsigned int nfds,  struct poll_list *list,
 int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
 {
    struct poll_wqueues table;
-    int fdcount, err;
-    unsigned int i;
-   struct poll_list *head;
-    struct poll_list *walk;
+    int err = -EFAULT, fdcount, len, size;
    /* Allocate small arguments on the stack to save memory and be
       faster - use long to make sure the buffer is aligned properly
       on 64 bit archs to avoid unaligned access */
    long stack_pps[POLL_STACK_ALLOC/sizeof(long)];
-   struct poll_list *stack_pp = NULL;
+   struct poll_list *const head = (struct poll_list *)stack_pps;
+    struct poll_list *walk = head;
+    unsigned long todo = nfds;
 
-   /* Do a sanity check on nfds ... */
    if (nfds > current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
       return -EINVAL;
 
-   poll_initwait(&table);
+   len = min_t(unsigned int, nfds, N_STACK_PPS);
+   for (;;) {
+      walk->next = NULL;
+      walk->len = len;
+      if (!len)
+         break;
 
-   head = NULL;
-   walk = NULL;
-   i = nfds;
-   err = -ENOMEM;
-   while(i!=0) {
-      struct poll_list *pp;
-      int num, size;
-      if (stack_pp == NULL)
-         num = N_STACK_PPS;
-      else
-         num = POLLFD_PER_PAGE;
-      if (num > i)
-         num = i;
-      size = sizeof(struct poll_list) + sizeof(struct pollfd)*num;
-      if (!stack_pp)
-         stack_pp = pp = (struct poll_list *)stack_pps;
-      else {
-         pp = kmalloc(size, GFP_KERNEL);
-         if (!pp)
-            goto out_fds;
-      }
-      pp->next=NULL;
-      pp->len = num;
-      if (head == NULL)
-         head = pp;
-      else
-         walk->next = pp;
+      if (copy_from_user(walk->entries, ufds + nfds-todo,
+               sizeof(struct pollfd) * walk->len))
+         goto out_fds;
 
-      walk = pp;
-      if (copy_from_user(pp->entries, ufds + nfds-i, 
-            sizeof(struct pollfd)*num)) {
-         err = -EFAULT;
+      todo -= walk->len;
+      if (!todo)
+         break;
+
+      len = min(todo, POLLFD_PER_PAGE);
+      size = sizeof(struct poll_list) + sizeof(struct pollfd) * len;
+      walk = walk->next = kmalloc(size, GFP_KERNEL);
+      if (!walk) {
+         err = -ENOMEM;
          goto out_fds;
       }
-      i -= pp->len;
    }
 
+   poll_initwait(&table);
    fdcount = do_poll(nfds, head, &table, timeout);
+   poll_freewait(&table);
 
-   /* OK, now copy the revents fields back to user space. */
-   walk = head;
-   err = -EFAULT;
-   while(walk != NULL) {
+   for (walk = head; walk; walk = walk->next) {
       struct pollfd *fds = walk->entries;
       int j;
 
-      for (j=0; j < walk->len; j++, ufds++) {
-         if(__put_user(fds[j].revents, &ufds->revents))
+      for (j = 0; j < walk->len; j++, ufds++)
+         if (__put_user(fds[j].revents, &ufds->revents))
             goto out_fds;
-      }
-      walk = walk->next;
      }
+
    err = fdcount;
-   if (!fdcount && signal_pending(current))
-      err = -EINTR;
 out_fds:
-   walk = head;
-   while(walk!=NULL) {
-      struct poll_list *pp = walk->next;
-      if (walk != stack_pp)
-         kfree(walk);
-      walk = pp;
+   walk = head->next;
+   while (walk) {
+      struct poll_list *pos = walk;
+      walk = walk->next;
+      kfree(pos);
    }
-   poll_freewait(&table);
+
    return err;
 }
 
+static long do_restart_poll(struct restart_block *restart_block)
+{
+   struct pollfd __user *ufds = (struct pollfd __user*)restart_block->arg0;
+   int nfds = restart_block->arg1;
+   s64 timeout = ((s64)restart_block->arg3<<32) | (s64)restart_block->arg2;
+   int ret;
+
+   ret = do_sys_poll(ufds, nfds, &timeout);
+   if (ret == -EINTR) {
+      restart_block->fn = do_restart_poll;
+      restart_block->arg2 = timeout & 0xFFFFFFFF;
+      restart_block->arg3 = (u64)timeout >> 32;
+      ret = -ERESTART_RESTARTBLOCK;
+   }
+   return ret;
+}
+
 asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
          long timeout_msecs)
 {
    s64 timeout_jiffies;
+   int ret;
 
    if (timeout_msecs > 0) {
 #if HZ > 1000
@@ -752,7 +745,18 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds,
       timeout_jiffies = timeout_msecs;
    }
 
-   return do_sys_poll(ufds, nfds, &timeout_jiffies);
+   ret = do_sys_poll(ufds, nfds, &timeout_jiffies);
+   if (ret == -EINTR) {
+      struct restart_block *restart_block;
+      restart_block = ¤t_thread_info()->restart_block;
+      restart_block->fn = do_restart_poll;
+      restart_block->arg0 = (unsigned long)ufds;
+      restart_block->arg1 = nfds;
+      restart_block->arg2 = timeout_jiffies & 0xFFFFFFFF;
+      restart_block->arg3 = (u64)timeout_jiffies >> 32;
+      ret = -ERESTART_RESTARTBLOCK;
+   }
+   return ret;
 }
 
 #ifdef TIF_RESTORE_SIGMASK


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.