[libvirt] [PATCH 3/3] Expose event loop implementation as a public API

Daniel P. Berrange berrange at redhat.com
Thu Mar 3 14:21:51 UTC 2011


Not all applications have an existing event loop they need
to integrate with. Forcing them to implement the libvirt
event loop integration APIs is an undue burden. This just
exposes our simple poll() based implementation for apps
to use. So instead of calling

   virEventRegister(....callbacks...)

The app would call

   virEventRegisterDefaultImpl()

And then have a thread somewhere calling

    static bool quit = false;
    ....
    while (!quit)
      virEventRunDefaultImpl()

* daemon/libvirtd.c, tools/console.c,
  tools/virsh.c: Convert to public event loop APIs
* include/libvirt/libvirt.h.in, src/libvirt_private.syms: Add
  virEventRegisterDefaultImpl and virEventRunDefaultImpl
* src/util/event.c: Implement virEventRegisterDefaultImpl
  and virEventRunDefaultImpl using poll() event loop
* src/util/event_poll.c: Add full error reporting
* src/util/virterror.c, include/libvirt/virterror.h: Add
  VIR_FROM_EVENTS
---
 daemon/libvirtd.c            |   12 +----
 include/libvirt/libvirt.h.in |    3 +
 include/libvirt/virterror.h  |    1 +
 src/libvirt_private.syms     |    8 ----
 src/libvirt_public.syms      |    6 +++
 src/util/event.c             |   94 +++++++++++++++++++++++++++++++++++++++++-
 src/util/event_poll.c        |   24 ++++++++++-
 src/util/virterror.c         |    3 +
 tools/console.c              |    3 +-
 tools/virsh.c                |    9 +---
 10 files changed, 133 insertions(+), 30 deletions(-)

diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index fdc9180..8c35627 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -873,8 +873,7 @@ static struct qemud_server *qemudInitialize(void) {
         return NULL;
     }
 
-    if (virEventPollInit() < 0) {
-        VIR_ERROR0(_("Failed to initialize event system"));
+    if (virEventRegisterDefaultImpl() < 0) {
         virMutexDestroy(&server->lock);
         if (virCondDestroy(&server->job) < 0)
         {}
@@ -937,13 +936,6 @@ static struct qemud_server *qemudInitialize(void) {
 # endif
 #endif
 
-    virEventRegisterImpl(virEventPollAddHandle,
-                         virEventPollUpdateHandle,
-                         virEventPollRemoveHandle,
-                         virEventPollAddTimeout,
-                         virEventPollUpdateTimeout,
-                         virEventPollRemoveTimeout);
-
     return server;
 }
 
@@ -2263,7 +2255,7 @@ qemudDispatchServerEvent(int watch, int fd, int events, void *opaque) {
 static int qemudOneLoop(void) {
     sig_atomic_t errors;
 
-    if (virEventPollRunOnce() < 0)
+    if (virEventRunDefaultImpl() < 0)
         return -1;
 
     /* Check for any signal handling errors and log them. */
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 5dfb752..618b350 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1768,6 +1768,9 @@ void virEventRegisterImpl(virEventAddHandleFunc addHandle,
                           virEventUpdateTimeoutFunc updateTimeout,
                           virEventRemoveTimeoutFunc removeTimeout);
 
+int virEventRegisterDefaultImpl(void);
+int virEventRunDefaultImpl(void);
+
 /*
  * Secret manipulation API
  */
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 5962dbf..6b8c789 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -79,6 +79,7 @@ typedef enum {
     VIR_FROM_SYSINFO = 37,	/* Error from sysinfo/SMBIOS */
     VIR_FROM_STREAMS = 38,	/* Error from I/O streams */
     VIR_FROM_VMWARE = 39,	/* Error from VMware driver */
+    VIR_FROM_EVENT = 40,       /* Error from event loop impl */
 } virErrorDomain;
 
 
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5c7f4df..56b5bdf 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -396,14 +396,6 @@ virEventUpdateTimeout;
 # event_poll.h
 virEventPollToNativeEvents;
 virEventPollFromNativeEvents;
-virEventPollRunOnce;
-virEventPollInit;
-virEventPollRemoveTimeout;
-virEventPollUpdateTimeout;
-virEventPollAddTimeout;
-virEventPollRemoveHandle;
-virEventPollUpdateHandle;
-virEventPollAddHandle;
 
 
 # fdstream.h
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 1a45be1..cca8d08 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -424,4 +424,10 @@ LIBVIRT_0.8.8 {
         virConnectGetSysinfo;
 } LIBVIRT_0.8.6;
 
+LIBVIRT_0.9.0 {
+    global:
+        virEventRegisterDefaultImpl;
+        virEventRunDefaultImpl;
+} LIBVIRT_0.8.8;
+
 # .... define new API here using predicted next version number ....
diff --git a/src/util/event.c b/src/util/event.c
index 680fef9..0d88b55 100644
--- a/src/util/event.c
+++ b/src/util/event.c
@@ -24,6 +24,9 @@
 #include <config.h>
 
 #include "event.h"
+#include "event_poll.h"
+#include "logging.h"
+#include "virterror_internal.h"
 
 #include <stdlib.h>
 
@@ -77,6 +80,15 @@ int virEventRemoveTimeout(int timer) {
     return removeTimeoutImpl(timer);
 }
 
+
+/*****************************************************
+ *
+ * Below this point are 3  *PUBLIC*  APIs for event
+ * loop integration with applications using libvirt.
+ * These API contracts cannot be changed.
+ *
+ *****************************************************/
+
 /**
  * virEventRegisterImpl:
  * @addHandle: the callback to add fd handles
@@ -86,14 +98,28 @@ int virEventRemoveTimeout(int timer) {
  * @updateTimeout: the callback to update a timeout
  * @removeTimeout: the callback to remove a timeout
  *
- * Registers an event implementation
+ * Registers an event implementation, to allow integration
+ * with an external event loop. Applications would use this
+ * to integrate with the libglib2 event loop, or libevent
+ * or the QT event loop.
+ *
+ * If an application does not need to integrate with an
+ * existing event loop implementation, then the
+ * virEventRegisterDefaultImpl method can be used to setup
+ * the generic libvirt implementation.
  */
 void virEventRegisterImpl(virEventAddHandleFunc addHandle,
                           virEventUpdateHandleFunc updateHandle,
                           virEventRemoveHandleFunc removeHandle,
                           virEventAddTimeoutFunc addTimeout,
                           virEventUpdateTimeoutFunc updateTimeout,
-                          virEventRemoveTimeoutFunc removeTimeout) {
+                          virEventRemoveTimeoutFunc removeTimeout)
+{
+    VIR_DEBUG("addHandle=%p updateHandle=%p removeHandle=%p "
+              "addTimeout=%p updateTimeout=%p removeTimeout=%p",
+              addHandle, updateHandle, removeHandle,
+              addTimeout, updateTimeout, removeTimeout);
+
     addHandleImpl = addHandle;
     updateHandleImpl = updateHandle;
     removeHandleImpl = removeHandle;
@@ -101,3 +127,67 @@ void virEventRegisterImpl(virEventAddHandleFunc addHandle,
     updateTimeoutImpl = updateTimeout;
     removeTimeoutImpl = removeTimeout;
 }
+
+/**
+ * virEventRegisterDefaultImpl:
+ *
+ * Registers a default event implementation based on the
+ * poll() system call. This is a generic implementation
+ * that can be used by any client application which does
+ * not have a need to integrate with an external event
+ * loop impl.
+ *
+ * Once registered, the application can invoke
+ * virEventRunDefaultImpl in a loop to process
+ * events
+ */
+int virEventRegisterDefaultImpl(void)
+{
+    VIR_DEBUG0("");
+
+    virResetLastError();
+
+    if (virEventPollInit() < 0) {
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    virEventRegisterImpl(
+        virEventPollAddHandle,
+        virEventPollUpdateHandle,
+        virEventPollRemoveHandle,
+        virEventPollAddTimeout,
+        virEventPollUpdateTimeout,
+        virEventPollRemoveTimeout
+        );
+
+    return 0;
+}
+
+
+/**
+ * virEventRunDefaultImpl:
+ *
+ * Run one iteration of the event loop. Applications
+ * will generally want to have a thread which invokes
+ * this method in an infinite loop
+ *
+ *  static bool quit = false;
+ *
+ *  while (!quit) {
+ *    if (virEventRunDefaultImpl() < 0)
+ *       ...print error...
+ *  }
+ */
+int virEventRunDefaultImpl(void)
+{
+    VIR_DEBUG0("");
+    virResetLastError();
+
+    if (virEventPollRunOnce() < 0) {
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/src/util/event_poll.c b/src/util/event_poll.c
index 1362840..dd83fc3 100644
--- a/src/util/event_poll.c
+++ b/src/util/event_poll.c
@@ -36,9 +36,16 @@
 #include "memory.h"
 #include "util.h"
 #include "ignore-value.h"
+#include "virterror_internal.h"
 
 #define EVENT_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__)
 
+#define VIR_FROM_THIS VIR_FROM_EVENT
+
+#define virEventError(code, ...)                                    \
+    virReportErrorHelper(NULL, VIR_FROM_EVENT, code, __FILE__,      \
+                         __FUNCTION__, __LINE__, __VA_ARGS__)
+
 static int virEventPollInterruptLocked(void);
 
 /* State for a single file handle being monitored */
@@ -316,6 +323,8 @@ static int virEventPollCalculateTimeout(int *timeout) {
         struct timeval tv;
 
         if (gettimeofday(&tv, NULL) < 0) {
+            virReportSystemError(errno, "%s",
+                                 _("Unable to get current time"));
             return -1;
         }
 
@@ -350,8 +359,10 @@ static struct pollfd *virEventPollMakePollFDs(int *nfds) {
     }
 
     /* Setup the poll file handle data structs */
-    if (VIR_ALLOC_N(fds, *nfds) < 0)
+    if (VIR_ALLOC_N(fds, *nfds) < 0) {
+        virReportOOMError();
         return NULL;
+    }
 
     *nfds = 0;
     for (i = 0 ; i < eventLoop.handlesCount ; i++) {
@@ -393,6 +404,8 @@ static int virEventPollDispatchTimeouts(void) {
     VIR_DEBUG("Dispatch %d", ntimeouts);
 
     if (gettimeofday(&tv, NULL) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to get current time"));
         return -1;
     }
     now = (((unsigned long long)tv.tv_sec)*1000) +
@@ -584,6 +597,8 @@ int virEventPollRunOnce(void) {
         if (errno == EINTR) {
             goto retry;
         }
+        virReportSystemError(errno, "%s",
+                             _("Unable to poll on file handles"));
         goto error_unlocked;
     }
     EVENT_DEBUG("Poll got %d event(s)", ret);
@@ -626,6 +641,8 @@ static void virEventPollHandleWakeup(int watch ATTRIBUTE_UNUSED,
 int virEventPollInit(void)
 {
     if (virMutexInit(&eventLoop.lock) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to initialize mutex"));
         return -1;
     }
 
@@ -634,12 +651,17 @@ int virEventPollInit(void)
         virSetNonBlock(eventLoop.wakeupfd[1]) < 0 ||
         virSetCloseExec(eventLoop.wakeupfd[0]) < 0 ||
         virSetCloseExec(eventLoop.wakeupfd[1]) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to setup wakeup pipe"));
         return -1;
     }
 
     if (virEventPollAddHandle(eventLoop.wakeupfd[0],
                               VIR_EVENT_HANDLE_READABLE,
                               virEventPollHandleWakeup, NULL, NULL) < 0) {
+        virEventError(VIR_ERR_INTERNAL_ERROR,
+                      _("Unable to add handle %d to event loop"),
+                      eventLoop.wakeupfd[0]);
         return -1;
     }
 
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 89bb2a5..aaa3720 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -200,6 +200,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
         case VIR_FROM_STREAMS:
             dom = "Streams ";
             break;
+        case VIR_FROM_EVENT:
+            dom = "Events ";
+            break;
     }
     return(dom);
 }
diff --git a/tools/console.c b/tools/console.c
index 84c28a3..b9dd268 100644
--- a/tools/console.c
+++ b/tools/console.c
@@ -44,7 +44,6 @@
 # include "virterror_internal.h"
 
 # include "event.h"
-# include "event_poll.h"
 
 /* ie  Ctrl-]  as per telnet */
 # define CTRL_CLOSE_BRACKET '\35'
@@ -350,7 +349,7 @@ int vshRunConsole(virDomainPtr dom, const char *devname)
                               NULL);
 
     while (!con->quit) {
-        if (virEventPollRunOnce() < 0)
+        if (virEventRunDefaultImpl() < 0)
             break;
     }
 
diff --git a/tools/virsh.c b/tools/virsh.c
index f7ad14d..2af307f 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -11672,13 +11672,8 @@ vshInit(vshControl *ctl)
     /* set up the signals handlers to catch disconnections */
     vshSetupSignals();
 
-    virEventRegisterImpl(virEventPollAddHandle,
-                         virEventPollUpdateHandle,
-                         virEventPollRemoveHandle,
-                         virEventPollAddTimeout,
-                         virEventPollUpdateTimeout,
-                         virEventPollRemoveTimeout);
-    virEventPollInit();
+    if (virEventRegisterDefaultImpl() < 0)
+        return FALSE;
 
     ctl->conn = virConnectOpenAuth(ctl->name,
                                    virConnectAuthPtrDefault,
-- 
1.7.4




More information about the libvir-list mailing list