QEMU domain event thread safety

This commit is contained in:
Daniel P. Berrange 2008-12-04 21:09:20 +00:00
parent 3527f16a94
commit bc898df2c7
11 changed files with 569 additions and 284 deletions

View File

@ -1,3 +1,18 @@
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

View File

@ -125,6 +125,49 @@ virDomainEventCallbackListRemoveConn(virConnectPtr conn,
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
@ -182,6 +225,62 @@ virDomainEventCallbackListAdd(virConnectPtr conn,
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
@ -192,14 +291,18 @@ void
virDomainEventQueueFree(virDomainEventQueuePtr queue)
{
int i;
if (!queue)
return;
for (i = 0; i < queue->count ; i++) {
VIR_FREE(queue->events[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
@ -208,7 +311,7 @@ virDomainEventQueueFree(virDomainEventQueuePtr queue)
* Returns: virDomainEventPtr on success NULL on failure.
*/
virDomainEventPtr
virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue)
virDomainEventQueuePop(virDomainEventQueuePtr evtQueue)
{
virDomainEventPtr ret;
@ -232,9 +335,8 @@ virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue)
}
/**
* 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
@ -242,37 +344,76 @@ virDomainEventCallbackQueuePop(virDomainEventQueuePtr evtQueue)
* 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");
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;
}

View File

@ -22,16 +22,17 @@
#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;
@ -58,13 +59,20 @@ int virDomainEventCallbackListRemove(virConnectPtr conn,
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;
@ -77,15 +85,40 @@ struct _virDomainEventQueue {
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

View File

@ -383,9 +383,21 @@ LIBVIRT_PRIVATE_@VERSION@ {
virDomainEventCallbackListFree;
virDomainEventCallbackListRemove;
virDomainEventCallbackListRemoveConn;
virDomainEventCallbackListMarkDelete;
virDomainEventCallbackListPurgeMarked;
virDomainEventQueueNew;
virDomainEventQueueFree;
virDomainEventCallbackQueuePop;
virDomainEventCallbackQueuePush;
virDomainEventQueuePop;
virDomainEventQueuePush;
virDomainEventNew;
virDomainEventNewFromDom;
virDomainEventNewFromObj;
virDomainEventNewFromDef;
virDomainEventFree;
virDomainEventDispatchDefaultFunc;
virDomainEventDispatch;
virDomainEventQueueDispatch;
/* driver.h */

View File

@ -71,6 +71,9 @@ struct qemud_driver {
/* An array of callbacks */
virDomainEventCallbackListPtr domainEventCallbacks;
virDomainEventQueuePtr domainEventQueue;
int domainEventTimer;
int domainEventDispatching;
};
/* Port numbers used for KVM migration. */

View File

@ -115,10 +115,10 @@ static int qemudSetNonBlock(int fd) {
}
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,
@ -160,8 +160,12 @@ qemudAutostartConfigs(struct qemud_driver *driver) {
vm->def->name,
err ? err->message : NULL);
} else {
qemudDomainEventDispatch(driver, vm, VIR_DOMAIN_EVENT_STARTED,
virDomainEventPtr event =
virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
if (event)
qemuDomainEventQueue(driver, event);
}
}
virDomainObjUnlock(vm);
@ -192,6 +196,12 @@ qemudStartup(void) {
/* 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,
@ -265,10 +275,14 @@ static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
struct qemud_driver *driver = opaque;
if (newVM)
qemudDomainEventDispatch(driver, vm,
if (newVM) {
virDomainEventPtr event =
virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_DEFINED,
VIR_DOMAIN_EVENT_DEFINED_ADDED);
if (event)
qemuDomainEventQueue(driver, event);
}
}
/**
@ -359,6 +373,10 @@ qemudShutdown(void) {
/* 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);
@ -1075,6 +1093,7 @@ static void
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;
@ -1107,12 +1126,12 @@ qemudDispatchVMEvent(int watch, int fd, int events, void *opaque) {
}
if (failed || quit) {
qemudShutdownVMDaemon(NULL, driver, vm);
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
quit ?
VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN :
VIR_DOMAIN_EVENT_STOPPED_FAILED);
qemudShutdownVMDaemon(NULL, driver, vm);
if (!vm->persistent) {
virDomainRemoveInactive(&driver->domains,
vm);
@ -1123,6 +1142,8 @@ qemudDispatchVMEvent(int watch, int fd, int events, void *opaque) {
cleanup:
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
}
@ -1591,6 +1612,7 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
virDomainDefPtr def;
virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL;
virDomainEventPtr event = NULL;
qemuDriverLock(driver);
if (!(def = virDomainDefParseString(conn, driver->caps, xml)))
@ -1627,7 +1649,8 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
vm = NULL;
goto cleanup;
}
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
@ -1638,6 +1661,8 @@ cleanup:
virDomainDefFree(def);
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return dom;
}
@ -1648,6 +1673,7 @@ static int qemudDomainSuspend(virDomainPtr dom) {
char *info;
virDomainObjPtr vm;
int ret = -1;
virDomainEventPtr event = NULL;
qemuDriverLock(driver);
vm = virDomainFindByID(&driver->domains, dom->id);
@ -1670,7 +1696,7 @@ static int qemudDomainSuspend(virDomainPtr dom) {
}
vm->state = VIR_DOMAIN_PAUSED;
qemudDebug("Reply %s", info);
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_SUSPENDED,
VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
VIR_FREE(info);
@ -1680,6 +1706,12 @@ static int qemudDomainSuspend(virDomainPtr dom) {
cleanup:
if (vm)
virDomainObjUnlock(vm);
if (event) {
qemuDriverLock(driver);
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
}
return ret;
}
@ -1689,6 +1721,7 @@ static int qemudDomainResume(virDomainPtr dom) {
char *info;
virDomainObjPtr vm;
int ret = -1;
virDomainEventPtr event = NULL;
qemuDriverLock(driver);
vm = virDomainFindByID(&driver->domains, dom->id);
@ -1712,7 +1745,7 @@ static int qemudDomainResume(virDomainPtr dom) {
}
vm->state = VIR_DOMAIN_RUNNING;
qemudDebug("Reply %s", info);
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_RESUMED,
VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
VIR_FREE(info);
@ -1722,6 +1755,11 @@ static int qemudDomainResume(virDomainPtr dom) {
cleanup:
if (vm)
virDomainObjUnlock(vm);
if (event) {
qemuDriverLock(driver);
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
}
return ret;
}
@ -1761,6 +1799,7 @@ static int qemudDomainDestroy(virDomainPtr dom) {
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
virDomainEventPtr event = NULL;
qemuDriverLock(driver);
vm = virDomainFindByID(&driver->domains, dom->id);
@ -1771,7 +1810,7 @@ static int qemudDomainDestroy(virDomainPtr dom) {
}
qemudShutdownVMDaemon(dom->conn, driver, vm);
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
if (!vm->persistent) {
@ -1784,6 +1823,8 @@ static int qemudDomainDestroy(virDomainPtr dom) {
cleanup:
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
@ -2053,6 +2094,7 @@ static int qemudDomainSave(virDomainPtr dom,
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));
@ -2154,7 +2196,7 @@ static int qemudDomainSave(virDomainPtr dom,
/* Shut it down */
qemudShutdownVMDaemon(dom->conn, driver, vm);
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_SAVED);
if (!vm->persistent) {
@ -2175,6 +2217,8 @@ cleanup:
unlink(path);
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
@ -2412,6 +2456,7 @@ static int qemudDomainRestore(virConnectPtr conn,
int ret = -1;
char *xml = NULL;
struct qemud_save_header header;
virDomainEventPtr event = NULL;
qemuDriverLock(driver);
/* Verify the header and read the XML */
@ -2495,7 +2540,7 @@ static int qemudDomainRestore(virConnectPtr conn,
goto cleanup;
}
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_RESTORED);
@ -2519,6 +2564,8 @@ cleanup:
close(fd);
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
@ -2599,6 +2646,7 @@ static int qemudDomainStart(virDomainPtr dom) {
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
virDomainEventPtr event = NULL;
qemuDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
@ -2612,13 +2660,18 @@ static int qemudDomainStart(virDomainPtr dom) {
ret = qemudStartVMDaemon(dom->conn, driver, vm, NULL);
if (ret != -1)
qemudDomainEventDispatch(driver, vm,
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;
}
@ -2628,6 +2681,7 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
virDomainDefPtr def;
virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL;
virDomainEventPtr event = NULL;
int newVM = 1;
qemuDriverLock(driver);
@ -2657,7 +2711,7 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
goto cleanup;
}
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_DEFINED,
newVM ?
VIR_DOMAIN_EVENT_DEFINED_ADDED :
@ -2669,6 +2723,8 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
cleanup:
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return dom;
}
@ -2676,6 +2732,7 @@ cleanup:
static int qemudDomainUndefine(virDomainPtr dom) {
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
virDomainEventPtr event = NULL;
int ret = -1;
qemuDriverLock(driver);
@ -2702,7 +2759,7 @@ static int qemudDomainUndefine(virDomainPtr dom) {
if (virDomainDeleteConfig(dom->conn, driver->configDir, driver->autostartDir, vm) < 0)
goto cleanup;
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_UNDEFINED,
VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
@ -2714,6 +2771,8 @@ static int qemudDomainUndefine(virDomainPtr dom) {
cleanup:
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
@ -3709,6 +3768,10 @@ qemudDomainEventDeregister (virConnectPtr conn,
int ret;
qemuDriverLock(driver);
if (driver->domainEventDispatching)
ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
callback);
else
ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
callback);
qemuDriverUnlock(driver);
@ -3716,34 +3779,58 @@ qemudDomainEventDeregister (virConnectPtr conn,
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;
struct qemud_driver *driver = opaque;
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);
}
}
/* 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. */
@ -3771,6 +3858,7 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
char hostname [HOST_NAME_MAX+1];
char migrateFrom [64];
const char *p;
virDomainEventPtr event = NULL;
int ret = -1;;
*uri_out = NULL;
@ -3892,7 +3980,8 @@ qemudDomainMigratePrepare2 (virConnectPtr dconn,
}
goto cleanup;
}
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_MIGRATED);
ret = 0;
@ -3904,6 +3993,8 @@ cleanup:
}
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
@ -3920,6 +4011,7 @@ qemudDomainMigratePerform (virDomainPtr dom,
{
struct qemud_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
virDomainEventPtr event = NULL;
char *safe_uri;
char cmd[HOST_NAME_MAX+50];
char *info = NULL;
@ -3946,9 +4038,12 @@ qemudDomainMigratePerform (virDomainPtr dom,
DEBUG ("stop reply: %s", info);
VIR_FREE(info);
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_SUSPENDED,
VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED);
if (event)
qemuDomainEventQueue(driver, event);
event = NULL;
}
if (resource > 0) {
@ -3987,7 +4082,8 @@ qemudDomainMigratePerform (virDomainPtr dom,
/* Clean up the source domain. */
qemudShutdownVMDaemon (dom->conn, driver, vm);
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
if (!vm->persistent) {
@ -4000,6 +4096,8 @@ cleanup:
VIR_FREE(info);
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return ret;
}
@ -4017,6 +4115,7 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
struct qemud_driver *driver = dconn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
virDomainEventPtr event = NULL;
char *info = NULL;
qemuDriverLock(driver);
@ -4034,12 +4133,12 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
VIR_FREE(info);
vm->state = VIR_DOMAIN_RUNNING;
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_RESUMED,
VIR_DOMAIN_EVENT_RESUMED_MIGRATED);
} else {
qemudShutdownVMDaemon (dconn, driver, vm);
qemudDomainEventDispatch(driver, vm,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_FAILED);
if (!vm->persistent) {
@ -4051,6 +4150,8 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
cleanup:
if (vm)
virDomainObjUnlock(vm);
if (event)
qemuDomainEventQueue(driver, event);
qemuDriverUnlock(driver);
return dom;
}

View File

@ -5484,59 +5484,62 @@ remoteRegister (void)
*
* 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;
event = remoteDomainReadEvent(conn, xdr);
if (!event)
return;
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);
}
}
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:
@ -5618,26 +5621,10 @@ remoteDomainEventFired(int watch,
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);
}

View File

@ -92,30 +92,33 @@ struct xenUnifiedDriver xenInotifyDriver = {
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:
@ -123,57 +126,70 @@ xenInotifyXendDomainsDirLookup(virConnectPtr conn, const char *filename) {
*/
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;
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;
static int
xenInotifyDomainLookup(virConnectPtr conn,
const char *filename,
char **name, unsigned char *uuid) {
if (useXenConfigCache)
return xenInotifyXenCacheLookup(filename, name, uuid);
else
dom->id = (info.state == VIR_DOMAIN_SHUTOFF) ? -1 : dom->id;
return dom;
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
@ -215,21 +231,22 @@ xenInotifyXendDomainsDirRemoveEntry(virConnectPtr conn ATTRIBUTE_UNUSED,
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"));
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;
}
@ -260,7 +277,6 @@ xenInotifyEvent(int watch ATTRIBUTE_UNUSED,
char *tmp, *name;
virConnectPtr conn = (virConnectPtr) data;
xenUnifiedPrivatePtr priv = NULL;
virDomainPtr dom = NULL;
DEBUG0("got inotify event");
@ -300,16 +316,15 @@ reread:
snprintf(fname, 1024, "%s/%s", configDir, name);
if (e->mask & (IN_DELETE | IN_MOVED_FROM)) {
if (!(dom = xenInotifyDomainLookup(conn, fname))) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("looking up dom"));
continue;
}
xenUnifiedDomainEventDispatch(conn->privateData, dom,
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"));
if (xenInotifyRemoveDomainConfigInfo(conn, fname) < 0 ) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
@ -317,21 +332,23 @@ reread:
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))) {
virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
"%s", _("looking up dom"));
continue;
}
xenUnifiedDomainEventDispatch(conn->privateData, dom,
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"));
}
}

View File

@ -1583,28 +1583,14 @@ xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr list,
*
*/
void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
virDomainPtr dom,
int event,
int detail)
virDomainEventPtr event)
{
int i;
virDomainEventCallbackListPtr cbList;
if (!priv || !priv->domainEventCallbacks)
return;
if(!priv) return;
cbList = priv->domainEventCallbacks;
if(!cbList) 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);
}

View File

@ -182,9 +182,7 @@ int xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr info,
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__ */

View File

@ -1215,7 +1215,7 @@ retry:
}
if (!found) {
virDomainPtr dom;
virDomainEventPtr event;
char *name;
unsigned char uuid[VIR_UUID_BUFLEN];
@ -1229,22 +1229,16 @@ retry:
continue;
}
dom = virGetDomain(conn, name, uuid);
if (dom) {
dom->id = new_domids[i];
/* This domain was not in the old list. Emit an event */
xenUnifiedDomainEventDispatch(priv, dom,
event = virDomainEventNew(new_domids[i], name, uuid,
VIR_DOMAIN_EVENT_STARTED,
VIR_DOMAIN_EVENT_STARTED_BOOTED);
if (event)
xenUnifiedDomainEventDispatch(priv, event);
/* Add to the list */
xenUnifiedAddDomainInfo(activeDomainList,
new_domids[i], name, uuid);
virUnrefDomain(dom);
}
VIR_FREE(name);
}
}
@ -1299,26 +1293,24 @@ retry:
}
if (!found) {
virDomainPtr dom = virGetDomain(conn,
virDomainEventPtr event =
virDomainEventNew(-1,
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,
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);
virUnrefDomain(dom);
removed = 1;
}
}
}
VIR_FREE(new_domids);