From 620103feaf425268d0d6547c9a10693ead4788bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bosdonnat?= Date: Tue, 26 Nov 2013 15:10:15 +0100 Subject: [PATCH] Extracted common parts of domain_event.[ch] to object_event.[ch] --- po/POTFILES.in | 1 + src/Makefile.am | 6 + src/conf/domain_event.c | 813 +------------------------------- src/conf/domain_event.h | 72 +-- src/conf/object_event.c | 792 +++++++++++++++++++++++++++++++ src/conf/object_event.h | 97 ++++ src/conf/object_event_private.h | 113 +++++ src/libvirt_private.syms | 15 +- 8 files changed, 1033 insertions(+), 876 deletions(-) create mode 100644 src/conf/object_event.c create mode 100644 src/conf/object_event.h create mode 100644 src/conf/object_event_private.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 0835b52dd5..49dfc9c019 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -21,6 +21,7 @@ src/conf/network_conf.c src/conf/node_device_conf.c src/conf/nwfilter_conf.c src/conf/nwfilter_params.c +src/conf/object_event.c src/conf/secret_conf.c src/conf/snapshot_conf.c src/conf/storage_conf.c diff --git a/src/Makefile.am b/src/Makefile.am index 87f510123e..a3ea55c633 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -241,6 +241,10 @@ DOMAIN_CONF_SOURCES = \ conf/domain_nwfilter.c conf/domain_nwfilter.h \ conf/snapshot_conf.c conf/snapshot_conf.h +OBJECT_EVENT_SOURCES = \ + conf/object_event.c conf/object_event.h \ + conf/object_event_private.h + DOMAIN_EVENT_SOURCES = \ conf/domain_event.c conf/domain_event.h @@ -292,6 +296,7 @@ DEVICE_CONF_SOURCES = \ CONF_SOURCES = \ $(NETDEV_CONF_SOURCES) \ $(DOMAIN_CONF_SOURCES) \ + $(OBJECT_EVENT_SOURCES) \ $(DOMAIN_EVENT_SOURCES) \ $(NETWORK_CONF_SOURCES) \ $(NWFILTER_CONF_SOURCES) \ @@ -2021,6 +2026,7 @@ libvirt_setuid_rpc_client_la_SOURCES = \ util/virutil.c \ util/viruuid.c \ conf/domain_event.c \ + conf/object_event.c \ rpc/virnetsocket.c \ rpc/virnetsocket.h \ rpc/virnetmessage.h \ diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index b7b8796d5b..da57129faa 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -3,6 +3,7 @@ * * Copyright (C) 2010-2013 Red Hat, Inc. * Copyright (C) 2008 VirtualIron + * Copyright (C) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,6 +25,8 @@ #include #include "domain_event.h" +#include "object_event.h" +#include "object_event_private.h" #include "virlog.h" #include "datatypes.h" #include "viralloc.h" @@ -32,59 +35,6 @@ #define VIR_FROM_THIS VIR_FROM_NONE -#define VIR_OBJECT_EVENT_CALLBACK(cb) ((virConnectObjectEventGenericCallback)(cb)) - -struct _virObjectMeta { - int id; - char *name; - unsigned char uuid[VIR_UUID_BUFLEN]; -}; -typedef struct _virObjectMeta virObjectMeta; -typedef virObjectMeta *virObjectMetaPtr; - -typedef struct _virObjectEventQueue virObjectEventQueue; -typedef virObjectEventQueue *virObjectEventQueuePtr; - -struct _virObjectEventCallbackList { - unsigned int nextID; - unsigned int count; - virObjectEventCallbackPtr *callbacks; -}; -typedef struct _virObjectEventCallbackList virObjectEventCallbackList; -typedef virObjectEventCallbackList *virObjectEventCallbackListPtr; - -struct _virObjectEventQueue { - unsigned int count; - virObjectEventPtr *events; -}; - -struct _virObjectEventState { - /* The list of domain event callbacks */ - virObjectEventCallbackListPtr callbacks; - /* The queue of object events */ - virObjectEventQueuePtr queue; - /* Timer for flushing events queue */ - int timer; - /* Flag if we're in process of dispatching */ - bool isDispatching; - virMutex lock; -}; - -struct _virObjectEventCallback { - int callbackID; - int eventID; - virConnectPtr conn; - virObjectMetaPtr meta; - virConnectObjectEventGenericCallback cb; - void *opaque; - virFreeCallback freecb; - int deleted; -}; - - - -static virClassPtr virObjectEventClass; -static virClassPtr virClassForObjectEvent(void); static virClassPtr virDomainEventClass; static virClassPtr virDomainEventLifecycleClass; @@ -98,7 +48,7 @@ static virClassPtr virDomainEventTrayChangeClass; static virClassPtr virDomainEventBalloonChangeClass; static virClassPtr virDomainEventDeviceRemovedClass; -static void virObjectEventDispose(void *obj); + static void virDomainEventDispose(void *obj); static void virDomainEventLifecycleDispose(void *obj); static void virDomainEventRTCChangeDispose(void *obj); @@ -111,11 +61,6 @@ static void virDomainEventTrayChangeDispose(void *obj); static void virDomainEventBalloonChangeDispose(void *obj); static void virDomainEventDeviceRemovedDispose(void *obj); -struct _virObjectEvent { - virObject parent; - int eventID; - virObjectMeta meta; -}; struct _virDomainEvent { virObjectEvent parent; @@ -222,26 +167,6 @@ typedef struct _virDomainEventDeviceRemoved virDomainEventDeviceRemoved; typedef virDomainEventDeviceRemoved *virDomainEventDeviceRemovedPtr; -static int virObjectEventOnceInit(void) -{ - if (!(virObjectEventClass = - virClassNew(virClassForObject(), - "virObjectEvent", - sizeof(virObjectEvent), - virObjectEventDispose))) - return -1; - return 0; -} - -VIR_ONCE_GLOBAL_INIT(virObjectEvent) - -virClassPtr virClassForObjectEvent(void) -{ - if (virObjectEventInitialize() < 0) - return NULL; - return virObjectEventClass; -} - static int virDomainEventsOnceInit(void) { if (!(virDomainEventClass = @@ -315,26 +240,6 @@ static int virDomainEventsOnceInit(void) VIR_ONCE_GLOBAL_INIT(virDomainEvents) -static int virObjectEventGetEventID(void *anyobj) -{ - virObjectEventPtr obj = anyobj; - - if (!virObjectIsClass(obj, virClassForObjectEvent())) { - VIR_WARN("Object %p (%s) is not a virObjectEvent instance", - obj, obj ? virClassName(obj->parent.klass) : "(unknown)"); - return -1; - } - return obj->eventID; -} - -static void virObjectEventDispose(void *obj) -{ - virObjectEventPtr event = obj; - - VIR_DEBUG("obj=%p", event); - - VIR_FREE(event->meta.name); -} static void virDomainEventDispose(void *obj) { @@ -437,29 +342,6 @@ static void virDomainEventDeviceRemovedDispose(void *obj) VIR_FREE(event->devAlias); } -/** - * virObjectEventCallbackListFree: - * @list: event callback list head - * - * Free the memory in the domain event callback list - */ -static void -virObjectEventCallbackListFree(virObjectEventCallbackListPtr list) -{ - size_t i; - if (!list) - return; - - for (i=0; icount; i++) { - virFreeCallback freecb = list->callbacks[i]->freecb; - if (freecb) - (*freecb)(list->callbacks[i]->opaque); - VIR_FREE(list->callbacks[i]); - } - VIR_FREE(list->callbacks); - VIR_FREE(list); -} - /** * virDomainEventCallbackListRemove: @@ -512,56 +394,6 @@ virDomainEventCallbackListRemove(virConnectPtr conn, } -/** - * virObjectEventCallbackListRemoveID: - * @conn: pointer to the connection - * @cbList: the list - * @callback: the callback to remove - * - * Internal function to remove a callback from a virObjectEventCallbackListPtr - */ -static int -virObjectEventCallbackListRemoveID(virConnectPtr conn, - virObjectEventCallbackListPtr cbList, - int callbackID) -{ - int ret = 0; - size_t i; - for (i = 0; i < cbList->count; i++) { - if (cbList->callbacks[i]->callbackID == callbackID && - cbList->callbacks[i]->conn == conn) { - virFreeCallback freecb = cbList->callbacks[i]->freecb; - if (freecb) - (*freecb)(cbList->callbacks[i]->opaque); - virObjectUnref(cbList->callbacks[i]->conn); - VIR_FREE(cbList->callbacks[i]); - - if (i < (cbList->count - 1)) - memmove(cbList->callbacks + i, - cbList->callbacks + i + 1, - sizeof(*(cbList->callbacks)) * - (cbList->count - (i + 1))); - - if (VIR_REALLOC_N(cbList->callbacks, - cbList->count - 1) < 0) { - ; /* Failure to reduce memory allocation isn't fatal */ - } - cbList->count--; - - for (i = 0; i < cbList->count; i++) { - if (!cbList->callbacks[i]->deleted) - ret++; - } - return ret; - } - } - - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not find event callback for removal")); - return -1; -} - - static int virDomainEventCallbackListMarkDelete(virConnectPtr conn, virObjectEventCallbackListPtr cbList, @@ -588,162 +420,6 @@ virDomainEventCallbackListMarkDelete(virConnectPtr conn, } -static int -virObjectEventCallbackListMarkDeleteID(virConnectPtr conn, - virObjectEventCallbackListPtr cbList, - int callbackID) -{ - int ret = 0; - size_t i; - for (i = 0; i < cbList->count; i++) { - if (cbList->callbacks[i]->callbackID == callbackID && - cbList->callbacks[i]->conn == conn) { - cbList->callbacks[i]->deleted = 1; - for (i = 0; i < cbList->count; i++) { - if (!cbList->callbacks[i]->deleted) - ret++; - } - return ret; - } - } - - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not find event callback for deletion")); - return -1; -} - - -static int -virObjectEventCallbackListPurgeMarked(virObjectEventCallbackListPtr cbList) -{ - int old_count = cbList->count; - int n; - for (n = 0; n < cbList->count; n++) { - if (cbList->callbacks[n]->deleted) { - virFreeCallback freecb = cbList->callbacks[n]->freecb; - if (freecb) - (*freecb)(cbList->callbacks[n]->opaque); - virObjectUnref(cbList->callbacks[n]->conn); - VIR_FREE(cbList->callbacks[n]); - - if (n < (cbList->count - 1)) - memmove(cbList->callbacks + n, - cbList->callbacks + n + 1, - sizeof(*(cbList->callbacks)) * - (cbList->count - (n + 1))); - cbList->count--; - n--; - } - } - if (cbList->count < old_count && - VIR_REALLOC_N(cbList->callbacks, cbList->count) < 0) { - ; /* Failure to reduce memory allocation isn't fatal */ - } - return 0; -} - - -/** - * virObjectEventCallbackListAddID: - * @conn: pointer to the connection - * @cbList: the list - * @uuid: the uuid of the object to filter on - * @name: the name of the object to filter on - * @id: the ID of the object to filter on - * @eventID: the event ID - * @callback: the callback to add - * @opaque: opaque data tio pass to callback - * @callbackID: filled with callback ID - * - * Internal function to add a callback from a virObjectEventCallbackListPtr - */ -static int -virObjectEventCallbackListAddID(virConnectPtr conn, - virObjectEventCallbackListPtr cbList, - unsigned char uuid[VIR_UUID_BUFLEN], - const char *name, - int id, - int eventID, - virConnectObjectEventGenericCallback callback, - void *opaque, - virFreeCallback freecb, - int *callbackID) -{ - virObjectEventCallbackPtr event; - size_t i; - int ret = 0; - - /* Check incoming */ - if (!cbList) { - return -1; - } - - /* check if we already have this callback on our list */ - for (i = 0; i < cbList->count; i++) { - if (cbList->callbacks[i]->cb == VIR_OBJECT_EVENT_CALLBACK(callback) && - cbList->callbacks[i]->eventID == eventID && - cbList->callbacks[i]->conn == conn && - ((uuid && cbList->callbacks[i]->meta && - memcmp(cbList->callbacks[i]->meta->uuid, - uuid, VIR_UUID_BUFLEN) == 0) || - (!uuid && !cbList->callbacks[i]->meta))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("event callback already tracked")); - return -1; - } - } - /* Allocate new event */ - if (VIR_ALLOC(event) < 0) - goto error; - event->conn = conn; - event->cb = callback; - event->eventID = eventID; - event->opaque = opaque; - event->freecb = freecb; - - if (name && uuid && id > 0) { - if (VIR_ALLOC(event->meta) < 0) - goto error; - if (VIR_STRDUP(event->meta->name, name) < 0) - goto error; - memcpy(event->meta->uuid, uuid, VIR_UUID_BUFLEN); - event->meta->id = id; - } - - /* Make space on list */ - if (VIR_REALLOC_N(cbList->callbacks, cbList->count + 1) < 0) - goto error; - - virObjectRef(event->conn); - - cbList->callbacks[cbList->count] = event; - cbList->count++; - - event->callbackID = cbList->nextID++; - - for (i = 0; i < cbList->count; i++) { - if (cbList->callbacks[i]->eventID == eventID && - cbList->callbacks[i]->conn == conn && - !cbList->callbacks[i]->deleted) - ret++; - } - - if (callbackID) - *callbackID = event->callbackID; - - return ret; - -error: - if (event) { - if (event->meta) - VIR_FREE(event->meta->name); - VIR_FREE(event->meta); - } - VIR_FREE(event); - return -1; -} - - /** * virDomainEventCallbackListAdd: * @conn: pointer to the connection @@ -767,184 +443,6 @@ virDomainEventCallbackListAdd(virConnectPtr conn, } - -static int -virObjectEventCallbackListEventID(virConnectPtr conn, - virObjectEventCallbackListPtr cbList, - int callbackID) -{ - size_t i; - - for (i = 0; i < cbList->count; i++) { - if (cbList->callbacks[i]->deleted) - continue; - - if (cbList->callbacks[i]->callbackID == callbackID && - cbList->callbacks[i]->conn == conn) - return cbList->callbacks[i]->eventID; - } - - return -1; -} - - -/** - * virObjectEventQueueClear: - * @queue: pointer to the queue - * - * Removes all elements from the queue - */ -static void -virObjectEventQueueClear(virObjectEventQueuePtr queue) -{ - size_t i; - if (!queue) - return; - - for (i = 0; i < queue->count; i++) { - virObjectUnref(queue->events[i]); - } - VIR_FREE(queue->events); - queue->count = 0; -} - -/** - * virObjectEventQueueFree: - * @queue: pointer to the queue - * - * Free the memory in the queue. We process this like a list here - */ -static void -virObjectEventQueueFree(virObjectEventQueuePtr queue) -{ - if (!queue) - return; - - virObjectEventQueueClear(queue); - VIR_FREE(queue); -} - -static virObjectEventQueuePtr -virObjectEventQueueNew(void) -{ - virObjectEventQueuePtr ret; - - ignore_value(VIR_ALLOC(ret)); - return ret; -} - -static void -virObjectEventStateLock(virObjectEventStatePtr state) -{ - virMutexLock(&state->lock); -} - -static void -virObjectEventStateUnlock(virObjectEventStatePtr state) -{ - virMutexUnlock(&state->lock); -} - -/** - * virObjectEventStateFree: - * @list: virObjectEventStatePtr to free - * - * Free a virObjectEventStatePtr and its members, and unregister the timer. - */ -void -virObjectEventStateFree(virObjectEventStatePtr state) -{ - if (!state) - return; - - virObjectEventCallbackListFree(state->callbacks); - virObjectEventQueueFree(state->queue); - - if (state->timer != -1) - virEventRemoveTimeout(state->timer); - - virMutexDestroy(&state->lock); - VIR_FREE(state); -} - - -static void virObjectEventStateFlush(virObjectEventStatePtr state); - -static void -virObjectEventTimer(int timer ATTRIBUTE_UNUSED, void *opaque) -{ - virObjectEventStatePtr state = opaque; - - virObjectEventStateFlush(state); -} - -/** - * virObjectEventStateNew: - */ -virObjectEventStatePtr -virObjectEventStateNew(void) -{ - virObjectEventStatePtr state = NULL; - - if (VIR_ALLOC(state) < 0) - goto error; - - if (virMutexInit(&state->lock) < 0) { - virReportSystemError(errno, "%s", - _("unable to initialize state mutex")); - VIR_FREE(state); - goto error; - } - - if (VIR_ALLOC(state->callbacks) < 0) - goto error; - - if (!(state->queue = virObjectEventQueueNew())) - goto error; - - state->timer = -1; - - return state; - -error: - virObjectEventStateFree(state); - return NULL; -} - -static void *virObjectEventNew(virClassPtr klass, - int eventID, - int id, - const char *name, - const unsigned char *uuid) -{ - virObjectEventPtr event; - - if (virObjectEventInitialize() < 0) - return NULL; - - if (!virClassIsDerivedFrom(klass, virObjectEventClass)) { - virReportInvalidArg(klass, - _("Class %s must derive from virObjectEvent"), - virClassName(klass)); - return NULL; - } - - if (!(event = virObjectNew(klass))) - return NULL; - - event->eventID = eventID; - - if (VIR_STRDUP(event->meta.name, name) < 0) { - VIR_FREE(event); - return NULL; - } - event->meta.id = id; - memcpy(event->meta.uuid, uuid, VIR_UUID_BUFLEN); - - VIR_DEBUG("obj=%p", event); - return event; -} - static void *virDomainEventNew(virClassPtr klass, int eventID, int id, @@ -953,7 +451,7 @@ static void *virDomainEventNew(virClassPtr klass, { virDomainEventPtr event; - if (virObjectEventInitialize() < 0) + if (virDomainEventsInitialize() < 0) return NULL; if (!virClassIsDerivedFrom(klass, virDomainEventClass)) { @@ -1611,42 +1109,8 @@ virObjectEventPtr virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom, devAlias); } -/** - * virObjectEventQueuePush: - * @evtQueue: the object event queue - * @event: the event to add - * - * Internal function to push to the back of a virObjectEventQueue - * - * Returns: 0 on success, -1 on failure - */ -static int -virObjectEventQueuePush(virObjectEventQueuePtr evtQueue, - virObjectEventPtr event) -{ - if (!evtQueue) { - return -1; - } - /* Make space on queue */ - if (VIR_REALLOC_N(evtQueue->events, - evtQueue->count + 1) < 0) - return -1; - - evtQueue->events[evtQueue->count] = event; - evtQueue->count++; - return 0; -} - - -typedef void (*virObjectEventDispatchFunc)(virConnectPtr conn, - virObjectEventPtr event, - virConnectObjectEventGenericCallback cb, - void *cbopaque, - void *opaque); - - -static void +void virDomainEventDispatchDefaultFunc(virConnectPtr conn, virObjectEventPtr event, virConnectDomainEventGenericCallback cb, @@ -1830,207 +1294,6 @@ cleanup: } -static int virObjectEventDispatchMatchCallback(virObjectEventPtr event, - virObjectEventCallbackPtr cb) -{ - if (!cb) - return 0; - if (cb->deleted) - return 0; - if (cb->eventID != virObjectEventGetEventID(event)) - return 0; - - if (cb->meta) { - /* Deliberately ignoring 'id' for matching, since that - * will cause problems when a domain switches between - * running & shutoff states & ignoring 'name' since - * Xen sometimes renames guests during migration, thus - * leaving 'uuid' as the only truly reliable ID we can use*/ - - if (memcmp(event->meta.uuid, cb->meta->uuid, VIR_UUID_BUFLEN) == 0) - return 1; - - return 0; - } else { - return 1; - } -} - - -static void -virObjectEventDispatch(virObjectEventPtr event, - virObjectEventCallbackListPtr callbacks, - virObjectEventDispatchFunc dispatch, - void *opaque) -{ - size_t i; - /* Cache this now, since we may be dropping the lock, - and have more callbacks added. We're guaranteed not - to have any removed */ - int cbCount = callbacks->count; - - for (i = 0; i < cbCount; i++) { - if (!virObjectEventDispatchMatchCallback(event, callbacks->callbacks[i])) - continue; - - (*dispatch)(callbacks->callbacks[i]->conn, - event, - callbacks->callbacks[i]->cb, - callbacks->callbacks[i]->opaque, - opaque); - } -} - - -static void -virObjectEventQueueDispatch(virObjectEventQueuePtr queue, - virObjectEventCallbackListPtr callbacks, - virObjectEventDispatchFunc dispatch, - void *opaque) -{ - size_t i; - - for (i = 0; i < queue->count; i++) { - virObjectEventDispatch(queue->events[i], callbacks, dispatch, opaque); - virObjectUnref(queue->events[i]); - } - VIR_FREE(queue->events); - queue->count = 0; -} - -void -virObjectEventStateQueue(virObjectEventStatePtr state, - virObjectEventPtr event) -{ - if (state->timer < 0) { - virObjectUnref(event); - return; - } - - virObjectEventStateLock(state); - - if (virObjectEventQueuePush(state->queue, event) < 0) { - VIR_DEBUG("Error adding event to queue"); - virObjectUnref(event); - } - - if (state->queue->count == 1) - virEventUpdateTimeout(state->timer, 0); - virObjectEventStateUnlock(state); -} - - -static void -virObjectEventStateDispatchFunc(virConnectPtr conn, - virObjectEventPtr event, - virConnectObjectEventGenericCallback cb, - void *cbopaque, - void *opaque) -{ - virObjectEventStatePtr state = opaque; - virEventNamespaceID namespace = (event->eventID & 0xFF00) >> 8; - - /* Drop the lock whle dispatching, for sake of re-entrancy */ - virObjectEventStateUnlock(state); - switch (namespace) - { - case VIR_EVENT_NAMESPACE_DOMAIN: - virDomainEventDispatchDefaultFunc(conn, event, - VIR_DOMAIN_EVENT_CALLBACK(cb), cbopaque, NULL); - break; - } - virObjectEventStateLock(state); -} - - -static void -virObjectEventStateFlush(virObjectEventStatePtr state) -{ - virObjectEventQueue tempQueue; - - virObjectEventStateLock(state); - state->isDispatching = true; - - /* Copy the queue, so we're reentrant safe when dispatchFunc drops the - * driver lock */ - tempQueue.count = state->queue->count; - tempQueue.events = state->queue->events; - state->queue->count = 0; - state->queue->events = NULL; - virEventUpdateTimeout(state->timer, -1); - - virObjectEventQueueDispatch(&tempQueue, - state->callbacks, - virObjectEventStateDispatchFunc, - state); - - /* Purge any deleted callbacks */ - virObjectEventCallbackListPurgeMarked(state->callbacks); - - state->isDispatching = false; - virObjectEventStateUnlock(state); -} - - -/** - * virObjectEventStateRegisterID: - * @conn: connection to associate with callback - * @state: domain event state - * @eventID: ID of the event type to register for - * @cb: function to remove from event - * @opaque: data blob to pass to callback - * @freecb: callback to free @opaque - * @callbackID: filled with callback ID - * - * Register the function @callbackID with connection @conn, - * from @state, for events of type @eventID. - * - * Returns: the number of callbacks now registered, or -1 on error - */ -int -virObjectEventStateRegisterID(virConnectPtr conn, - virObjectEventStatePtr state, - unsigned char *uuid, - const char *name, - int id, - int eventID, - virConnectObjectEventGenericCallback cb, - void *opaque, - virFreeCallback freecb, - int *callbackID) -{ - int ret = -1; - - virObjectEventStateLock(state); - - if ((state->callbacks->count == 0) && - (state->timer == -1) && - (state->timer = virEventAddTimeout(-1, - virObjectEventTimer, - state, - NULL)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("could not initialize domain event timer")); - goto cleanup; - } - - ret = virObjectEventCallbackListAddID(conn, state->callbacks, - uuid, name, id, eventID, cb, opaque, freecb, - callbackID); - - if (ret == -1 && - state->callbacks->count == 0 && - state->timer != -1) { - virEventRemoveTimeout(state->timer); - state->timer = -1; - } - -cleanup: - virObjectEventStateUnlock(state); - return ret; -} - - /** * virDomainEventStateRegister: * @conn: connection to associate with callback @@ -2155,67 +1418,3 @@ virDomainEventStateDeregister(virConnectPtr conn, virObjectEventStateUnlock(state); return ret; } - - -/** - * virObjectEventStateDeregisterID: - * @conn: connection to associate with callback - * @state: object event state - * @callbackID: ID of the function to remove from event - * - * Unregister the function @callbackID with connection @conn, - * from @state, for events. - * - * Returns: the number of callbacks still registered, or -1 on error - */ -int -virObjectEventStateDeregisterID(virConnectPtr conn, - virObjectEventStatePtr state, - int callbackID) -{ - int ret; - - virObjectEventStateLock(state); - if (state->isDispatching) - ret = virObjectEventCallbackListMarkDeleteID(conn, - state->callbacks, callbackID); - else - ret = virObjectEventCallbackListRemoveID(conn, - state->callbacks, callbackID); - - if (state->callbacks->count == 0 && - state->timer != -1) { - virEventRemoveTimeout(state->timer); - state->timer = -1; - virObjectEventQueueClear(state->queue); - } - - virObjectEventStateUnlock(state); - return ret; -} - - -/** - * virObjectEventStateEventID: - * @conn: connection associated with the callback - * @state: object event state - * @callbackID: the callback to query - * - * Query what event ID type is associated with the - * callback @callbackID for connection @conn - * - * Returns 0 on success, -1 on error - */ -int -virObjectEventStateEventID(virConnectPtr conn, - virObjectEventStatePtr state, - int callbackID) -{ - int ret; - - virObjectEventStateLock(state); - ret = virObjectEventCallbackListEventID(conn, - state->callbacks, callbackID); - virObjectEventStateUnlock(state); - return ret; -} diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index ec1b3d68b8..c7fa0e31d5 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -3,6 +3,7 @@ * * Copyright (C) 2012 Red Hat, Inc. * Copyright (C) 2008 VirtualIron + * Copyright (C) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -26,29 +27,10 @@ #ifndef __DOMAIN_EVENT_H__ # define __DOMAIN_EVENT_H__ +# include "object_event.h" # include "domain_conf.h" -/** Event IDs are computed in the following way: - virEventNamespaceID << 8 + vir*EventId - */ -typedef enum { - VIR_EVENT_NAMESPACE_DOMAIN = 0, /* 0 to keep value of virDomainEventId unchanged */ -} virEventNamespaceID; - -typedef struct _virObjectEventCallback virObjectEventCallback; -typedef virObjectEventCallback *virObjectEventCallbackPtr; - -/** - * Dispatching domain events that come in while - * in a call / response rpc - */ -typedef struct _virObjectEvent virObjectEvent; -typedef virObjectEvent *virObjectEventPtr; - -typedef struct _virObjectEventState virObjectEventState; -typedef virObjectEventState *virObjectEventStatePtr; - virObjectEventPtr virDomainEventLifecycleNew(int id, const char *name, const unsigned char *uuid, @@ -149,27 +131,6 @@ virObjectEventPtr virDomainEventDeviceRemovedNewFromObj(virDomainObjPtr obj, virObjectEventPtr virDomainEventDeviceRemovedNewFromDom(virDomainPtr dom, const char *devAlias); -void virObjectEventStateFree(virObjectEventStatePtr state); -virObjectEventStatePtr -virObjectEventStateNew(void); - -/* - * virConnectObjectEventGenericCallback: - * @conn: the connection pointer - * @obj: the object pointer - * @opaque: application specified data - * - * A generic object event callback handler. Specific events usually - * have a customization with extra parameters - */ -typedef void (*virConnectObjectEventGenericCallback)(virConnectPtr conn, - void *obj, - void *opaque); - -void -virObjectEventStateQueue(virObjectEventStatePtr state, - virObjectEventPtr event) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int virDomainEventStateRegister(virConnectPtr conn, virObjectEventStatePtr state, virConnectDomainEventCallback callback, @@ -190,27 +151,12 @@ virDomainEventStateDeregister(virConnectPtr conn, virObjectEventStatePtr state, virConnectDomainEventCallback callback) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); -int -virObjectEventStateRegisterID(virConnectPtr conn, - virObjectEventStatePtr state, - unsigned char *uuid, - const char *name, - int id, - int eventID, - virConnectObjectEventGenericCallback cb, - void *opaque, - virFreeCallback freecb, - int *callbackID) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(7); -int -virObjectEventStateDeregisterID(virConnectPtr conn, - virObjectEventStatePtr state, - int callbackID) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -int -virObjectEventStateEventID(virConnectPtr conn, - virObjectEventStatePtr state, - int callbackID) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +void +virDomainEventDispatchDefaultFunc(virConnectPtr conn, + virObjectEventPtr event, + virConnectDomainEventGenericCallback cb, + void *cbopaque, + void *opaque); #endif diff --git a/src/conf/object_event.c b/src/conf/object_event.c new file mode 100644 index 0000000000..fc4d9bbcb7 --- /dev/null +++ b/src/conf/object_event.c @@ -0,0 +1,792 @@ +/* + * object_event.c: object event queue processing helpers + * + * Copyright (C) 2010-2013 Red Hat, Inc. + * Copyright (C) 2008 VirtualIron + * Copyright (C) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Ben Guthro + */ + +#include + +#include "domain_event.h" +#include "object_event.h" +#include "object_event_private.h" +#include "virlog.h" +#include "datatypes.h" +#include "viralloc.h" +#include "virerror.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +struct _virObjectEventQueue { + unsigned int count; + virObjectEventPtr *events; +}; + +static virClassPtr virObjectEventClass; + +static void virObjectEventDispose(void *obj); + +static int virObjectEventOnceInit(void) +{ + if (!(virObjectEventClass = + virClassNew(virClassForObject(), + "virObjectEvent", + sizeof(virObjectEvent), + virObjectEventDispose))) + return -1; + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virObjectEvent) + +virClassPtr virClassForObjectEvent(void) +{ + if (virObjectEventInitialize() < 0) + return NULL; + return virObjectEventClass; +} + +int virObjectEventGetEventID(void *anyobj) +{ + virObjectEventPtr obj = anyobj; + + if (!virObjectIsClass(obj, virClassForObjectEvent())) { + VIR_WARN("Object %p (%s) is not a virObjectEvent instance", + obj, obj ? virClassName(obj->parent.klass) : "(unknown)"); + return -1; + } + return obj->eventID; +} + +static void virObjectEventDispose(void *obj) +{ + virObjectEventPtr event = obj; + + VIR_DEBUG("obj=%p", event); + + VIR_FREE(event->meta.name); +} + +/** + * virObjectEventCallbackListFree: + * @list: event callback list head + * + * Free the memory in the domain event callback list + */ +static void +virObjectEventCallbackListFree(virObjectEventCallbackListPtr list) +{ + size_t i; + if (!list) + return; + + for (i=0; icount; i++) { + virFreeCallback freecb = list->callbacks[i]->freecb; + if (freecb) + (*freecb)(list->callbacks[i]->opaque); + VIR_FREE(list->callbacks[i]); + } + VIR_FREE(list->callbacks); + VIR_FREE(list); +} + + +/** + * virObjectEventCallbackListRemoveID: + * @conn: pointer to the connection + * @cbList: the list + * @callback: the callback to remove + * + * Internal function to remove a callback from a virObjectEventCallbackListPtr + */ +static int +virObjectEventCallbackListRemoveID(virConnectPtr conn, + virObjectEventCallbackListPtr cbList, + int callbackID) +{ + int ret = 0; + size_t i; + for (i = 0; i < cbList->count; i++) { + if (cbList->callbacks[i]->callbackID == callbackID && + cbList->callbacks[i]->conn == conn) { + virFreeCallback freecb = cbList->callbacks[i]->freecb; + if (freecb) + (*freecb)(cbList->callbacks[i]->opaque); + virObjectUnref(cbList->callbacks[i]->conn); + VIR_FREE(cbList->callbacks[i]); + + if (i < (cbList->count - 1)) + memmove(cbList->callbacks + i, + cbList->callbacks + i + 1, + sizeof(*(cbList->callbacks)) * + (cbList->count - (i + 1))); + + if (VIR_REALLOC_N(cbList->callbacks, + cbList->count - 1) < 0) { + ; /* Failure to reduce memory allocation isn't fatal */ + } + cbList->count--; + + for (i = 0; i < cbList->count; i++) { + if (!cbList->callbacks[i]->deleted) + ret++; + } + return ret; + } + } + + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not find event callback for removal")); + return -1; +} + + +static int +virObjectEventCallbackListMarkDeleteID(virConnectPtr conn, + virObjectEventCallbackListPtr cbList, + int callbackID) +{ + int ret = 0; + size_t i; + for (i = 0; i < cbList->count; i++) { + if (cbList->callbacks[i]->callbackID == callbackID && + cbList->callbacks[i]->conn == conn) { + cbList->callbacks[i]->deleted = 1; + for (i = 0; i < cbList->count; i++) { + if (!cbList->callbacks[i]->deleted) + ret++; + } + return ret; + } + } + + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not find event callback for deletion")); + return -1; +} + + +static int +virObjectEventCallbackListPurgeMarked(virObjectEventCallbackListPtr cbList) +{ + int old_count = cbList->count; + int n; + for (n = 0; n < cbList->count; n++) { + if (cbList->callbacks[n]->deleted) { + virFreeCallback freecb = cbList->callbacks[n]->freecb; + if (freecb) + (*freecb)(cbList->callbacks[n]->opaque); + virObjectUnref(cbList->callbacks[n]->conn); + VIR_FREE(cbList->callbacks[n]); + + if (n < (cbList->count - 1)) + memmove(cbList->callbacks + n, + cbList->callbacks + n + 1, + sizeof(*(cbList->callbacks)) * + (cbList->count - (n + 1))); + cbList->count--; + n--; + } + } + if (cbList->count < old_count && + VIR_REALLOC_N(cbList->callbacks, cbList->count) < 0) { + ; /* Failure to reduce memory allocation isn't fatal */ + } + return 0; +} + + +/** + * virObjectEventCallbackListAddID: + * @conn: pointer to the connection + * @cbList: the list + * @uuid: the uuid of the object to filter on + * @name: the name of the object to filter on + * @id: the ID of the object to filter on + * @eventID: the event ID + * @callback: the callback to add + * @opaque: opaque data tio pass to callback + * @callbackID: filled with callback ID + * + * Internal function to add a callback from a virObjectEventCallbackListPtr + */ +int +virObjectEventCallbackListAddID(virConnectPtr conn, + virObjectEventCallbackListPtr cbList, + unsigned char uuid[VIR_UUID_BUFLEN], + const char *name, + int id, + int eventID, + virConnectObjectEventGenericCallback callback, + void *opaque, + virFreeCallback freecb, + int *callbackID) +{ + virObjectEventCallbackPtr event; + size_t i; + int ret = 0; + + /* Check incoming */ + if (!cbList) { + return -1; + } + + /* check if we already have this callback on our list */ + for (i = 0; i < cbList->count; i++) { + if (cbList->callbacks[i]->cb == VIR_OBJECT_EVENT_CALLBACK(callback) && + cbList->callbacks[i]->eventID == eventID && + cbList->callbacks[i]->conn == conn && + ((uuid && cbList->callbacks[i]->meta && + memcmp(cbList->callbacks[i]->meta->uuid, + uuid, VIR_UUID_BUFLEN) == 0) || + (!uuid && !cbList->callbacks[i]->meta))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("event callback already tracked")); + return -1; + } + } + /* Allocate new event */ + if (VIR_ALLOC(event) < 0) + goto error; + event->conn = conn; + event->cb = callback; + event->eventID = eventID; + event->opaque = opaque; + event->freecb = freecb; + + if (name && uuid && id > 0) { + if (VIR_ALLOC(event->meta) < 0) + goto error; + if (VIR_STRDUP(event->meta->name, name) < 0) + goto error; + memcpy(event->meta->uuid, uuid, VIR_UUID_BUFLEN); + event->meta->id = id; + } + + /* Make space on list */ + if (VIR_REALLOC_N(cbList->callbacks, cbList->count + 1) < 0) + goto error; + + virObjectRef(event->conn); + + cbList->callbacks[cbList->count] = event; + cbList->count++; + + event->callbackID = cbList->nextID++; + + for (i = 0; i < cbList->count; i++) { + if (cbList->callbacks[i]->eventID == eventID && + cbList->callbacks[i]->conn == conn && + !cbList->callbacks[i]->deleted) + ret++; + } + + if (callbackID) + *callbackID = event->callbackID; + + return ret; + +error: + if (event) { + if (event->meta) + VIR_FREE(event->meta->name); + VIR_FREE(event->meta); + } + VIR_FREE(event); + return -1; +} + + +static int +virObjectEventCallbackListEventID(virConnectPtr conn, + virObjectEventCallbackListPtr cbList, + int callbackID) +{ + size_t i; + + for (i = 0; i < cbList->count; i++) { + if (cbList->callbacks[i]->deleted) + continue; + + if (cbList->callbacks[i]->callbackID == callbackID && + cbList->callbacks[i]->conn == conn) + return cbList->callbacks[i]->eventID; + } + + return -1; +} + + +/** + * virObjectEventQueueClear: + * @queue: pointer to the queue + * + * Removes all elements from the queue + */ +void +virObjectEventQueueClear(virObjectEventQueuePtr queue) +{ + size_t i; + if (!queue) + return; + + for (i = 0; i < queue->count; i++) { + virObjectUnref(queue->events[i]); + } + VIR_FREE(queue->events); + queue->count = 0; +} + +/** + * virObjectEventQueueFree: + * @queue: pointer to the queue + * + * Free the memory in the queue. We process this like a list here + */ +static void +virObjectEventQueueFree(virObjectEventQueuePtr queue) +{ + if (!queue) + return; + + virObjectEventQueueClear(queue); + VIR_FREE(queue); +} + +static virObjectEventQueuePtr +virObjectEventQueueNew(void) +{ + virObjectEventQueuePtr ret; + + ignore_value(VIR_ALLOC(ret)); + return ret; +} + +void +virObjectEventStateLock(virObjectEventStatePtr state) +{ + virMutexLock(&state->lock); +} + +void +virObjectEventStateUnlock(virObjectEventStatePtr state) +{ + virMutexUnlock(&state->lock); +} + +/** + * virObjectEventStateFree: + * @list: virObjectEventStatePtr to free + * + * Free a virObjectEventStatePtr and its members, and unregister the timer. + */ +void +virObjectEventStateFree(virObjectEventStatePtr state) +{ + if (!state) + return; + + virObjectEventCallbackListFree(state->callbacks); + virObjectEventQueueFree(state->queue); + + if (state->timer != -1) + virEventRemoveTimeout(state->timer); + + virMutexDestroy(&state->lock); + VIR_FREE(state); +} + + +static void virObjectEventStateFlush(virObjectEventStatePtr state); + +void +virObjectEventTimer(int timer ATTRIBUTE_UNUSED, void *opaque) +{ + virObjectEventStatePtr state = opaque; + + virObjectEventStateFlush(state); +} + +/** + * virObjectEventStateNew: + */ +virObjectEventStatePtr +virObjectEventStateNew(void) +{ + virObjectEventStatePtr state = NULL; + + if (VIR_ALLOC(state) < 0) + goto error; + + if (virMutexInit(&state->lock) < 0) { + virReportSystemError(errno, "%s", + _("unable to initialize state mutex")); + VIR_FREE(state); + goto error; + } + + if (VIR_ALLOC(state->callbacks) < 0) + goto error; + + if (!(state->queue = virObjectEventQueueNew())) + goto error; + + state->timer = -1; + + return state; + +error: + virObjectEventStateFree(state); + return NULL; +} + +void *virObjectEventNew(virClassPtr klass, + int eventID, + int id, + const char *name, + const unsigned char *uuid) +{ + virObjectEventPtr event; + + if (virObjectEventInitialize() < 0) + return NULL; + + if (!virClassIsDerivedFrom(klass, virObjectEventClass)) { + virReportInvalidArg(klass, + _("Class %s must derive from virObjectEvent"), + virClassName(klass)); + return NULL; + } + + if (!(event = virObjectNew(klass))) + return NULL; + + event->eventID = eventID; + + if (VIR_STRDUP(event->meta.name, name) < 0) { + VIR_FREE(event); + return NULL; + } + event->meta.id = id; + memcpy(event->meta.uuid, uuid, VIR_UUID_BUFLEN); + + VIR_DEBUG("obj=%p", event); + return event; +} + +/** + * virObjectEventQueuePush: + * @evtQueue: the object event queue + * @event: the event to add + * + * Internal function to push to the back of a virObjectEventQueue + * + * Returns: 0 on success, -1 on failure + */ +static int +virObjectEventQueuePush(virObjectEventQueuePtr evtQueue, + virObjectEventPtr event) +{ + if (!evtQueue) { + return -1; + } + + /* Make space on queue */ + if (VIR_REALLOC_N(evtQueue->events, + evtQueue->count + 1) < 0) + return -1; + + evtQueue->events[evtQueue->count] = event; + evtQueue->count++; + return 0; +} + + +typedef void (*virObjectEventDispatchFunc)(virConnectPtr conn, + virObjectEventPtr event, + virConnectObjectEventGenericCallback cb, + void *cbopaque, + void *opaque); + + +static int virObjectEventDispatchMatchCallback(virObjectEventPtr event, + virObjectEventCallbackPtr cb) +{ + if (!cb) + return 0; + if (cb->deleted) + return 0; + if (cb->eventID != virObjectEventGetEventID(event)) + return 0; + + if (cb->meta) { + /* Deliberately ignoring 'id' for matching, since that + * will cause problems when a domain switches between + * running & shutoff states & ignoring 'name' since + * Xen sometimes renames guests during migration, thus + * leaving 'uuid' as the only truly reliable ID we can use*/ + + if (memcmp(event->meta.uuid, cb->meta->uuid, VIR_UUID_BUFLEN) == 0) + return 1; + + return 0; + } else { + return 1; + } +} + + +static void +virObjectEventDispatch(virObjectEventPtr event, + virObjectEventCallbackListPtr callbacks, + virObjectEventDispatchFunc dispatch, + void *opaque) +{ + size_t i; + /* Cache this now, since we may be dropping the lock, + and have more callbacks added. We're guaranteed not + to have any removed */ + int cbCount = callbacks->count; + + for (i = 0; i < cbCount; i++) { + if (!virObjectEventDispatchMatchCallback(event, callbacks->callbacks[i])) + continue; + + (*dispatch)(callbacks->callbacks[i]->conn, + event, + callbacks->callbacks[i]->cb, + callbacks->callbacks[i]->opaque, + opaque); + } +} + + +static void +virObjectEventQueueDispatch(virObjectEventQueuePtr queue, + virObjectEventCallbackListPtr callbacks, + virObjectEventDispatchFunc dispatch, + void *opaque) +{ + size_t i; + + for (i = 0; i < queue->count; i++) { + virObjectEventDispatch(queue->events[i], callbacks, dispatch, opaque); + virObjectUnref(queue->events[i]); + } + VIR_FREE(queue->events); + queue->count = 0; +} + +void +virObjectEventStateQueue(virObjectEventStatePtr state, + virObjectEventPtr event) +{ + if (state->timer < 0) { + virObjectUnref(event); + return; + } + + virObjectEventStateLock(state); + + if (virObjectEventQueuePush(state->queue, event) < 0) { + VIR_DEBUG("Error adding event to queue"); + virObjectUnref(event); + } + + if (state->queue->count == 1) + virEventUpdateTimeout(state->timer, 0); + virObjectEventStateUnlock(state); +} + + +static void +virObjectEventStateDispatchFunc(virConnectPtr conn, + virObjectEventPtr event, + virConnectObjectEventGenericCallback cb, + void *cbopaque, + void *opaque) +{ + virObjectEventStatePtr state = opaque; + virEventNamespaceID namespace = (event->eventID & 0xFF00) >> 8; + + /* Drop the lock whle dispatching, for sake of re-entrancy */ + virObjectEventStateUnlock(state); + switch (namespace) + { + case VIR_EVENT_NAMESPACE_DOMAIN: + virDomainEventDispatchDefaultFunc(conn, event, + VIR_DOMAIN_EVENT_CALLBACK(cb), cbopaque, NULL); + break; + } + virObjectEventStateLock(state); +} + + +static void +virObjectEventStateFlush(virObjectEventStatePtr state) +{ + virObjectEventQueue tempQueue; + + virObjectEventStateLock(state); + state->isDispatching = true; + + /* Copy the queue, so we're reentrant safe when dispatchFunc drops the + * driver lock */ + tempQueue.count = state->queue->count; + tempQueue.events = state->queue->events; + state->queue->count = 0; + state->queue->events = NULL; + virEventUpdateTimeout(state->timer, -1); + + virObjectEventQueueDispatch(&tempQueue, + state->callbacks, + virObjectEventStateDispatchFunc, + state); + + /* Purge any deleted callbacks */ + virObjectEventCallbackListPurgeMarked(state->callbacks); + + state->isDispatching = false; + virObjectEventStateUnlock(state); +} + + +/** + * virObjectEventStateRegisterID: + * @conn: connection to associate with callback + * @state: domain event state + * @eventID: ID of the event type to register for + * @cb: function to remove from event + * @opaque: data blob to pass to callback + * @freecb: callback to free @opaque + * @callbackID: filled with callback ID + * + * Register the function @callbackID with connection @conn, + * from @state, for events of type @eventID. + * + * Returns: the number of callbacks now registered, or -1 on error + */ +int +virObjectEventStateRegisterID(virConnectPtr conn, + virObjectEventStatePtr state, + unsigned char *uuid, + const char *name, + int id, + int eventID, + virConnectObjectEventGenericCallback cb, + void *opaque, + virFreeCallback freecb, + int *callbackID) +{ + int ret = -1; + + virObjectEventStateLock(state); + + if ((state->callbacks->count == 0) && + (state->timer == -1) && + (state->timer = virEventAddTimeout(-1, + virObjectEventTimer, + state, + NULL)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("could not initialize domain event timer")); + goto cleanup; + } + + ret = virObjectEventCallbackListAddID(conn, state->callbacks, + uuid, name, id, eventID, cb, opaque, freecb, + callbackID); + + if (ret == -1 && + state->callbacks->count == 0 && + state->timer != -1) { + virEventRemoveTimeout(state->timer); + state->timer = -1; + } + +cleanup: + virObjectEventStateUnlock(state); + return ret; +} + + +/** + * virObjectEventStateDeregisterID: + * @conn: connection to associate with callback + * @state: object event state + * @callbackID: ID of the function to remove from event + * + * Unregister the function @callbackID with connection @conn, + * from @state, for events. + * + * Returns: the number of callbacks still registered, or -1 on error + */ +int +virObjectEventStateDeregisterID(virConnectPtr conn, + virObjectEventStatePtr state, + int callbackID) +{ + int ret; + + virObjectEventStateLock(state); + if (state->isDispatching) + ret = virObjectEventCallbackListMarkDeleteID(conn, + state->callbacks, callbackID); + else + ret = virObjectEventCallbackListRemoveID(conn, + state->callbacks, callbackID); + + if (state->callbacks->count == 0 && + state->timer != -1) { + virEventRemoveTimeout(state->timer); + state->timer = -1; + virObjectEventQueueClear(state->queue); + } + + virObjectEventStateUnlock(state); + return ret; +} + + +/** + * virObjectEventStateEventID: + * @conn: connection associated with the callback + * @state: object event state + * @callbackID: the callback to query + * + * Query what event ID type is associated with the + * callback @callbackID for connection @conn + * + * Returns 0 on success, -1 on error + */ +int +virObjectEventStateEventID(virConnectPtr conn, + virObjectEventStatePtr state, + int callbackID) +{ + int ret; + + virObjectEventStateLock(state); + ret = virObjectEventCallbackListEventID(conn, + state->callbacks, callbackID); + virObjectEventStateUnlock(state); + return ret; +} diff --git a/src/conf/object_event.h b/src/conf/object_event.h new file mode 100644 index 0000000000..edd3e87f45 --- /dev/null +++ b/src/conf/object_event.h @@ -0,0 +1,97 @@ +/* + * object_event.h: object event queue processing helpers + * + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2008 VirtualIron + * Copyright (C) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Ben Guthro + */ + +#include "internal.h" + +#ifndef __OBJECT_EVENT_H__ +# define __OBJECT_EVENT_H__ + +/** Event IDs are computed in the following way: + virEventNamespaceID << 8 + vir*EventId + */ +typedef enum { + VIR_EVENT_NAMESPACE_DOMAIN = 0, /* 0 to keep value of virDomainEventId unchanged */ +} virEventNamespaceID; + +typedef struct _virObjectEventCallback virObjectEventCallback; +typedef virObjectEventCallback *virObjectEventCallbackPtr; + +/** + * Dispatching domain events that come in while + * in a call / response rpc + */ +typedef struct _virObjectEvent virObjectEvent; +typedef virObjectEvent *virObjectEventPtr; + +typedef struct _virObjectEventState virObjectEventState; +typedef virObjectEventState *virObjectEventStatePtr; + + +void virObjectEventStateFree(virObjectEventStatePtr state); +virObjectEventStatePtr +virObjectEventStateNew(void); + +/* + * virConnectObjectEventGenericCallback: + * @conn: the connection pointer + * @obj: the object pointer + * @opaque: application specified data + * + * A generic object event callback handler. Specific events usually + * have a customization with extra parameters + */ +typedef void (*virConnectObjectEventGenericCallback)(virConnectPtr conn, + void *obj, + void *opaque); + +# define VIR_OBJECT_EVENT_CALLBACK(cb) ((virConnectObjectEventGenericCallback)(cb)) + +void +virObjectEventStateQueue(virObjectEventStatePtr state, + virObjectEventPtr event) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int +virObjectEventStateRegisterID(virConnectPtr conn, + virObjectEventStatePtr state, + unsigned char *uuid, + const char *name, + int id, + int eventID, + virConnectObjectEventGenericCallback cb, + void *opaque, + virFreeCallback freecb, + int *callbackID) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(7); +int +virObjectEventStateDeregisterID(virConnectPtr conn, + virObjectEventStatePtr state, + int callbackID) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int +virObjectEventStateEventID(virConnectPtr conn, + virObjectEventStatePtr state, + int callbackID) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +#endif diff --git a/src/conf/object_event_private.h b/src/conf/object_event_private.h new file mode 100644 index 0000000000..e4ebd95710 --- /dev/null +++ b/src/conf/object_event_private.h @@ -0,0 +1,113 @@ +/* + * object_event_private.h: object event queue processing helpers + * + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2008 VirtualIron + * Copyright (C) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + * Author: Ben Guthro + */ + +#include "datatypes.h" + +#ifndef __OBJECT_EVENT_PRIVATE_H__ +# define __OBJECT_EVENT_PRIVATE_H__ + +struct _virObjectMeta { + int id; + char *name; + unsigned char uuid[VIR_UUID_BUFLEN]; +}; +typedef struct _virObjectMeta virObjectMeta; +typedef virObjectMeta *virObjectMetaPtr; + +struct _virObjectEventCallbackList { + unsigned int nextID; + unsigned int count; + virObjectEventCallbackPtr *callbacks; +}; +typedef struct _virObjectEventCallbackList virObjectEventCallbackList; +typedef virObjectEventCallbackList *virObjectEventCallbackListPtr; + +typedef struct _virObjectEventQueue virObjectEventQueue; +typedef virObjectEventQueue *virObjectEventQueuePtr; + +struct _virObjectEventState { + /* The list of domain event callbacks */ + virObjectEventCallbackListPtr callbacks; + /* The queue of object events */ + virObjectEventQueuePtr queue; + /* Timer for flushing events queue */ + int timer; + /* Flag if we're in process of dispatching */ + bool isDispatching; + virMutex lock; +}; + +struct _virObjectEventCallback { + int callbackID; + int eventID; + virConnectPtr conn; + virObjectMetaPtr meta; + virConnectObjectEventGenericCallback cb; + void *opaque; + virFreeCallback freecb; + int deleted; +}; + +struct _virObjectEvent { + virObject parent; + int eventID; + virObjectMeta meta; +}; + +virClassPtr virClassForObjectEvent(void); + +int virObjectEventGetEventID(void *anyobj); + +int +virObjectEventCallbackListAddID(virConnectPtr conn, + virObjectEventCallbackListPtr cbList, + unsigned char *uuid, + const char *name, + int id, + int eventID, + virConnectObjectEventGenericCallback callback, + void *opaque, + virFreeCallback freecb, + int *callbackID); + +void +virObjectEventQueueClear(virObjectEventQueuePtr queue); + +void +virObjectEventStateLock(virObjectEventStatePtr state); + +void +virObjectEventStateUnlock(virObjectEventStatePtr state); + +void +virObjectEventTimer(int timer, void *opaque); + +void *virObjectEventNew(virClassPtr klass, + int eventID, + int id, + const char *name, + const unsigned char *uuid); + + +#endif diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 36018c5001..3ca20e495b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -452,12 +452,6 @@ virDomainEventTrayChangeNewFromDom; virDomainEventTrayChangeNewFromObj; virDomainEventWatchdogNewFromDom; virDomainEventWatchdogNewFromObj; -virObjectEventStateDeregisterID; -virObjectEventStateEventID; -virObjectEventStateFree; -virObjectEventStateNew; -virObjectEventStateQueue; -virObjectEventStateRegisterID; # conf/domain_nwfilter.h @@ -629,6 +623,15 @@ virNWFilterVarValueGetNthValue; virNWFilterVarValueGetSimple; +# conf/object_event.h +virObjectEventStateDeregisterID; +virObjectEventStateEventID; +virObjectEventStateFree; +virObjectEventStateNew; +virObjectEventStateQueue; +virObjectEventStateRegisterID; + + # conf/secret_conf.h virSecretDefFormat; virSecretDefFree;