On 27.06.2012 14:46, Daniel P. Berrange wrote: > On Wed, Jun 27, 2012 at 02:44:02PM +0200, Michal Privoznik wrote: >> On 27.06.2012 14:36, Eric Blake wrote: >>> On 06/27/2012 06:12 AM, Michal Privoznik wrote: >>>> virConnectDomainEventRegisterAny() takes a domain as an argument. >>>> So it should be possible to register the same event (be it >>>> VIR_DOMAIN_EVENT_ID_LIFECYCLE for example) for two different domains. >>>> That is, we need to take domain into account when searching for >>>> duplicate event being already registered. >>>> --- >>>> src/conf/domain_event.c | 6 +++++- >>>> 1 files changed, 5 insertions(+), 1 deletions(-) >>>> >>>> diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c >>>> index 4ecc413..3cfd940 100644 >>>> --- a/src/conf/domain_event.c >>>> +++ b/src/conf/domain_event.c >>>> @@ -363,7 +363,11 @@ virDomainEventCallbackListAddID(virConnectPtr conn, >>>> for (i = 0 ; i < cbList->count ; i++) { >>>> if (cbList->callbacks[i]->cb == VIR_DOMAIN_EVENT_CALLBACK(callback) && >>>> cbList->callbacks[i]->eventID == eventID && >>>> - cbList->callbacks[i]->conn == conn) { >>>> + cbList->callbacks[i]->conn == conn && >>>> + ((dom && cbList->callbacks[i]->dom && >>>> + memcmp(cbList->callbacks[i]->dom->uuid, >>>> + dom->uuid, VIR_UUID_BUFLEN) == 0) || >>>> + (!dom && !cbList->callbacks[i]->dom))) { >>> >>> This misses the case of registering a catchall against NULL domain then >>> attempting to re-register the same event against a specific domain >>> (which one of the two would fire?). It also misses the case of >>> registering a domain-specific handler, then attempting to broaden things >>> into a global handler. >> >> Yes, but that's intentional. In both cases both events are fired. >> >>> >>> I think the idea of double registration makes sense (in particular, if I >>> have a per-domain callback, but then want to switch to global, I would >>> rather have a window with both handlers at once than a window with no >>> handler at all), but I have not tested whether we actually handle it by >>> firing both the global and domain-specific callback. >> >> I've tested it and it works. > > How ? The remote driver does not ever pass the virDomainPtr arg > over the wire, and it restricts itself to 1 single callback per > event type. Only the client side drivers (test, esx, virtualbox) > could possibly work, but not KVM, LXC, Xen, UML > > Daniel > I am attaching the reproducer. My output: zippy@bart ~/work/tmp $ gcc repro.c -o repro -lvirt -ggdb3 && LD_LIBRARY_PATH="/home/mprivozn/work/libvirt/libvirt.git/src/.libs/" ./repro qemu:///system myDomainEventCallback2 EVENT: Domain f16(-1) Defined Updated o:cb1 myDomainEventCallback2 EVENT: Domain f17(-1) Defined Updated o:cb1 myDomainEventCallback2 EVENT: Domain f17(-1) Defined Updated o:cb2 So we can see cb1 and cb2 firing up at once (cb1 is registered against NULL, cb2 against f17 domain). Michal
#include <libvirt/libvirt.h> #include <libvirt/virterror.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <string.h> int run = 1; static void stop(int sig) { printf("Exiting on signal %d\n", sig); 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; } 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; } 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 = "Failed"; 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; } return ret; } static int myDomainEventCallback2(virConnectPtr conn, virDomainPtr dom, int event, int detail, void *opaque) { printf("%s EVENT: Domain %s(%d) %s %s o:%s\n", __func__, virDomainGetName(dom), virDomainGetID(dom), eventToString(event), eventDetailToString(event, detail), (char *)opaque); return 0; } static void myFreeFunc(void *opaque) { char *str = opaque; printf("%s: Freeing [%s]\n", __func__, str); free(str); } int main(int argc, char *argv[]) { virConnectPtr conn = NULL; virDomainPtr dom1 = NULL, dom2 = NULL; int callback1ret = -1, callback2ret = -1; int ret = -1; struct sigaction action_stop; memset(&action_stop, 0, sizeof(action_stop)); action_stop.sa_handler = stop; sigaction(SIGTERM, &action_stop, NULL); sigaction(SIGINT, &action_stop, NULL); virEventRegisterDefaultImpl(); conn = virConnectOpenAuth(argc > 1 ? argv[1] : NULL, virConnectAuthPtrDefault, 0); if (!conn) { fprintf(stderr, "conn\n"); return -1; } dom1 = virDomainLookupByName(conn, argc > 2 ? argv[2] : "f16"); dom2 = virDomainLookupByName(conn, argc > 3 ? argv[3] : "f17"); if (!dom1 || !dom2) { fprintf(stderr, "dom\n"); goto cleanup; } callback1ret = virConnectDomainEventRegisterAny(conn, NULL, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback2), strdup("cb1"), myFreeFunc); callback2ret = virConnectDomainEventRegisterAny(conn, dom2, VIR_DOMAIN_EVENT_ID_LIFECYCLE, VIR_DOMAIN_EVENT_CALLBACK(myDomainEventCallback2), strdup("cb2"), myFreeFunc); if (callback1ret < 0) { fprintf(stderr, ":( cb1\n"); goto cleanup; } if (callback2ret < 0) { fprintf(stderr, ":( cb2\n"); goto cleanup; } if (virConnectSetKeepAlive(conn, 5, 3) < 0) { fprintf(stderr, "ka\n"); goto cleanup; } while (run && virConnectIsAlive(conn) == 1) { if (virEventRunDefaultImpl() < 0) { fprintf(stderr, "event\n"); } } ret = 0; cleanup: if (callback1ret >= 0) virConnectDomainEventDeregisterAny(conn, callback1ret); if (callback2ret >= 0) virConnectDomainEventDeregisterAny(conn, callback2ret); if (dom1) virDomainFree(dom1); if (dom2) virDomainFree(dom2); if (conn) virConnectClose(conn); return ret; }
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list