From 4b4b61c329534f61512e0ed0c6db7b721c35cabe Mon Sep 17 00:00:00 2001 From: Jim Fehlig Date: Thu, 19 Dec 2013 13:54:39 +0800 Subject: [PATCH] libxl: Add job support to libxl driver Follows the pattern used in the QEMU driver for managing multiple, simultaneous jobs within the driver. Signed-off-by: Jim Fehlig --- src/libxl/libxl_domain.c | 128 +++++++++++++++++++++++++++++++++++++++ src/libxl/libxl_domain.h | 38 ++++++++++++ 2 files changed, 166 insertions(+) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index eb2e50e20b..fdc4661ece 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -30,10 +30,18 @@ #include "virerror.h" #include "virlog.h" #include "virstring.h" +#include "virtime.h" #define VIR_FROM_THIS VIR_FROM_LIBXL +VIR_ENUM_IMPL(libxlDomainJob, LIBXL_JOB_LAST, + "none", + "query", + "destroy", + "modify", +); + /* Object used to store info related to libxl event registrations */ typedef struct _libxlEventHookInfo libxlEventHookInfo; typedef libxlEventHookInfo *libxlEventHookInfoPtr; @@ -284,6 +292,119 @@ static const libxl_osevent_hooks libxl_event_callbacks = { .timeout_deregister = libxlDomainObjTimeoutDeregisterEventHook, }; +static int +libxlDomainObjInitJob(libxlDomainObjPrivatePtr priv) +{ + memset(&priv->job, 0, sizeof(priv->job)); + + if (virCondInit(&priv->job.cond) < 0) + return -1; + + return 0; +} + +static void +libxlDomainObjResetJob(libxlDomainObjPrivatePtr priv) +{ + struct libxlDomainJobObj *job = &priv->job; + + job->active = LIBXL_JOB_NONE; + job->owner = 0; +} + +static void +libxlDomainObjFreeJob(libxlDomainObjPrivatePtr priv) +{ + ignore_value(virCondDestroy(&priv->job.cond)); +} + +/* Give up waiting for mutex after 30 seconds */ +#define LIBXL_JOB_WAIT_TIME (1000ull * 30) + +/* + * obj must be locked before calling, libxlDriverPrivatePtr must NOT be locked + * + * This must be called by anything that will change the VM state + * in any way + * + * Upon successful return, the object will have its ref count increased, + * successful calls must be followed by EndJob eventually + */ +int +libxlDomainObjBeginJob(libxlDriverPrivatePtr driver ATTRIBUTE_UNUSED, + virDomainObjPtr obj, + enum libxlDomainJob job) +{ + libxlDomainObjPrivatePtr priv = obj->privateData; + unsigned long long now; + unsigned long long then; + + if (virTimeMillisNow(&now) < 0) + return -1; + then = now + LIBXL_JOB_WAIT_TIME; + + virObjectRef(obj); + + while (priv->job.active) { + VIR_DEBUG("Wait normal job condition for starting job: %s", + libxlDomainJobTypeToString(job)); + if (virCondWaitUntil(&priv->job.cond, &obj->parent.lock, then) < 0) + goto error; + } + + libxlDomainObjResetJob(priv); + + VIR_DEBUG("Starting job: %s", libxlDomainJobTypeToString(job)); + priv->job.active = job; + priv->job.owner = virThreadSelfID(); + + return 0; + +error: + VIR_WARN("Cannot start job (%s) for domain %s;" + " current job is (%s) owned by (%d)", + libxlDomainJobTypeToString(job), + obj->def->name, + libxlDomainJobTypeToString(priv->job.active), + priv->job.owner); + + if (errno == ETIMEDOUT) + virReportError(VIR_ERR_OPERATION_TIMEOUT, + "%s", _("cannot acquire state change lock")); + else + virReportSystemError(errno, + "%s", _("cannot acquire job mutex")); + + virObjectUnref(obj); + return -1; +} + +/* + * obj must be locked before calling + * + * To be called after completing the work associated with the + * earlier libxlDomainBeginJob() call + * + * Returns true if the remaining reference count on obj is + * non-zero, false if the reference count has dropped to zero + * and obj is disposed. + */ +bool +libxlDomainObjEndJob(libxlDriverPrivatePtr driver ATTRIBUTE_UNUSED, + virDomainObjPtr obj) +{ + libxlDomainObjPrivatePtr priv = obj->privateData; + enum libxlDomainJob job = priv->job.active; + + VIR_DEBUG("Stopping job: %s", + libxlDomainJobTypeToString(job)); + + libxlDomainObjResetJob(priv); + virCondSignal(&priv->job.cond); + + return virObjectUnref(obj); +} + static void * libxlDomainObjPrivateAlloc(void) { @@ -300,6 +421,12 @@ libxlDomainObjPrivateAlloc(void) return NULL; } + if (libxlDomainObjInitJob(priv) < 0) { + virChrdevFree(priv->devs); + virObjectUnref(priv); + return NULL; + } + return priv; } @@ -311,6 +438,7 @@ libxlDomainObjPrivateDispose(void *obj) if (priv->deathW) libxl_evdisable_domain_death(priv->ctx, priv->deathW); + libxlDomainObjFreeJob(priv); virChrdevFree(priv->devs); libxl_ctx_free(priv->ctx); if (priv->logger_file) diff --git a/src/libxl/libxl_domain.h b/src/libxl/libxl_domain.h index 8565820523..0a29d387ba 100644 --- a/src/libxl/libxl_domain.h +++ b/src/libxl/libxl_domain.h @@ -30,6 +30,31 @@ # include "libxl_conf.h" # include "virchrdev.h" +# define JOB_MASK(job) (1 << (job - 1)) +# define DEFAULT_JOB_MASK \ + (JOB_MASK(LIBXL_JOB_DESTROY) | \ + JOB_MASK(LIBXL_JOB_ABORT)) + +/* Only 1 job is allowed at any time + * A job includes *all* libxl.so api, even those just querying + * information, not merely actions */ +enum libxlDomainJob { + LIBXL_JOB_NONE = 0, /* Always set to 0 for easy if (jobActive) conditions */ + LIBXL_JOB_QUERY, /* Doesn't change any state */ + LIBXL_JOB_DESTROY, /* Destroys the domain (cannot be masked out) */ + LIBXL_JOB_MODIFY, /* May change state */ + + LIBXL_JOB_LAST +}; +VIR_ENUM_DECL(libxlDomainJob) + + +struct libxlDomainJobObj { + virCond cond; /* Use to coordinate jobs */ + enum libxlDomainJob active; /* Currently running job */ + int owner; /* Thread which set current job */ +}; + typedef struct _libxlDomainObjPrivate libxlDomainObjPrivate; typedef libxlDomainObjPrivate *libxlDomainObjPrivatePtr; struct _libxlDomainObjPrivate { @@ -43,6 +68,8 @@ struct _libxlDomainObjPrivate { /* console */ virChrdevsPtr devs; libxl_evgen_domain_death *deathW; + + struct libxlDomainJobObj job; }; @@ -53,4 +80,15 @@ extern virDomainDefParserConfig libxlDomainDefParserConfig; int libxlDomainObjPrivateInitCtx(virDomainObjPtr vm); +int +libxlDomainObjBeginJob(libxlDriverPrivatePtr driver, + virDomainObjPtr obj, + enum libxlDomainJob job) + ATTRIBUTE_RETURN_CHECK; + +bool +libxlDomainObjEndJob(libxlDriverPrivatePtr driver, + virDomainObjPtr obj) + ATTRIBUTE_RETURN_CHECK; + #endif /* LIBXL_DOMAIN_H */