fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / um / os-Linux / sigio.c
index 0ecac56..b2e1fd8 100644 (file)
@@ -19,6 +19,7 @@
 #include "user_util.h"
 #include "sigio.h"
 #include "os.h"
+#include "um_malloc.h"
 
 /* Protected by sigio_lock(), also used by sigio_cleanup, which is an
  * exitcall.
@@ -43,17 +44,9 @@ struct pollfds {
 /* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
  * synchronizes with it.
  */
-static struct pollfds current_poll = {
-       .poll           = NULL,
-       .size           = 0,
-       .used           = 0
-};
-
-static struct pollfds next_poll = {
-       .poll           = NULL,
-       .size           = 0,
-       .used           = 0
-};
+static struct pollfds current_poll;
+static struct pollfds next_poll;
+static struct pollfds all_sigio_fds;
 
 static int write_sigio_thread(void *unused)
 {
@@ -78,7 +71,8 @@ static int write_sigio_thread(void *unused)
                                n = os_read_file(sigio_private[1], &c, sizeof(c));
                                if(n != sizeof(c))
                                        printk("write_sigio_thread : "
-                                              "read failed, err = %d\n", -n);
+                                              "read on socket failed, "
+                                              "err = %d\n", -n);
                                tmp = current_poll;
                                current_poll = next_poll;
                                next_poll = tmp;
@@ -93,35 +87,38 @@ static int write_sigio_thread(void *unused)
 
                        n = os_write_file(respond_fd, &c, sizeof(c));
                        if(n != sizeof(c))
-                               printk("write_sigio_thread : write failed, "
-                                      "err = %d\n", -n);
+                               printk("write_sigio_thread : write on socket "
+                                      "failed, err = %d\n", -n);
                }
        }
 
        return 0;
 }
 
-static int need_poll(int n)
+static int need_poll(struct pollfds *polls, int n)
 {
-       if(n <= next_poll.size){
-               next_poll.used = n;
-               return(0);
-       }
-       kfree(next_poll.poll);
-       next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd));
-       if(next_poll.poll == NULL){
+       struct pollfd *new;
+
+       if(n <= polls->size)
+               return 0;
+
+       new = um_kmalloc_atomic(n * sizeof(struct pollfd));
+       if(new == NULL){
                printk("need_poll : failed to allocate new pollfds\n");
-               next_poll.size = 0;
-               next_poll.used = 0;
-               return(-1);
+               return -ENOMEM;
        }
-       next_poll.size = n;
-       next_poll.used = n;
-       return(0);
+
+       memcpy(new, polls->poll, polls->used * sizeof(struct pollfd));
+       kfree(polls->poll);
+
+       polls->poll = new;
+       polls->size = n;
+       return 0;
 }
 
 /* Must be called with sigio_lock held, because it's needed by the marked
- * critical section. */
+ * critical section.
+ */
 static void update_thread(void)
 {
        unsigned long flags;
@@ -156,34 +153,39 @@ static void update_thread(void)
        set_signals(flags);
 }
 
-static int add_sigio_fd(int fd, int read)
+int add_sigio_fd(int fd)
 {
-       int err = 0, i, n, events;
+       struct pollfd *p;
+       int err = 0, i, n;
 
        sigio_lock();
+       for(i = 0; i < all_sigio_fds.used; i++){
+               if(all_sigio_fds.poll[i].fd == fd)
+                       break;
+       }
+       if(i == all_sigio_fds.used)
+               goto out;
+
+       p = &all_sigio_fds.poll[i];
+
        for(i = 0; i < current_poll.used; i++){
                if(current_poll.poll[i].fd == fd)
                        goto out;
        }
 
-       n = current_poll.used + 1;
-       err = need_poll(n);
+       n = current_poll.used;
+       err = need_poll(&next_poll, n + 1);
        if(err)
                goto out;
 
-       for(i = 0; i < current_poll.used; i++)
-               next_poll.poll[i] = current_poll.poll[i];
-
-       if(read) events = POLLIN;
-       else events = POLLOUT;
-
-       next_poll.poll[n - 1] = ((struct pollfd) { .fd          = fd,
-                                                  .events      = events,
-                                                  .revents     = 0 });
+       memcpy(next_poll.poll, current_poll.poll,
+              current_poll.used * sizeof(struct pollfd));
+       next_poll.poll[n] = *p;
+       next_poll.used = n + 1;
        update_thread();
  out:
        sigio_unlock();
-       return(err);
+       return err;
 }
 
 int ignore_sigio_fd(int fd)
@@ -205,19 +207,16 @@ int ignore_sigio_fd(int fd)
        if(i == current_poll.used)
                goto out;
 
-       err = need_poll(current_poll.used - 1);
+       err = need_poll(&next_poll, current_poll.used - 1);
        if(err)
                goto out;
 
        for(i = 0; i < current_poll.used; i++){
                p = &current_poll.poll[i];
-               if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i];
-       }
-       if(n == i){
-               printk("ignore_sigio_fd : fd %d not found\n", fd);
-               err = -1;
-               goto out;
+               if(p->fd != fd)
+                       next_poll.poll[n++] = *p;
        }
+       next_poll.used = current_poll.used - 1;
 
        update_thread();
  out:
@@ -234,7 +233,7 @@ static struct pollfd *setup_initial_poll(int fd)
                printk("setup_initial_poll : failed to allocate poll\n");
                return NULL;
        }
-       *p = ((struct pollfd) { .fd     = fd,
+       *p = ((struct pollfd) { .fd             = fd,
                                .events         = POLLIN,
                                .revents        = 0 });
        return p;
@@ -323,6 +322,8 @@ out_close1:
 
 void maybe_sigio_broken(int fd, int read)
 {
+       int err;
+
        if(!isatty(fd))
                return;
 
@@ -330,7 +331,18 @@ void maybe_sigio_broken(int fd, int read)
                return;
 
        write_sigio_workaround();
-       add_sigio_fd(fd, read);
+
+       sigio_lock();
+       err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1);
+       if(err)
+               goto out;
+
+       all_sigio_fds.poll[all_sigio_fds.used++] =
+               ((struct pollfd) { .fd          = fd,
+                                  .events      = read ? POLLIN : POLLOUT,
+                                  .revents     = 0 });
+out:
+       sigio_unlock();
 }
 
 static void sigio_cleanup(void)