This commit was generated by cvs2svn to compensate for changes in r1129,
[linux-2.6.git] / arch / um / kernel / irq_user.c
index 57fe9bb..0e32f5f 100644 (file)
@@ -6,7 +6,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <signal.h>
 #include <string.h>
 #include <sys/poll.h>
@@ -16,7 +15,6 @@
 #include "kern_util.h"
 #include "user.h"
 #include "process.h"
-#include "signal_user.h"
 #include "sigio.h"
 #include "irq_user.h"
 #include "os.h"
@@ -30,7 +28,6 @@ struct irq_fd {
        int pid;
        int events;
        int current_events;
-       int freed;
 };
 
 static struct irq_fd *active_fds = NULL;
@@ -42,14 +39,17 @@ static int pollfds_size = 0;
 
 extern int io_count, intr_count;
 
+extern void free_irqs(void);
+
 void sigio_handler(int sig, union uml_pt_regs *regs)
 {
-       struct irq_fd *irq_fd, *next;
+       struct irq_fd *irq_fd;
        int i, n;
 
        if(smp_sigio_handler()) return;
        while(1){
-               if((n = poll(pollfds, pollfds_num, 0)) < 0){
+               n = poll(pollfds, pollfds_num, 0);
+               if(n < 0){
                        if(errno == EINTR) continue;
                        printk("sigio_handler : poll returned %d, "
                               "errno = %d\n", n, errno);
@@ -66,28 +66,15 @@ void sigio_handler(int sig, union uml_pt_regs *regs)
                        irq_fd = irq_fd->next;
                }
 
-               for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){
-                       next = irq_fd->next;
+               for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
                        if(irq_fd->current_events != 0){
                                irq_fd->current_events = 0;
                                do_IRQ(irq_fd->irq, regs);
-
-                               /* This is here because the next irq may be
-                                * freed in the handler.  If a console goes
-                                * away, both the read and write irqs will be
-                                * freed.  After do_IRQ, ->next will point to
-                                * a good IRQ.
-                                * Irqs can't be freed inside their handlers,
-                                * so the next best thing is to have them
-                                * marked as needing freeing, so that they
-                                * can be freed here.
-                                */
-                               next = irq_fd->next;
-                               if(irq_fd->freed)
-                                       free_irq(irq_fd->irq, irq_fd->id);
                        }
                }
        }
+
+       free_irqs();
 }
 
 int activate_ipi(int fd, int pid)
@@ -135,8 +122,7 @@ int activate_fd(int irq, int fd, int type, void *dev_id)
                                     .irq               = irq,
                                     .pid               = pid,
                                     .events            = events,
-                                    .current_events    = 0,
-                                    .freed             = 0  } );
+                                    .current_events    = 0 } );
 
        /* Critical section - locked by a spinlock because this stuff can
         * be changed from interrupt handlers.  The stuff above is done 
@@ -233,9 +219,15 @@ static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
                                       (*prev)->fd, pollfds[i].fd);
                                goto out;
                        }
-                       memcpy(&pollfds[i], &pollfds[i + 1],
-                              (pollfds_num - i - 1) * sizeof(pollfds[0]));
+
                        pollfds_num--;
+
+                       /* This moves the *whole* array after pollfds[i] (though
+                        * it doesn't spot as such)! */
+
+                       memmove(&pollfds[i], &pollfds[i + 1],
+                              (pollfds_num - i) * sizeof(pollfds[0]));
+
                        if(last_irq_ptr == &old_fd->next) 
                                last_irq_ptr = prev;
                        *prev = (*prev)->next;
@@ -263,7 +255,7 @@ static int same_irq_and_dev(struct irq_fd *irq, void *d)
        return((irq->irq == data->irq) && (irq->id == data->dev));
 }
 
-void free_irq_by_irq_and_dev(int irq, void *dev)
+void free_irq_by_irq_and_dev(unsigned int irq, void *dev)
 {
        struct irq_and_dev data = ((struct irq_and_dev) { .irq  = irq,
                                                          .dev  = dev });
@@ -306,26 +298,6 @@ static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
        return(irq);
 }
 
-void free_irq_later(int irq, void *dev_id)
-{
-       struct irq_fd *irq_fd;
-       unsigned long flags;
-
-       flags = irq_lock();
-       for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
-               if((irq_fd->irq == irq) && (irq_fd->id == dev_id))
-                       break;
-       }
-       if(irq_fd == NULL){
-               printk("free_irq_later found no irq, irq = %d, "
-                      "dev_id = 0x%p\n", irq, dev_id);
-               goto out;
-       }
-       irq_fd->freed = 1;
- out:
-       irq_unlock(flags);
-}
-
 void reactivate_fd(int fd, int irqnum)
 {
        struct irq_fd *irq;
@@ -364,36 +336,49 @@ void deactivate_fd(int fd, int irqnum)
        irq_unlock(flags);
 }
 
-void forward_ipi(int fd, int pid)
+int deactivate_all_fds(void)
 {
-       if(fcntl(fd, F_SETOWN, pid) < 0){
-               int save_errno = errno;
-               if(fcntl(fd, F_GETOWN, 0) != pid){
-                       printk("forward_ipi: F_SETOWN failed, fd = %d, "
-                              "me = %d, target = %d, errno = %d\n", fd, 
-                              os_getpid(), pid, save_errno);
-               }
+       struct irq_fd *irq;
+       int err;
+
+       for(irq=active_fds;irq != NULL;irq = irq->next){
+               err = os_clear_fd_async(irq->fd);
+               if(err)
+                       return(err);
        }
+       /* If there is a signal already queued, after unblocking ignore it */
+       set_handler(SIGIO, SIG_IGN, 0, -1);
+
+       return(0);
+}
+
+void forward_ipi(int fd, int pid)
+{
+       int err;
+
+       err = os_set_owner(fd, pid);
+       if(err < 0)
+               printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
+                      "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
 }
 
 void forward_interrupts(int pid)
 {
        struct irq_fd *irq;
        unsigned long flags;
+       int err;
 
        flags = irq_lock();
        for(irq=active_fds;irq != NULL;irq = irq->next){
-               if(fcntl(irq->fd, F_SETOWN, pid) < 0){
-                       int save_errno = errno;
-                       if(fcntl(irq->fd, F_GETOWN, 0) != pid){
-                               /* XXX Just remove the irq rather than
-                                * print out an infinite stream of these
-                                */
-                               printk("Failed to forward %d to pid %d, "
-                                      "errno = %d\n", irq->fd, pid, 
-                                      save_errno);
-                       }
+               err = os_set_owner(irq->fd, pid);
+               if(err < 0){
+                       /* XXX Just remove the irq rather than
+                        * print out an infinite stream of these
+                        */
+                       printk("Failed to forward %d to pid %d, err = %d\n",
+                              irq->fd, pid, -err);
                }
+
                irq->pid = pid;
        }
        irq_unlock(flags);