Signed-off-by: Gregory Haskins <[EMAIL PROTECTED]>
---

 drivers/kvm/kvm.h      |    2 +
 drivers/kvm/kvm_main.c |   82 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 0f6cc32..b5bfc91 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -331,6 +331,8 @@ struct kvm_vcpu_irq {
        int                  deferred;
        struct task_struct  *task;
        int                  guest_mode;
+       wait_queue_head_t    wq;
+       int                  usignal;
 };
 
 struct kvm_vcpu {
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index a160638..6b40c18 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -40,6 +40,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
+#include <linux/poll.h>
 
 #include "x86_emulate.h"
 #include "segment_descriptor.h"
@@ -304,6 +305,7 @@ static struct kvm *kvm_create_vm(void)
                memset(&vcpu->irq, 0, sizeof(vcpu->irq));
                spin_lock_init(&vcpu->irq.lock);
                vcpu->irq.deferred = -1;
+               init_waitqueue_head(&vcpu->irq.wq);
 
                vcpu->cpu = -1;
                vcpu->kvm = kvm;
@@ -2265,11 +2267,78 @@ static int kvm_vcpu_release(struct inode *inode, struct 
file *filp)
        return 0;
 }
 
+static unsigned int kvm_vcpu_poll(struct file *filp, poll_table *wait)
+{
+       struct kvm_vcpu *vcpu = filp->private_data;
+       unsigned int events = 0;
+       unsigned long flags;
+
+       poll_wait(filp, &vcpu->irq.wq, wait);
+
+       spin_lock_irqsave(&vcpu->irq.lock, flags);
+       if (vcpu->irq.usignal)
+               events |= POLLIN;
+       spin_unlock_irqrestore(&vcpu->irq.lock, flags);
+
+       return events;
+}
+
+static ssize_t kvm_vcpu_read(struct file *filp, char __user *buf, size_t count,
+                            loff_t *ppos)
+{
+       struct kvm_vcpu *vcpu = filp->private_data;
+       ssize_t res = -EAGAIN;
+       DECLARE_WAITQUEUE(wait, current);
+       unsigned long flags;
+       int val;
+
+       if (count < sizeof(vcpu->irq.usignal))
+               return -EINVAL;
+
+       spin_lock_irqsave(&vcpu->irq.lock, flags);
+
+       val = vcpu->irq.usignal;
+
+       if (val > 0)
+               res = sizeof(val);
+       else if (!(filp->f_flags & O_NONBLOCK)) {
+               __add_wait_queue(&vcpu->irq.wq, &wait);
+               for (res = 0;;) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (val > 0) {
+                               res = sizeof(val);
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               res = -ERESTARTSYS;
+                               break;
+                       }
+                       spin_unlock_irqrestore(&vcpu->irq.lock, flags);
+                       schedule();
+                       spin_lock_irqsave(&vcpu->irq.lock, flags);
+               }
+               __remove_wait_queue(&vcpu->irq.wq, &wait);
+               __set_current_state(TASK_RUNNING);
+       }
+
+       if (res > 0)
+               vcpu->irq.usignal = 0;
+
+       spin_unlock_irqrestore(&vcpu->irq.lock, flags);
+
+       if (res > 0 && put_user(val, (int __user *) buf))
+               return -EFAULT;
+
+       return res;
+}
+
 static struct file_operations kvm_vcpu_fops = {
        .release        = kvm_vcpu_release,
        .unlocked_ioctl = kvm_vcpu_ioctl,
        .compat_ioctl   = kvm_vcpu_ioctl,
        .mmap           = kvm_vcpu_mmap,
+       .poll           = kvm_vcpu_poll,
+       .read           = kvm_vcpu_read,
 };
 
 /*
@@ -2336,6 +2405,7 @@ static void kvm_vcpu_intr(struct kvm_irqsink *this,
        struct kvm_vcpu *vcpu = (struct kvm_vcpu*)this->private;
        unsigned long flags;
        int direct_ipi = -1;
+       int indirect_sig = 0;
 
        spin_lock_irqsave(&vcpu->irq.lock, flags);
 
@@ -2357,6 +2427,15 @@ static void kvm_vcpu_intr(struct kvm_irqsink *this,
                                 */
                                direct_ipi = task_cpu(vcpu->irq.task);
                                BUG_ON(direct_ipi == smp_processor_id());
+                       } else {
+                               /*
+                                * otherwise, we must assume that we could be
+                                * blocked anywhere, including userspace. Send
+                                * a signal to give everyone a chance to get
+                                * notification
+                                */
+                               vcpu->irq.usignal++;
+                               indirect_sig = 1;
                        }
                }
        }
@@ -2379,6 +2458,9 @@ static void kvm_vcpu_intr(struct kvm_irqsink *this,
                smp_call_function_single(direct_ipi,
                                         kvm_vcpu_guest_intr,
                                         vcpu, 0, 0);
+
+       if (indirect_sig && waitqueue_active(&vcpu->irq.wq))
+               wake_up(&vcpu->irq.wq);
 }
 
 static void kvm_vcpu_irqsink_init(struct kvm_vcpu *vcpu)


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to