From a9a87c8dbdd5ed3fe550d0696ea03700a311da29 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 3 Nov 2014 15:15:22 +0200 Subject: [PATCH] xen: fix low-level interrupt handling with osv The Xen code registers a function that calls semaphore::signal as an interrupt handler, however that function is not smp safe and may crash, and in events it generates are likely to be ignored, since they are just appended to the reactor queue without any real wakeup to the reactor thread. Switch to using an eventfd. That's still unsafe, but a little better, since its signalling is smp safe, and will cause the reactor thread to wake up in case it was asleep. With this, we are able to receive multiple packets. --- core/xen/evtchn.cc | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/core/xen/evtchn.cc b/core/xen/evtchn.cc index 440049e4e2..149c23f1a2 100644 --- a/core/xen/evtchn.cc +++ b/core/xen/evtchn.cc @@ -77,6 +77,7 @@ void userspace_evtchn::umask(int *port, unsigned count) #ifdef HAVE_OSV class kernel_evtchn: public evtchn { static void make_ready(void *arg); + static void process_interrupts(readable_eventfd* fd, semaphore* sem); public: kernel_evtchn(unsigned otherend) : evtchn(otherend) {} virtual int bind() override; @@ -85,8 +86,9 @@ public: void kernel_evtchn::make_ready(void *arg) { printf("Got an interrupt!\n"); - semaphore *sem = reinterpret_cast(arg); - sem->signal(); + int fd = reinterpret_cast(arg); + uint64_t one = 1; + ::write(fd, &one, sizeof(one)); } int kernel_evtchn::bind() { @@ -95,12 +97,25 @@ int kernel_evtchn::bind() { int port; irq = bind_listening_port_to_irq(_otherend, &port); - intr_add_handler("", irq, NULL, make_ready, init_port(port), 0, 0); + // We need to convert extra-seastar events to intra-seastar events + // (in this case, the semaphore interface of evtchn). The only + // way to do that currently is via eventfd. + semaphore* sem = init_port(port); + auto fd = new readable_eventfd; + auto wfd = fd->get_write_fd(); + intr_add_handler("", irq, NULL, make_ready, reinterpret_cast(uintptr_t(wfd)), 0, 0); unmask_evtchn(port); - + process_interrupts(fd, sem); return evtchn_from_irq(irq); } +void kernel_evtchn::process_interrupts(readable_eventfd* fd, semaphore* sem) { + fd->wait().then([fd, sem] (size_t ignore) { + sem->signal(); + process_interrupts(fd, sem); + }); +} + void kernel_evtchn::notify(int port) { notify_remote_via_evtchn(port); }