diff --git a/tools/python/xen/lowlevel/xu/xu.c b/tools/python/xen/lowlevel/xu/xu.c index 2a4f229fef..d403099cec 100644 --- a/tools/python/xen/lowlevel/xu/xu.c +++ b/tools/python/xen/lowlevel/xu/xu.c @@ -57,6 +57,19 @@ #endif +/* Set the close-on-exec flag on a file descriptor. Doesn't currently bother + * to check for errors. */ +static void set_cloexec(int fd) +{ + int flags = fcntl(fd, F_GETFD, 0); + + if ( flags < 0 ) + return; + + flags |= FD_CLOEXEC; + fcntl(fd, F_SETFD, flags); +} + /* * *********************** NOTIFIER *********************** */ @@ -197,6 +210,7 @@ static PyObject *xu_notifier_new(PyObject *self, PyObject *args) PyObject_Del((PyObject *)xun); return PyErr_SetFromErrno(PyExc_IOError); } + set_cloexec(xun->evtchn_fd); return (PyObject *)xun; } @@ -896,6 +910,7 @@ static int __xu_port_connect(xu_port_object *xup) PyErr_SetString(port_error, "Could not open '/dev/mem'"); return -1; } + set_cloexec(xup->mem_fd); /* Set the General-Purpose Subject whose page frame will be mapped. */ (void)ioctl(xup->mem_fd, _IO('M', 1), (unsigned long)xup->remote_dom); diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index e7ee55da02..1fcef0f03e 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -13,19 +13,6 @@ #include #include -/* - * GENERIC SCHEDULING CALLBACK MECHANISMS - */ - -/* Schedule an asynchronous callback for the specified domain. */ -static inline void guest_async_callback(struct domain *d) -{ - int running = test_bit(DF_RUNNING, &d->flags); - domain_unblock(d); - if ( running ) - smp_send_event_check_cpu(d->processor); -} - /* * EVENT-CHANNEL NOTIFICATIONS * NB. On x86, the atomic bit operations also act as memory barriers. There @@ -36,13 +23,29 @@ static inline void guest_async_callback(struct domain *d) static inline void evtchn_set_pending(struct domain *d, int port) { shared_info_t *s = d->shared_info; + int running; + + /* These three operations must happen in strict order. */ if ( !test_and_set_bit(port, &s->evtchn_pending[0]) && !test_bit (port, &s->evtchn_mask[0]) && !test_and_set_bit(port>>5, &s->evtchn_pending_sel) ) { /* The VCPU pending flag must be set /after/ update to evtchn-pend. */ - s->vcpu_data[0].evtchn_upcall_pending = 1; - guest_async_callback(d); + set_bit(0, &s->vcpu_data[0].evtchn_upcall_pending); + + /* + * NB1. 'flags' and 'processor' must be checked /after/ update of + * pending flag. These values may fluctuate (after all, we hold no + * locks) but the key insight is that each change will cause + * evtchn_upcall_pending to be polled. + * + * NB2. We save DF_RUNNING across the unblock to avoid a needless + * IPI for domains that we IPI'd to unblock. + */ + running = test_bit(DF_RUNNING, &d->flags); + domain_unblock(d); + if ( running ) + smp_send_event_check_cpu(d->processor); } }