From 2ed6cc7bec41dd344d41ea1531f6760c93099128 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 2 Mar 2011 16:59:54 +0000 Subject: [PATCH] Expose event loop implementation as a public API 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 + po/POTFILES.in | 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 +--- 11 files changed, 134 insertions(+), 30 deletions(-) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 602edbe379..452566cc3f 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -893,8 +893,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) {} @@ -957,13 +956,6 @@ static struct qemud_server *qemudInitialize(void) { # endif #endif - virEventRegisterImpl(virEventPollAddHandle, - virEventPollUpdateHandle, - virEventPollRemoveHandle, - virEventPollAddTimeout, - virEventPollUpdateTimeout, - virEventPollRemoveTimeout); - return server; } @@ -2283,7 +2275,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 5dfb752176..618b350c35 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 5962dbfee5..6b8c789541 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/po/POTFILES.in b/po/POTFILES.in index 9852f97d7a..1ed276507e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -88,6 +88,7 @@ src/util/cgroup.c src/util/command.c src/util/conf.c src/util/dnsmasq.c +src/util/event_poll.c src/util/hooks.c src/util/hostusb.c src/util/interface.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 07810eacc0..efcf3c5ec0 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 1a45be1420..cca8d085e7 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 680fef9131..0d88b557b6 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -24,6 +24,9 @@ #include #include "event.h" +#include "event_poll.h" +#include "logging.h" +#include "virterror_internal.h" #include @@ -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 13628409cd..dd83fc34a8 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 89bb2a5aca..aaa37206c2 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 84c28a3792..b9dd26832d 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 95bcfcc987..f3754d7433 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -11677,13 +11677,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, -- GitLab