[libvirt] [PATCH 0/6] Misc improvements to events code

From: "Daniel P. Berrange" <berrange@redhat.com> This is a followup to the recent network events patches to improve a few things I noticed when testing this out for real. Daniel P. Berrange (6): Move examples/domain-events/event-c to examples/object-events Update event demo program to support network events too Add 'detail' arg to network lifecycle event internals Introduce abstract virNetworkEvent class Remove the event namespace concept Add debug output when registering event handlers Makefile.am | 2 +- configure.ac | 2 +- examples/domain-events/events-c/Makefile.am | 24 - examples/domain-events/events-c/event-test.c | 644 ------------------------- examples/object-events/Makefile.am | 24 + examples/object-events/event-test.c | 685 +++++++++++++++++++++++++++ src/conf/domain_event.c | 18 +- src/conf/domain_event.h | 2 + src/conf/network_event.c | 58 ++- src/conf/network_event.h | 6 +- src/conf/object_event.c | 33 +- src/conf/object_event.h | 11 +- src/conf/object_event_private.h | 2 + src/network/bridge_driver.c | 15 +- src/remote/remote_driver.c | 2 +- src/test/test_driver.c | 15 +- 16 files changed, 828 insertions(+), 715 deletions(-) delete mode 100644 examples/domain-events/events-c/Makefile.am delete mode 100644 examples/domain-events/events-c/event-test.c create mode 100644 examples/object-events/Makefile.am create mode 100644 examples/object-events/event-test.c -- 1.8.3.1

From: "Daniel P. Berrange" <berrange@redhat.com> The domain events demo program isn't really tied to domain events anymore, so rename it to object events. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- Makefile.am | 2 +- configure.ac | 2 +- examples/domain-events/events-c/Makefile.am | 24 - examples/domain-events/events-c/event-test.c | 644 --------------------------- examples/object-events/Makefile.am | 24 + examples/object-events/event-test.c | 644 +++++++++++++++++++++++++++ 6 files changed, 670 insertions(+), 670 deletions(-) delete mode 100644 examples/domain-events/events-c/Makefile.am delete mode 100644 examples/domain-events/events-c/event-test.c create mode 100644 examples/object-events/Makefile.am create mode 100644 examples/object-events/event-test.c diff --git a/Makefile.am b/Makefile.am index 2cbf71a..88c7073 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,7 @@ LCOV = lcov GENHTML = genhtml SUBDIRS = . gnulib/lib include src daemon tools docs gnulib/tests \ - tests po examples/domain-events/events-c examples/hellolibvirt \ + tests po examples/object-events examples/hellolibvirt \ examples/dominfo examples/apparmor examples/xml/nwfilter \ examples/openauth examples/systemtap diff --git a/configure.ac b/configure.ac index 4465e01..d99e0df 100644 --- a/configure.ac +++ b/configure.ac @@ -2554,7 +2554,7 @@ AC_CONFIG_FILES([\ tools/Makefile \ tests/Makefile \ examples/apparmor/Makefile \ - examples/domain-events/events-c/Makefile \ + examples/object-events/Makefile \ examples/dominfo/Makefile \ examples/openauth/Makefile \ examples/hellolibvirt/Makefile \ diff --git a/examples/domain-events/events-c/Makefile.am b/examples/domain-events/events-c/Makefile.am deleted file mode 100644 index 86500a0..0000000 --- a/examples/domain-events/events-c/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -## Copyright (C) 2005-2011, 2013 Red Hat, Inc. -## -## 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 -## <http://www.gnu.org/licenses/>. - -INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ - -I$(top_builddir)/gnulib/lib -I$(top_srcdir)/gnulib/lib \ - -I$(top_srcdir) -noinst_PROGRAMS = event-test -event_test_CFLAGS = $(WARN_CFLAGS) -event_test_SOURCES = event-test.c -event_test_LDADD = $(top_builddir)/src/libvirt.la \ - $(top_builddir)/gnulib/lib/libgnu.la diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c deleted file mode 100644 index 52aa3d0..0000000 --- a/examples/domain-events/events-c/event-test.c +++ /dev/null @@ -1,644 +0,0 @@ -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <inttypes.h> - -#include <libvirt/libvirt.h> -#include <libvirt/virterror.h> - -#define VIR_DEBUG(fmt) printf("%s:%d: " fmt "\n", __func__, __LINE__) -#define STREQ(a,b) (strcmp(a,b) == 0) - -#ifndef ATTRIBUTE_UNUSED -# define ATTRIBUTE_UNUSED __attribute__((__unused__)) -#endif - -int run = 1; - -/* Prototypes */ -const char *eventToString(int event); -int myEventAddHandleFunc (int fd, int event, - virEventHandleCallback cb, - void *opaque, - virFreeCallback ff); -void myEventUpdateHandleFunc(int watch, int event); -int myEventRemoveHandleFunc(int watch); - -int myEventAddTimeoutFunc(int timeout, - virEventTimeoutCallback cb, - void *opaque, - virFreeCallback ff); -void myEventUpdateTimeoutFunc(int timer, int timout); -int myEventRemoveTimeoutFunc(int timer); - -int myEventHandleTypeToPollEvent(virEventHandleType events); -virEventHandleType myPollEventToEventHandleType(int events); - -void usage(const char *pname); - -/* Callback functions */ - - -static void connectClose(virConnectPtr conn ATTRIBUTE_UNUSED, - int reason, - void *opaque ATTRIBUTE_UNUSED) -{ - switch (reason) { - case VIR_CONNECT_CLOSE_REASON_ERROR: - fprintf(stderr, "Connection closed due to I/O error\n"); - break; - case VIR_CONNECT_CLOSE_REASON_EOF: - fprintf(stderr, "Connection closed due to end of file\n"); - break; - case VIR_CONNECT_CLOSE_REASON_KEEPALIVE: - fprintf(stderr, "Connection closed due to keepalive timeout\n"); - break; - case VIR_CONNECT_CLOSE_REASON_CLIENT: - fprintf(stderr, "Connection closed due to client request\n"); - break; - default: - fprintf(stderr, "Connection closed due to unknown reason\n"); - break; - }; - run = 0; -} - -const char *eventToString(int event) { - const char *ret = ""; - switch ((virDomainEventType) event) { - case VIR_DOMAIN_EVENT_DEFINED: - ret ="Defined"; - break; - case VIR_DOMAIN_EVENT_UNDEFINED: - ret ="Undefined"; - break; - case VIR_DOMAIN_EVENT_STARTED: - ret ="Started"; - break; - case VIR_DOMAIN_EVENT_SUSPENDED: - ret ="Suspended"; - break; - case VIR_DOMAIN_EVENT_RESUMED: - ret ="Resumed"; - break; - case VIR_DOMAIN_EVENT_STOPPED: - ret ="Stopped"; - break; - case VIR_DOMAIN_EVENT_SHUTDOWN: - ret = "Shutdown"; - break; - case VIR_DOMAIN_EVENT_PMSUSPENDED: - ret = "PMSuspended"; - break; - case VIR_DOMAIN_EVENT_CRASHED: - ret = "Crashed"; - break; - } - return ret; -} - -static const char *eventDetailToString(int event, int detail) { - const char *ret = ""; - switch ((virDomainEventType) event) { - case VIR_DOMAIN_EVENT_DEFINED: - if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED) - ret = "Added"; - else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED) - ret = "Updated"; - break; - case VIR_DOMAIN_EVENT_UNDEFINED: - if (detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) - ret = "Removed"; - break; - case VIR_DOMAIN_EVENT_STARTED: - switch ((virDomainEventStartedDetailType) detail) { - case VIR_DOMAIN_EVENT_STARTED_BOOTED: - ret = "Booted"; - break; - case VIR_DOMAIN_EVENT_STARTED_MIGRATED: - ret = "Migrated"; - break; - case VIR_DOMAIN_EVENT_STARTED_RESTORED: - ret = "Restored"; - break; - case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT: - ret = "Snapshot"; - break; - case VIR_DOMAIN_EVENT_STARTED_WAKEUP: - ret = "Event wakeup"; - break; - } - break; - case VIR_DOMAIN_EVENT_SUSPENDED: - switch ((virDomainEventSuspendedDetailType) detail) { - case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED: - ret = "Paused"; - break; - case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: - ret = "Migrated"; - break; - case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR: - ret = "I/O Error"; - break; - case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG: - ret = "Watchdog"; - break; - case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED: - ret = "Restored"; - break; - case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: - ret = "Snapshot"; - break; - case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR: - ret = "API error"; - break; - } - break; - case VIR_DOMAIN_EVENT_RESUMED: - switch ((virDomainEventResumedDetailType) detail) { - case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED: - ret = "Unpaused"; - break; - case VIR_DOMAIN_EVENT_RESUMED_MIGRATED: - ret = "Migrated"; - break; - case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT: - ret = "Snapshot"; - break; - } - break; - case VIR_DOMAIN_EVENT_STOPPED: - switch ((virDomainEventStoppedDetailType) detail) { - case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN: - ret = "Shutdown"; - break; - case VIR_DOMAIN_EVENT_STOPPED_DESTROYED: - ret = "Destroyed"; - break; - case VIR_DOMAIN_EVENT_STOPPED_CRASHED: - ret = "Crashed"; - break; - case VIR_DOMAIN_EVENT_STOPPED_MIGRATED: - ret = "Migrated"; - break; - case VIR_DOMAIN_EVENT_STOPPED_SAVED: - ret = "Saved"; - break; - case VIR_DOMAIN_EVENT_STOPPED_FAILED: - ret = "Failed"; - break; - case VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT: - ret = "Snapshot"; - break; - } - break; - case VIR_DOMAIN_EVENT_SHUTDOWN: - switch ((virDomainEventShutdownDetailType) detail) { - case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: - ret = "Finished"; - break; - } - break; - case VIR_DOMAIN_EVENT_PMSUSPENDED: - switch ((virDomainEventPMSuspendedDetailType) detail) { - case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY: - ret = "Memory"; - break; - case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK: - ret = "Disk"; - break; - } - break; - case VIR_DOMAIN_EVENT_CRASHED: - switch ((virDomainEventCrashedDetailType) detail) { - case VIR_DOMAIN_EVENT_CRASHED_PANICKED: - ret = "Panicked"; - break; - } - break; - } - return ret; -} - -static int myDomainEventCallback1(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - int event, - int detail, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom), - virDomainGetID(dom), eventToString(event), - eventDetailToString(event, detail)); - return 0; -} - -static int myDomainEventCallback2(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - int event, - int detail, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom), - virDomainGetID(dom), eventToString(event), - eventDetailToString(event, detail)); - return 0; -} - -static int myDomainEventRebootCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) rebooted\n", __func__, virDomainGetName(dom), - virDomainGetID(dom)); - - return 0; -} - -static int myDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - long long offset, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) rtc change %" PRIdMAX "\n", - __func__, virDomainGetName(dom), virDomainGetID(dom), - (intmax_t)offset); - - return 0; -} - -static int myDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - unsigned long long actual, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) balloon change %" PRIuMAX "KB\n", - __func__, virDomainGetName(dom), virDomainGetID(dom), (uintmax_t)actual); - - return 0; -} - -static int myDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - int action, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) watchdog action=%d\n", __func__, virDomainGetName(dom), - virDomainGetID(dom), action); - - return 0; -} - -static int myDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - const char *srcPath, - const char *devAlias, - int action, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) io error path=%s alias=%s action=%d\n", __func__, virDomainGetName(dom), - virDomainGetID(dom), srcPath, devAlias, action); - - return 0; -} - -static int myDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - int phase, - virDomainEventGraphicsAddressPtr local, - virDomainEventGraphicsAddressPtr remote, - const char *authScheme, - virDomainEventGraphicsSubjectPtr subject, - void *opaque ATTRIBUTE_UNUSED) -{ - size_t i; - printf("%s EVENT: Domain %s(%d) graphics ", __func__, virDomainGetName(dom), - virDomainGetID(dom)); - - switch (phase) { - case VIR_DOMAIN_EVENT_GRAPHICS_CONNECT: - printf("connected "); - break; - case VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE: - printf("initialized "); - break; - case VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT: - printf("disconnected "); - break; - } - - printf("local: family=%d node=%s service=%s ", - local->family, local->node, local->service); - printf("remote: family=%d node=%s service=%s ", - remote->family, remote->node, remote->service); - - printf("auth: %s ", authScheme); - for (i = 0; i < subject->nidentity; i++) { - printf(" identity: %s=%s", - subject->identities[i].type, - subject->identities[i].name); - } - printf("\n"); - - return 0; -} - -static int myDomainEventControlErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) control error\n", __func__, virDomainGetName(dom), - virDomainGetID(dom)); - - return 0; -} - - -const char *diskChangeReasonStrings[] = { - "startupPolicy", /* 0 */ - /* add new reason here */ -}; -static int myDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - const char *oldSrcPath, - const char *newSrcPath, - const char *devAlias, - int reason, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) disk change oldSrcPath: %s newSrcPath: %s devAlias: %s reason: %s\n", - __func__, virDomainGetName(dom), virDomainGetID(dom), - oldSrcPath, newSrcPath, devAlias, diskChangeReasonStrings[reason]); - return 0; -} - -const char *trayChangeReasonStrings[] = { - "open", - "close", -}; - -static int myDomainEventTrayChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - const char *devAlias, - int reason, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) removable disk's tray change devAlias: %s reason: %s\n", - __func__, virDomainGetName(dom), virDomainGetID(dom), - devAlias, trayChangeReasonStrings[reason]); - return 0; -} - -static int myDomainEventPMWakeupCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - int reason ATTRIBUTE_UNUSED, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) system pmwakeup\n", - __func__, virDomainGetName(dom), virDomainGetID(dom)); - return 0; -} - -static int myDomainEventPMSuspendCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - int reason ATTRIBUTE_UNUSED, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) system pmsuspend\n", - __func__, virDomainGetName(dom), virDomainGetID(dom)); - return 0; -} - -static int myDomainEventPMSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - int reason ATTRIBUTE_UNUSED, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) system pmsuspend-disk\n", - __func__, virDomainGetName(dom), virDomainGetID(dom)); - return 0; -} - -static int -myDomainEventDeviceRemovedCallback(virConnectPtr conn ATTRIBUTE_UNUSED, - virDomainPtr dom, - const char *devAlias, - void *opaque ATTRIBUTE_UNUSED) -{ - printf("%s EVENT: Domain %s(%d) device removed: %s\n", - __func__, virDomainGetName(dom), virDomainGetID(dom), devAlias); - return 0; -} - -static void myFreeFunc(void *opaque) -{ - char *str = opaque; - printf("%s: Freeing [%s]\n", __func__, str); - free(str); -} - - -/* main test functions */ - -void usage(const char *pname) -{ - printf("%s uri\n", pname); -} - - -static void stop(int sig) -{ - printf("Exiting on signal %d\n", sig); - run = 0; -} - - -int main(int argc, char **argv) -{ - int callback1ret = -1; - int callback2ret = -1; - int callback3ret = -1; - int callback4ret = -1; - int callback5ret = -1; - int callback6ret = -1; - int callback7ret = -1; - int callback8ret = -1; - int callback9ret = -1; - int callback10ret = -1; - int callback11ret = -1; - int callback12ret = -1; - int callback13ret = -1; - int callback14ret = -1; - int callback15ret = -1; - struct sigaction action_stop; - - memset(&action_stop, 0, sizeof(action_stop)); - - action_stop.sa_handler = stop; - - if (argc > 1 && STREQ(argv[1], "--help")) { - usage(argv[0]); - return -1; - } - - if (virInitialize() < 0) { - fprintf(stderr, "Failed to initialize libvirt"); - return -1; - } - - if (virEventRegisterDefaultImpl() < 0) { - virErrorPtr err = virGetLastError(); - fprintf(stderr, "Failed to register event implementation: %s\n", - err && err->message ? err->message: "Unknown error"); - return -1; - } - - virConnectPtr dconn = NULL; - dconn = virConnectOpenAuth(argc > 1 ? argv[1] : NULL, - virConnectAuthPtrDefault, - VIR_CONNECT_RO); - if (!dconn) { - printf("error opening\n"); - return -1; - } - - virConnectRegisterCloseCallback(dconn, - connectClose, NULL, NULL); - - sigaction(SIGTERM, &action_stop, NULL); - sigaction(SIGINT, &action_stop, NULL); - - VIR_DEBUG("Registering domain event cbs"); - - /* Add 2 callbacks to prove this works with more than just one */ - callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1, - strdup("callback 1"), myFreeFunc); - callback2ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_LIFECYCLE, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback2), - strdup("callback 2"), myFreeFunc); - callback3ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_REBOOT, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRebootCallback), - strdup("callback reboot"), myFreeFunc); - callback4ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_RTC_CHANGE, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRTCChangeCallback), - strdup("callback rtcchange"), myFreeFunc); - callback5ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_WATCHDOG, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventWatchdogCallback), - strdup("callback watchdog"), myFreeFunc); - callback6ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_IO_ERROR, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventIOErrorCallback), - strdup("callback io error"), myFreeFunc); - callback7ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_GRAPHICS, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventGraphicsCallback), - strdup("callback graphics"), myFreeFunc); - callback8ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_CONTROL_ERROR, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventControlErrorCallback), - strdup("callback control error"), myFreeFunc); - callback9ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_DISK_CHANGE, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDiskChangeCallback), - strdup("disk change"), myFreeFunc); - callback10ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventTrayChangeCallback), - strdup("tray change"), myFreeFunc); - callback11ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_PMWAKEUP, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMWakeupCallback), - strdup("pmwakeup"), myFreeFunc); - callback12ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_PMSUSPEND, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMSuspendCallback), - strdup("pmsuspend"), myFreeFunc); - callback13ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventBalloonChangeCallback), - strdup("callback balloonchange"), myFreeFunc); - callback14ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMSuspendDiskCallback), - strdup("pmsuspend-disk"), myFreeFunc); - callback15ret = virConnectDomainEventRegisterAny(dconn, - NULL, - VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, - VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDeviceRemovedCallback), - strdup("device removed"), myFreeFunc); - - if ((callback1ret != -1) && - (callback2ret != -1) && - (callback3ret != -1) && - (callback4ret != -1) && - (callback5ret != -1) && - (callback6ret != -1) && - (callback7ret != -1) && - (callback9ret != -1) && - (callback10ret != -1) && - (callback11ret != -1) && - (callback12ret != -1) && - (callback13ret != -1) && - (callback14ret != -1) && - (callback15ret != -1)) { - if (virConnectSetKeepAlive(dconn, 5, 3) < 0) { - virErrorPtr err = virGetLastError(); - fprintf(stderr, "Failed to start keepalive protocol: %s\n", - err && err->message ? err->message : "Unknown error"); - run = 0; - } - - while (run) { - if (virEventRunDefaultImpl() < 0) { - virErrorPtr err = virGetLastError(); - fprintf(stderr, "Failed to run event loop: %s\n", - err && err->message ? err->message : "Unknown error"); - } - } - - VIR_DEBUG("Deregistering event handlers"); - virConnectDomainEventDeregister(dconn, myDomainEventCallback1); - virConnectDomainEventDeregisterAny(dconn, callback2ret); - virConnectDomainEventDeregisterAny(dconn, callback3ret); - virConnectDomainEventDeregisterAny(dconn, callback4ret); - virConnectDomainEventDeregisterAny(dconn, callback5ret); - virConnectDomainEventDeregisterAny(dconn, callback6ret); - virConnectDomainEventDeregisterAny(dconn, callback7ret); - virConnectDomainEventDeregisterAny(dconn, callback9ret); - virConnectDomainEventDeregisterAny(dconn, callback10ret); - virConnectDomainEventDeregisterAny(dconn, callback11ret); - virConnectDomainEventDeregisterAny(dconn, callback12ret); - virConnectDomainEventDeregisterAny(dconn, callback13ret); - virConnectDomainEventDeregisterAny(dconn, callback14ret); - virConnectDomainEventDeregisterAny(dconn, callback15ret); - if (callback8ret != -1) - virConnectDomainEventDeregisterAny(dconn, callback8ret); - } - - VIR_DEBUG("Closing connection"); - if (dconn && virConnectClose(dconn) < 0) { - printf("error closing\n"); - } - - printf("done\n"); - return 0; -} diff --git a/examples/object-events/Makefile.am b/examples/object-events/Makefile.am new file mode 100644 index 0000000..86500a0 --- /dev/null +++ b/examples/object-events/Makefile.am @@ -0,0 +1,24 @@ +## Copyright (C) 2005-2011, 2013 Red Hat, Inc. +## +## 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 +## <http://www.gnu.org/licenses/>. + +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_builddir)/gnulib/lib -I$(top_srcdir)/gnulib/lib \ + -I$(top_srcdir) +noinst_PROGRAMS = event-test +event_test_CFLAGS = $(WARN_CFLAGS) +event_test_SOURCES = event-test.c +event_test_LDADD = $(top_builddir)/src/libvirt.la \ + $(top_builddir)/gnulib/lib/libgnu.la diff --git a/examples/object-events/event-test.c b/examples/object-events/event-test.c new file mode 100644 index 0000000..52aa3d0 --- /dev/null +++ b/examples/object-events/event-test.c @@ -0,0 +1,644 @@ +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <inttypes.h> + +#include <libvirt/libvirt.h> +#include <libvirt/virterror.h> + +#define VIR_DEBUG(fmt) printf("%s:%d: " fmt "\n", __func__, __LINE__) +#define STREQ(a,b) (strcmp(a,b) == 0) + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__((__unused__)) +#endif + +int run = 1; + +/* Prototypes */ +const char *eventToString(int event); +int myEventAddHandleFunc (int fd, int event, + virEventHandleCallback cb, + void *opaque, + virFreeCallback ff); +void myEventUpdateHandleFunc(int watch, int event); +int myEventRemoveHandleFunc(int watch); + +int myEventAddTimeoutFunc(int timeout, + virEventTimeoutCallback cb, + void *opaque, + virFreeCallback ff); +void myEventUpdateTimeoutFunc(int timer, int timout); +int myEventRemoveTimeoutFunc(int timer); + +int myEventHandleTypeToPollEvent(virEventHandleType events); +virEventHandleType myPollEventToEventHandleType(int events); + +void usage(const char *pname); + +/* Callback functions */ + + +static void connectClose(virConnectPtr conn ATTRIBUTE_UNUSED, + int reason, + void *opaque ATTRIBUTE_UNUSED) +{ + switch (reason) { + case VIR_CONNECT_CLOSE_REASON_ERROR: + fprintf(stderr, "Connection closed due to I/O error\n"); + break; + case VIR_CONNECT_CLOSE_REASON_EOF: + fprintf(stderr, "Connection closed due to end of file\n"); + break; + case VIR_CONNECT_CLOSE_REASON_KEEPALIVE: + fprintf(stderr, "Connection closed due to keepalive timeout\n"); + break; + case VIR_CONNECT_CLOSE_REASON_CLIENT: + fprintf(stderr, "Connection closed due to client request\n"); + break; + default: + fprintf(stderr, "Connection closed due to unknown reason\n"); + break; + }; + run = 0; +} + +const char *eventToString(int event) { + const char *ret = ""; + switch ((virDomainEventType) event) { + case VIR_DOMAIN_EVENT_DEFINED: + ret ="Defined"; + break; + case VIR_DOMAIN_EVENT_UNDEFINED: + ret ="Undefined"; + break; + case VIR_DOMAIN_EVENT_STARTED: + ret ="Started"; + break; + case VIR_DOMAIN_EVENT_SUSPENDED: + ret ="Suspended"; + break; + case VIR_DOMAIN_EVENT_RESUMED: + ret ="Resumed"; + break; + case VIR_DOMAIN_EVENT_STOPPED: + ret ="Stopped"; + break; + case VIR_DOMAIN_EVENT_SHUTDOWN: + ret = "Shutdown"; + break; + case VIR_DOMAIN_EVENT_PMSUSPENDED: + ret = "PMSuspended"; + break; + case VIR_DOMAIN_EVENT_CRASHED: + ret = "Crashed"; + break; + } + return ret; +} + +static const char *eventDetailToString(int event, int detail) { + const char *ret = ""; + switch ((virDomainEventType) event) { + case VIR_DOMAIN_EVENT_DEFINED: + if (detail == VIR_DOMAIN_EVENT_DEFINED_ADDED) + ret = "Added"; + else if (detail == VIR_DOMAIN_EVENT_DEFINED_UPDATED) + ret = "Updated"; + break; + case VIR_DOMAIN_EVENT_UNDEFINED: + if (detail == VIR_DOMAIN_EVENT_UNDEFINED_REMOVED) + ret = "Removed"; + break; + case VIR_DOMAIN_EVENT_STARTED: + switch ((virDomainEventStartedDetailType) detail) { + case VIR_DOMAIN_EVENT_STARTED_BOOTED: + ret = "Booted"; + break; + case VIR_DOMAIN_EVENT_STARTED_MIGRATED: + ret = "Migrated"; + break; + case VIR_DOMAIN_EVENT_STARTED_RESTORED: + ret = "Restored"; + break; + case VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT: + ret = "Snapshot"; + break; + case VIR_DOMAIN_EVENT_STARTED_WAKEUP: + ret = "Event wakeup"; + break; + } + break; + case VIR_DOMAIN_EVENT_SUSPENDED: + switch ((virDomainEventSuspendedDetailType) detail) { + case VIR_DOMAIN_EVENT_SUSPENDED_PAUSED: + ret = "Paused"; + break; + case VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED: + ret = "Migrated"; + break; + case VIR_DOMAIN_EVENT_SUSPENDED_IOERROR: + ret = "I/O Error"; + break; + case VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG: + ret = "Watchdog"; + break; + case VIR_DOMAIN_EVENT_SUSPENDED_RESTORED: + ret = "Restored"; + break; + case VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT: + ret = "Snapshot"; + break; + case VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR: + ret = "API error"; + break; + } + break; + case VIR_DOMAIN_EVENT_RESUMED: + switch ((virDomainEventResumedDetailType) detail) { + case VIR_DOMAIN_EVENT_RESUMED_UNPAUSED: + ret = "Unpaused"; + break; + case VIR_DOMAIN_EVENT_RESUMED_MIGRATED: + ret = "Migrated"; + break; + case VIR_DOMAIN_EVENT_RESUMED_FROM_SNAPSHOT: + ret = "Snapshot"; + break; + } + break; + case VIR_DOMAIN_EVENT_STOPPED: + switch ((virDomainEventStoppedDetailType) detail) { + case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN: + ret = "Shutdown"; + break; + case VIR_DOMAIN_EVENT_STOPPED_DESTROYED: + ret = "Destroyed"; + break; + case VIR_DOMAIN_EVENT_STOPPED_CRASHED: + ret = "Crashed"; + break; + case VIR_DOMAIN_EVENT_STOPPED_MIGRATED: + ret = "Migrated"; + break; + case VIR_DOMAIN_EVENT_STOPPED_SAVED: + ret = "Saved"; + break; + case VIR_DOMAIN_EVENT_STOPPED_FAILED: + ret = "Failed"; + break; + case VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT: + ret = "Snapshot"; + break; + } + break; + case VIR_DOMAIN_EVENT_SHUTDOWN: + switch ((virDomainEventShutdownDetailType) detail) { + case VIR_DOMAIN_EVENT_SHUTDOWN_FINISHED: + ret = "Finished"; + break; + } + break; + case VIR_DOMAIN_EVENT_PMSUSPENDED: + switch ((virDomainEventPMSuspendedDetailType) detail) { + case VIR_DOMAIN_EVENT_PMSUSPENDED_MEMORY: + ret = "Memory"; + break; + case VIR_DOMAIN_EVENT_PMSUSPENDED_DISK: + ret = "Disk"; + break; + } + break; + case VIR_DOMAIN_EVENT_CRASHED: + switch ((virDomainEventCrashedDetailType) detail) { + case VIR_DOMAIN_EVENT_CRASHED_PANICKED: + ret = "Panicked"; + break; + } + break; + } + return ret; +} + +static int myDomainEventCallback1(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int event, + int detail, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom), + virDomainGetID(dom), eventToString(event), + eventDetailToString(event, detail)); + return 0; +} + +static int myDomainEventCallback2(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int event, + int detail, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) %s %s\n", __func__, virDomainGetName(dom), + virDomainGetID(dom), eventToString(event), + eventDetailToString(event, detail)); + return 0; +} + +static int myDomainEventRebootCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) rebooted\n", __func__, virDomainGetName(dom), + virDomainGetID(dom)); + + return 0; +} + +static int myDomainEventRTCChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + long long offset, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) rtc change %" PRIdMAX "\n", + __func__, virDomainGetName(dom), virDomainGetID(dom), + (intmax_t)offset); + + return 0; +} + +static int myDomainEventBalloonChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + unsigned long long actual, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) balloon change %" PRIuMAX "KB\n", + __func__, virDomainGetName(dom), virDomainGetID(dom), (uintmax_t)actual); + + return 0; +} + +static int myDomainEventWatchdogCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int action, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) watchdog action=%d\n", __func__, virDomainGetName(dom), + virDomainGetID(dom), action); + + return 0; +} + +static int myDomainEventIOErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *srcPath, + const char *devAlias, + int action, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) io error path=%s alias=%s action=%d\n", __func__, virDomainGetName(dom), + virDomainGetID(dom), srcPath, devAlias, action); + + return 0; +} + +static int myDomainEventGraphicsCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int phase, + virDomainEventGraphicsAddressPtr local, + virDomainEventGraphicsAddressPtr remote, + const char *authScheme, + virDomainEventGraphicsSubjectPtr subject, + void *opaque ATTRIBUTE_UNUSED) +{ + size_t i; + printf("%s EVENT: Domain %s(%d) graphics ", __func__, virDomainGetName(dom), + virDomainGetID(dom)); + + switch (phase) { + case VIR_DOMAIN_EVENT_GRAPHICS_CONNECT: + printf("connected "); + break; + case VIR_DOMAIN_EVENT_GRAPHICS_INITIALIZE: + printf("initialized "); + break; + case VIR_DOMAIN_EVENT_GRAPHICS_DISCONNECT: + printf("disconnected "); + break; + } + + printf("local: family=%d node=%s service=%s ", + local->family, local->node, local->service); + printf("remote: family=%d node=%s service=%s ", + remote->family, remote->node, remote->service); + + printf("auth: %s ", authScheme); + for (i = 0; i < subject->nidentity; i++) { + printf(" identity: %s=%s", + subject->identities[i].type, + subject->identities[i].name); + } + printf("\n"); + + return 0; +} + +static int myDomainEventControlErrorCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) control error\n", __func__, virDomainGetName(dom), + virDomainGetID(dom)); + + return 0; +} + + +const char *diskChangeReasonStrings[] = { + "startupPolicy", /* 0 */ + /* add new reason here */ +}; +static int myDomainEventDiskChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *oldSrcPath, + const char *newSrcPath, + const char *devAlias, + int reason, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) disk change oldSrcPath: %s newSrcPath: %s devAlias: %s reason: %s\n", + __func__, virDomainGetName(dom), virDomainGetID(dom), + oldSrcPath, newSrcPath, devAlias, diskChangeReasonStrings[reason]); + return 0; +} + +const char *trayChangeReasonStrings[] = { + "open", + "close", +}; + +static int myDomainEventTrayChangeCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *devAlias, + int reason, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) removable disk's tray change devAlias: %s reason: %s\n", + __func__, virDomainGetName(dom), virDomainGetID(dom), + devAlias, trayChangeReasonStrings[reason]); + return 0; +} + +static int myDomainEventPMWakeupCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int reason ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) system pmwakeup\n", + __func__, virDomainGetName(dom), virDomainGetID(dom)); + return 0; +} + +static int myDomainEventPMSuspendCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int reason ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) system pmsuspend\n", + __func__, virDomainGetName(dom), virDomainGetID(dom)); + return 0; +} + +static int myDomainEventPMSuspendDiskCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + int reason ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) system pmsuspend-disk\n", + __func__, virDomainGetName(dom), virDomainGetID(dom)); + return 0; +} + +static int +myDomainEventDeviceRemovedCallback(virConnectPtr conn ATTRIBUTE_UNUSED, + virDomainPtr dom, + const char *devAlias, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Domain %s(%d) device removed: %s\n", + __func__, virDomainGetName(dom), virDomainGetID(dom), devAlias); + return 0; +} + +static void myFreeFunc(void *opaque) +{ + char *str = opaque; + printf("%s: Freeing [%s]\n", __func__, str); + free(str); +} + + +/* main test functions */ + +void usage(const char *pname) +{ + printf("%s uri\n", pname); +} + + +static void stop(int sig) +{ + printf("Exiting on signal %d\n", sig); + run = 0; +} + + +int main(int argc, char **argv) +{ + int callback1ret = -1; + int callback2ret = -1; + int callback3ret = -1; + int callback4ret = -1; + int callback5ret = -1; + int callback6ret = -1; + int callback7ret = -1; + int callback8ret = -1; + int callback9ret = -1; + int callback10ret = -1; + int callback11ret = -1; + int callback12ret = -1; + int callback13ret = -1; + int callback14ret = -1; + int callback15ret = -1; + struct sigaction action_stop; + + memset(&action_stop, 0, sizeof(action_stop)); + + action_stop.sa_handler = stop; + + if (argc > 1 && STREQ(argv[1], "--help")) { + usage(argv[0]); + return -1; + } + + if (virInitialize() < 0) { + fprintf(stderr, "Failed to initialize libvirt"); + return -1; + } + + if (virEventRegisterDefaultImpl() < 0) { + virErrorPtr err = virGetLastError(); + fprintf(stderr, "Failed to register event implementation: %s\n", + err && err->message ? err->message: "Unknown error"); + return -1; + } + + virConnectPtr dconn = NULL; + dconn = virConnectOpenAuth(argc > 1 ? argv[1] : NULL, + virConnectAuthPtrDefault, + VIR_CONNECT_RO); + if (!dconn) { + printf("error opening\n"); + return -1; + } + + virConnectRegisterCloseCallback(dconn, + connectClose, NULL, NULL); + + sigaction(SIGTERM, &action_stop, NULL); + sigaction(SIGINT, &action_stop, NULL); + + VIR_DEBUG("Registering domain event cbs"); + + /* Add 2 callbacks to prove this works with more than just one */ + callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1, + strdup("callback 1"), myFreeFunc); + callback2ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_LIFECYCLE, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback2), + strdup("callback 2"), myFreeFunc); + callback3ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_REBOOT, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRebootCallback), + strdup("callback reboot"), myFreeFunc); + callback4ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_RTC_CHANGE, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventRTCChangeCallback), + strdup("callback rtcchange"), myFreeFunc); + callback5ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_WATCHDOG, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventWatchdogCallback), + strdup("callback watchdog"), myFreeFunc); + callback6ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_IO_ERROR, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventIOErrorCallback), + strdup("callback io error"), myFreeFunc); + callback7ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_GRAPHICS, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventGraphicsCallback), + strdup("callback graphics"), myFreeFunc); + callback8ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_CONTROL_ERROR, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventControlErrorCallback), + strdup("callback control error"), myFreeFunc); + callback9ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_DISK_CHANGE, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDiskChangeCallback), + strdup("disk change"), myFreeFunc); + callback10ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_TRAY_CHANGE, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventTrayChangeCallback), + strdup("tray change"), myFreeFunc); + callback11ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_PMWAKEUP, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMWakeupCallback), + strdup("pmwakeup"), myFreeFunc); + callback12ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_PMSUSPEND, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMSuspendCallback), + strdup("pmsuspend"), myFreeFunc); + callback13ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventBalloonChangeCallback), + strdup("callback balloonchange"), myFreeFunc); + callback14ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventPMSuspendDiskCallback), + strdup("pmsuspend-disk"), myFreeFunc); + callback15ret = virConnectDomainEventRegisterAny(dconn, + NULL, + VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, + VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDeviceRemovedCallback), + strdup("device removed"), myFreeFunc); + + if ((callback1ret != -1) && + (callback2ret != -1) && + (callback3ret != -1) && + (callback4ret != -1) && + (callback5ret != -1) && + (callback6ret != -1) && + (callback7ret != -1) && + (callback9ret != -1) && + (callback10ret != -1) && + (callback11ret != -1) && + (callback12ret != -1) && + (callback13ret != -1) && + (callback14ret != -1) && + (callback15ret != -1)) { + if (virConnectSetKeepAlive(dconn, 5, 3) < 0) { + virErrorPtr err = virGetLastError(); + fprintf(stderr, "Failed to start keepalive protocol: %s\n", + err && err->message ? err->message : "Unknown error"); + run = 0; + } + + while (run) { + if (virEventRunDefaultImpl() < 0) { + virErrorPtr err = virGetLastError(); + fprintf(stderr, "Failed to run event loop: %s\n", + err && err->message ? err->message : "Unknown error"); + } + } + + VIR_DEBUG("Deregistering event handlers"); + virConnectDomainEventDeregister(dconn, myDomainEventCallback1); + virConnectDomainEventDeregisterAny(dconn, callback2ret); + virConnectDomainEventDeregisterAny(dconn, callback3ret); + virConnectDomainEventDeregisterAny(dconn, callback4ret); + virConnectDomainEventDeregisterAny(dconn, callback5ret); + virConnectDomainEventDeregisterAny(dconn, callback6ret); + virConnectDomainEventDeregisterAny(dconn, callback7ret); + virConnectDomainEventDeregisterAny(dconn, callback9ret); + virConnectDomainEventDeregisterAny(dconn, callback10ret); + virConnectDomainEventDeregisterAny(dconn, callback11ret); + virConnectDomainEventDeregisterAny(dconn, callback12ret); + virConnectDomainEventDeregisterAny(dconn, callback13ret); + virConnectDomainEventDeregisterAny(dconn, callback14ret); + virConnectDomainEventDeregisterAny(dconn, callback15ret); + if (callback8ret != -1) + virConnectDomainEventDeregisterAny(dconn, callback8ret); + } + + VIR_DEBUG("Closing connection"); + if (dconn && virConnectClose(dconn) < 0) { + printf("error closing\n"); + } + + printf("done\n"); + return 0; +} -- 1.8.3.1

On Wed, 2013-12-11 at 15:28 +0000, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
The domain events demo program isn't really tied to domain events anymore, so rename it to object events.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- Makefile.am | 2 +- configure.ac | 2 +- examples/domain-events/events-c/Makefile.am | 24 - examples/domain-events/events-c/event-test.c | 644 --------------------------- examples/object-events/Makefile.am | 24 + examples/object-events/event-test.c | 644 +++++++++++++++++++++++++++
Changing the /examples/domain-events/events-c/event-test in .gitignore would be great in that patch. And as mentioned on IRC, git config diff.renames true would simplify that patch a lot. -- Cedric

On 11.12.2013 16:28, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
The domain events demo program isn't really tied to domain events anymore, so rename it to object events.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- Makefile.am | 2 +- configure.ac | 2 +- examples/domain-events/events-c/Makefile.am | 24 - examples/domain-events/events-c/event-test.c | 644 --------------------------- examples/object-events/Makefile.am | 24 + examples/object-events/event-test.c | 644 +++++++++++++++++++++++++++ 6 files changed, 670 insertions(+), 670 deletions(-) delete mode 100644 examples/domain-events/events-c/Makefile.am delete mode 100644 examples/domain-events/events-c/event-test.c create mode 100644 examples/object-events/Makefile.am create mode 100644 examples/object-events/event-test.c
Not only .gitingore as Cederic mentions, but the specfile & cfg.mk too. ACK if you fix those. Michal

From: "Daniel P. Berrange" <berrange@redhat.com> --- examples/object-events/event-test.c | 45 +++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/examples/object-events/event-test.c b/examples/object-events/event-test.c index 52aa3d0..6a279cf 100644 --- a/examples/object-events/event-test.c +++ b/examples/object-events/event-test.c @@ -223,6 +223,27 @@ static const char *eventDetailToString(int event, int detail) { return ret; } +static const char * +networkEventToString(int event) +{ + const char *ret = ""; + switch ((virNetworkEventLifecycleType) event) { + case VIR_NETWORK_EVENT_DEFINED: + ret ="Defined"; + break; + case VIR_NETWORK_EVENT_UNDEFINED: + ret ="Undefined"; + break; + case VIR_NETWORK_EVENT_STARTED: + ret ="Started"; + break; + case VIR_NETWORK_EVENT_STOPPED: + ret ="Stopped"; + break; + } + return ret; +} + static int myDomainEventCallback1(virConnectPtr conn ATTRIBUTE_UNUSED, virDomainPtr dom, int event, @@ -432,6 +453,18 @@ myDomainEventDeviceRemovedCallback(virConnectPtr conn ATTRIBUTE_UNUSED, return 0; } +static int myNetworkEventCallback2(virConnectPtr conn ATTRIBUTE_UNUSED, + virNetworkPtr dom, + int event, + int detail, + void *opaque ATTRIBUTE_UNUSED) +{ + printf("%s EVENT: Network %s %s %d\n", __func__, virNetworkGetName(dom), + networkEventToString(event), detail); + return 0; +} + + static void myFreeFunc(void *opaque) { char *str = opaque; @@ -472,6 +505,7 @@ int main(int argc, char **argv) int callback13ret = -1; int callback14ret = -1; int callback15ret = -1; + int callback16ret = -1; struct sigaction action_stop; memset(&action_stop, 0, sizeof(action_stop)); @@ -510,7 +544,7 @@ int main(int argc, char **argv) sigaction(SIGTERM, &action_stop, NULL); sigaction(SIGINT, &action_stop, NULL); - VIR_DEBUG("Registering domain event cbs"); + VIR_DEBUG("Registering event cbs"); /* Add 2 callbacks to prove this works with more than just one */ callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1, @@ -585,6 +619,11 @@ int main(int argc, char **argv) VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDeviceRemovedCallback), strdup("device removed"), myFreeFunc); + callback16ret = virConnectNetworkEventRegisterAny(dconn, + NULL, + VIR_NETWORK_EVENT_ID_LIFECYCLE, + VIR_NETWORK_EVENT_CALLBACK(myNetworkEventCallback2), + strdup("callback 2"), myFreeFunc); if ((callback1ret != -1) && (callback2ret != -1) && @@ -599,7 +638,8 @@ int main(int argc, char **argv) (callback12ret != -1) && (callback13ret != -1) && (callback14ret != -1) && - (callback15ret != -1)) { + (callback15ret != -1) && + (callback16ret != -1)) { if (virConnectSetKeepAlive(dconn, 5, 3) < 0) { virErrorPtr err = virGetLastError(); fprintf(stderr, "Failed to start keepalive protocol: %s\n", @@ -630,6 +670,7 @@ int main(int argc, char **argv) virConnectDomainEventDeregisterAny(dconn, callback13ret); virConnectDomainEventDeregisterAny(dconn, callback14ret); virConnectDomainEventDeregisterAny(dconn, callback15ret); + virConnectNetworkEventDeregisterAny(dconn, callback16ret); if (callback8ret != -1) virConnectDomainEventDeregisterAny(dconn, callback8ret); } -- 1.8.3.1

On 11.12.2013 16:28, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
--- examples/object-events/event-test.c | 45 +++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/examples/object-events/event-test.c b/examples/object-events/event-test.c index 52aa3d0..6a279cf 100644 --- a/examples/object-events/event-test.c +++ b/examples/object-events/event-test.c
@@ -472,6 +505,7 @@ int main(int argc, char **argv) int callback13ret = -1; int callback14ret = -1; int callback15ret = -1; + int callback16ret = -1; struct sigaction action_stop;
memset(&action_stop, 0, sizeof(action_stop)); @@ -510,7 +544,7 @@ int main(int argc, char **argv) sigaction(SIGTERM, &action_stop, NULL); sigaction(SIGINT, &action_stop, NULL);
- VIR_DEBUG("Registering domain event cbs"); + VIR_DEBUG("Registering event cbs");
/* Add 2 callbacks to prove this works with more than just one */ callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1, @@ -585,6 +619,11 @@ int main(int argc, char **argv) VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED, VIR_DOMAIN_EVENT_CALLBACK(myDomainEventDeviceRemovedCallback), strdup("device removed"), myFreeFunc); + callback16ret = virConnectNetworkEventRegisterAny(dconn, + NULL, + VIR_NETWORK_EVENT_ID_LIFECYCLE, + VIR_NETWORK_EVENT_CALLBACK(myNetworkEventCallback2), + strdup("callback 2"), myFreeFunc);
Probably s/callback 2/network callback/.
if ((callback1ret != -1) && (callback2ret != -1) && @@ -599,7 +638,8 @@ int main(int argc, char **argv) (callback12ret != -1) && (callback13ret != -1) && (callback14ret != -1) && - (callback15ret != -1)) { + (callback15ret != -1) && + (callback16ret != -1)) { if (virConnectSetKeepAlive(dconn, 5, 3) < 0) { virErrorPtr err = virGetLastError(); fprintf(stderr, "Failed to start keepalive protocol: %s\n", @@ -630,6 +670,7 @@ int main(int argc, char **argv) virConnectDomainEventDeregisterAny(dconn, callback13ret); virConnectDomainEventDeregisterAny(dconn, callback14ret); virConnectDomainEventDeregisterAny(dconn, callback15ret); + virConnectNetworkEventDeregisterAny(dconn, callback16ret); if (callback8ret != -1) virConnectDomainEventDeregisterAny(dconn, callback8ret); }
ACK with that one nit fixed. Michal

From: "Daniel P. Berrange" <berrange@redhat.com> While the public API & wire protocol included the 'detail' arg for network lifecycle events, the internal event handling code did not process it. This meant that if a future libvirtd server starts sending non-0 'detail' args, the current libvirt client will not process them. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/network_event.c | 7 +++++-- src/conf/network_event.h | 3 ++- src/network/bridge_driver.c | 15 ++++++++++----- src/remote/remote_driver.c | 2 +- src/test/test_driver.c | 15 ++++++++++----- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/conf/network_event.c b/src/conf/network_event.c index 4a02523..b885ced 100644 --- a/src/conf/network_event.c +++ b/src/conf/network_event.c @@ -32,6 +32,7 @@ struct _virNetworkEventLifecycle { virObjectEvent parent; int type; + int detail; }; typedef struct _virNetworkEventLifecycle virNetworkEventLifecycle; typedef virNetworkEventLifecycle *virNetworkEventLifecyclePtr; @@ -80,7 +81,7 @@ virNetworkEventDispatchDefaultFunc(virConnectPtr conn, networkLifecycleEvent = (virNetworkEventLifecyclePtr)event; ((virConnectNetworkEventLifecycleCallback)cb)(conn, net, networkLifecycleEvent->type, - 0, + networkLifecycleEvent->detail, cbopaque); goto cleanup; } @@ -135,7 +136,8 @@ virNetworkEventStateRegisterID(virConnectPtr conn, virObjectEventPtr virNetworkEventLifecycleNew(const char *name, const unsigned char *uuid, - int type) + int type, + int detail) { virNetworkEventLifecyclePtr event; int eventId = (VIR_EVENT_NAMESPACE_NETWORK << 8) + VIR_NETWORK_EVENT_ID_LIFECYCLE; @@ -149,6 +151,7 @@ virNetworkEventLifecycleNew(const char *name, return NULL; event->type = type; + event->detail = detail; return (virObjectEventPtr)event; } diff --git a/src/conf/network_event.h b/src/conf/network_event.h index 44b762e..1eef771 100644 --- a/src/conf/network_event.h +++ b/src/conf/network_event.h @@ -40,7 +40,8 @@ virNetworkEventStateRegisterID(virConnectPtr conn, virObjectEventPtr virNetworkEventLifecycleNew(const char *name, const unsigned char *uuid, - int type); + int type, + int detail); void virNetworkEventDispatchDefaultFunc(virConnectPtr conn, diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 1bde7d7..3e10758 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2559,7 +2559,8 @@ static virNetworkPtr networkCreateXML(virConnectPtr conn, const char *xml) { event = virNetworkEventLifecycleNew(network->def->name, network->def->uuid, - VIR_NETWORK_EVENT_STARTED); + VIR_NETWORK_EVENT_STARTED, + 0); VIR_INFO("Creating network '%s'", network->def->name); ret = virGetNetwork(conn, network->def->name, network->def->uuid); @@ -2621,7 +2622,8 @@ static virNetworkPtr networkDefineXML(virConnectPtr conn, const char *xml) { } event = virNetworkEventLifecycleNew(def->name, def->uuid, - VIR_NETWORK_EVENT_DEFINED); + VIR_NETWORK_EVENT_DEFINED, + 0); VIR_INFO("Defining network '%s'", def->name); ret = virGetNetwork(conn, def->name, def->uuid); @@ -2673,7 +2675,8 @@ networkUndefine(virNetworkPtr net) { event = virNetworkEventLifecycleNew(network->def->name, network->def->uuid, - VIR_NETWORK_EVENT_UNDEFINED); + VIR_NETWORK_EVENT_UNDEFINED, + 0); VIR_INFO("Undefining network '%s'", network->def->name); if (!active) { @@ -2890,7 +2893,8 @@ static int networkCreate(virNetworkPtr net) { event = virNetworkEventLifecycleNew(network->def->name, network->def->uuid, - VIR_NETWORK_EVENT_STARTED); + VIR_NETWORK_EVENT_STARTED, + 0); cleanup: if (event) @@ -2930,7 +2934,8 @@ static int networkDestroy(virNetworkPtr net) { event = virNetworkEventLifecycleNew(network->def->name, network->def->uuid, - VIR_NETWORK_EVENT_STOPPED); + VIR_NETWORK_EVENT_STOPPED, + 0); if (!network->persistent) { if (networkRemoveInactive(driver, network) < 0) { diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 7bd4b24..be282d6 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -4918,7 +4918,7 @@ remoteNetworkBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, if (!net) return; - event = virNetworkEventLifecycleNew(net->name, net->uuid, msg->event); + event = virNetworkEventLifecycleNew(net->name, net->uuid, msg->event, msg->detail); virNetworkFree(net); remoteDomainEventQueue(priv, event); diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 30d2636..a48404a 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -3542,7 +3542,8 @@ static virNetworkPtr testNetworkCreateXML(virConnectPtr conn, const char *xml) { net->active = 1; event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid, - VIR_NETWORK_EVENT_STARTED); + VIR_NETWORK_EVENT_STARTED, + 0); ret = virGetNetwork(conn, net->def->name, net->def->uuid); @@ -3575,7 +3576,8 @@ virNetworkPtr testNetworkDefineXML(virConnectPtr conn, const char *xml) net->persistent = 1; event = virNetworkEventLifecycleNew(net->def->name, net->def->uuid, - VIR_NETWORK_EVENT_DEFINED); + VIR_NETWORK_EVENT_DEFINED, + 0); ret = virGetNetwork(conn, net->def->name, net->def->uuid); @@ -3611,7 +3613,8 @@ static int testNetworkUndefine(virNetworkPtr network) { } event = virNetworkEventLifecycleNew(network->name, network->uuid, - VIR_NETWORK_EVENT_UNDEFINED); + VIR_NETWORK_EVENT_UNDEFINED, + 0); virNetworkRemoveInactive(&privconn->networks, privnet); @@ -3699,7 +3702,8 @@ static int testNetworkCreate(virNetworkPtr network) { privnet->active = 1; event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid, - VIR_NETWORK_EVENT_STARTED); + VIR_NETWORK_EVENT_STARTED, + 0); ret = 0; cleanup: @@ -3727,7 +3731,8 @@ static int testNetworkDestroy(virNetworkPtr network) { privnet->active = 0; event = virNetworkEventLifecycleNew(privnet->def->name, privnet->def->uuid, - VIR_NETWORK_EVENT_STOPPED); + VIR_NETWORK_EVENT_STOPPED, + 0); if (!privnet->persistent) { virNetworkRemoveInactive(&privconn->networks, privnet); -- 1.8.3.1

On 11.12.2013 16:28, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
While the public API & wire protocol included the 'detail' arg for network lifecycle events, the internal event handling code did not process it. This meant that if a future libvirtd server starts sending non-0 'detail' args, the current libvirt client will not process them.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/network_event.c | 7 +++++-- src/conf/network_event.h | 3 ++- src/network/bridge_driver.c | 15 ++++++++++----- src/remote/remote_driver.c | 2 +- src/test/test_driver.c | 15 ++++++++++----- 5 files changed, 28 insertions(+), 14 deletions(-)
ACK Michal

From: "Daniel P. Berrange" <berrange@redhat.com> Inject a virNetworkEvent class between virObjectEvent and virNetworkEventLifecycle to mirror virDomainEvent. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/network_event.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/conf/network_event.c b/src/conf/network_event.c index b885ced..b1312b7 100644 --- a/src/conf/network_event.c +++ b/src/conf/network_event.c @@ -28,23 +28,40 @@ #include "datatypes.h" #include "virlog.h" -struct _virNetworkEventLifecycle { +struct _virNetworkEvent { virObjectEvent parent; + /* Unused attribute to get virNetworkEvent class being created */ + bool dummy; +}; +typedef struct _virNetworkEvent virNetworkEvent; +typedef virNetworkEvent *virNetworkEventPtr; + +struct _virNetworkEventLifecycle { + virNetworkEvent parent; + int type; int detail; }; typedef struct _virNetworkEventLifecycle virNetworkEventLifecycle; typedef virNetworkEventLifecycle *virNetworkEventLifecyclePtr; +static virClassPtr virNetworkEventClass; static virClassPtr virNetworkEventLifecycleClass; +static void virNetworkEventDispose(void *obj); static void virNetworkEventLifecycleDispose(void *obj); static int virNetworkEventsOnceInit(void) { - if (!(virNetworkEventLifecycleClass = + if (!(virNetworkEventClass = virClassNew(virClassForObjectEvent(), + "virNetworkEvent", + sizeof(virNetworkEvent), + virNetworkEventDispose))) + return -1; + if (!(virNetworkEventLifecycleClass = + virClassNew(virNetworkEventClass, "virNetworkEventLifecycle", sizeof(virNetworkEventLifecycle), virNetworkEventLifecycleDispose))) @@ -55,6 +72,14 @@ virNetworkEventsOnceInit(void) VIR_ONCE_GLOBAL_INIT(virNetworkEvents) void +virNetworkEventDispose(void *obj) +{ + virNetworkEventPtr event = obj; + VIR_DEBUG("obj=%p", event); +} + + +void virNetworkEventLifecycleDispose(void *obj) { virNetworkEventLifecyclePtr event = obj; -- 1.8.3.1

On 11.12.2013 16:28, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Inject a virNetworkEvent class between virObjectEvent and virNetworkEventLifecycle to mirror virDomainEvent.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/network_event.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/src/conf/network_event.c b/src/conf/network_event.c index b885ced..b1312b7 100644 --- a/src/conf/network_event.c +++ b/src/conf/network_event.c @@ -28,23 +28,40 @@ #include "datatypes.h" #include "virlog.h"
-struct _virNetworkEventLifecycle { +struct _virNetworkEvent { virObjectEvent parent;
+ /* Unused attribute to get virNetworkEvent class being created */ + bool dummy; +}; +typedef struct _virNetworkEvent virNetworkEvent; +typedef virNetworkEvent *virNetworkEventPtr; + +struct _virNetworkEventLifecycle { + virNetworkEvent parent; + int type; int detail; }; typedef struct _virNetworkEventLifecycle virNetworkEventLifecycle; typedef virNetworkEventLifecycle *virNetworkEventLifecyclePtr;
+static virClassPtr virNetworkEventClass; static virClassPtr virNetworkEventLifecycleClass; +static void virNetworkEventDispose(void *obj); static void virNetworkEventLifecycleDispose(void *obj);
static int virNetworkEventsOnceInit(void) { - if (!(virNetworkEventLifecycleClass = + if (!(virNetworkEventClass = virClassNew(virClassForObjectEvent(), + "virNetworkEvent", + sizeof(virNetworkEvent), + virNetworkEventDispose))) + return -1; + if (!(virNetworkEventLifecycleClass = + virClassNew(virNetworkEventClass, "virNetworkEventLifecycle", sizeof(virNetworkEventLifecycle), virNetworkEventLifecycleDispose))) @@ -55,6 +72,14 @@ virNetworkEventsOnceInit(void) VIR_ONCE_GLOBAL_INIT(virNetworkEvents)
void +virNetworkEventDispose(void *obj) +{ + virNetworkEventPtr event = obj; + VIR_DEBUG("obj=%p", event); +} + + +void virNetworkEventLifecycleDispose(void *obj) { virNetworkEventLifecyclePtr event = obj;
This patch alone wouldn't make much sense. But in the light of the very next patch it's more than desired. ACK Michal

From: "Daniel P. Berrange" <berrange@redhat.com> The event namespace concept is redundant since the same information is available by looking at the class hierarchy of the events. Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/domain_event.c | 18 ++++++++++++++++-- src/conf/domain_event.h | 2 ++ src/conf/network_event.c | 22 ++++++++++++++++------ src/conf/network_event.h | 3 +++ src/conf/object_event.c | 28 +++++++++++++++------------- src/conf/object_event.h | 11 +++-------- src/conf/object_event_private.h | 2 ++ 7 files changed, 57 insertions(+), 29 deletions(-) diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 64035f7..03164dc 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -437,6 +437,7 @@ virDomainEventCallbackListAdd(virConnectPtr conn, virFreeCallback freecb) { return virObjectEventCallbackListAddID(conn, cbList, NULL, NULL, 0, + virDomainEventClass, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_OBJECT_EVENT_CALLBACK(callback), opaque, freecb, NULL); @@ -1366,6 +1367,9 @@ virDomainEventStateRegister(virConnectPtr conn, { int ret = -1; + if (virDomainEventsInitialize() < 0) + return -1; + virObjectEventStateLock(state); if ((state->callbacks->count == 0) && @@ -1420,14 +1424,17 @@ virDomainEventStateRegisterID(virConnectPtr conn, virFreeCallback freecb, int *callbackID) { + if (virDomainEventsInitialize() < 0) + return -1; + if (dom) return virObjectEventStateRegisterID(conn, state, dom->uuid, dom->name, - dom->id, eventID, + dom->id, virDomainEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), opaque, freecb, callbackID); else return virObjectEventStateRegisterID(conn, state, NULL, NULL, 0, - eventID, + virDomainEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), opaque, freecb, callbackID); } @@ -1468,3 +1475,10 @@ virDomainEventStateDeregister(virConnectPtr conn, virObjectEventStateUnlock(state); return ret; } + + +virClassPtr +virDomainEventGetBaseClass(void) +{ + return virDomainEventClass; +} diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index 30156ed..5433950 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -30,6 +30,8 @@ # include "object_event.h" # include "domain_conf.h" +virClassPtr +virDomainEventGetBaseClass(void); virObjectEventPtr virDomainEventLifecycleNew(int id, diff --git a/src/conf/network_event.c b/src/conf/network_event.c index b1312b7..3108fea 100644 --- a/src/conf/network_event.c +++ b/src/conf/network_event.c @@ -98,7 +98,7 @@ virNetworkEventDispatchDefaultFunc(virConnectPtr conn, if (!net) return; - switch ((virNetworkEventID) (event->eventID &0xFF)) { + switch ((virNetworkEventID)event->eventID) { case VIR_NETWORK_EVENT_ID_LIFECYCLE: { virNetworkEventLifecyclePtr networkLifecycleEvent; @@ -147,14 +147,18 @@ virNetworkEventStateRegisterID(virConnectPtr conn, virFreeCallback freecb, int *callbackID) { - int nsEventID = (VIR_EVENT_NAMESPACE_NETWORK << 8) + eventID; + if (virNetworkEventsInitialize() < 0) + return -1; + if (net) return virObjectEventStateRegisterID(conn, state, - net->uuid, net->name, 0, nsEventID, + net->uuid, net->name, 0, + virNetworkEventClass, eventID, cb, opaque, freecb, callbackID); else return virObjectEventStateRegisterID(conn, state, - NULL, NULL, 0, nsEventID, + NULL, NULL, 0, + virNetworkEventClass, eventID, cb, opaque, freecb, callbackID); } @@ -165,13 +169,12 @@ virNetworkEventLifecycleNew(const char *name, int detail) { virNetworkEventLifecyclePtr event; - int eventId = (VIR_EVENT_NAMESPACE_NETWORK << 8) + VIR_NETWORK_EVENT_ID_LIFECYCLE; if (virNetworkEventsInitialize() < 0) return NULL; if (!(event = virObjectEventNew(virNetworkEventLifecycleClass, - eventId, + VIR_NETWORK_EVENT_ID_LIFECYCLE, 0, name, uuid))) return NULL; @@ -180,3 +183,10 @@ virNetworkEventLifecycleNew(const char *name, return (virObjectEventPtr)event; } + + +virClassPtr +virNetworkEventGetBaseClass(void) +{ + return virNetworkEventClass; +} diff --git a/src/conf/network_event.h b/src/conf/network_event.h index 1eef771..5b3b933 100644 --- a/src/conf/network_event.h +++ b/src/conf/network_event.h @@ -27,6 +27,9 @@ #ifndef __NETWORK_EVENT_H__ # define __NETWORK_EVENT_H__ +virClassPtr +virNetworkEventGetBaseClass(void); + int virNetworkEventStateRegisterID(virConnectPtr conn, virObjectEventStatePtr state, diff --git a/src/conf/object_event.c b/src/conf/object_event.c index ec00aaf..964dccf 100644 --- a/src/conf/object_event.c +++ b/src/conf/object_event.c @@ -227,6 +227,7 @@ virObjectEventCallbackListPurgeMarked(virObjectEventCallbackListPtr cbList) * @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 + * @klass: the base event class * @eventID: the event ID * @callback: the callback to add * @opaque: opaque data tio pass to callback @@ -240,6 +241,7 @@ virObjectEventCallbackListAddID(virConnectPtr conn, unsigned char uuid[VIR_UUID_BUFLEN], const char *name, int id, + virClassPtr klass, int eventID, virConnectObjectEventGenericCallback callback, void *opaque, @@ -258,6 +260,7 @@ virObjectEventCallbackListAddID(virConnectPtr conn, /* 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]->klass == klass && cbList->callbacks[i]->eventID == eventID && cbList->callbacks[i]->conn == conn && ((uuid && cbList->callbacks[i]->meta && @@ -274,6 +277,7 @@ virObjectEventCallbackListAddID(virConnectPtr conn, goto error; event->conn = conn; event->cb = callback; + event->klass = klass; event->eventID = eventID; event->opaque = opaque; event->freecb = freecb; @@ -299,7 +303,8 @@ virObjectEventCallbackListAddID(virConnectPtr conn, event->callbackID = cbList->nextID++; for (i = 0; i < cbList->count; i++) { - if (cbList->callbacks[i]->eventID == eventID && + if (cbList->callbacks[i]->klass == klass && + cbList->callbacks[i]->eventID == eventID && cbList->callbacks[i]->conn == conn && !cbList->callbacks[i]->deleted) ret++; @@ -542,6 +547,8 @@ virObjectEventDispatchMatchCallback(virObjectEventPtr event, return 0; if (cb->deleted) return 0; + if (!virObjectIsClass(event, cb->klass)) + return 0; if (cb->eventID != virObjectEventGetEventID(event)) return 0; @@ -633,22 +640,17 @@ virObjectEventStateDispatchFunc(virConnectPtr conn, 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: + if (virObjectIsClass(event, virDomainEventGetBaseClass())) virDomainEventDispatchDefaultFunc(conn, event, VIR_DOMAIN_EVENT_CALLBACK(cb), cbopaque, NULL); - break; - case VIR_EVENT_NAMESPACE_NETWORK: + else if (virObjectIsClass(event, virNetworkEventGetBaseClass())) virNetworkEventDispatchDefaultFunc(conn, event, VIR_NETWORK_EVENT_CALLBACK(cb), cbopaque, NULL); - break; - default: + else VIR_ERROR(_("Unknown event namespace to dispatch")); - } virObjectEventStateLock(state); } @@ -686,6 +688,7 @@ virObjectEventStateFlush(virObjectEventStatePtr state) * virObjectEventStateRegisterID: * @conn: connection to associate with callback * @state: domain event state + * @klass: the base event class * @eventID: ID of the event type to register for * @cb: function to remove from event * @opaque: data blob to pass to callback @@ -703,6 +706,7 @@ virObjectEventStateRegisterID(virConnectPtr conn, unsigned char *uuid, const char *name, int id, + virClassPtr klass, int eventID, virConnectObjectEventGenericCallback cb, void *opaque, @@ -725,7 +729,8 @@ virObjectEventStateRegisterID(virConnectPtr conn, } ret = virObjectEventCallbackListAddID(conn, state->callbacks, - uuid, name, id, eventID, cb, opaque, freecb, + uuid, name, id, klass, eventID, + cb, opaque, freecb, callbackID); if (ret == -1 && @@ -800,9 +805,6 @@ virObjectEventStateEventID(virConnectPtr conn, virObjectEventStateLock(state); ret = virObjectEventCallbackListEventID(conn, state->callbacks, callbackID); - /* Callers don't need to know we are namespacing the event Ids */ - if (ret >= 0) - ret = (0xFF & ret); virObjectEventStateUnlock(state); return ret; } diff --git a/src/conf/object_event.h b/src/conf/object_event.h index 50cfe19..211defb 100644 --- a/src/conf/object_event.h +++ b/src/conf/object_event.h @@ -24,17 +24,11 @@ #include "internal.h" +#include "virobject.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 */ - VIR_EVENT_NAMESPACE_NETWORK = 1, -} virEventNamespaceID; - typedef struct _virObjectEventCallback virObjectEventCallback; typedef virObjectEventCallback *virObjectEventCallbackPtr; @@ -78,6 +72,7 @@ virObjectEventStateRegisterID(virConnectPtr conn, unsigned char *uuid, const char *name, int id, + virClassPtr klass, int eventID, virConnectObjectEventGenericCallback cb, void *opaque, diff --git a/src/conf/object_event_private.h b/src/conf/object_event_private.h index f41f432..f1cc60a 100644 --- a/src/conf/object_event_private.h +++ b/src/conf/object_event_private.h @@ -60,6 +60,7 @@ struct _virObjectEventState { struct _virObjectEventCallback { int callbackID; + virClassPtr klass; int eventID; virConnectPtr conn; virObjectMetaPtr meta; @@ -87,6 +88,7 @@ virObjectEventCallbackListAddID(virConnectPtr conn, unsigned char *uuid, const char *name, int id, + virClassPtr klass, int eventID, virConnectObjectEventGenericCallback callback, void *opaque, -- 1.8.3.1

On Wed, 2013-12-11 at 15:28 +0000, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
...
@@ -633,22 +640,17 @@ virObjectEventStateDispatchFunc(virConnectPtr conn, 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: + if (virObjectIsClass(event, virDomainEventGetBaseClass())) virDomainEventDispatchDefaultFunc(conn, event, VIR_DOMAIN_EVENT_CALLBACK(cb), cbopaque, NULL); - break; - case VIR_EVENT_NAMESPACE_NETWORK: + else if (virObjectIsClass(event, virNetworkEventGetBaseClass())) virNetworkEventDispatchDefaultFunc(conn, event, VIR_NETWORK_EVENT_CALLBACK(cb), cbopaque, NULL); - break; - default: + else VIR_ERROR(_("Unknown event namespace to dispatch")); - } virObjectEventStateLock(state); }
In this function we may get a crash if we have network event callback registered but nothing registered for domain events. Indeed, in such a case the virDomainEventGetBaseClass() would return NULL and we'll have a crash when checking the inheritance. This is why I see a crash with the patched virt-manager, and not with the event-test. -- Cedric

On 11.12.2013 16:28, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
The event namespace concept is redundant since the same information is available by looking at the class hierarchy of the events.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/domain_event.c | 18 ++++++++++++++++-- src/conf/domain_event.h | 2 ++ src/conf/network_event.c | 22 ++++++++++++++++------ src/conf/network_event.h | 3 +++ src/conf/object_event.c | 28 +++++++++++++++------------- src/conf/object_event.h | 11 +++-------- src/conf/object_event_private.h | 2 ++ 7 files changed, 57 insertions(+), 29 deletions(-)
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c index 64035f7..03164dc 100644 --- a/src/conf/domain_event.c +++ b/src/conf/domain_event.c @@ -437,6 +437,7 @@ virDomainEventCallbackListAdd(virConnectPtr conn, virFreeCallback freecb) { return virObjectEventCallbackListAddID(conn, cbList, NULL, NULL, 0, + virDomainEventClass, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_OBJECT_EVENT_CALLBACK(callback), opaque, freecb, NULL); @@ -1366,6 +1367,9 @@ virDomainEventStateRegister(virConnectPtr conn, { int ret = -1;
+ if (virDomainEventsInitialize() < 0) + return -1; + virObjectEventStateLock(state);
if ((state->callbacks->count == 0) && @@ -1420,14 +1424,17 @@ virDomainEventStateRegisterID(virConnectPtr conn, virFreeCallback freecb, int *callbackID) { + if (virDomainEventsInitialize() < 0) + return -1; + if (dom) return virObjectEventStateRegisterID(conn, state, dom->uuid, dom->name, - dom->id, eventID, + dom->id, virDomainEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), opaque, freecb, callbackID); else return virObjectEventStateRegisterID(conn, state, NULL, NULL, 0, - eventID, + virDomainEventClass, eventID, VIR_OBJECT_EVENT_CALLBACK(cb), opaque, freecb, callbackID); } @@ -1468,3 +1475,10 @@ virDomainEventStateDeregister(virConnectPtr conn, virObjectEventStateUnlock(state); return ret; } + + +virClassPtr +virDomainEventGetBaseClass(void) +{ + return virDomainEventClass; +} diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h index 30156ed..5433950 100644 --- a/src/conf/domain_event.h +++ b/src/conf/domain_event.h @@ -30,6 +30,8 @@ # include "object_event.h" # include "domain_conf.h"
+virClassPtr +virDomainEventGetBaseClass(void);
virObjectEventPtr virDomainEventLifecycleNew(int id, diff --git a/src/conf/network_event.c b/src/conf/network_event.c index b1312b7..3108fea 100644 --- a/src/conf/network_event.c +++ b/src/conf/network_event.c @@ -98,7 +98,7 @@ virNetworkEventDispatchDefaultFunc(virConnectPtr conn, if (!net) return;
- switch ((virNetworkEventID) (event->eventID &0xFF)) { + switch ((virNetworkEventID)event->eventID) {
Honestly, I was never big fan of misusing eventID to carry the namespace too. ACK if you fix the crash Cederic pointed out. Michal

From: "Daniel P. Berrange" <berrange@redhat.com> Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/object_event.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/conf/object_event.c b/src/conf/object_event.c index 964dccf..518fa1e 100644 --- a/src/conf/object_event.c +++ b/src/conf/object_event.c @@ -252,6 +252,11 @@ virObjectEventCallbackListAddID(virConnectPtr conn, size_t i; int ret = 0; + VIR_DEBUG("conn=%p cblist=%p uuid=%p name=%s id=%d " + "klass=%p eventID=%d callback=%p opaque=%p", + conn, cbList, uuid, name, id, klass, eventID, + callback, opaque); + /* Check incoming */ if (!cbList) { return -1; -- 1.8.3.1

On 11.12.2013 16:28, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com> --- src/conf/object_event.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/src/conf/object_event.c b/src/conf/object_event.c index 964dccf..518fa1e 100644 --- a/src/conf/object_event.c +++ b/src/conf/object_event.c @@ -252,6 +252,11 @@ virObjectEventCallbackListAddID(virConnectPtr conn, size_t i; int ret = 0;
+ VIR_DEBUG("conn=%p cblist=%p uuid=%p name=%s id=%d " + "klass=%p eventID=%d callback=%p opaque=%p", + conn, cbList, uuid, name, id, klass, eventID, + callback, opaque); + /* Check incoming */ if (!cbList) { return -1;
ACK Michal
participants (3)
-
Cedric Bosdonnat
-
Daniel P. Berrange
-
Michal Privoznik