This patch implements the virDomainSaveJob method for the test driver as a proof of concept. First of all it adds a inJob flag to the testDom and testNet objects. This is to make sure that operations which may change an objects run state are rejected, if a background job is active. Then it merely implements the virDomainSaveJob method as per the previous description. Actually it doesn't really do any save operation, this impl just illustrates the way progress updates propagate back to the caller, and the use of cancellation. test.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 3 deletions(-) Dan. diff -r 356d3624723c src/test.c --- a/src/test.c Fri Jan 04 18:22:17 2008 -0500 +++ b/src/test.c Fri Jan 04 18:24:56 2008 -0500 @@ -72,6 +72,28 @@ typedef enum { VIR_DOMAIN_RENAME_RESTART= 4/* restart under an new unique name */ } virDomainRestart; +typedef enum { + TEST_JOB_INACTIVE = 0, + TEST_JOB_DOMAIN_START = 1, + TEST_JOB_DOMAIN_SAVE = 2, + TEST_JOB_DOMAIN_RESTORE = 3, + TEST_JOB_DOMAIN_CORE = 4, + TEST_JOB_NETWORK_START = 5, +} testJobType; + +typedef struct _testJob testJob; +typedef struct _testJob *testJobPtr; + +struct _testJob { + int type; + union { + struct { + int domidx; + char *path; + } save; + } data; +}; + struct _testDev { char name[20]; int mode; @@ -82,6 +104,7 @@ typedef struct _testDev *testDevPtr; #define MAX_DEVICES 10 struct _testDom { + int inJob; int active; int config; int id; @@ -102,6 +125,7 @@ typedef struct _testDom *testDomPtr; typedef struct _testDom *testDomPtr; struct _testNet { + int inJob; int active; int config; int running; @@ -209,6 +233,20 @@ static const virNodeInfo defaultNodeInfo /* To be called after GET_DOMAIN */ #define RELEASE_DOMAIN() \ pthread_mutex_unlock(&privconn->lock) + +#define CHECK_DOMAIN_JOB_INACTIVE(dom, ret) \ + if (privdom->inJob) { \ + testError((dom)->conn, (dom), NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); \ + RELEASE_DOMAIN(); \ + return (ret); \ + } + +#define CHECK_NETWORK_JOB_INACTIVE(net, ret) \ + if (privnet->inJob) { \ + testError((net)->conn, NULL, (net), VIR_ERR_INVALID_ARG, __FUNCTION__); \ + RELEASE_NETWORK(); \ + return (ret); \ + } static void @@ -1234,6 +1272,7 @@ static int testDestroyDomain (virDomainP static int testDestroyDomain (virDomainPtr domain) { GET_DOMAIN(domain, -1); + CHECK_DOMAIN_JOB_INACTIVE(domain, -1); if (privdom->config) { privdom->info.state = VIR_DOMAIN_SHUTOFF; @@ -1249,6 +1288,7 @@ static int testResumeDomain (virDomainPt static int testResumeDomain (virDomainPtr domain) { GET_DOMAIN(domain, -1); + CHECK_DOMAIN_JOB_INACTIVE(domain, -1); if (privdom->info.state != VIR_DOMAIN_PAUSED) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "domain not paused"); @@ -1264,6 +1304,7 @@ static int testPauseDomain (virDomainPtr static int testPauseDomain (virDomainPtr domain) { GET_DOMAIN(domain, -1); + CHECK_DOMAIN_JOB_INACTIVE(domain, -1); if (privdom->info.state == VIR_DOMAIN_SHUTOFF || privdom->info.state == VIR_DOMAIN_PAUSED) { @@ -1280,6 +1321,7 @@ static int testShutdownDomain (virDomain static int testShutdownDomain (virDomainPtr domain) { GET_DOMAIN(domain, -1); + CHECK_DOMAIN_JOB_INACTIVE(domain, -1); if (privdom->info.state == VIR_DOMAIN_SHUTOFF) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "domain not running"); @@ -1298,6 +1340,7 @@ static int testRebootDomain (virDomainPt static int testRebootDomain (virDomainPtr domain, virDomainRestart action) { GET_DOMAIN(domain, -1); + CHECK_DOMAIN_JOB_INACTIVE(domain, -1); if (!action) action = VIR_DOMAIN_RESTART; @@ -1369,6 +1412,7 @@ static int testDomainSave(virDomainPtr d char *xml; int fd, len; GET_DOMAIN(domain, -1); + CHECK_DOMAIN_JOB_INACTIVE(domain, -1); xml = testDomainDumpXMLLocked(domain, privdom, 0); @@ -1418,6 +1462,69 @@ static int testDomainSave(virDomainPtr d return 0; } +static void testDomainSaveWorker(virJobPtr job, void *data) +{ + testJobPtr jobInfo = data; + int countdown = 50; + virJobInitialize(job, countdown); + + do { + sleep(1); + + if (virJobFinishCancel(job)) + return; + + virJobUpdateRel(job, 1, -1, 2); + } while (countdown--); + + if (jobInfo) + jobInfo = jobInfo; + + virJobFinishSuccess(job); +} + +static virJobPtr testDomainSaveJob(virDomainPtr domain, + const char *path) +{ + virJobPtr job; + testJobPtr privjob; + GET_DOMAIN(domain, NULL); + CHECK_DOMAIN_JOB_INACTIVE(domain, NULL); + + privjob = malloc(sizeof(*privjob)); + if (privjob == NULL) { + testError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, "job"); + RELEASE_DOMAIN(); + return (NULL); + } + memset(privjob, 0, sizeof(*privjob)); + + privjob->type = TEST_JOB_DOMAIN_SAVE; + privjob->data.save.domidx = domidx; + privjob->data.save.path = strdup(path); + if (privjob->data.save.path == NULL) { + testError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, "job"); + goto cleanup; + } + + job = virJobCreate(domain->conn, + domain->conn->driver->jobDriver, + testDomainSaveWorker, + NULL, + privjob, + VIR_JOB_BOUNDED); + + RELEASE_DOMAIN(); + + return job; + + cleanup: + if (privjob->data.save.path) free(privjob->data.save.path); + free(privjob); + RELEASE_DOMAIN(); + return (NULL); +} + static int testDomainRestore(virConnectPtr conn, const char *path) @@ -1490,6 +1597,7 @@ static int testDomainCoreDump(virDomainP { int fd; GET_DOMAIN(domain, -1); + CHECK_DOMAIN_JOB_INACTIVE(domain, -1); if ((fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, @@ -1680,6 +1788,7 @@ static virDomainPtr testDomainDefineXML( static int testDomainCreate(virDomainPtr domain) { GET_DOMAIN(domain, -1); + CHECK_DOMAIN_JOB_INACTIVE(domain, -1); if (privdom->info.state != VIR_DOMAIN_SHUTOFF) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, @@ -1697,6 +1806,7 @@ static int testDomainCreate(virDomainPtr static int testDomainUndefine(virDomainPtr domain) { GET_DOMAIN(domain, -1); + CHECK_DOMAIN_JOB_INACTIVE(domain, -1); if (privdom->info.state != VIR_DOMAIN_SHUTOFF) { testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, @@ -1979,6 +2089,7 @@ static virNetworkPtr testNetworkDefine(v static int testNetworkUndefine(virNetworkPtr network) { GET_NETWORK(network, -1); + CHECK_NETWORK_JOB_INACTIVE(network, -1); if (privnet->running) { testError(network->conn, NULL, network, VIR_ERR_INTERNAL_ERROR, @@ -1995,6 +2106,7 @@ static int testNetworkUndefine(virNetwor static int testNetworkStart(virNetworkPtr network) { GET_NETWORK(network, -1); + CHECK_NETWORK_JOB_INACTIVE(network, -1); if (privnet->running) { testError(network->conn, NULL, network, VIR_ERR_INTERNAL_ERROR, @@ -2011,6 +2123,7 @@ static int testNetworkStart(virNetworkPt static int testNetworkDestroy(virNetworkPtr network) { GET_NETWORK(network, -1); + CHECK_NETWORK_JOB_INACTIVE(network, -1); if (privnet->config) { privnet->running = 0; @@ -2098,7 +2211,7 @@ static virDriver testDriver = { VIR_DRV_TEST, "Test", LIBVIR_VERSION_NUMBER, - NULL, /* jobDriver */ + &defaultJobDriver, /* jobDriver */ testOpen, /* open */ testClose, /* close */ NULL, /* supports_feature */ @@ -2127,7 +2240,7 @@ static virDriver testDriver = { testSetMemory, /* domainSetMemory */ testGetDomainInfo, /* domainGetInfo */ testDomainSave, /* domainSave */ - NULL, /* domainSaveJob */ + testDomainSaveJob, /* domainSaveJob */ testDomainRestore, /* domainRestore */ NULL, /* domainRestoreJob */ testDomainCoreDump, /* domainCoreDump */ @@ -2161,7 +2274,7 @@ static virDriver testDriver = { static virNetworkDriver testNetworkDriver = { "Test", - NULL, /* jobDriver */ + &defaultJobDriver, /* jobDriver */ testOpenNetwork, /* open */ testCloseNetwork, /* close */ testNumNetworks, /* numOfNetworks */ -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list