#include "memory.h"
#include "network_conf.h"
#include "domain_conf.h"
+#include "domain_event.h"
+#include "event.h"
#include "storage_conf.h"
#include "xml.h"
#include "threads.h"
+#include "logging.h"
#define VIR_FROM_THIS VIR_FROM_TEST
virStoragePoolObjList pools;
int numCells;
testCell cells[MAX_CELLS];
+
+
+ /* An array of callbacks */
+ virDomainEventCallbackListPtr domainEventCallbacks;
+ virDomainEventQueuePtr domainEventQueue;
+ int domainEventTimer;
+ int domainEventDispatching;
};
typedef struct _testConn testConn;
typedef struct _testConn *testConnPtr;
virReportErrorHelper(conn, VIR_FROM_TEST, code, __FILE__, \
__FUNCTION__, __LINE__, fmt)
+static int testClose(virConnectPtr conn);
+static void testDomainEventFlush(int timer, void *opaque);
+static void testDomainEventQueue(testConnPtr driver,
+ virDomainEventPtr event);
+
+
static void testDriverLock(testConnPtr driver)
{
virMutexLock(&driver->lock);
ret = testOpenFromFile(conn,
conn->uri->path);
+ if (ret == VIR_DRV_OPEN_SUCCESS) {
+ testConnPtr privconn = conn->privateData;
+ /* Init callback list */
+ if (VIR_ALLOC(privconn->domainEventCallbacks) < 0 ||
+ !(privconn->domainEventQueue = virDomainEventQueueNew())) {
+ virReportOOMError(NULL);
+ testClose(conn);
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ if ((privconn->domainEventTimer =
+ virEventAddTimeout(-1, testDomainEventFlush, privconn, NULL)) < 0)
+ DEBUG0("virEventAddTimeout failed: No addTimeoutImpl defined. "
+ "continuing without events.");
+ }
+
return (ret);
}
virDomainObjListFree(&privconn->domains);
virNetworkObjListFree(&privconn->networks);
virStoragePoolObjListFree(&privconn->pools);
+
+ virDomainEventCallbackListFree(privconn->domainEventCallbacks);
+ virDomainEventQueueFree(privconn->domainEventQueue);
+
+ if (privconn->domainEventTimer != -1)
+ virEventRemoveTimeout(privconn->domainEventTimer);
+
testDriverUnlock(privconn);
virMutexDestroy(&privconn->lock);
virDomainPtr ret = NULL;
virDomainDefPtr def;
virDomainObjPtr dom = NULL;
+ virDomainEventPtr event = NULL;
testDriverLock(privconn);
if ((def = virDomainDefParseString(conn, privconn->caps, xml,
dom->state = VIR_DOMAIN_RUNNING;
dom->def->id = privconn->nextDomID++;
+ event = virDomainEventNewFromObj(dom,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
+
ret = virGetDomain(conn, def->name, def->uuid);
if (ret)
ret->id = def->id;
cleanup:
if (dom)
virDomainObjUnlock(dom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
{
testConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
+ virDomainEventPtr event = NULL;
int ret = -1;
testDriverLock(privconn);
privdom->state = VIR_DOMAIN_SHUTOFF;
privdom->def->id = -1;
domain->id = -1;
+ event = virDomainEventNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
if (!privdom->persistent) {
virDomainRemoveInactive(&privconn->domains,
privdom);
privdom = NULL;
}
+
ret = 0;
cleanup:
if (privdom)
virDomainObjUnlock(privdom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
{
testConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
+ virDomainEventPtr event = NULL;
int ret = -1;
testDriverLock(privconn);
}
privdom->state = VIR_DOMAIN_RUNNING;
+ event = virDomainEventNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_RESUMED,
+ VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
ret = 0;
cleanup:
if (privdom)
virDomainObjUnlock(privdom);
+ if (event) {
+ testDriverLock(privconn);
+ testDomainEventQueue(privconn, event);
+ testDriverUnlock(privconn);
+ }
return ret;
}
{
testConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
+ virDomainEventPtr event = NULL;
int ret = -1;
testDriverLock(privconn);
}
privdom->state = VIR_DOMAIN_PAUSED;
+ event = virDomainEventNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_SUSPENDED,
+ VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
ret = 0;
cleanup:
if (privdom)
virDomainObjUnlock(privdom);
+
+ if (event) {
+ testDriverLock(privconn);
+ testDomainEventQueue(privconn, event);
+ testDriverUnlock(privconn);
+ }
return ret;
}
{
testConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
+ virDomainEventPtr event = NULL;
int ret = -1;
testDriverLock(privconn);
privdom->state = VIR_DOMAIN_SHUTOFF;
domain->id = -1;
privdom->def->id = -1;
+ event = virDomainEventNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
if (!privdom->persistent) {
virDomainRemoveInactive(&privconn->domains,
privdom);
cleanup:
if (privdom)
virDomainObjUnlock(privdom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
{
testConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
+ virDomainEventPtr event = NULL;
int ret = -1;
testDriverLock(privconn);
break;
}
- if (privdom->state == VIR_DOMAIN_SHUTOFF && !privdom->persistent) {
- virDomainRemoveInactive(&privconn->domains,
- privdom);
- privdom = NULL;
+ if (privdom->state == VIR_DOMAIN_SHUTOFF) {
+ event = virDomainEventNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
+ if (!privdom->persistent) {
+ virDomainRemoveInactive(&privconn->domains,
+ privdom);
+ privdom = NULL;
+ }
}
ret = 0;
cleanup:
if (privdom)
virDomainObjUnlock(privdom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
int fd = -1;
int len;
virDomainObjPtr privdom;
+ virDomainEventPtr event = NULL;
int ret = -1;
testDriverLock(privconn);
fd = -1;
privdom->state = VIR_DOMAIN_SHUTOFF;
+ event = virDomainEventNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_SAVED);
if (!privdom->persistent) {
virDomainRemoveInactive(&privconn->domains,
privdom);
}
if (privdom)
virDomainObjUnlock(privdom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
int len;
virDomainDefPtr def = NULL;
virDomainObjPtr dom = NULL;
+ virDomainEventPtr event = NULL;
int ret = -1;
if ((fd = open(path, O_RDONLY)) < 0) {
dom->state = VIR_DOMAIN_RUNNING;
dom->def->id = privconn->nextDomID++;
def = NULL;
+ event = virDomainEventNewFromObj(dom,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_RESTORED);
ret = dom->def->id;
cleanup:
close(fd);
if (dom)
virDomainObjUnlock(dom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
testConnPtr privconn = domain->conn->privateData;
int fd = -1;
virDomainObjPtr privdom;
+ virDomainEventPtr event = NULL;
int ret = -1;
testDriverLock(privconn);
goto cleanup;
}
privdom->state = VIR_DOMAIN_SHUTOFF;
+ event = virDomainEventNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STOPPED,
+ VIR_DOMAIN_EVENT_STOPPED_CRASHED);
if (!privdom->persistent) {
virDomainRemoveInactive(&privconn->domains,
privdom);
close(fd);
if (privdom)
virDomainObjUnlock(privdom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
virDomainPtr ret = NULL;
virDomainDefPtr def;
virDomainObjPtr dom = NULL;
+ virDomainEventPtr event = NULL;
testDriverLock(privconn);
if ((def = virDomainDefParseString(conn, privconn->caps, xml,
}
dom->persistent = 1;
dom->def->id = -1;
+ event = virDomainEventNewFromObj(dom,
+ VIR_DOMAIN_EVENT_DEFINED,
+ VIR_DOMAIN_EVENT_DEFINED_ADDED);
ret = virGetDomain(conn, def->name, def->uuid);
def = NULL;
virDomainDefFree(def);
if (dom)
virDomainObjUnlock(dom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
static int testDomainCreate(virDomainPtr domain) {
testConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
+ virDomainEventPtr event = NULL;
int ret = -1;
testDriverLock(privconn);
domain->id = privdom->def->id = privconn->nextDomID++;
privdom->state = VIR_DOMAIN_RUNNING;
+ event = virDomainEventNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_STARTED,
+ VIR_DOMAIN_EVENT_STARTED_BOOTED);
ret = 0;
cleanup:
if (privdom)
virDomainObjUnlock(privdom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
static int testDomainUndefine(virDomainPtr domain) {
testConnPtr privconn = domain->conn->privateData;
virDomainObjPtr privdom;
+ virDomainEventPtr event = NULL;
int ret = -1;
testDriverLock(privconn);
}
privdom->state = VIR_DOMAIN_SHUTOFF;
+ event = virDomainEventNewFromObj(privdom,
+ VIR_DOMAIN_EVENT_UNDEFINED,
+ VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
virDomainRemoveInactive(&privconn->domains,
privdom);
privdom = NULL;
cleanup:
if (privdom)
virDomainObjUnlock(privdom);
+ if (event)
+ testDomainEventQueue(privconn, event);
testDriverUnlock(privconn);
return ret;
}
}
+static int
+testDomainEventRegister (virConnectPtr conn,
+ virConnectDomainEventCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ testConnPtr driver = conn->privateData;
+ int ret;
+
+ testDriverLock(driver);
+ ret = virDomainEventCallbackListAdd(conn, driver->domainEventCallbacks,
+ callback, opaque, freecb);
+ testDriverUnlock(driver);
+
+ return ret;
+}
+
+static int
+testDomainEventDeregister (virConnectPtr conn,
+ virConnectDomainEventCallback callback)
+{
+ testConnPtr driver = conn->privateData;
+ int ret;
+
+ testDriverLock(driver);
+ if (driver->domainEventDispatching)
+ ret = virDomainEventCallbackListMarkDelete(conn, driver->domainEventCallbacks,
+ callback);
+ else
+ ret = virDomainEventCallbackListRemove(conn, driver->domainEventCallbacks,
+ callback);
+ testDriverUnlock(driver);
+
+ return ret;
+}
+
+static void testDomainEventDispatchFunc(virConnectPtr conn,
+ virDomainEventPtr event,
+ virConnectDomainEventCallback cb,
+ void *cbopaque,
+ void *opaque)
+{
+ testConnPtr driver = opaque;
+
+ /* Drop the lock whle dispatching, for sake of re-entrancy */
+ testDriverUnlock(driver);
+ virDomainEventDispatchDefaultFunc(conn, event, cb, cbopaque, NULL);
+ testDriverLock(driver);
+}
+
+static void testDomainEventFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
+{
+ testConnPtr driver = opaque;
+ virDomainEventQueue tempQueue;
+
+ testDriverLock(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,
+ testDomainEventDispatchFunc,
+ driver);
+
+ /* Purge any deleted callbacks */
+ virDomainEventCallbackListPurgeMarked(driver->domainEventCallbacks);
+
+ driver->domainEventDispatching = 0;
+ testDriverUnlock(driver);
+}
+
+
+/* driver must be locked before calling */
+static void testDomainEventQueue(testConnPtr driver,
+ virDomainEventPtr event)
+{
+ if (driver->domainEventTimer < 0) {
+ virDomainEventFree(event);
+ return;
+ }
+
+ if (virDomainEventQueuePush(driver->domainEventQueue,
+ event) < 0)
+ virDomainEventFree(event);
+
+ if (driver->domainEventQueue->count == 1)
+ virEventUpdateTimeout(driver->domainEventTimer, 0);
+}
+
+
static virDriver testDriver = {
VIR_DRV_TEST,
"Test",
NULL, /* domainMemoryPeek */
testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
NULL, /* getFreeMemory */
- NULL, /* domainEventRegister */
- NULL, /* domainEventDeregister */
+ testDomainEventRegister, /* domainEventRegister */
+ testDomainEventDeregister, /* domainEventDeregister */
NULL, /* domainMigratePrepare2 */
NULL, /* domainMigrateFinish2 */
};