Index: 2008-08-06/xen/common/domain.c =================================================================== --- 2008-08-06.orig/xen/common/domain.c 2008-08-07 11:03:33.000000000 +0200 +++ 2008-08-06/xen/common/domain.c 2008-08-07 12:04:00.000000000 +0200 @@ -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: 2008-08-06/xen/common/event_channel.c =================================================================== --- 2008-08-06.orig/xen/common/event_channel.c 2008-08-07 11:03:33.000000000 +0200 +++ 2008-08-06/xen/common/event_channel.c 2008-08-07 15:24:17.000000000 +0200 @@ -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: 2008-08-06/xen/common/schedule.c =================================================================== --- 2008-08-06.orig/xen/common/schedule.c 2008-08-07 11:03:33.000000000 +0200 +++ 2008-08-06/xen/common/schedule.c 2008-08-07 15:27:07.000000000 +0200 @@ -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; } @@ -758,10 +761,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: 2008-08-06/xen/include/xen/sched.h =================================================================== --- 2008-08-06.orig/xen/include/xen/sched.h 2008-08-07 11:03:33.000000000 +0200 +++ 2008-08-06/xen/include/xen/sched.h 2008-08-07 10:07:56.000000000 +0200 @@ -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? */