
On Fri, Oct 17, 2008 at 12:02:52PM -0400, Ben Guthro wrote:
Register for, and dispatch domain event callbacks
qemu_conf.h | 3 ++ qemu_driver.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 2 deletions(-)
diff --git a/src/qemu_conf.h b/src/qemu_conf.h index cfd7d35..d06c4d7 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -63,6 +63,9 @@ struct qemud_driver { char *vncListen;
virCapsPtr caps; + + /* An array of callbacks */ + virDomainEventCallbackListPtr domainEventCallbacks; };
diff --git a/src/qemu_driver.c b/src/qemu_driver.c index a86b787..9792541 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -159,6 +159,10 @@ qemudStartup(void) { /* Don't have a dom0 so start from 1 */ qemu_driver->nextvmid = 1;
+ /* Init callback list */ + if(VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0) + return -1; + if (!uid) { if (asprintf(&qemu_driver->logDir, "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1) @@ -301,6 +305,9 @@ qemudShutdown(void) { VIR_FREE(qemu_driver->autostartDir); VIR_FREE(qemu_driver->vncTLSx509certdir);
+ /* Free domain callback list */ + virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks); + if (qemu_driver->brctl) brShutdown(qemu_driver->brctl);
@@ -742,6 +749,8 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) { return -1; }
+static virDomainPtr qemudDomainLookupByName(virConnectPtr conn, const char *name); + static int qemudStartVMDaemon(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, @@ -756,6 +765,7 @@ static int qemudStartVMDaemon(virConnectPtr conn, unsigned int qemuCmdFlags; fd_set keepfd; const char *emulator; + virDomainPtr dom;
FD_ZERO(&keepfd);
@@ -918,6 +928,11 @@ static int qemudStartVMDaemon(virConnectPtr conn, qemudShutdownVMDaemon(conn, driver, vm); return -1; } + dom = qemudDomainLookupByName(conn,vm->def->name); + if(dom) + virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_STARTED); + else + DEBUG0("Warning - dom is NULL at domain start"); }
return ret; @@ -1503,6 +1518,7 @@ static int qemudDomainSuspend(virDomainPtr dom) { } vm->state = VIR_DOMAIN_PAUSED; qemudDebug("Reply %s", info); + virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_SUSPENDED); VIR_FREE(info); return 0; } @@ -1531,6 +1547,7 @@ static int qemudDomainResume(virDomainPtr dom) { } vm->state = VIR_DOMAIN_RUNNING; qemudDebug("Reply %s", info); + virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_RESUMED); VIR_FREE(info); return 0; } @@ -1572,7 +1589,7 @@ static int qemudDomainDestroy(virDomainPtr dom) { if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); - + virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_STOPPED); return 0; }
@@ -1903,7 +1920,7 @@ static int qemudDomainSave(virDomainPtr dom, if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); - + virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_SAVED); return 0; }
@@ -2104,6 +2121,7 @@ static int qemudDomainRestore(virConnectPtr conn, struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; virDomainDefPtr def; virDomainObjPtr vm; + virDomainPtr dom; int fd; int ret; char *xml; @@ -2210,6 +2228,11 @@ static int qemudDomainRestore(virConnectPtr conn, vm->state = VIR_DOMAIN_RUNNING; }
+ dom = virDomainLookupByID(conn, def->id); + if(dom) { + virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_RESTORED); + VIR_FREE(dom); + } return 0; }
@@ -3051,6 +3074,52 @@ done: }
+static int qemudDomainEventRegister (virConnectPtr conn, + void *callback, + void *opaque) +{ + struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; + + return virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks, callback, opaque); +} + +static int qemudDomainEventDeregister (virConnectPtr conn, + void *callback) +{ + struct qemud_driver *driver = (struct qemud_driver *)conn->privateData; + + return virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks, callback); +} + +static void qemudDomainEventDispatch (virDomainPtr dom, + virDomainEventType evt) +{ + int i; + struct qemud_driver *driver; + virDomainEventCallbackListPtr cbList; + + if(!dom->conn) { + DEBUG0("Invalid conn"); + return; + } + driver = (struct qemud_driver *)dom->conn->privateData; + + if(!driver) { + DEBUG0("Invalid driver"); + return; + } + cbList = driver->domainEventCallbacks; + + for(i=0;i<cbList->count;i++) { + if(cbList->callbacks[i] && cbList->callbacks[i]->cb) + DEBUG("Dispatching callback %p %p event %d", cbList->callbacks[i], cbList->callbacks[i]->cb, evt); + cbList->callbacks[i]->cb(cbList->callbacks[i]->conn, + dom, evt, + cbList->callbacks[i]->opaque); + } + +}
THis all basically works fine, but there's one tiny missing bit. If a domain shuts down from an external trigger - eg guest admin does a 'shutdown -h', or host admin does 'kill -TERM $qemu', then no STOPPED event is fired. For this we need to hook into the qemudDispatchVMFailure() method. This introduces a small problem though - we don't have a 'virDomainPtr' object here, so we can't call the generic virDispatchDomainEvent() method. Of course virDispatchDomainEvent() just delegates back into the driver - in this case qemudDomainEventDispatch(), which has no hard requirement to have a 'virDomainPtr' object. Each registered callback has a 'virConnectPtr' object associated with it, so we can simply fetch a virDomainPtr as required. To demonstrate this I'm attching a patch which applies ontop of yours to make this method call directly. With this, I think we can remove the 'domainEventDispatch' field in driver.h - though obviously the other non-QEMU drivers need changing to match too. diff --git a/src/qemu_driver.c b/src/qemu_driver.c --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -105,6 +105,10 @@ static int qemudSetNonBlock(int fd) { return -1; } + +static void qemudDomainEventDispatch (struct qemud_driver *driver, + virDomainObjPtr vm, + virDomainEventType evt); static void qemudDispatchVMEvent(int fd, int events, void *opaque); static int qemudStartVMDaemon(virConnectPtr conn, @@ -930,7 +934,7 @@ static int qemudStartVMDaemon(virConnect } dom = qemudDomainLookupByName(conn,vm->def->name); if(dom) - virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_STARTED); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED); else DEBUG0("Warning - dom is NULL at domain start"); } @@ -1027,6 +1031,7 @@ static int qemudDispatchVMFailure(struct static int qemudDispatchVMFailure(struct qemud_driver *driver, virDomainObjPtr vm, int fd ATTRIBUTE_UNUSED) { qemudShutdownVMDaemon(NULL, driver, vm); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STOPPED); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); @@ -1518,7 +1523,7 @@ static int qemudDomainSuspend(virDomainP } vm->state = VIR_DOMAIN_PAUSED; qemudDebug("Reply %s", info); - virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_SUSPENDED); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SUSPENDED); VIR_FREE(info); return 0; } @@ -1547,7 +1552,7 @@ static int qemudDomainResume(virDomainPt } vm->state = VIR_DOMAIN_RUNNING; qemudDebug("Reply %s", info); - virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_RESUMED); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESUMED); VIR_FREE(info); return 0; } @@ -1586,10 +1591,10 @@ static int qemudDomainDestroy(virDomainP } qemudShutdownVMDaemon(dom->conn, driver, vm); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STOPPED); if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); - virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_STOPPED); return 0; } @@ -1920,7 +1925,7 @@ static int qemudDomainSave(virDomainPtr if (!vm->persistent) virDomainRemoveInactive(&driver->domains, vm); - virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_SAVED); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_SAVED); return 0; } @@ -2230,7 +2235,7 @@ static int qemudDomainRestore(virConnect dom = virDomainLookupByID(conn, def->id); if(dom) { - virDispatchDomainEvent(dom, VIR_DOMAIN_EVENT_RESTORED); + qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_RESTORED); VIR_FREE(dom); } return 0; @@ -3090,31 +3095,28 @@ static int qemudDomainEventDeregister (v return virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks, callback); } -static void qemudDomainEventDispatch (virDomainPtr dom, +static void qemudDomainEventDispatch (struct qemud_driver *driver, + virDomainObjPtr vm, virDomainEventType evt) { int i; - struct qemud_driver *driver; virDomainEventCallbackListPtr cbList; - if(!dom->conn) { - DEBUG0("Invalid conn"); - return; - } - driver = (struct qemud_driver *)dom->conn->privateData; - - if(!driver) { - DEBUG0("Invalid driver"); - return; - } cbList = driver->domainEventCallbacks; for(i=0;i<cbList->count;i++) { - if(cbList->callbacks[i] && cbList->callbacks[i]->cb) - DEBUG("Dispatching callback %p %p event %d", cbList->callbacks[i], cbList->callbacks[i]->cb, evt); - cbList->callbacks[i]->cb(cbList->callbacks[i]->conn, - dom, evt, - cbList->callbacks[i]->opaque); + if(cbList->callbacks[i] && cbList->callbacks[i]->cb) { + virConnectPtr conn = cbList->callbacks[i]->conn; + virDomainPtr dom = virGetDomain(conn, vm->def->name, vm->def->uuid); + if (dom) { + dom->id = virDomainIsActive(vm) ? vm->def->id : -1; + DEBUG("Dispatching callback %p %p event %d", cbList->callbacks[i], cbList->callbacks[i]->cb, evt); + cbList->callbacks[i]->cb(cbList->callbacks[i]->conn, + dom, evt, + cbList->callbacks[i]->opaque); + virDomainFree(dom); + } + } } } @@ -3191,7 +3193,7 @@ static virDriver qemuDriver = { #endif qemudDomainEventRegister, /* domainEventRegister */ qemudDomainEventDeregister, /* domainEventDeregister */ - qemudDomainEventDispatch, /* domainEventDispatch */ + NULL, }; Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|