+Thu Dec 4 21:09:41 GMT 2008 Daniel P. Berrange <berrange@redhat.com>
+
+ QEMU domain events thread safety
+ * src/domain_event.c, src/domain_event.h: Add convenient
+ methods for dispatching a list of events, and a single
+ event to a list of callbacks. Change signature of push
+ method to take a pre-allocated virDomainEventPtr object
+ * src/libvirt_sym.version.in: Export new event methods
+ to daemon code / drivers
+ * src/qemu_conf.h, src/qemu_driver.c: Make event dispatch
+ threadsafe by doing asynchronously
+ * src/remote_internal.c, src/xen_inotify.c, src/xen_unified.c,
+ src/xen_unified.h, src/xs_internal.c: Update for changes in
+ domain event APIs
+
Thu Dec 4 21:05:41 GMT 2008 Daniel P. Berrange <berrange@redhat.com>
* src/qemu_conf.h: Add a driver lock variable
return 0;
}
+int virDomainEventCallbackListMarkDelete(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ virConnectDomainEventCallback callback)
+{
+ int i;
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->conn == conn &&
+ cbList->callbacks[i]->cb == callback) {
+ cbList->callbacks[i]->deleted = 1;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList)
+{
+ int old_count = cbList->count;
+ int i;
+ for (i = 0 ; i < cbList->count ; i++) {
+ if (cbList->callbacks[i]->deleted) {
+ virFreeCallback freecb = cbList->callbacks[i]->freecb;
+ if (freecb)
+ (*freecb)(cbList->callbacks[i]->opaque);
+ virUnrefConnect(cbList->callbacks[i]->conn);
+ VIR_FREE(cbList->callbacks[i]);
+
+ if (i < (cbList->count - 1))
+ memmove(cbList->callbacks + i,
+ cbList->callbacks + i + 1,
+ sizeof(*(cbList->callbacks)) *
+ (cbList->count - (i + 1)));
+ cbList->count--;
+ i--;
+ }
+ }
+ if (cbList->count < old_count &&
+ VIR_REALLOC_N(cbList->callbacks, cbList->count) < 0) {
+ ; /* Failure to reduce memory allocation isn't fatal */
+ }
+ return 0;
+}
+
/**
* virDomainEventCallbackListAdd:
* @conn: pointer to the connection
return 0;
}
+void virDomainEventFree(virDomainEventPtr event)
+{
+ if (!event)
+ return;
+
+ VIR_FREE(event->name);
+ VIR_FREE(event);
+}
+
+
+virDomainEventQueuePtr virDomainEventQueueNew(void)
+{
+ virDomainEventQueuePtr ret;
+
+ if (VIR_ALLOC(ret) < 0)
+ return NULL;
+
+ return ret;
+}
+
+virDomainEventPtr virDomainEventNew(int id, const char *name,
+ const unsigned char *uuid,
+ int type, int detail)
+{
+ virDomainEventPtr event;
+
+ if (VIR_ALLOC(event) < 0)
+ return NULL;
+
+ event->type = type;
+ event->detail = detail;
+ if (!(event->name = strdup(name))) {
+ VIR_FREE(event);
+ return NULL;
+ }
+ event->id = id;
+ memcpy(event->uuid, uuid, VIR_UUID_BUFLEN);
+
+ return event;
+}
+
+virDomainEventPtr virDomainEventNewFromDom(virDomainPtr dom, int type, int detail)
+{
+ return virDomainEventNew(dom->id, dom->name, dom->uuid, type, detail);
+}
+
+virDomainEventPtr virDomainEventNewFromObj(virDomainObjPtr obj, int type, int detail)
+{
+ return virDomainEventNewFromDef(obj->def, type, detail);
+}
+
+virDomainEventPtr virDomainEventNewFromDef(virDomainDefPtr def, int type, int detail)
+{
+ return virDomainEventNew(def->id, def->name, def->uuid, type, detail);
+}
+
/**
* virDomainEventQueueFree:
* @queue: pointer to the queue
virDomainEventQueueFree(virDomainEventQueuePtr queue)
{
int i;
- for ( i=0 ; i<queue->count ; i++ ) {
- VIR_FREE(queue->events[i]);
+ if (!queue)
+ return;
+
+ for (i = 0; i < queue->count ; i++) {
+ virDomainEventFree(queue->events[i]);
}
+ VIR_FREE(queue->events);
VIR_FREE(queue);
}
/**
- * virDomainEventCallbackQueuePop:
+ * virDomainEventQueuePop:
* @evtQueue: the queue of events
*
* Internal function to pop off, and return the front of the queue
* Returns: virDomainEventPtr on success NULL on failure.
*/
virDomainEventPtr
-virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue)
+virDomainEventQueuePop(virDomainEventQueuePtr evtQueue)
{
virDomainEventPtr ret;
}
/**
- * virDomainEventCallbackQueuePush:
+ * virDomainEventQueuePush:
* @evtQueue: the dom event queue
- * @dom: the domain to add
* @event: the event to add
*
* Internal function to push onto the back of an virDomainEventQueue
* Returns: 0 on success, -1 on failure
*/
int
-virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue,
- virDomainPtr dom,
- int event,
- int detail)
+virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
+ virDomainEventPtr event)
{
- virDomainEventPtr domEvent;
-
- /* Check incoming */
- if ( !evtQueue ) {
- return -1;
- }
-
- /* Allocate new event */
- if (VIR_ALLOC(domEvent) < 0) {
- DEBUG0("Error allocating event");
+ if (!evtQueue) {
return -1;
}
- domEvent->dom = dom;
- domEvent->event = event;
- domEvent->detail = detail;
/* Make space on queue */
if (VIR_REALLOC_N(evtQueue->events,
evtQueue->count + 1) < 0) {
DEBUG0("Error reallocating queue");
- VIR_FREE(domEvent);
return -1;
}
- evtQueue->events[evtQueue->count] = domEvent;
+ evtQueue->events[evtQueue->count] = event;
evtQueue->count++;
return 0;
}
+
+void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
+ virDomainEventPtr event,
+ virConnectDomainEventCallback cb,
+ void *cbopaque,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ virDomainPtr dom = virGetDomain(conn, event->name, event->uuid);
+ if (dom) {
+ dom->id = event->id;
+ (*cb)(conn, dom, event->type, event->detail, cbopaque);
+ virDomainFree(dom);
+ }
+}
+
+
+void virDomainEventDispatch(virDomainEventPtr event,
+ virDomainEventCallbackListPtr callbacks,
+ virDomainEventDispatchFunc dispatch,
+ void *opaque)
+{
+ int i;
+ /* Cache this now, since we may be dropping the lock,
+ and have more callbacks added. We're guarenteed not
+ to have any removed */
+ int cbCount = callbacks->count;
+
+ for (i = 0 ; i < cbCount ; i++) {
+ if (callbacks->callbacks[i] &&
+ !callbacks->callbacks[i]->deleted) {
+ (*dispatch)(callbacks->callbacks[i]->conn,
+ event,
+ callbacks->callbacks[i]->cb,
+ callbacks->callbacks[i]->opaque,
+ opaque);
+ }
+ }
+}
+
+
+void virDomainEventQueueDispatch(virDomainEventQueuePtr queue,
+ virDomainEventCallbackListPtr callbacks,
+ virDomainEventDispatchFunc dispatch,
+ void *opaque)
+{
+ int i;
+
+ for (i = 0 ; i < queue->count ; i++) {
+ virDomainEventDispatch(queue->events[i], callbacks, dispatch, opaque);
+ virDomainEventFree(queue->events[i]);
+ }
+ VIR_FREE(queue->events);
+ queue->count = 0;
+}
#include "internal.h"
-
#ifndef __DOMAIN_EVENT_H__
#define __DOMAIN_EVENT_H__
+#include "domain_conf.h"
+
struct _virDomainEventCallback {
virConnectPtr conn;
virConnectDomainEventCallback cb;
void *opaque;
virFreeCallback freecb;
-
+ int deleted;
};
typedef struct _virDomainEventCallback virDomainEventCallback;
typedef virDomainEventCallback *virDomainEventCallbackPtr;
int virDomainEventCallbackListRemoveConn(virConnectPtr conn,
virDomainEventCallbackListPtr cbList);
+int virDomainEventCallbackListMarkDelete(virConnectPtr conn,
+ virDomainEventCallbackListPtr cbList,
+ virConnectDomainEventCallback callback);
+int virDomainEventCallbackListPurgeMarked(virDomainEventCallbackListPtr cbList);
+
/**
* Dispatching domain events that come in while
* in a call / response rpc
*/
struct _virDomainEvent {
- virDomainPtr dom;
- int event;
+ int id;
+ char *name;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ int type;
int detail;
};
typedef struct _virDomainEvent virDomainEvent;
typedef struct _virDomainEventQueue virDomainEventQueue;
typedef virDomainEventQueue *virDomainEventQueuePtr;
-int virDomainEventCallbackQueuePush(virDomainEventQueuePtr evtQueue,
- virDomainPtr dom,
- int event,
- int detail);
+virDomainEventQueuePtr virDomainEventQueueNew(void);
+
+virDomainEventPtr virDomainEventNew(int id, const char *name, const unsigned char *uuid, int type, int detail);
+virDomainEventPtr virDomainEventNewFromDom(virDomainPtr dom, int type, int detail);
+virDomainEventPtr virDomainEventNewFromObj(virDomainObjPtr obj, int type, int detail);
+virDomainEventPtr virDomainEventNewFromDef(virDomainDefPtr def, int type, int detail);
+
+int virDomainEventQueuePush(virDomainEventQueuePtr evtQueue,
+ virDomainEventPtr event);
virDomainEventPtr
-virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue);
+virDomainEventQueuePop(virDomainEventQueuePtr evtQueue);
+void virDomainEventFree(virDomainEventPtr event);
void virDomainEventQueueFree(virDomainEventQueuePtr queue);
+typedef void (*virDomainEventDispatchFunc)(virConnectPtr conn,
+ virDomainEventPtr event,
+ virConnectDomainEventCallback cb,
+ void *cbopaque,
+ void *opaque);
+void virDomainEventDispatchDefaultFunc(virConnectPtr conn,
+ virDomainEventPtr event,
+ virConnectDomainEventCallback cb,
+ void *cbopaque,
+ void *opaque);
+
+void virDomainEventDispatch(virDomainEventPtr event,
+ virDomainEventCallbackListPtr cbs,
+ virDomainEventDispatchFunc dispatch,
+ void *opaque);
+void virDomainEventQueueDispatch(virDomainEventQueuePtr queue,
+ virDomainEventCallbackListPtr cbs,
+ virDomainEventDispatchFunc dispatch,
+ void *opaque);
#endif
virDomainEventCallbackListFree;
virDomainEventCallbackListRemove;
virDomainEventCallbackListRemoveConn;
+ virDomainEventCallbackListMarkDelete;
+ virDomainEventCallbackListPurgeMarked;
+ virDomainEventQueueNew;
virDomainEventQueueFree;
- virDomainEventCallbackQueuePop;
- virDomainEventCallbackQueuePush;
+ virDomainEventQueuePop;
+ virDomainEventQueuePush;
+ virDomainEventNew;
+ virDomainEventNewFromDom;
+ virDomainEventNewFromObj;
+ virDomainEventNewFromDef;
+ virDomainEventFree;
+ virDomainEventDispatchDefaultFunc;
+ virDomainEventDispatch;
+ virDomainEventQueueDispatch;
+
/* driver.h */
/* An array of callbacks */
virDomainEventCallbackListPtr domainEventCallbacks;
+ virDomainEventQueuePtr domainEventQueue;
+ int domainEventTimer;
+ int domainEventDispatching;
};
/* Port numbers used for KVM migration. */
}
-static void qemudDomainEventDispatch (struct qemud_driver *driver,
- virDomainObjPtr vm,
- int event,
- int detail);
+
+static void qemuDomainEventFlush(int timer, void *opaque);
+static void qemuDomainEventQueue(struct qemud_driver *driver,
+ virDomainEventPtr event);
static void qemudDispatchVMEvent(int watch,
int fd,
vm->def->name,
err ? err->message : NULL);
} else {
- qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
+ virDomainEventPtr event =
+ virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
+ if (event)
+ qemuDomainEventQueue(driver, event);
}
}
virDomainObjUnlock(vm);
/* Init callback list */
if(VIR_ALLOC(qemu_driver->domainEventCallbacks) < 0)
goto out_of_memory;
+ if (!(qemu_driver->domainEventQueue = virDomainEventQueueNew()))
+ goto out_of_memory;
+
+ if ((qemu_driver->domainEventTimer =
+ virEventAddTimeout(-1, qemuDomainEventFlush, qemu_driver, NULL)) < 0)
+ goto error;
if (!uid) {
if (asprintf(&qemu_driver->logDir,
{
struct qemud_driver *driver = opaque;
- if (newVM)
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_DEFINED,
- VIR_DOMAIN_EVENT_DEFINED_ADDED);
+ if (newVM) {
+ virDomainEventPtr event =
+ virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_DEFINED,
+ VIR_DOMAIN_EVENT_DEFINED_ADDED);
+ if (event)
+ qemuDomainEventQueue(driver, event);
+ }
}
/**
/* Free domain callback list */
virDomainEventCallbackListFree(qemu_driver->domainEventCallbacks);
+ virDomainEventQueueFree(qemu_driver->domainEventQueue);
+
+ if (qemu_driver->domainEventTimer != -1)
+ virEventRemoveTimeout(qemu_driver->domainEventTimer);
if (qemu_driver->brctl)
brShutdown(qemu_driver->brctl);
qemudDispatchVMEvent(int watch, int fd, int events, void *opaque) {
struct qemud_driver *driver = opaque;
virDomainObjPtr vm = NULL;
+ virDomainEventPtr event = NULL;
unsigned int i;
int quit = 0, failed = 0;
}
if (failed || quit) {
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ quit ?
+ VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN :
+ VIR_DOMAIN_EVENT_STOPPED_FAILED);
qemudShutdownVMDaemon(NULL, driver, vm);
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_STOPPED,
- quit ?
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN :
- VIR_DOMAIN_EVENT_STOPPED_FAILED);
if (!vm->persistent) {
virDomainRemoveInactive(&driver->domains,
vm);
cleanup:
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
}
virDomainDefPtr def;
virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL;
+ virDomainEventPtr event = NULL;
qemuDriverLock(driver);
if (!(def = virDomainDefParseString(conn, driver->caps, xml)))
vm = NULL;
goto cleanup;
}
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
+
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom) dom->id = vm->def->id;
virDomainDefFree(def);
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return dom;
}
char *info;
virDomainObjPtr vm;
int ret = -1;
+ virDomainEventPtr event = NULL;
qemuDriverLock(driver);
vm = virDomainFindByID(&driver->domains, dom->id);
}
vm->state = VIR_DOMAIN_PAUSED;
qemudDebug("Reply %s", info);
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
VIR_FREE(info);
}
ret = 0;
cleanup:
if (vm)
virDomainObjUnlock(vm);
+
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
return ret;
}
char *info;
virDomainObjPtr vm;
int ret = -1;
+ virDomainEventPtr event = NULL;
qemuDriverLock(driver);
vm = virDomainFindByID(&driver->domains, dom->id);
}
vm->state = VIR_DOMAIN_RUNNING;
qemudDebug("Reply %s", info);
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_RESUMED,
- VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
VIR_FREE(info);
}
ret = 0;
cleanup:
if (vm)
virDomainObjUnlock(vm);
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
return ret;
}
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
+ virDomainEventPtr event = NULL;
qemuDriverLock(driver);
vm = virDomainFindByID(&driver->domains, dom->id);
}
qemudShutdownVMDaemon(dom->conn, driver, vm);
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
if (!vm->persistent) {
virDomainRemoveInactive(&driver->domains,
vm);
cleanup:
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
char *xml = NULL;
struct qemud_save_header header;
int ret = -1;
+ virDomainEventPtr event = NULL;
memset(&header, 0, sizeof(header));
memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
/* Shut it down */
qemudShutdownVMDaemon(dom->conn, driver, vm);
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SAVED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
if (!vm->persistent) {
virDomainRemoveInactive(&driver->domains,
vm);
unlink(path);
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
int ret = -1;
char *xml = NULL;
struct qemud_save_header header;
+ virDomainEventPtr event = NULL;
qemuDriverLock(driver);
/* Verify the header and read the XML */
goto cleanup;
}
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_RESTORED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_RESTORED);
/* If it was running before, resume it now. */
if (header.was_running) {
close(fd);
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
+ virDomainEventPtr event = NULL;
qemuDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL);
if (ret != -1)
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
cleanup:
if (vm)
virDomainObjUnlock(vm);
+ if (event) {
+ qemuDriverLock(driver);
+ qemuDomainEventQueue(driver, event);
+ qemuDriverUnlock(driver);
+ }
return ret;
}
virDomainDefPtr def;
virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL;
+ virDomainEventPtr event = NULL;
int newVM = 1;
qemuDriverLock(driver);
goto cleanup;
}
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_DEFINED,
- newVM ?
- VIR_DOMAIN_EVENT_DEFINED_ADDED :
- VIR_DOMAIN_EVENT_DEFINED_UPDATED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_DEFINED,
+ newVM ?
+ VIR_DOMAIN_EVENT_DEFINED_ADDED :
+ VIR_DOMAIN_EVENT_DEFINED_UPDATED);
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom) dom->id = vm->def->id;
cleanup:
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return dom;
}
static int qemudDomainUndefine(virDomainPtr dom) {
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
+ virDomainEventPtr event = NULL;
int ret = -1;
qemuDriverLock(driver);
if (virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm) < 0)
goto cleanup;
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_UNDEFINED,
- VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_UNDEFINED,
+ VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
virDomainRemoveInactive(&driver->domains,
vm);
cleanup:
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
int ret;
qemuDriverLock(driver);
- ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
- callback);
+ if (driver->domainEventDispatching)
+ ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
+ callback);
+ else
+ ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
+ callback);
qemuDriverUnlock(driver);
return ret;
}
-static void qemudDomainEventDispatch (struct qemud_driver *driver,
- virDomainObjPtr vm,
- int event,
- int detail)
+static void qemuDomainEventDispatchFunc(virConnectPtr conn,
+ virDomainEventPtr event,
+ virConnectDomainEventCallback cb,
+ void *cbopaque,
+ void *opaque)
{
- int i;
- virDomainEventCallbackListPtr cbList;
-
- cbList = driver->domainEventCallbacks;
-
- for(i=0 ; i < cbList->count ; i++) {
- 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 detail %d",
- cbList->callbacks[i],
- cbList->callbacks[i]->cb, event, detail);
- cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
- dom, event, detail,
- cbList->callbacks[i]->opaque);
- virDomainFree(dom);
- }
- }
- }
+ struct qemud_driver *driver = opaque;
+ /* Drop the lock whle dispatching, for sake of re-entrancy */
+ qemuDriverUnlock(driver);
+ virDomainEventDispatchDefaultFunc(conn, event, cb, cbopaque, NULL);
+ qemuDriverLock(driver);
+}
+
+static void qemuDomainEventFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
+{
+ struct qemud_driver *driver = opaque;
+ virDomainEventQueue tempQueue;
+
+ qemuDriverLock(driver);
+
+ driver->domainEventDispatching = 1;
+
+ /* Copy the queue, so we're reentrant safe */
+ tempQueue.count = driver->domainEventQueue->count;
+ tempQueue.events = driver->domainEventQueue->events;
+ driver->domainEventQueue->count = 0;
+ driver->domainEventQueue->events = NULL;
+
+ virEventUpdateTimeout(driver->domainEventTimer, -1);
+ virDomainEventQueueDispatch(&tempQueue,
+ driver->domainEventCallbacks,
+ qemuDomainEventDispatchFunc,
+ driver);
+
+ /* Purge any deleted callbacks */
+ virDomainEventCallbackListPurgeMarked(driver->domainEventCallbacks);
+
+ driver->domainEventDispatching = 0;
+ qemuDriverUnlock(driver);
+}
+
+
+/* driver must be locked before calling */
+static void qemuDomainEventQueue(struct qemud_driver *driver,
+ virDomainEventPtr event)
+{
+ if (virDomainEventQueuePush(driver->domainEventQueue,
+ event) < 0)
+ virDomainEventFree(event);
+ if (qemu_driver->domainEventQueue->count == 1)
+ virEventUpdateTimeout(driver->domainEventTimer, 0);
}
/* Migration support. */
char hostname [HOST_NAME_MAX+1];
char migrateFrom [64];
const char *p;
+ virDomainEventPtr event = NULL;
int ret = -1;;
*uri_out = NULL;
}
goto cleanup;
}
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_MIGRATED);
+
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_MIGRATED);
ret = 0;
cleanup:
}
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
{
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
+ virDomainEventPtr event = NULL;
char *safe_uri;
char cmd[HOST_NAME_MAX+50];
char *info = NULL;
DEBUG ("stop reply: %s", info);
VIR_FREE(info);
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_SUSPENDED,
- VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
+ if (event)
+ qemuDomainEventQueue(driver, event);
+ event = NULL;
}
if (resource > 0) {
/* Clean up the source domain. */
qemudShutdownVMDaemon (dom->conn, driver, vm);
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
+
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
if (!vm->persistent) {
virDomainRemoveInactive(&driver->domains, vm);
vm = NULL;
VIR_FREE(info);
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
struct qemud_driver *driver = dconn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
+ virDomainEventPtr event = NULL;
char *info = NULL;
qemuDriverLock(driver);
dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
VIR_FREE(info);
vm->state = VIR_DOMAIN_RUNNING;
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_RESUMED,
- VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
} else {
qemudShutdownVMDaemon (dconn, driver, vm);
- qemudDomainEventDispatch(driver, vm,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_FAILED);
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_FAILED);
if (!vm->persistent) {
virDomainRemoveInactive(&driver->domains, vm);
vm = NULL;
cleanup:
if (vm)
virDomainObjUnlock(vm);
+ if (event)
+ qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return dom;
}
*
* Read the event data off the wire
*/
-static int
-remoteDomainReadEvent(virConnectPtr conn, XDR *xdr,
- virDomainPtr *dom, int *event, int *detail)
+static virDomainEventPtr
+remoteDomainReadEvent(virConnectPtr conn, XDR *xdr)
{
remote_domain_event_ret ret;
+ virDomainPtr dom;
+ virDomainEventPtr event = NULL;
memset (&ret, 0, sizeof ret);
/* unmarshall parameters, and process it*/
if (! xdr_remote_domain_event_ret(xdr, &ret) ) {
error (conn, VIR_ERR_RPC,
_("remoteDomainProcessEvent: unmarshalling ret"));
- return -1;
+ return NULL;
}
- *dom = get_nonnull_domain(conn,ret.dom);
- *event = ret.event;
- *detail = ret.detail;
+ dom = get_nonnull_domain(conn,ret.dom);
+ if (!dom)
+ return NULL;
- return 0;
+ event = virDomainEventNewFromDom(dom, ret.event, ret.detail);
+
+ virDomainFree(dom);
+ return event;
}
static void
remoteDomainProcessEvent(virConnectPtr conn, XDR *xdr)
{
- virDomainPtr dom;
- int event, detail, i;
struct private_data *priv = conn->privateData;
+ virDomainEventPtr event;
- if(!remoteDomainReadEvent(conn, xdr, &dom, &event, &detail)) {
- DEBUG0("Calling domain event callbacks (no queue)");
- for(i=0 ; i < priv->callbackList->count ; i++) {
- if (priv->callbackList->callbacks[i] )
- priv->callbackList->callbacks[i]->cb(
- conn, dom, event, detail,
- priv->callbackList->callbacks[i]->opaque);
- }
- }
+ event = remoteDomainReadEvent(conn, xdr);
+ if (!event)
+ return;
+
+ DEBUG0("Calling domain event callbacks (no queue)");
+ virDomainEventDispatch(event, priv->callbackList,
+ virDomainEventDispatchDefaultFunc, NULL);
+ virDomainEventFree(event);
}
static void
remoteDomainQueueEvent(virConnectPtr conn, XDR *xdr)
{
- virDomainPtr dom;
- int event, detail;
struct private_data *priv = conn->privateData;
+ virDomainEventPtr event;
- if(!remoteDomainReadEvent(conn, xdr, &dom, &event, &detail))
- {
- if( virDomainEventCallbackQueuePush(priv->domainEvents,
- dom, event, detail) < 0 ) {
- DEBUG("%s", "Error adding event to queue");
- }
- }
+ event = remoteDomainReadEvent(conn, xdr);
+ if (!event)
+ return;
+
+ if (virDomainEventQueuePush(priv->domainEvents,
+ event) < 0)
+ DEBUG0("Error adding event to queue");
+
+ virDomainEventFree(event);
}
/** remoteDomainEventFired:
void
remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
{
- int i;
- virDomainEventPtr domEvent;
- void *user_data = NULL;
virConnectPtr conn = opaque;
struct private_data *priv = conn->privateData;
- while( (domEvent = virDomainEventCallbackQueuePop(priv->domainEvents)) ) {
- DEBUG(" Flushing %p", domEvent);
- for (i=0 ; i < priv->callbackList->count ; i++) {
- if( priv->callbackList->callbacks[i] ) {
- user_data = priv->callbackList->callbacks[i]->opaque;
- priv->callbackList->callbacks[i]->cb(domEvent->dom->conn,
- domEvent->dom,
- domEvent->event,
- domEvent->detail,
- user_data);
- }
- }
- VIR_FREE(domEvent);
- }
-
+ virDomainEventQueueDispatch(priv->domainEvents, priv->callbackList,
+ virDomainEventDispatchDefaultFunc, NULL);
virEventUpdateTimeout(priv->eventFlushTimer, -1);
}
NULL, /* domainSetSchedulerParameters */
};
-static virDomainPtr
-xenInotifyXenCacheLookup(virConnectPtr conn, const char *filename) {
+static int
+xenInotifyXenCacheLookup(const char *filename,
+ char **name, unsigned char *uuid) {
xenXMConfCachePtr entry;
- virDomainPtr dom;
if (!(entry = virHashLookup(xenXMGetConfigCache(), filename))) {
DEBUG("No config found for %s", filename);
- return NULL;
+ return -1;
}
- if(!(dom = virGetDomain(conn, entry->def->name,
- (unsigned char*)entry->def->uuid))) {
+ *name = strdup(entry->def->name);
+ memcpy(uuid, entry->def->uuid, VIR_UUID_BUFLEN);
+
+ if (!*name) {
DEBUG0("Error getting dom from def");
- return NULL;
+ return -1;
}
- return dom;
+ return 0;
}
-static virDomainPtr
-xenInotifyXendDomainsDirLookup(virConnectPtr conn, const char *filename) {
+static int
+xenInotifyXendDomainsDirLookup(virConnectPtr conn, const char *filename,
+ char **name, unsigned char *uuid) {
int i;
virDomainPtr dom;
const char *uuid_str;
- unsigned char uuid[VIR_UUID_BUFLEN];
+ unsigned char rawuuid[VIR_UUID_BUFLEN];
/* xend is managing domains. we will get
* a filename in the manner:
*/
uuid_str = filename + strlen(LIBVIRTD_DOMAINS_DIR) + 1;
- if (virUUIDParse(uuid_str, uuid) < 0) {
+ if (virUUIDParse(uuid_str, rawuuid) < 0) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"parsing uuid %s", uuid_str);
- return (NULL);
+ return -1;
}
/* call directly into xend here, as driver may not yet
be set during open while we are building our
initial list of domains */
DEBUG("Looking for dom with uuid: %s", uuid_str);
- if(!(dom = xenDaemonLookupByUUID(conn, uuid))) {
+ /* XXX Should not have to go via a virDomainPtr obj instance */
+ if(!(dom = xenDaemonLookupByUUID(conn, rawuuid))) {
/* If we are here, the domain has gone away.
search for, and create a domain from the stored
list info */
for (i=0; i<configInfoList->count; i++) {
if (!memcmp(uuid, configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN)) {
- if(!(dom = virGetDomain(conn, configInfoList->doms[i]->name,
- configInfoList->doms[i]->uuid))) {
+ *name = strdup(configInfoList->doms[i]->name);
+ if (!*name) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"finding dom for %s", uuid_str);
- return NULL;
+ return -1;
}
+ memcpy(uuid, configInfoList->doms[i]->uuid, VIR_UUID_BUFLEN);
DEBUG0("Found dom on list");
- return dom;
+ return 0;
}
}
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("finding dom on config list"));
- return NULL;
+ "%s", _("finding dom on config list"));
+ return -1;
}
+ if (!(*name = strdup(dom->name)))
+ return -1;
+ memcpy(uuid, dom->uuid, VIR_UUID_BUFLEN);
+ virDomainFree(dom);
/* succeeded too find domain by uuid */
- return dom;
+ return 0;
}
-static virDomainPtr
-xenInotifyDomainLookup(virConnectPtr conn, const char *filename) {
- virDomainPtr dom;
- virDomainInfo info;
-
- dom = useXenConfigCache ? xenInotifyXenCacheLookup(conn, filename) :
- xenInotifyXendDomainsDirLookup(conn, filename);
-
- if(dom) {
- if ( (useXenConfigCache ? xenXMDomainGetInfo(dom, &info) :
- xenDaemonDomainGetInfo(dom, &info)) < 0)
- dom->id = -1;
- else
- dom->id = (info.state == VIR_DOMAIN_SHUTOFF) ? -1 : dom->id;
- return dom;
- }
- return NULL;
+static int
+xenInotifyDomainLookup(virConnectPtr conn,
+ const char *filename,
+ char **name, unsigned char *uuid) {
+ if (useXenConfigCache)
+ return xenInotifyXenCacheLookup(filename, name, uuid);
+ else
+ return xenInotifyXendDomainsDirLookup(conn, filename, name, uuid);
+}
+
+static virDomainEventPtr
+xenInotifyDomainEventFromFile(virConnectPtr conn,
+ const char *filename,
+ int type, int detail) {
+ virDomainEventPtr event;
+ char *name = NULL;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+
+ if (xenInotifyDomainLookup(conn, filename, &name, uuid) < 0)
+ return NULL;
+
+ event = virDomainEventNew(-1, name, uuid, type, detail);
+ VIR_FREE(name);
+ return event;
}
static int
static int
xenInotifyXendDomainsDirAddEntry(virConnectPtr conn,
const char *fname) {
- virDomainPtr dom = xenInotifyDomainLookup(conn, fname);
- if(!dom) {
+ char *name = NULL;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ if (xenInotifyDomainLookup(conn, fname, &name, uuid) < 0) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("Error looking up domain"));
+ "%s", _("Error looking up domain"));
return -1;
}
if( xenUnifiedAddDomainInfo(configInfoList,
- dom->id, dom->name, dom->uuid) < 0) {
+ -1, name, uuid) < 0) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config cache"));
- virUnrefDomain(dom);
+ VIR_FREE(name);
return -1;
}
- virUnrefDomain(dom);
+ VIR_FREE(name);
return 0;
}
char *tmp, *name;
virConnectPtr conn = (virConnectPtr) data;
xenUnifiedPrivatePtr priv = NULL;
- virDomainPtr dom = NULL;
DEBUG0("got inotify event");
snprintf(fname, 1024, "%s/%s", configDir, name);
if (e->mask & (IN_DELETE | IN_MOVED_FROM)) {
- if (!(dom = xenInotifyDomainLookup(conn, fname))) {
+ virDomainEventPtr event =
+ xenInotifyDomainEventFromFile(conn, fname,
+ VIR_DOMAIN_EVENT_UNDEFINED,
+ VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
+ if (!event)
+ xenUnifiedDomainEventDispatch(conn->privateData, event);
+ else
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("looking up dom"));
- continue;
- }
-
- xenUnifiedDomainEventDispatch(conn->privateData, dom,
- VIR_DOMAIN_EVENT_UNDEFINED,
- VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
-
+ "%s", _("looking up dom"));
if (xenInotifyRemoveDomainConfigInfo(conn, fname) < 0 ) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
return;
}
} else if (e->mask & ( IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO) ) {
+ virDomainEventPtr event;
if (xenInotifyAddDomainConfigInfo(conn, fname) < 0 ) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("Error adding file to config cache"));
return;
}
- if (!(dom = xenInotifyDomainLookup(conn, fname))) {
+ event = xenInotifyDomainEventFromFile(conn, fname,
+ VIR_DOMAIN_EVENT_DEFINED,
+ VIR_DOMAIN_EVENT_DEFINED_ADDED);
+
+ if (event)
+ xenUnifiedDomainEventDispatch(conn->privateData, event);
+ else
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("looking up dom"));
- continue;
- }
+ "%s", _("looking up dom"));
- xenUnifiedDomainEventDispatch(conn->privateData, dom,
- VIR_DOMAIN_EVENT_DEFINED,
- VIR_DOMAIN_EVENT_DEFINED_ADDED);
}
}
*
*/
void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
- virDomainPtr dom,
- int event,
- int detail)
+ virDomainEventPtr event)
{
- int i;
- virDomainEventCallbackListPtr cbList;
-
- if(!priv) return;
-
- cbList = priv->domainEventCallbacks;
- if(!cbList) return;
+ if (!priv || !priv->domainEventCallbacks)
+ return;
- for(i=0 ; i < cbList->count ; i++) {
- if(cbList->callbacks[i] && cbList->callbacks[i]->cb) {
- if (dom) {
- DEBUG("Dispatching callback %p %p event %d",
- cbList->callbacks[i],
- cbList->callbacks[i]->cb, event);
- cbList->callbacks[i]->cb(cbList->callbacks[i]->conn,
- dom, event, detail,
- cbList->callbacks[i]->opaque);
- }
- }
- }
+ virDomainEventDispatch(event,
+ priv->domainEventCallbacks,
+ virDomainEventDispatchDefaultFunc,
+ NULL);
+ virDomainEventFree(event);
}
int id, char *name,
unsigned char *uuid);
void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
- virDomainPtr dom,
- int event,
- int detail);
+ virDomainEventPtr event);
unsigned long xenUnifiedVersion(void);
#endif /* __VIR_XEN_UNIFIED_H__ */
}
if (!found) {
- virDomainPtr dom;
+ virDomainEventPtr event;
char *name;
unsigned char uuid[VIR_UUID_BUFLEN];
continue;
}
- dom = virGetDomain(conn, name, uuid);
- if (dom) {
- dom->id = new_domids[i];
+ event = virDomainEventNew(new_domids[i], name, uuid,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
+ if (event)
+ xenUnifiedDomainEventDispatch(priv, event);
- /* This domain was not in the old list. Emit an event */
- xenUnifiedDomainEventDispatch(priv, dom,
- VIR_DOMAIN_EVENT_STARTED,
- VIR_DOMAIN_EVENT_STARTED_BOOTED);
-
- /* Add to the list */
- xenUnifiedAddDomainInfo(activeDomainList,
- new_domids[i], name, uuid);
-
- virUnrefDomain(dom);
- }
+ /* Add to the list */
+ xenUnifiedAddDomainInfo(activeDomainList,
+ new_domids[i], name, uuid);
VIR_FREE(name);
}
}
if (!found) {
- virDomainPtr dom = virGetDomain(conn,
- activeDomainList->doms[j]->name,
- activeDomainList->doms[j]->uuid);
- if(dom) {
- dom->id = -1;
- /* This domain was not in the new list. Emit an event */
- xenUnifiedDomainEventDispatch(priv, dom,
- VIR_DOMAIN_EVENT_STOPPED,
- VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
- /* Remove from the list */
- xenUnifiedRemoveDomainInfo(activeDomainList,
- activeDomainList->doms[j]->id,
- activeDomainList->doms[j]->name,
- activeDomainList->doms[j]->uuid);
-
- virUnrefDomain(dom);
- removed = 1;
- }
+ virDomainEventPtr event =
+ virDomainEventNew(-1,
+ activeDomainList->doms[j]->name,
+ activeDomainList->doms[j]->uuid,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+ if (event)
+ xenUnifiedDomainEventDispatch(priv, event);
+
+ /* Remove from the list */
+ xenUnifiedRemoveDomainInfo(activeDomainList,
+ activeDomainList->doms[j]->id,
+ activeDomainList->doms[j]->name,
+ activeDomainList->doms[j]->uuid);
+
+ removed = 1;
}
}