[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Wait queues, allowing conditional sleep in hypervisor context.



# HG changeset patch
# User Keir Fraser <keir@xxxxxxx>
# Date 1290012157 0
# Node ID c1b7aae86cf51c7a80925d050a3b7b3ef08e7cc2
# Parent  deb438d43e79943643914f708b37354dc53f79f4
Wait queues, allowing conditional sleep in hypervisor context.

Signed-off-by: Keir Fraser <keir@xxxxxxx>
---
 xen/arch/x86/domain.c   |    2 
 xen/arch/x86/hvm/hvm.c  |    3 
 xen/common/Makefile     |    1 
 xen/common/domain.c     |    5 +
 xen/common/schedule.c   |    5 +
 xen/common/wait.c       |  165 ++++++++++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/sched.h |    4 +
 xen/include/xen/wait.h  |   54 +++++++++++++++
 8 files changed, 239 insertions(+)

diff -r deb438d43e79 -r c1b7aae86cf5 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Tue Nov 16 15:41:28 2010 +0000
+++ b/xen/arch/x86/domain.c     Wed Nov 17 16:42:37 2010 +0000
@@ -33,6 +33,7 @@
 #include <xen/pci.h>
 #include <xen/paging.h>
 #include <xen/cpu.h>
+#include <xen/wait.h>
 #include <public/sysctl.h>
 #include <asm/regs.h>
 #include <asm/mc146818rtc.h>
@@ -77,6 +78,7 @@ static void continue_idle_domain(struct 
 
 static void continue_nonidle_domain(struct vcpu *v)
 {
+    check_wakeup_from_wait();
     reset_stack_and_jump(ret_from_intr);
 }
 
diff -r deb438d43e79 -r c1b7aae86cf5 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Tue Nov 16 15:41:28 2010 +0000
+++ b/xen/arch/x86/hvm/hvm.c    Wed Nov 17 16:42:37 2010 +0000
@@ -34,6 +34,7 @@
 #include <xen/event.h>
 #include <xen/paging.h>
 #include <xen/cpu.h>
+#include <xen/wait.h>
 #include <asm/shadow.h>
 #include <asm/hap.h>
 #include <asm/current.h>
@@ -282,6 +283,8 @@ void hvm_do_resume(struct vcpu *v)
     ioreq_t *p;
 
     pt_restore_timer(v);
+
+    check_wakeup_from_wait();
 
     /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
     p = get_ioreq(v);
diff -r deb438d43e79 -r c1b7aae86cf5 xen/common/Makefile
--- a/xen/common/Makefile       Tue Nov 16 15:41:28 2010 +0000
+++ b/xen/common/Makefile       Wed Nov 17 16:42:37 2010 +0000
@@ -31,6 +31,7 @@ obj-y += trace.o
 obj-y += trace.o
 obj-y += version.o
 obj-y += vsprintf.o
+obj-y += wait.o
 obj-y += xmalloc_tlsf.o
 obj-y += rcupdate.o
 obj-y += tmem.o
diff -r deb438d43e79 -r c1b7aae86cf5 xen/common/domain.c
--- a/xen/common/domain.c       Tue Nov 16 15:41:28 2010 +0000
+++ b/xen/common/domain.c       Wed Nov 17 16:42:37 2010 +0000
@@ -27,6 +27,7 @@
 #include <xen/percpu.h>
 #include <xen/multicall.h>
 #include <xen/rcupdate.h>
+#include <xen/wait.h>
 #include <acpi/cpufreq/cpufreq.h>
 #include <asm/debugger.h>
 #include <public/sched.h>
@@ -162,10 +163,12 @@ struct vcpu *alloc_vcpu(
         v->vcpu_info = ((vcpu_id < XEN_LEGACY_MAX_VCPUS)
                         ? (vcpu_info_t *)&shared_info(d, vcpu_info[vcpu_id])
                         : &dummy_vcpu_info);
+        init_waitqueue_vcpu(v);
     }
 
     if ( sched_init_vcpu(v, cpu_id) != 0 )
     {
+        destroy_waitqueue_vcpu(v);
         free_vcpu_struct(v);
         return NULL;
     }
@@ -173,6 +176,7 @@ struct vcpu *alloc_vcpu(
     if ( vcpu_initialise(v) != 0 )
     {
         sched_destroy_vcpu(v);
+        destroy_waitqueue_vcpu(v);
         free_vcpu_struct(v);
         return NULL;
     }
@@ -617,6 +621,7 @@ static void complete_domain_destroy(stru
         tasklet_kill(&v->continue_hypercall_tasklet);
         vcpu_destroy(v);
         sched_destroy_vcpu(v);
+        destroy_waitqueue_vcpu(v);
     }
 
     grant_table_destroy(d);
diff -r deb438d43e79 -r c1b7aae86cf5 xen/common/schedule.c
--- a/xen/common/schedule.c     Tue Nov 16 15:41:28 2010 +0000
+++ b/xen/common/schedule.c     Wed Nov 17 16:42:37 2010 +0000
@@ -1396,6 +1396,11 @@ void sched_tick_resume(void)
     SCHED_OP(sched, tick_resume, cpu);
 }
 
+void wait(void)
+{
+    schedule();
+}
+
 #ifdef CONFIG_COMPAT
 #include "compat/schedule.c"
 #endif
diff -r deb438d43e79 -r c1b7aae86cf5 xen/common/wait.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/wait.c Wed Nov 17 16:42:37 2010 +0000
@@ -0,0 +1,165 @@
+/******************************************************************************
+ * wait.c
+ * 
+ * Sleep in hypervisor context for some event to occur.
+ */
+
+#include <xen/config.h>
+#include <xen/sched.h>
+#include <xen/wait.h>
+
+struct waitqueue_vcpu {
+    struct list_head list;
+    struct vcpu *vcpu;
+#ifdef CONFIG_X86
+    /*
+     * Xen/x86 does not have per-vcpu hypervisor stacks. So we must save the
+     * hypervisor context before sleeping (descheduling), setjmp/longjmp-style.
+     */
+    void *esp;
+    char stack[1500];
+#endif
+};
+
+int init_waitqueue_vcpu(struct vcpu *v)
+{
+    struct waitqueue_vcpu *wqv;
+
+    wqv = xmalloc(struct waitqueue_vcpu);
+    if ( wqv == NULL )
+        return -ENOMEM;
+
+    memset(wqv, 0, sizeof(*wqv));
+    INIT_LIST_HEAD(&wqv->list);
+    wqv->vcpu = v;
+
+    v->waitqueue_vcpu = wqv;
+
+    return 0;
+}
+
+void destroy_waitqueue_vcpu(struct vcpu *v)
+{
+    struct waitqueue_vcpu *wqv;
+
+    wqv = v->waitqueue_vcpu;
+    if ( wqv == NULL )
+        return;
+
+    BUG_ON(!list_empty(&wqv->list));
+    xfree(wqv);
+
+    v->waitqueue_vcpu = NULL;
+}
+
+void init_waitqueue_head(struct waitqueue_head *wq)
+{
+    spin_lock_init(&wq->lock);
+    INIT_LIST_HEAD(&wq->list);
+}
+
+void wake_up(struct waitqueue_head *wq)
+{
+    struct waitqueue_vcpu *wqv;
+
+    spin_lock(&wq->lock);
+
+    while ( !list_empty(&wq->list) )
+    {
+        wqv = list_entry(wq->list.next, struct waitqueue_vcpu, list);
+        list_del_init(&wqv->list);
+        vcpu_unpause(wqv->vcpu);
+    }
+
+    spin_unlock(&wq->lock);
+}
+
+#ifdef CONFIG_X86
+
+static void __prepare_to_wait(struct waitqueue_vcpu *wqv)
+{
+    char *cpu_info = (char *)get_cpu_info();
+    asm volatile (
+#ifdef CONFIG_X86_64
+        "push %%rax; push %%rbx; push %%rcx; push %%rdx; push %%rdi; "
+        "push %%rbp; push %%r8; push %%r9; push %%r10; push %%r11; "
+        "push %%r12; push %%r13; push %%r14; push %%r15; call 1f; "
+        "1: mov 80(%%rsp),%%rdi; mov 96(%%rsp),%%rcx; mov %%rsp,%%rsi; "
+        "sub %%rsi,%%rcx; rep movsb; mov %%rsp,%%rsi; pop %%rax; "
+        "pop %%r15; pop %%r14; pop %%r13; pop %%r12; "
+        "pop %%r11; pop %%r10; pop %%r9; pop %%r8; "
+        "pop %%rbp; pop %%rdi; pop %%rdx; pop %%rcx; pop %%rbx; pop %%rax"
+#else
+        "push %%eax; push %%ebx; push %%ecx; push %%edx; push %%edi; "
+        "push %%ebp; call 1f; "
+        "1: mov 8(%%esp),%%edi; mov 16(%%esp),%%ecx; mov %%esp,%%esi; "
+        "sub %%esi,%%ecx; rep movsb; mov %%esp,%%esi; pop %%eax; "
+        "pop %%ebp; pop %%edi; pop %%edx; pop %%ecx; pop %%ebx; pop %%eax"
+#endif
+        : "=S" (wqv->esp)
+        : "c" (cpu_info), "D" (wqv->stack)
+        : "memory" );
+    BUG_ON((cpu_info - (char *)wqv->esp) > sizeof(wqv->stack));
+}
+
+static void __finish_wait(struct waitqueue_vcpu *wqv)
+{
+    wqv->esp = NULL;
+}
+
+void check_wakeup_from_wait(void)
+{
+    struct waitqueue_vcpu *wqv = current->waitqueue_vcpu;
+
+    ASSERT(list_empty(&wqv->list));
+
+    if ( likely(wqv->esp == NULL) )
+        return;
+
+    asm volatile (
+        "mov %1,%%"__OP"sp; rep movsb; jmp *(%%"__OP"sp)"
+        : : "S" (wqv->stack), "D" (wqv->esp),
+        "c" ((char *)get_cpu_info() - (char *)wqv->esp)
+        : "memory" );
+}
+
+#else /* !CONFIG_X86 */
+
+#define __prepare_to_wait(wqv) ((void)0)
+#define __finish_wait(wqv) ((void)0)
+
+#endif
+
+void prepare_to_wait(struct waitqueue_head *wq)
+{
+    struct vcpu *curr = current;
+    struct waitqueue_vcpu *wqv = curr->waitqueue_vcpu;
+
+    ASSERT(list_empty(&wqv->list));
+
+    spin_lock(&wq->lock);
+    list_add_tail(&wqv->list, &wq->list);
+    vcpu_pause_nosync(curr);
+    spin_unlock(&wq->lock);
+
+    __prepare_to_wait(wqv);
+}
+
+void finish_wait(struct waitqueue_head *wq)
+{
+    struct vcpu *curr = current;
+    struct waitqueue_vcpu *wqv = curr->waitqueue_vcpu;
+
+    __finish_wait(wqv);
+
+    if ( list_empty(&wqv->list) )
+        return;
+
+    spin_lock(&wq->lock);
+    if ( !list_empty(&wqv->list) )
+    {
+        list_del_init(&wqv->list);
+        vcpu_unpause(curr);
+    }
+    spin_unlock(&wq->lock);
+}
diff -r deb438d43e79 -r c1b7aae86cf5 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Tue Nov 16 15:41:28 2010 +0000
+++ b/xen/include/xen/sched.h   Wed Nov 17 16:42:37 2010 +0000
@@ -80,6 +80,8 @@ void evtchn_destroy(struct domain *d); /
 void evtchn_destroy(struct domain *d); /* from domain_kill */
 void evtchn_destroy_final(struct domain *d); /* from complete_domain_destroy */
 
+struct waitqueue_vcpu;
+
 struct vcpu 
 {
     int              vcpu_id;
@@ -172,6 +174,8 @@ struct vcpu
 
     /* Multicall information. */
     struct mc_state  mc_state;
+
+    struct waitqueue_vcpu *waitqueue_vcpu;
 
     struct arch_vcpu arch;
 };
diff -r deb438d43e79 -r c1b7aae86cf5 xen/include/xen/wait.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/xen/wait.h    Wed Nov 17 16:42:37 2010 +0000
@@ -0,0 +1,54 @@
+/******************************************************************************
+ * wait.h
+ * 
+ * Sleep in hypervisor context for some event to occur.
+ */
+
+#ifndef __XEN_WAIT_H__
+#define __XEN_WAIT_H__
+
+#include <xen/types.h>
+#include <xen/list.h>
+#include <xen/spinlock.h>
+
+struct waitqueue_head {
+    spinlock_t lock;
+    struct list_head list;
+};
+
+/* Statically define and initialise a waitqueue. */
+#define DEFINE_WAITQUEUE_HEAD(name)             \
+    struct waitqueue_head name = {              \
+        .lock = SPIN_LOCK_UNLOCKED,             \
+        .list = LIST_HEAD_INIT((name).list)     \
+    }
+
+/* Dynamically initialise a waitqueue. */
+void init_waitqueue_head(struct waitqueue_head *wq);
+
+/* Wake all VCPUs waiting on specified waitqueue. */
+void wake_up(struct waitqueue_head *wq);
+
+/* Wait on specified waitqueue until @condition is true. */
+#define wait_event(wq, condition)               \
+do {                                            \
+    if ( condition )                            \
+        break;                                  \
+    for ( ; ; ) {                               \
+        prepare_to_wait(&wq);                   \
+        if ( condition )                        \
+            break;                              \
+        wait();                                 \
+    }                                           \
+    finish_wait(&wq);                           \
+} while (0)
+
+/* Private functions. */
+int init_waitqueue_vcpu(struct vcpu *v);
+void destroy_waitqueue_vcpu(struct vcpu *v);
+void prepare_to_wait(struct waitqueue_head *wq);
+void wait(void);
+void finish_wait(struct waitqueue_head *wq);
+void check_wakeup_from_wait(void);
+
+#endif /* __XEN_WAIT_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.