164 lines
5.3 KiB
Diff
164 lines
5.3 KiB
Diff
Index: xen-3.3.1-testing/xen/common/domain.c
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/xen/common/domain.c
|
|
+++ xen-3.3.1-testing/xen/common/domain.c
|
|
@@ -209,6 +209,7 @@ struct domain *domain_create(
|
|
atomic_set(&d->refcnt, 1);
|
|
spin_lock_init(&d->domain_lock);
|
|
spin_lock_init(&d->page_alloc_lock);
|
|
+ spin_lock_init(&d->poll_lock);
|
|
spin_lock_init(&d->shutdown_lock);
|
|
spin_lock_init(&d->hypercall_deadlock_mutex);
|
|
INIT_LIST_HEAD(&d->page_list);
|
|
@@ -653,7 +654,7 @@ void vcpu_reset(struct vcpu *v)
|
|
|
|
v->fpu_initialised = 0;
|
|
v->fpu_dirtied = 0;
|
|
- v->is_polling = 0;
|
|
+ v->poll_evtchn = 0;
|
|
v->is_initialised = 0;
|
|
v->nmi_pending = 0;
|
|
v->mce_pending = 0;
|
|
Index: xen-3.3.1-testing/xen/common/event_channel.c
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/xen/common/event_channel.c
|
|
+++ xen-3.3.1-testing/xen/common/event_channel.c
|
|
@@ -545,6 +545,7 @@ out:
|
|
static int evtchn_set_pending(struct vcpu *v, int port)
|
|
{
|
|
struct domain *d = v->domain;
|
|
+ unsigned long flags;
|
|
|
|
/*
|
|
* The following bit operations must happen in strict order.
|
|
@@ -564,19 +565,36 @@ static int evtchn_set_pending(struct vcp
|
|
}
|
|
|
|
/* Check if some VCPU might be polling for this event. */
|
|
- if ( unlikely(d->is_polling) )
|
|
+ if ( likely(!d->is_polling) )
|
|
+ return 0;
|
|
+
|
|
+ spin_lock_irqsave(&d->poll_lock, flags);
|
|
+
|
|
+ if ( likely(d->is_polling) )
|
|
{
|
|
- d->is_polling = 0;
|
|
+ bool_t is_polling = 0;
|
|
+
|
|
+ d->is_polling = -1;
|
|
smp_mb(); /* check vcpu poll-flags /after/ clearing domain poll-flag */
|
|
for_each_vcpu ( d, v )
|
|
{
|
|
- if ( !v->is_polling )
|
|
+ int poll_evtchn = v->poll_evtchn;
|
|
+
|
|
+ if ( !poll_evtchn )
|
|
+ continue;
|
|
+ if ( poll_evtchn > 0 && poll_evtchn != port )
|
|
+ {
|
|
+ is_polling = 1;
|
|
continue;
|
|
- v->is_polling = 0;
|
|
+ }
|
|
+ v->poll_evtchn = 0;
|
|
vcpu_unblock(v);
|
|
}
|
|
+ cmpxchg(&d->is_polling, -1, is_polling);
|
|
}
|
|
|
|
+ spin_unlock_irqrestore(&d->poll_lock, flags);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
Index: xen-3.3.1-testing/xen/common/schedule.c
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/xen/common/schedule.c
|
|
+++ xen-3.3.1-testing/xen/common/schedule.c
|
|
@@ -348,7 +348,7 @@ static long do_poll(struct sched_poll *s
|
|
return -EFAULT;
|
|
|
|
set_bit(_VPF_blocked, &v->pause_flags);
|
|
- v->is_polling = 1;
|
|
+ v->poll_evtchn = -1;
|
|
d->is_polling = 1;
|
|
|
|
/* Check for events /after/ setting flags: avoids wakeup waiting race. */
|
|
@@ -369,6 +369,9 @@ static long do_poll(struct sched_poll *s
|
|
goto out;
|
|
}
|
|
|
|
+ if ( i == 1 )
|
|
+ v->poll_evtchn = port;
|
|
+
|
|
if ( sched_poll->timeout != 0 )
|
|
set_timer(&v->poll_timer, sched_poll->timeout);
|
|
|
|
@@ -378,7 +381,7 @@ static long do_poll(struct sched_poll *s
|
|
return 0;
|
|
|
|
out:
|
|
- v->is_polling = 0;
|
|
+ v->poll_evtchn = 0;
|
|
clear_bit(_VPF_blocked, &v->pause_flags);
|
|
return rc;
|
|
}
|
|
@@ -760,10 +763,10 @@ static void poll_timer_fn(void *data)
|
|
{
|
|
struct vcpu *v = data;
|
|
|
|
- if ( !v->is_polling )
|
|
+ if ( !v->poll_evtchn )
|
|
return;
|
|
|
|
- v->is_polling = 0;
|
|
+ v->poll_evtchn = 0;
|
|
vcpu_unblock(v);
|
|
}
|
|
|
|
Index: xen-3.3.1-testing/xen/include/xen/sched.h
|
|
===================================================================
|
|
--- xen-3.3.1-testing.orig/xen/include/xen/sched.h
|
|
+++ xen-3.3.1-testing/xen/include/xen/sched.h
|
|
@@ -106,8 +106,6 @@ struct vcpu
|
|
bool_t fpu_initialised;
|
|
/* Has the FPU been used since it was last saved? */
|
|
bool_t fpu_dirtied;
|
|
- /* Is this VCPU polling any event channels (SCHEDOP_poll)? */
|
|
- bool_t is_polling;
|
|
/* Initialization completed for this VCPU? */
|
|
bool_t is_initialised;
|
|
/* Currently running on a CPU? */
|
|
@@ -137,6 +135,11 @@ struct vcpu
|
|
unsigned long pause_flags;
|
|
atomic_t pause_count;
|
|
|
|
+ /* Is this VCPU polling any event channels (SCHEDOP_poll)?
|
|
+ * Positive values indicate a single, negative values multiple channels
|
|
+ * being polled. */
|
|
+ int poll_evtchn;
|
|
+
|
|
/* IRQ-safe virq_lock protects against delivering VIRQ to stale evtchn. */
|
|
u16 virq_to_evtchn[NR_VIRQS];
|
|
spinlock_t virq_lock;
|
|
@@ -210,7 +213,7 @@ struct domain
|
|
/* Is this guest being debugged by dom0? */
|
|
bool_t debugger_attached;
|
|
/* Are any VCPUs polling event channels (SCHEDOP_poll)? */
|
|
- bool_t is_polling;
|
|
+ signed char is_polling;
|
|
/* Is this guest dying (i.e., a zombie)? */
|
|
enum { DOMDYING_alive, DOMDYING_dying, DOMDYING_dead } is_dying;
|
|
/* Domain is paused by controller software? */
|
|
@@ -218,6 +221,9 @@ struct domain
|
|
/* Domain's VCPUs are pinned 1:1 to physical CPUs? */
|
|
bool_t is_pinned;
|
|
|
|
+ /* Protects is_polling modification in evtchn_set_pending(). */
|
|
+ spinlock_t poll_lock;
|
|
+
|
|
/* Guest has shut down (inc. reason code)? */
|
|
spinlock_t shutdown_lock;
|
|
bool_t is_shutting_down; /* in process of shutting down? */
|